aboutsummaryrefslogtreecommitdiffstats
path: root/kernel/auditsc.c
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 /kernel/auditsc.c
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>
Diffstat (limited to 'kernel/auditsc.c')
-rw-r--r--kernel/auditsc.c142
1 files changed, 118 insertions, 24 deletions
diff --git a/kernel/auditsc.c b/kernel/auditsc.c
index 55ba331757c..73f932b7deb 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/**