aboutsummaryrefslogtreecommitdiffstats
path: root/kernel/auditsc.c
diff options
context:
space:
mode:
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 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/**