aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAmy Griffis <amy.griffis@hp.com>2005-11-03 11:00:25 -0500
committerAl Viro <viro@zeniv.linux.org.uk>2006-03-20 14:08:53 -0500
commit73241ccca0f7786933f1d31b3d86f2456549953a (patch)
treedaa7efabfb7aa2f511a467606786820949e8763e
parentf38aa94224c5517a40ba56d453779f70d3229803 (diff)
[PATCH] Collect more inode information during syscall processing.
This patch augments the collection of inode info during syscall processing. It represents part of the functionality that was provided by the auditfs patch included in RHEL4. Specifically, it: - Collects information for target inodes created or removed during syscalls. Previous code only collects information for the target inode's parent. - Adds the audit_inode() hook to syscalls that operate on a file descriptor (e.g. fchown), enabling audit to do inode filtering for these calls. - Modifies filtering code to check audit context for either an inode # or a parent inode # matching a given rule. - Modifies logging to provide inode # for both parent and child. - Protect debug info from NULL audit_names.name. [AV: folded a later typo fix from the same author] Signed-off-by: Amy Griffis <amy.griffis@hp.com> Signed-off-by: David Woodhouse <dwmw2@infradead.org> Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
-rw-r--r--fs/namei.c1
-rw-r--r--fs/open.c8
-rw-r--r--fs/xattr.c11
-rw-r--r--include/linux/audit.h18
-rw-r--r--include/linux/fsnotify.h5
-rw-r--r--kernel/auditsc.c142
6 files changed, 157 insertions, 28 deletions
diff --git a/fs/namei.c b/fs/namei.c
index f6619af9e957..51cfc9c3ed00 100644
--- a/fs/namei.c
+++ b/fs/namei.c
@@ -1353,6 +1353,7 @@ static int may_delete(struct inode *dir,struct dentry *victim,int isdir)
1353 return -ENOENT; 1353 return -ENOENT;
1354 1354
1355 BUG_ON(victim->d_parent->d_inode != dir); 1355 BUG_ON(victim->d_parent->d_inode != dir);
1356 audit_inode_child(victim->d_name.name, victim->d_inode, dir->i_ino);
1356 1357
1357 error = permission(dir,MAY_WRITE | MAY_EXEC, NULL); 1358 error = permission(dir,MAY_WRITE | MAY_EXEC, NULL);
1358 if (error) 1359 if (error)
diff --git a/fs/open.c b/fs/open.c
index 70e0230d8e77..70510004d06e 100644
--- a/fs/open.c
+++ b/fs/open.c
@@ -27,6 +27,7 @@
27#include <linux/pagemap.h> 27#include <linux/pagemap.h>
28#include <linux/syscalls.h> 28#include <linux/syscalls.h>
29#include <linux/rcupdate.h> 29#include <linux/rcupdate.h>
30#include <linux/audit.h>
30 31
31#include <asm/unistd.h> 32#include <asm/unistd.h>
32 33
@@ -626,6 +627,8 @@ asmlinkage long sys_fchmod(unsigned int fd, mode_t mode)
626 dentry = file->f_dentry; 627 dentry = file->f_dentry;
627 inode = dentry->d_inode; 628 inode = dentry->d_inode;
628 629
630 audit_inode(NULL, inode, 0);
631
629 err = -EROFS; 632 err = -EROFS;
630 if (IS_RDONLY(inode)) 633 if (IS_RDONLY(inode))
631 goto out_putf; 634 goto out_putf;
@@ -775,7 +778,10 @@ asmlinkage long sys_fchown(unsigned int fd, uid_t user, gid_t group)
775 778
776 file = fget(fd); 779 file = fget(fd);
777 if (file) { 780 if (file) {
778 error = chown_common(file->f_dentry, user, group); 781 struct dentry * dentry;
782 dentry = file->f_dentry;
783 audit_inode(NULL, dentry->d_inode, 0);
784 error = chown_common(dentry, user, group);
779 fput(file); 785 fput(file);
780 } 786 }
781 return error; 787 return error;
diff --git a/fs/xattr.c b/fs/xattr.c
index 80eca7d3d69f..e416190f5e9c 100644
--- a/fs/xattr.c
+++ b/fs/xattr.c
@@ -17,6 +17,7 @@
17#include <linux/syscalls.h> 17#include <linux/syscalls.h>
18#include <linux/module.h> 18#include <linux/module.h>
19#include <linux/fsnotify.h> 19#include <linux/fsnotify.h>
20#include <linux/audit.h>
20#include <asm/uaccess.h> 21#include <asm/uaccess.h>
21 22
22 23
@@ -234,12 +235,15 @@ sys_fsetxattr(int fd, char __user *name, void __user *value,
234 size_t size, int flags) 235 size_t size, int flags)
235{ 236{
236 struct file *f; 237 struct file *f;
238 struct dentry *dentry;
237 int error = -EBADF; 239 int error = -EBADF;
238 240
239 f = fget(fd); 241 f = fget(fd);
240 if (!f) 242 if (!f)
241 return error; 243 return error;
242 error = setxattr(f->f_dentry, name, value, size, flags); 244 dentry = f->f_dentry;
245 audit_inode(NULL, dentry->d_inode, 0);
246 error = setxattr(dentry, name, value, size, flags);
243 fput(f); 247 fput(f);
244 return error; 248 return error;
245} 249}
@@ -458,12 +462,15 @@ asmlinkage long
458sys_fremovexattr(int fd, char __user *name) 462sys_fremovexattr(int fd, char __user *name)
459{ 463{
460 struct file *f; 464 struct file *f;
465 struct dentry *dentry;
461 int error = -EBADF; 466 int error = -EBADF;
462 467
463 f = fget(fd); 468 f = fget(fd);
464 if (!f) 469 if (!f)
465 return error; 470 return error;
466 error = removexattr(f->f_dentry, name); 471 dentry = f->f_dentry;
472 audit_inode(NULL, dentry->d_inode, 0);
473 error = removexattr(dentry, name);
467 fput(f); 474 fput(f);
468 return error; 475 return error;
469} 476}
diff --git a/include/linux/audit.h b/include/linux/audit.h
index fd65078e794a..739b954cb242 100644
--- a/include/linux/audit.h
+++ b/include/linux/audit.h
@@ -260,7 +260,20 @@ extern void audit_syscall_entry(struct task_struct *task, int arch,
260extern void audit_syscall_exit(struct task_struct *task, int failed, long return_code); 260extern void audit_syscall_exit(struct task_struct *task, int failed, long return_code);
261extern void audit_getname(const char *name); 261extern void audit_getname(const char *name);
262extern void audit_putname(const char *name); 262extern void audit_putname(const char *name);
263extern void audit_inode(const char *name, const struct inode *inode, unsigned flags); 263extern void __audit_inode(const char *name, const struct inode *inode, unsigned flags);
264extern void __audit_inode_child(const char *dname, const struct inode *inode,
265 unsigned long pino);
266static inline void audit_inode(const char *name, const struct inode *inode,
267 unsigned flags) {
268 if (unlikely(current->audit_context))
269 __audit_inode(name, inode, flags);
270}
271static inline void audit_inode_child(const char *dname,
272 const struct inode *inode,
273 unsigned long pino) {
274 if (unlikely(current->audit_context))
275 __audit_inode_child(dname, inode, pino);
276}
264 277
265 /* Private API (for audit.c only) */ 278 /* Private API (for audit.c only) */
266extern int audit_receive_filter(int type, int pid, int uid, int seq, 279extern int audit_receive_filter(int type, int pid, int uid, int seq,
@@ -283,7 +296,10 @@ extern int audit_filter_user(struct netlink_skb_parms *cb, int type);
283#define audit_syscall_exit(t,f,r) do { ; } while (0) 296#define audit_syscall_exit(t,f,r) do { ; } while (0)
284#define audit_getname(n) do { ; } while (0) 297#define audit_getname(n) do { ; } while (0)
285#define audit_putname(n) do { ; } while (0) 298#define audit_putname(n) do { ; } while (0)
299#define __audit_inode(n,i,f) do { ; } while (0)
300#define __audit_inode_child(d,i,p) do { ; } while (0)
286#define audit_inode(n,i,f) do { ; } while (0) 301#define audit_inode(n,i,f) do { ; } while (0)
302#define audit_inode_child(d,i,p) do { ; } while (0)
287#define audit_receive_filter(t,p,u,s,d,l) ({ -EOPNOTSUPP; }) 303#define audit_receive_filter(t,p,u,s,d,l) ({ -EOPNOTSUPP; })
288#define auditsc_get_stamp(c,t,s) do { BUG(); } while (0) 304#define auditsc_get_stamp(c,t,s) do { BUG(); } while (0)
289#define audit_get_loginuid(c) ({ -1; }) 305#define audit_get_loginuid(c) ({ -1; })
diff --git a/include/linux/fsnotify.h b/include/linux/fsnotify.h
index b5ff64d2f092..94919c376a72 100644
--- a/include/linux/fsnotify.h
+++ b/include/linux/fsnotify.h
@@ -15,6 +15,7 @@
15 15
16#include <linux/dnotify.h> 16#include <linux/dnotify.h>
17#include <linux/inotify.h> 17#include <linux/inotify.h>
18#include <linux/audit.h>
18 19
19/* 20/*
20 * fsnotify_move - file old_name at old_dir was moved to new_name at new_dir 21 * fsnotify_move - file old_name at old_dir was moved to new_name at new_dir
@@ -45,6 +46,8 @@ static inline void fsnotify_move(struct inode *old_dir, struct inode *new_dir,
45 if (source) { 46 if (source) {
46 inotify_inode_queue_event(source, IN_MOVE_SELF, 0, NULL); 47 inotify_inode_queue_event(source, IN_MOVE_SELF, 0, NULL);
47 } 48 }
49 audit_inode_child(old_name, source, old_dir->i_ino);
50 audit_inode_child(new_name, target, new_dir->i_ino);
48} 51}
49 52
50/* 53/*
@@ -74,6 +77,7 @@ static inline void fsnotify_create(struct inode *inode, struct dentry *dentry)
74{ 77{
75 inode_dir_notify(inode, DN_CREATE); 78 inode_dir_notify(inode, DN_CREATE);
76 inotify_inode_queue_event(inode, IN_CREATE, 0, dentry->d_name.name); 79 inotify_inode_queue_event(inode, IN_CREATE, 0, dentry->d_name.name);
80 audit_inode_child(dentry->d_name.name, dentry->d_inode, inode->i_ino);
77} 81}
78 82
79/* 83/*
@@ -84,6 +88,7 @@ static inline void fsnotify_mkdir(struct inode *inode, struct dentry *dentry)
84 inode_dir_notify(inode, DN_CREATE); 88 inode_dir_notify(inode, DN_CREATE);
85 inotify_inode_queue_event(inode, IN_CREATE | IN_ISDIR, 0, 89 inotify_inode_queue_event(inode, IN_CREATE | IN_ISDIR, 0,
86 dentry->d_name.name); 90 dentry->d_name.name);
91 audit_inode_child(dentry->d_name.name, dentry->d_inode, inode->i_ino);
87} 92}
88 93
89/* 94/*
diff --git a/kernel/auditsc.c b/kernel/auditsc.c
index 55ba331757c5..73f932b7deb6 100644
--- a/kernel/auditsc.c
+++ b/kernel/auditsc.c
@@ -2,6 +2,7 @@
2 * Handles all system-call specific auditing features. 2 * Handles all system-call specific auditing features.
3 * 3 *
4 * Copyright 2003-2004 Red Hat Inc., Durham, North Carolina. 4 * Copyright 2003-2004 Red Hat Inc., Durham, North Carolina.
5 * Copyright 2005 Hewlett-Packard Development Company, L.P.
5 * Copyright (C) 2005 IBM Corporation 6 * Copyright (C) 2005 IBM Corporation
6 * All Rights Reserved. 7 * All Rights Reserved.
7 * 8 *
@@ -31,11 +32,16 @@
31 * The support of additional filter rules compares (>, <, >=, <=) was 32 * The support of additional filter rules compares (>, <, >=, <=) was
32 * added by Dustin Kirkland <dustin.kirkland@us.ibm.com>, 2005. 33 * added by Dustin Kirkland <dustin.kirkland@us.ibm.com>, 2005.
33 * 34 *
35 * Modified by Amy Griffis <amy.griffis@hp.com> to collect additional
36 * filesystem information.
34 */ 37 */
35 38
36#include <linux/init.h> 39#include <linux/init.h>
37#include <asm/types.h> 40#include <asm/types.h>
38#include <asm/atomic.h> 41#include <asm/atomic.h>
42#include <asm/types.h>
43#include <linux/fs.h>
44#include <linux/namei.h>
39#include <linux/mm.h> 45#include <linux/mm.h>
40#include <linux/module.h> 46#include <linux/module.h>
41#include <linux/mount.h> 47#include <linux/mount.h>
@@ -97,12 +103,12 @@ enum audit_state {
97struct audit_names { 103struct audit_names {
98 const char *name; 104 const char *name;
99 unsigned long ino; 105 unsigned long ino;
106 unsigned long pino;
100 dev_t dev; 107 dev_t dev;
101 umode_t mode; 108 umode_t mode;
102 uid_t uid; 109 uid_t uid;
103 gid_t gid; 110 gid_t gid;
104 dev_t rdev; 111 dev_t rdev;
105 unsigned flags;
106}; 112};
107 113
108struct audit_aux_data { 114struct audit_aux_data {
@@ -515,7 +521,8 @@ static int audit_filter_rules(struct task_struct *tsk,
515 case AUDIT_INODE: 521 case AUDIT_INODE:
516 if (ctx) { 522 if (ctx) {
517 for (j = 0; j < ctx->name_count; j++) { 523 for (j = 0; j < ctx->name_count; j++) {
518 if ( audit_comparator(ctx->names[j].ino, op, value)) { 524 if (audit_comparator(ctx->names[j].ino, op, value) ||
525 audit_comparator(ctx->names[j].pino, op, value)) {
519 ++result; 526 ++result;
520 break; 527 break;
521 } 528 }
@@ -696,17 +703,17 @@ static inline void audit_free_names(struct audit_context *context)
696#if AUDIT_DEBUG == 2 703#if AUDIT_DEBUG == 2
697 if (context->auditable 704 if (context->auditable
698 ||context->put_count + context->ino_count != context->name_count) { 705 ||context->put_count + context->ino_count != context->name_count) {
699 printk(KERN_ERR "audit.c:%d(:%d): major=%d in_syscall=%d" 706 printk(KERN_ERR "%s:%d(:%d): major=%d in_syscall=%d"
700 " name_count=%d put_count=%d" 707 " name_count=%d put_count=%d"
701 " ino_count=%d [NOT freeing]\n", 708 " ino_count=%d [NOT freeing]\n",
702 __LINE__, 709 __FILE__, __LINE__,
703 context->serial, context->major, context->in_syscall, 710 context->serial, context->major, context->in_syscall,
704 context->name_count, context->put_count, 711 context->name_count, context->put_count,
705 context->ino_count); 712 context->ino_count);
706 for (i = 0; i < context->name_count; i++) 713 for (i = 0; i < context->name_count; i++)
707 printk(KERN_ERR "names[%d] = %p = %s\n", i, 714 printk(KERN_ERR "names[%d] = %p = %s\n", i,
708 context->names[i].name, 715 context->names[i].name,
709 context->names[i].name); 716 context->names[i].name ?: "(null)");
710 dump_stack(); 717 dump_stack();
711 return; 718 return;
712 } 719 }
@@ -932,27 +939,34 @@ static void audit_log_exit(struct audit_context *context, gfp_t gfp_mask)
932 } 939 }
933 } 940 }
934 for (i = 0; i < context->name_count; i++) { 941 for (i = 0; i < context->name_count; i++) {
942 unsigned long ino = context->names[i].ino;
943 unsigned long pino = context->names[i].pino;
944
935 ab = audit_log_start(context, gfp_mask, AUDIT_PATH); 945 ab = audit_log_start(context, gfp_mask, AUDIT_PATH);
936 if (!ab) 946 if (!ab)
937 continue; /* audit_panic has been called */ 947 continue; /* audit_panic has been called */
938 948
939 audit_log_format(ab, "item=%d", i); 949 audit_log_format(ab, "item=%d", i);
940 if (context->names[i].name) { 950
941 audit_log_format(ab, " name="); 951 audit_log_format(ab, " name=");
952 if (context->names[i].name)
942 audit_log_untrustedstring(ab, context->names[i].name); 953 audit_log_untrustedstring(ab, context->names[i].name);
943 } 954 else
944 audit_log_format(ab, " flags=%x\n", context->names[i].flags); 955 audit_log_format(ab, "(null)");
945 956
946 if (context->names[i].ino != (unsigned long)-1) 957 if (pino != (unsigned long)-1)
947 audit_log_format(ab, " inode=%lu dev=%02x:%02x mode=%#o" 958 audit_log_format(ab, " parent=%lu", pino);
948 " ouid=%u ogid=%u rdev=%02x:%02x", 959 if (ino != (unsigned long)-1)
949 context->names[i].ino, 960 audit_log_format(ab, " inode=%lu", ino);
950 MAJOR(context->names[i].dev), 961 if ((pino != (unsigned long)-1) || (ino != (unsigned long)-1))
951 MINOR(context->names[i].dev), 962 audit_log_format(ab, " dev=%02x:%02x mode=%#o"
952 context->names[i].mode, 963 " ouid=%u ogid=%u rdev=%02x:%02x",
953 context->names[i].uid, 964 MAJOR(context->names[i].dev),
954 context->names[i].gid, 965 MINOR(context->names[i].dev),
955 MAJOR(context->names[i].rdev), 966 context->names[i].mode,
967 context->names[i].uid,
968 context->names[i].gid,
969 MAJOR(context->names[i].rdev),
956 MINOR(context->names[i].rdev)); 970 MINOR(context->names[i].rdev));
957 audit_log_end(ab); 971 audit_log_end(ab);
958 } 972 }
@@ -1174,7 +1188,7 @@ void audit_putname(const char *name)
1174 for (i = 0; i < context->name_count; i++) 1188 for (i = 0; i < context->name_count; i++)
1175 printk(KERN_ERR "name[%d] = %p = %s\n", i, 1189 printk(KERN_ERR "name[%d] = %p = %s\n", i,
1176 context->names[i].name, 1190 context->names[i].name,
1177 context->names[i].name); 1191 context->names[i].name ?: "(null)");
1178 } 1192 }
1179#endif 1193#endif
1180 __putname(name); 1194 __putname(name);
@@ -1204,7 +1218,7 @@ void audit_putname(const char *name)
1204 * 1218 *
1205 * Called from fs/namei.c:path_lookup(). 1219 * Called from fs/namei.c:path_lookup().
1206 */ 1220 */
1207void audit_inode(const char *name, const struct inode *inode, unsigned flags) 1221void __audit_inode(const char *name, const struct inode *inode, unsigned flags)
1208{ 1222{
1209 int idx; 1223 int idx;
1210 struct audit_context *context = current->audit_context; 1224 struct audit_context *context = current->audit_context;
@@ -1230,13 +1244,93 @@ void audit_inode(const char *name, const struct inode *inode, unsigned flags)
1230 ++context->ino_count; 1244 ++context->ino_count;
1231#endif 1245#endif
1232 } 1246 }
1233 context->names[idx].flags = flags;
1234 context->names[idx].ino = inode->i_ino;
1235 context->names[idx].dev = inode->i_sb->s_dev; 1247 context->names[idx].dev = inode->i_sb->s_dev;
1236 context->names[idx].mode = inode->i_mode; 1248 context->names[idx].mode = inode->i_mode;
1237 context->names[idx].uid = inode->i_uid; 1249 context->names[idx].uid = inode->i_uid;
1238 context->names[idx].gid = inode->i_gid; 1250 context->names[idx].gid = inode->i_gid;
1239 context->names[idx].rdev = inode->i_rdev; 1251 context->names[idx].rdev = inode->i_rdev;
1252 if ((flags & LOOKUP_PARENT) && (strcmp(name, "/") != 0) &&
1253 (strcmp(name, ".") != 0)) {
1254 context->names[idx].ino = (unsigned long)-1;
1255 context->names[idx].pino = inode->i_ino;
1256 } else {
1257 context->names[idx].ino = inode->i_ino;
1258 context->names[idx].pino = (unsigned long)-1;
1259 }
1260}
1261
1262/**
1263 * audit_inode_child - collect inode info for created/removed objects
1264 * @dname: inode's dentry name
1265 * @inode: inode being audited
1266 * @pino: inode number of dentry parent
1267 *
1268 * For syscalls that create or remove filesystem objects, audit_inode
1269 * can only collect information for the filesystem object's parent.
1270 * This call updates the audit context with the child's information.
1271 * Syscalls that create a new filesystem object must be hooked after
1272 * the object is created. Syscalls that remove a filesystem object
1273 * must be hooked prior, in order to capture the target inode during
1274 * unsuccessful attempts.
1275 */
1276void __audit_inode_child(const char *dname, const struct inode *inode,
1277 unsigned long pino)
1278{
1279 int idx;
1280 struct audit_context *context = current->audit_context;
1281
1282 if (!context->in_syscall)
1283 return;
1284
1285 /* determine matching parent */
1286 if (dname)
1287 for (idx = 0; idx < context->name_count; idx++)
1288 if (context->names[idx].pino == pino) {
1289 const char *n;
1290 const char *name = context->names[idx].name;
1291 int dlen = strlen(dname);
1292 int nlen = name ? strlen(name) : 0;
1293
1294 if (nlen < dlen)
1295 continue;
1296
1297 /* disregard trailing slashes */
1298 n = name + nlen - 1;
1299 while ((*n == '/') && (n > name))
1300 n--;
1301
1302 /* find last path component */
1303 n = n - dlen + 1;
1304 if (n < name)
1305 continue;
1306 else if (n > name) {
1307 if (*--n != '/')
1308 continue;
1309 else
1310 n++;
1311 }
1312
1313 if (strncmp(n, dname, dlen) == 0)
1314 goto update_context;
1315 }
1316
1317 /* catch-all in case match not found */
1318 idx = context->name_count++;
1319 context->names[idx].name = NULL;
1320 context->names[idx].pino = pino;
1321#if AUDIT_DEBUG
1322 context->ino_count++;
1323#endif
1324
1325update_context:
1326 if (inode) {
1327 context->names[idx].ino = inode->i_ino;
1328 context->names[idx].dev = inode->i_sb->s_dev;
1329 context->names[idx].mode = inode->i_mode;
1330 context->names[idx].uid = inode->i_uid;
1331 context->names[idx].gid = inode->i_gid;
1332 context->names[idx].rdev = inode->i_rdev;
1333 }
1240} 1334}
1241 1335
1242/** 1336/**