aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-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/**