ofs | hex dump | ascii |
---|
0000 | 89 50 4e 47 0d 0a 1a 0a 00 00 00 0d 49 48 44 52 00 00 06 51 00 00 03 0a 08 06 00 00 00 15 9b 62 | .PNG........IHDR...Q...........b |
0020 | dc 00 00 00 01 73 52 47 42 00 ae ce 1c e9 00 00 00 09 70 48 59 73 00 00 1e c2 00 00 1e c2 01 6e | .....sRGB.........pHYs.........n |
0040 | d0 75 3e 00 00 02 0b 69 54 58 74 58 4d 4c 3a 63 6f 6d 2e 61 64 6f 62 65 2e 78 6d 70 00 00 00 00 | .u>....iTXtXML:com.adobe.xmp.... |
0060 | 00 3c 78 3a 78 6d 70 6d 65 74 61 20 78 6d 6c 6e 73 3a 78 3d 22 61 64 6f 62 65 3a 6e 73 3a 6d 65 | .<x:xmpmeta.xmlns:x="adobe:ns:me |
0080 | 74 61 2f 22 20 78 3a 78 6d 70 74 6b 3d 22 58 4d 50 20 43 6f 72 65 20 35 2e 34 2e 30 22 3e 0a 20 | ta/".x:xmptk="XMP.Core.5.4.0">.. |
00a0 | 20 20 3c 72 64 66 3a 52 44 46 20 78 6d 6c 6e 73 3a 72 64 66 3d 22 68 74 74 70 3a 2f 2f 77 77 77 | ..<rdf:RDF.xmlns:rdf="http://www |
00c0 | 2e 77 33 2e 6f 72 67 2f 31 39 39 39 2f 30 32 2f 32 32 2d 72 64 66 2d 73 79 6e 74 61 78 2d 6e 73 | .w3.org/1999/02/22-rdf-syntax-ns |
00e0 | 23 22 3e 0a 20 20 20 20 20 20 3c 72 64 66 3a 44 65 73 63 72 69 70 74 69 6f 6e 20 72 64 66 3a 61 | #">.......<rdf:Description.rdf:a |
0100 | 62 6f 75 74 3d 22 22 0a 20 20 20 20 20 20 20 20 20 20 20 20 78 6d 6c 6e 73 3a 74 69 66 66 3d 22 | bout="".............xmlns:tiff=" |
0120 | 68 74 74 70 3a 2f 2f 6e 73 2e 61 64 6f 62 65 2e 63 6f 6d 2f 74 69 66 66 2f 31 2e 30 2f 22 3e 0a | http://ns.adobe.com/tiff/1.0/">. |
0140 | 20 20 20 20 20 20 20 20 20 3c 74 69 66 66 3a 52 65 73 6f 6c 75 74 69 6f 6e 55 6e 69 74 3e 32 3c | .........<tiff:ResolutionUnit>2< |
0160 | 2f 74 69 66 66 3a 52 65 73 6f 6c 75 74 69 6f 6e 55 6e 69 74 3e 0a 20 20 20 20 20 20 20 20 20 3c | /tiff:ResolutionUnit>..........< |
0180 | 74 69 66 66 3a 43 6f 6d 70 72 65 73 73 69 6f 6e 3e 35 3c 2f 74 69 66 66 3a 43 6f 6d 70 72 65 73 | tiff:Compression>5</tiff:Compres |
01a0 | 73 69 6f 6e 3e 0a 20 20 20 20 20 20 20 20 20 3c 74 69 66 66 3a 4f 72 69 65 6e 74 61 74 69 6f 6e | sion>..........<tiff:Orientation |
01c0 | 3e 31 3c 2f 74 69 66 66 3a 4f 72 69 65 6e 74 61 74 69 6f 6e 3e 0a 20 20 20 20 20 20 20 20 20 3c | >1</tiff:Orientation>..........< |
01e0 | 74 69 66 66 3a 50 68 6f 74 6f 6d 65 74 72 69 63 49 6e 74 65 72 70 72 65 74 61 74 69 6f 6e 3e 32 | tiff:PhotometricInterpretation>2 |
0200 | 3c 2f 74 69 66 66 3a 50 68 6f 74 6f 6d 65 74 72 69 63 49 6e 74 65 72 70 72 65 74 61 74 69 6f 6e | </tiff:PhotometricInterpretation |
0220 | 3e 0a 20 20 20 20 20 20 3c 2f 72 64 66 3a 44 65 73 63 72 69 70 74 69 6f 6e 3e 0a 20 20 20 3c 2f | >.......</rdf:Description>....</ |
0240 | 72 64 66 3a 52 44 46 3e 0a 3c 2f 78 3a 78 6d 70 6d 65 74 61 3e 0a 86 d2 ae 24 00 00 40 00 49 44 | rdf:RDF>.</x:xmpmeta>....$..@.ID |
0260 | 41 54 78 01 ec dd 07 bc 14 d5 f9 ff f1 43 47 8a 08 56 9a a2 60 01 15 45 51 51 6c 7f 8d 5d 83 46 | ATx..........CG..V..`..EQQl..].F |
0280 | 63 c5 1a 5b ec 60 89 ed 67 34 0a b6 28 96 88 b1 c4 5e b1 d7 c4 c4 88 0d a3 62 03 b1 61 03 a9 2a | c..[.`..g4..(....^.......b..a..* |
02a0 | 28 28 22 9d ff f3 9d 3b 67 39 0c bb 7b 77 f7 ee 5e ee dd fd 1c 5f cf 9d 33 65 cf 9c 79 ef 78 d9 | (("....;g9..{w..^...._..3e..y.x. |
02c0 | 3b cf 9e 19 e7 28 08 20 80 00 02 08 20 80 00 02 08 20 80 00 02 08 20 80 00 02 08 20 80 00 02 08 | ;....(.......................... |
02e0 | 20 80 00 02 08 20 80 00 02 08 20 80 00 02 08 20 80 00 02 08 20 80 00 02 08 20 80 00 02 08 20 80 | ................................ |
0300 | 00 02 08 20 80 00 02 08 20 80 00 02 08 20 80 00 02 08 20 80 00 02 08 20 80 00 02 08 20 80 00 02 | ................................ |
0320 | 08 20 80 00 02 08 20 80 00 02 08 20 80 00 02 08 20 80 00 02 08 20 80 00 02 08 20 80 00 02 08 20 | ................................ |
0340 | 80 00 02 08 20 80 00 02 08 20 80 00 02 08 20 80 00 02 08 20 80 00 02 08 20 80 00 02 08 20 80 00 | ................................ |
0360 | 02 08 20 80 00 02 08 20 80 00 02 08 20 80 00 02 08 20 80 00 02 08 20 80 00 02 08 20 80 00 02 08 | ................................ |
0380 | 20 80 00 02 08 20 80 00 02 08 20 80 00 02 08 20 80 00 02 08 20 80 00 02 08 20 80 00 02 08 20 80 | ................................ |
03a0 | 00 02 08 20 80 00 02 08 20 80 00 02 08 20 80 00 02 08 20 80 00 02 08 20 80 00 02 08 20 80 00 02 | ................................ |
03c0 | 08 20 80 00 02 08 20 80 00 02 08 20 80 00 02 08 20 80 00 02 08 20 80 00 02 08 20 80 00 02 08 20 | ................................ |
03e0 | 80 00 02 08 20 80 00 02 08 20 80 00 02 08 20 80 00 02 08 20 80 00 02 08 20 80 00 02 08 20 80 00 | ................................ |
0400 | 02 08 20 80 00 02 08 20 80 00 02 08 20 80 00 02 08 20 80 00 02 08 20 80 00 02 08 20 80 00 02 08 | ................................ |
0420 | 20 80 00 02 08 20 80 00 02 08 20 80 00 02 08 20 80 00 02 08 20 80 00 02 08 20 80 00 02 08 20 80 | ................................ |
0440 | 00 02 08 20 80 00 02 08 20 80 00 02 08 20 80 00 02 08 20 80 00 02 08 20 80 00 02 08 20 80 00 02 | ................................ |
0460 | 08 20 80 00 02 08 20 80 00 02 08 20 80 00 02 08 20 80 00 02 08 20 80 00 02 08 20 80 00 02 08 20 | ................................ |
0480 | 80 00 02 08 20 80 00 02 08 20 80 00 02 08 20 80 00 02 08 20 80 00 02 08 20 80 00 02 08 20 80 00 | ................................ |
04a0 | 02 08 20 80 00 02 08 20 80 00 02 08 20 80 00 02 08 20 80 00 02 08 20 80 00 02 08 20 80 00 02 08 | ................................ |
04c0 | 20 80 00 02 08 20 80 00 02 08 20 80 00 02 08 20 80 00 02 08 20 80 00 02 08 20 80 00 02 08 20 80 | ................................ |
04e0 | 00 02 08 20 80 00 02 08 20 80 00 02 08 20 80 00 02 08 20 80 00 02 08 20 80 00 02 08 20 80 00 02 | ................................ |
0500 | 08 20 80 00 02 08 20 80 00 02 08 20 80 00 02 08 20 80 00 02 08 20 80 00 02 08 20 80 00 02 08 20 | ................................ |
0520 | 80 00 02 08 20 80 00 02 08 20 80 00 02 08 20 80 00 02 08 20 80 00 02 08 20 80 00 02 08 20 80 00 | ................................ |
0540 | 02 08 20 80 00 02 08 20 80 00 02 08 20 80 00 02 08 20 80 00 02 08 20 80 00 02 08 20 80 00 02 08 | ................................ |
0560 | 20 80 00 02 08 20 80 00 02 08 20 80 00 02 08 20 80 00 02 08 20 80 00 02 08 20 80 00 02 08 20 80 | ................................ |
0580 | 00 02 08 20 80 00 02 08 20 80 00 02 08 20 80 00 02 08 20 80 00 02 08 20 80 00 02 08 20 80 00 02 | ................................ |
05a0 | 08 20 80 00 02 08 20 80 00 02 08 20 80 00 02 08 20 80 00 02 08 20 80 00 02 08 20 80 00 02 08 20 | ................................ |
05c0 | 80 00 02 08 20 80 00 02 08 20 80 00 02 08 20 80 00 02 08 20 80 00 02 08 20 80 00 02 08 20 80 00 | ................................ |
05e0 | 02 08 20 80 00 02 08 20 80 00 02 08 20 80 00 02 08 20 80 00 02 08 20 80 00 02 08 20 80 00 02 08 | ................................ |
0600 | 20 80 00 02 08 20 80 00 02 08 20 80 00 02 08 20 80 00 02 08 20 80 00 02 08 20 80 00 02 08 20 80 | ................................ |
0620 | 00 02 08 20 80 00 02 08 20 80 00 02 08 20 80 00 02 08 20 80 00 02 08 20 80 00 02 08 20 80 00 02 | ................................ |
0640 | 08 20 80 00 02 08 20 80 00 02 08 20 80 00 02 08 20 80 00 02 08 20 80 00 02 08 20 80 00 02 08 20 | ................................ |
0660 | 80 00 02 08 20 80 00 02 08 20 80 00 02 08 20 80 00 02 08 20 80 00 02 08 20 80 00 02 08 20 80 00 | ................................ |
0680 | 02 08 20 80 00 02 08 20 80 00 02 08 20 80 00 02 08 20 80 00 02 08 20 80 00 02 08 20 80 00 02 08 | ................................ |
06a0 | 20 80 00 02 08 20 80 00 02 08 20 80 00 02 08 20 80 00 02 08 20 80 00 02 08 20 80 00 02 08 20 80 | ................................ |
06c0 | 00 02 08 20 80 00 02 08 20 80 00 02 08 20 80 00 02 08 20 80 00 02 08 20 80 00 02 08 20 80 00 02 | ................................ |
06e0 | 08 20 80 00 02 08 20 80 00 02 08 20 80 00 02 08 20 80 00 02 08 20 80 00 02 08 20 80 00 02 08 20 | ................................ |
0700 | 80 00 02 08 20 80 00 02 08 20 80 00 02 08 20 80 00 02 08 20 80 00 02 08 20 80 00 02 08 20 80 00 | ................................ |
0720 | 02 08 20 80 00 02 08 20 80 00 02 08 20 80 00 02 08 20 80 00 02 08 20 80 00 02 08 20 80 00 02 08 | ................................ |
0740 | 20 80 00 02 08 20 80 00 02 08 20 80 00 02 08 20 80 00 02 08 20 80 00 02 08 20 80 00 02 08 20 80 | ................................ |
0760 | 00 02 08 20 80 00 02 08 20 80 00 02 08 20 80 00 02 08 20 80 00 02 08 20 80 00 02 08 20 80 00 02 | ................................ |
0780 | 08 20 80 00 02 08 20 80 00 02 08 20 80 00 02 08 20 80 00 02 08 20 80 00 02 08 20 80 00 02 08 20 | ................................ |
07a0 | 80 00 02 08 20 80 00 02 08 20 80 00 02 08 20 80 00 02 08 20 80 00 02 08 20 80 00 02 08 20 80 00 | ................................ |
07c0 | 02 08 20 80 00 02 08 20 80 00 02 08 20 80 00 02 08 20 80 00 02 08 20 80 00 02 08 20 80 00 02 08 | ................................ |
07e0 | 20 80 00 02 08 20 80 00 02 08 20 80 00 02 08 20 80 00 02 08 20 80 00 02 08 20 80 00 02 08 20 80 | ................................ |
0800 | 00 02 08 20 80 00 02 08 20 80 00 02 08 20 80 00 02 08 20 80 00 02 08 20 80 00 02 08 20 80 00 02 | ................................ |
0820 | 08 20 80 00 02 08 20 80 00 02 08 20 80 00 02 08 20 80 00 02 08 20 80 00 02 08 20 80 00 02 08 20 | ................................ |
0840 | 80 00 02 08 20 80 00 02 08 20 80 00 02 08 20 80 00 02 08 20 80 00 02 08 20 80 00 02 08 20 80 00 | ................................ |
0860 | 02 08 20 80 00 02 08 20 80 00 02 08 20 80 00 02 08 20 80 00 02 08 20 80 00 02 08 20 80 00 02 08 | ................................ |
0880 | 20 80 00 02 08 20 80 00 02 08 20 80 00 02 08 20 80 00 02 08 20 80 00 02 08 20 80 00 02 08 20 80 | ................................ |
08a0 | 00 02 08 20 80 00 02 08 20 80 00 02 08 20 80 00 02 08 20 80 00 02 08 20 80 00 02 08 20 80 00 02 | ................................ |
08c0 | 08 20 80 00 02 08 20 80 00 02 08 20 80 00 02 08 20 80 00 02 08 20 80 00 02 08 20 80 00 02 08 20 | ................................ |
08e0 | 80 00 02 08 20 80 00 02 08 20 80 00 02 08 20 80 00 02 08 20 80 00 02 08 20 80 00 02 08 20 80 00 | ................................ |
0900 | 02 08 20 80 00 02 08 20 80 00 02 08 20 80 00 02 08 20 80 00 02 08 20 80 00 02 08 20 80 00 02 08 | ................................ |
0920 | 20 80 00 02 08 20 80 00 02 08 20 80 00 02 08 20 80 00 02 08 20 80 00 02 08 20 80 00 02 08 20 80 | ................................ |
0940 | 00 02 08 20 80 00 02 08 20 80 00 02 08 20 80 00 02 08 20 80 00 02 08 20 80 00 02 08 20 80 00 02 | ................................ |
0960 | 08 20 80 00 02 08 20 80 00 02 08 20 80 00 02 08 20 80 00 02 08 20 80 00 02 08 20 80 00 02 08 20 | ................................ |
0980 | 80 00 02 08 20 80 00 02 08 20 80 00 02 08 20 80 00 02 08 20 80 00 02 08 20 80 00 02 08 20 80 00 | ................................ |
09a0 | 02 08 20 80 00 02 08 20 80 00 02 08 20 80 00 02 08 20 80 00 02 08 20 80 00 02 08 20 80 00 02 08 | ................................ |
09c0 | 20 80 00 02 08 20 80 00 02 08 20 80 00 02 08 20 80 00 02 08 20 80 00 02 08 20 80 00 02 08 20 80 | ................................ |
09e0 | 00 02 08 20 80 00 02 08 20 80 00 02 08 20 80 00 02 08 20 80 00 02 08 20 80 00 02 08 20 80 00 02 | ................................ |
0a00 | 08 20 80 00 02 08 20 80 00 02 08 20 80 00 02 08 20 80 00 02 08 20 80 00 02 08 20 80 00 02 08 20 | ................................ |
0a20 | 80 00 02 08 20 80 00 02 08 20 80 00 02 08 20 80 00 02 08 20 80 00 02 08 20 80 00 02 08 20 80 00 | ................................ |
0a40 | 02 08 20 80 00 02 08 20 80 00 02 08 20 80 00 02 08 20 80 00 02 08 20 80 00 02 08 20 80 00 02 08 | ................................ |
0a60 | 20 80 00 02 08 20 80 00 02 08 20 80 00 02 08 20 80 00 02 08 20 80 00 02 08 20 80 00 02 08 20 80 | ................................ |
0a80 | 0/* audit_watch.c -- watching inodes
*
* Copyright 2003-2009 Red Hat, Inc.
* Copyright 2005 Hewlett-Packard Development Company, L.P.
* Copyright 2005 IBM Corporation
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include <linux/file.h>
#include <linux/kernel.h>
#include <linux/audit.h>
#include <linux/kthread.h>
#include <linux/mutex.h>
#include <linux/fs.h>
#include <linux/fsnotify_backend.h>
#include <linux/namei.h>
#include <linux/netlink.h>
#include <linux/sched.h>
#include <linux/slab.h>
#include <linux/security.h>
#include "audit.h"
/*
* Reference counting:
*
* audit_parent: lifetime is from audit_init_parent() to receipt of an FS_IGNORED
* event. Each audit_watch holds a reference to its associated parent.
*
* audit_watch: if added to lists, lifetime is from audit_init_watch() to
* audit_remove_watch(). Additionally, an audit_watch may exist
* temporarily to assist in searching existing filter data. Each
* audit_krule holds a reference to its associated watch.
*/
struct audit_watch {
atomic_t count; /* reference count */
dev_t dev; /* associated superblock device */
char *path; /* insertion path */
unsigned long ino; /* associated inode number */
struct audit_parent *parent; /* associated parent */
struct list_head wlist; /* entry in parent->watches list */
struct list_head rules; /* anchor for krule->rlist */
};
struct audit_parent {
struct list_head watches; /* anchor for audit_watch->wlist */
struct fsnotify_mark mark; /* fsnotify mark on the inode */
};
/* fsnotify handle. */
static struct fsnotify_group *audit_watch_group;
/* fsnotify events we care about. */
#define AUDIT_FS_WATCH (FS_MOVE | FS_CREATE | FS_DELETE | FS_DELETE_SELF |\
FS_MOVE_SELF | FS_EVENT_ON_CHILD)
static void audit_free_parent(struct audit_parent *parent)
{
WARN_ON(!list_empty(&parent->watches));
kfree(parent);
}
static void audit_watch_free_mark(struct fsnotify_mark *entry)
{
struct audit_parent *parent;
parent = container_of(entry, struct audit_parent, mark);
audit_free_parent(parent);
}
static void audit_get_parent(struct audit_parent *parent)
{
if (likely(parent))
fsnotify_get_mark(&parent->mark);
}
static void audit_put_parent(struct audit_parent *parent)
{
if (likely(parent))
fsnotify_put_mark(&parent->mark);
}
/*
* Find and return the audit_parent on the given inode. If found a reference
* is taken on this parent.
*/
static inline struct audit_parent *audit_find_parent(struct inode *inode)
{
struct audit_parent *parent = NULL;
struct fsnotify_mark *entry;
entry = fsnotify_find_inode_mark(audit_watch_group, inode);
if (entry)
parent = container_of(entry, struct audit_parent, mark);
return parent;
}
void audit_get_watch(struct audit_watch *watch)
{
atomic_inc(&watch->count);
}
void audit_put_watch(struct audit_watch *watch)
{
if (atomic_dec_and_test(&watch->count)) {
WARN_ON(watch->parent);
WARN_ON(!list_empty(&watch->rules));
kfree(watch->path);
kfree(watch);
}
}
static void audit_remove_watch(struct audit_watch *watch)
{
list_del(&watch->wlist);
audit_put_parent(watch->parent);
watch->parent = NULL;
audit_put_watch(watch); /* match initial get */
}
char *audit_watch_path(struct audit_watch *watch)
{
return watch->path;
}
int audit_watch_compare(struct audit_watch *watch, unsigned long ino, dev_t dev)
{
return (watch->ino != AUDIT_INO_UNSET) &&
(watch->ino == ino) &&
(watch->dev == dev);
}
/* Initialize a parent watch entry. */
static struct audit_parent *audit_init_parent(struct path *path)
{
struct inode *inode = d_backing_inode(path->dentry);
struct audit_parent *parent;
int ret;
parent = kzalloc(sizeof(*parent), GFP_KERNEL);
if (unlikely(!parent))
return ERR_PTR(-ENOMEM);
INIT_LIST_HEAD(&parent->watches);
fsnotify_init_mark(&parent->mark, audit_watch_free_mark);
parent->mark.mask = AUDIT_FS_WATCH;
ret = fsnotify_add_mark(&parent->mark, audit_watch_group, inode, NULL, 0);
if (ret < 0) {
audit_free_parent(parent);
return ERR_PTR(ret);
}
return parent;
}
/* Initialize a watch entry. */
static struct audit_watch *audit_init_watch(char *path)
{
struct audit_watch *watch;
watch = kzalloc(sizeof(*watch), GFP_KERNEL);
if (unlikely(!watch))
return ERR_PTR(-ENOMEM);
INIT_LIST_HEAD(&watch->rules);
atomic_set(&watch->count, 1);
watch->path = path;
watch->dev = AUDIT_DEV_UNSET;
watch->ino = AUDIT_INO_UNSET;
return watch;
}
/* Translate a watch string to kernel respresentation. */
int audit_to_watch(struct audit_krule *krule, char *path, int len, u32 op)
{
struct audit_watch *watch;
if (!audit_watch_group)
return -EOPNOTSUPP;
if (path[0] != '/' || path[len-1] == '/' ||
krule->listnr != AUDIT_FILTER_EXIT ||
op != Audit_equal ||
krule->inode_f || krule->watch || krule->tree)
return -EINVAL;
watch = audit_init_watch(path);
if (IS_ERR(watch))
return PTR_ERR(watch);
krule->watch = watch;
return 0;
}
/* Duplicate the given audit watch. The new watch's rules list is initialized
* to an empty list and wlist is undefined. */
static struct audit_watch *audit_dupe_watch(struct audit_watch *old)
{
char *path;
struct audit_watch *new;
path = kstrdup(old->path, GFP_KERNEL);
if (unlikely(!path))
return ERR_PTR(-ENOMEM);
new = audit_init_watch(path);
if (IS_ERR(new)) {
kfree(path);
goto out;
}
new->dev = old->dev;
new->ino = old->ino;
audit_get_parent(old->parent);
new->parent = old->parent;
out:
return new;
}
static void audit_watch_log_rule_change(struct audit_krule *r, struct audit_watch *w, char *op)
{
if (audit_enabled) {
struct audit_buffer *ab;
ab = audit_log_start(NULL, GFP_NOFS, AUDIT_CONFIG_CHANGE);
if (unlikely(!ab))
return;
audit_log_format(ab, "auid=%u ses=%u op=",
from_kuid(&init_user_ns, audit_get_loginuid(current)),
audit_get_sessionid(current));
audit_log_string(ab, op);
audit_log_format(ab, " path=");
audit_log_untrustedstring(ab, w->path);
audit_log_key(ab, r->filterkey);
audit_log_format(ab, " list=%d res=1", r->listnr);
audit_log_end(ab);
}
}
/* Update inode info in audit rules based on filesystem event. */
static void audit_update_watch(struct audit_parent *parent,
const char *dname, dev_t dev,
unsigned long ino, unsigned invalidating)
{
struct audit_watch *owatch, *nwatch, *nextw;
struct audit_krule *r, *nextr;
struct audit_entry *oentry, *nentry;
mutex_lock(&audit_filter_mutex);
/* Run all of the watches on this parent looking for the one that
* matches the given dname */
list_for_each_entry_safe(owatch, nextw, &parent->watches, wlist) {
if (audit_compare_dname_path(dname, owatch->path,
AUDIT_NAME_FULL))
continue;
/* If the update involves invalidating rules, do the inode-based
* filtering now, so we don't omit records. */
if (invalidating && !audit_dummy_context())
audit_filter_inodes(current, current->audit_context);
/* updating ino will likely change which audit_hash_list we
* are on so we need a new watch for the new list */
nwatch = audit_dupe_watch(owatch);
if (IS_ERR(nwatch)) {
mutex_unlock(&audit_filter_mutex);
audit_panic("error updating watch, skipping");
return;
}
nwatch->dev = dev;
nwatch->ino = ino;
list_for_each_entry_safe(r, nextr, &owatch->rules, rlist) {
oentry = container_of(r, struct audit_entry, rule);
list_del(&oentry->rule.rlist);
list_del_rcu(&oentry->list);
nentry = audit_dupe_rule(&oentry->rule);
if (IS_ERR(nentry)) {
list_del(&oentry->rule.list);
audit_panic("error updating watch, removing");
} else {
int h = audit_hash_ino((u32)ino);
/*
* nentry->rule.watch == oentry->rule.watch so
* we must drop that reference and set it to our
* new watch.
*/
audit_put_watch(nentry->rule.watch);
audit_get_watch(nwatch);
nentry->rule.watch = nwatch;
list_add(&nentry->rule.rlist, &nwatch->rules);
list_add_rcu(&nentry->list, &audit_inode_hash[h]);
list_replace(&oentry->rule.list,
&nentry->rule.list);
}
if (oentry->rule.exe)
audit_remove_mark(oentry->rule.exe);
audit_watch_log_rule_change(r, owatch, "updated_rules");
call_rcu(&oentry->rcu, audit_free_rule_rcu);
}
audit_remove_watch(owatch);
goto add_watch_to_parent; /* event applies to a single watch */
}
mutex_unlock(&audit_filter_mutex);
return;
add_watch_to_parent:
list_add(&nwatch->wlist, &parent->watches);
mutex_unlock(&audit_filter_mutex);
return;
}
/* Remove all watches & rules associated with a parent that is going away. */
static void audit_remove_parent_watches(struct audit_parent *parent)
{
struct audit_watch *w, *nextw;
struct audit_krule *r, *nextr;
struct audit_entry *e;
mutex_lock(&audit_filter_mutex);
list_for_each_entry_safe(w, nextw, &parent->watches, wlist) {
list_for_each_entry_safe(r, nextr, &w->rules, rlist) {
e = container_of(r, struct audit_entry, rule);
audit_watch_log_rule_change(r, w, "remove_rule");
if (e->rule.exe)
audit_remove_mark(e->rule.exe);
list_del(&r->rlist);
list_del(&r->list);
list_del_rcu(&e->list);
call_rcu(&e->rcu, audit_free_rule_rcu);
}
audit_remove_watch(w);
}
mutex_unlock(&audit_filter_mutex);
fsnotify_destroy_mark(&parent->mark, audit_watch_group);
}
/* Get path information necessary for adding watches. */
static int audit_get_nd(struct audit_watch *watch, struct path *parent)
{
struct dentry *d = kern_path_locked(watch->path, parent);
if (IS_ERR(d))
return PTR_ERR(d);
mutex_unlock(&d_backing_inode(parent->dentry)->i_mutex);
if (d_is_positive(d)) {
/* update watch filter fields */
watch->dev = d_backing_inode(d)->i_sb->s_dev;
watch->ino = d_backing_inode(d)->i_ino;
}
dput(d);
return 0;
}
/* Associate the given rule with an existing parent.
* Caller must hold audit_filter_mutex. */
static void audit_add_to_parent(struct audit_krule *krule,
struct audit_parent *parent)
{
struct audit_watch *w, *watch = krule->watch;
int watch_found = 0;
BUG_ON(!mutex_is_locked(&audit_filter_mutex));
list_for_each_entry(w, &parent->watches, wlist) {
if (strcmp(watch->path, w->path))
continue;
watch_found = 1;
/* put krule's ref to temporary watch */
audit_put_watch(watch);
audit_get_watch(w);
krule->watch = watch = w;
audit_put_parent(parent);
break;
}
if (!watch_found) {
watch->parent = parent;
audit_get_watch(watch);
list_add(&watch->wlist, &parent->watches);
}
list_add(&krule->rlist, &watch->rules);
}
/* Find a matching watch entry, or add this one.
* Caller must hold audit_filter_mutex. */
int audit_add_watch(struct audit_krule *krule, struct list_head **list)
{
struct audit_watch *watch = krule->watch;
struct audit_parent *parent;
struct path parent_path;
int h, ret = 0;
mutex_unlock(&audit_filter_mutex);
/* Avoid calling path_lookup under audit_filter_mutex. */
ret = audit_get_nd(watch, &parent_path);
/* caller expects mutex locked */
mutex_lock(&audit_filter_mutex);
if (ret)
return ret;
/* either find an old parent or attach a new one */
parent = audit_find_parent(d_backing_inode(parent_path.dentry));
if (!parent) {
parent = audit_init_parent(&parent_path);
if (IS_ERR(parent)) {
ret = PTR_ERR(parent);
goto error;
}
}
audit_add_to_parent(krule, parent);
h = audit_hash_ino((u32)watch->ino);
*list = &audit_inode_hash[h];
error:
path_put(&parent_path);
return ret;
}
void audit_remove_watch_rule(struct audit_krule *krule)
{
struct audit_watch *watch = krule->watch;
struct audit_parent *parent = watch->parent;
list_del(&krule->rlist);
if (list_empty(&watch->rules)) {
audit_remove_watch(watch);
if (list_empty(&parent->watches)) {
audit_get_parent(parent);
fsnotify_destroy_mark(&parent->mark, audit_watch_group);
audit_put_parent(parent);
}
}
}
/* Update watch data in audit rules based on fsnotify events. */
static int audit_watch_handle_event(struct fsnotify_group *group,
struct inode *to_tell,
struct fsnotify_mark *inode_mark,
struct fsnotify_mark *vfsmount_mark,
u32 mask, void *data, int data_type,
const unsigned char *dname, u32 cookie)
{
struct inode *inode;
struct audit_parent *parent;
parent = container_of(inode_mark, struct audit_parent, mark);
BUG_ON(group != audit_watch_group);
switch (data_type) {
case (FSNOTIFY_EVENT_PATH):
inode = d_backing_inode(((struct path *)data)->dentry);
break;
case (FSNOTIFY_EVENT_INODE):
inode = (struct inode *)data;
break;
default:
BUG();
inode = NULL;
break;
};
if (mask & (FS_CREATE|FS_MOVED_TO) && inode)
audit_update_watch(parent, dname, inode->i_sb->s_dev, inode->i_ino, 0);
else if (mask & (FS_DELETE|FS_MOVED_FROM))
audit_update_watch(parent, dname, AUDIT_DEV_UNSET, AUDIT_INO_UNSET, 1);
else if (mask & (FS_DELETE_SELF|FS_UNMOUNT|FS_MOVE_SELF))
audit_remove_parent_watches(parent);
return 0;
}
static const struct fsnotify_ops audit_watch_fsnotify_ops = {
.handle_event = audit_watch_handle_event,
};
static int __init audit_watch_init(void)
{
audit_watch_group = fsnotify_alloc_group(&audit_watch_fsnotify_ops);
if (IS_ERR(audit_watch_group)) {
audit_watch_group = NULL;
audit_panic("cannot create audit fsnotify group");
}
return 0;
}
device_initcall(audit_watch_init);
int audit_dupe_exe(struct audit_krule *new, struct audit_krule *old)
{
struct audit_fsnotify_mark *audit_mark;
char *pathname;
pathname = kstrdup(audit_mark_path(old->exe), GFP_KERNEL);
if (!pathname)
return -ENOMEM;
audit_mark = audit_alloc_mark(new, pathname, strlen(pathname));
if (IS_ERR(audit_mark)) {
kfree(pathname);
return PTR_ERR(audit_mark);
}
new->exe = audit_mark;
return 0;
}
int audit_exe_compare(struct task_struct *tsk, struct audit_fsnotify_mark *mark)
{
struct file *exe_file;
unsigned long ino;
dev_t dev;
exe_file = get_task_exe_file(tsk);
if (!exe_file)
return 0;
ino = exe_file->f_inode->i_ino;
dev = exe_file->f_inode->i_sb->s_dev;
fput(exe_file);
return audit_mark_compare(mark, ino, dev);
}
|