aboutsummaryrefslogtreecommitdiffstats
path: root/kernel/auditsc.c
diff options
context:
space:
mode:
Diffstat (limited to 'kernel/auditsc.c')
-rw-r--r--kernel/auditsc.c221
1 files changed, 220 insertions, 1 deletions
diff --git a/kernel/auditsc.c b/kernel/auditsc.c
index 8a85c203be12..80ecab0942ef 100644
--- a/kernel/auditsc.c
+++ b/kernel/auditsc.c
@@ -65,6 +65,7 @@
65#include <linux/binfmts.h> 65#include <linux/binfmts.h>
66#include <linux/highmem.h> 66#include <linux/highmem.h>
67#include <linux/syscalls.h> 67#include <linux/syscalls.h>
68#include <linux/inotify.h>
68 69
69#include "audit.h" 70#include "audit.h"
70 71
@@ -179,6 +180,11 @@ struct audit_aux_data_pids {
179 int pid_count; 180 int pid_count;
180}; 181};
181 182
183struct audit_tree_refs {
184 struct audit_tree_refs *next;
185 struct audit_chunk *c[31];
186};
187
182/* The per-task audit context. */ 188/* The per-task audit context. */
183struct audit_context { 189struct audit_context {
184 int dummy; /* must be the first element */ 190 int dummy; /* must be the first element */
@@ -211,6 +217,9 @@ struct audit_context {
211 pid_t target_pid; 217 pid_t target_pid;
212 u32 target_sid; 218 u32 target_sid;
213 219
220 struct audit_tree_refs *trees, *first_trees;
221 int tree_count;
222
214#if AUDIT_DEBUG 223#if AUDIT_DEBUG
215 int put_count; 224 int put_count;
216 int ino_count; 225 int ino_count;
@@ -265,6 +274,117 @@ static int audit_match_perm(struct audit_context *ctx, int mask)
265 } 274 }
266} 275}
267 276
277/*
278 * We keep a linked list of fixed-sized (31 pointer) arrays of audit_chunk *;
279 * ->first_trees points to its beginning, ->trees - to the current end of data.
280 * ->tree_count is the number of free entries in array pointed to by ->trees.
281 * Original condition is (NULL, NULL, 0); as soon as it grows we never revert to NULL,
282 * "empty" becomes (p, p, 31) afterwards. We don't shrink the list (and seriously,
283 * it's going to remain 1-element for almost any setup) until we free context itself.
284 * References in it _are_ dropped - at the same time we free/drop aux stuff.
285 */
286
287#ifdef CONFIG_AUDIT_TREE
288static int put_tree_ref(struct audit_context *ctx, struct audit_chunk *chunk)
289{
290 struct audit_tree_refs *p = ctx->trees;
291 int left = ctx->tree_count;
292 if (likely(left)) {
293 p->c[--left] = chunk;
294 ctx->tree_count = left;
295 return 1;
296 }
297 if (!p)
298 return 0;
299 p = p->next;
300 if (p) {
301 p->c[30] = chunk;
302 ctx->trees = p;
303 ctx->tree_count = 30;
304 return 1;
305 }
306 return 0;
307}
308
309static int grow_tree_refs(struct audit_context *ctx)
310{
311 struct audit_tree_refs *p = ctx->trees;
312 ctx->trees = kzalloc(sizeof(struct audit_tree_refs), GFP_KERNEL);
313 if (!ctx->trees) {
314 ctx->trees = p;
315 return 0;
316 }
317 if (p)
318 p->next = ctx->trees;
319 else
320 ctx->first_trees = ctx->trees;
321 ctx->tree_count = 31;
322 return 1;
323}
324#endif
325
326static void unroll_tree_refs(struct audit_context *ctx,
327 struct audit_tree_refs *p, int count)
328{
329#ifdef CONFIG_AUDIT_TREE
330 struct audit_tree_refs *q;
331 int n;
332 if (!p) {
333 /* we started with empty chain */
334 p = ctx->first_trees;
335 count = 31;
336 /* if the very first allocation has failed, nothing to do */
337 if (!p)
338 return;
339 }
340 n = count;
341 for (q = p; q != ctx->trees; q = q->next, n = 31) {
342 while (n--) {
343 audit_put_chunk(q->c[n]);
344 q->c[n] = NULL;
345 }
346 }
347 while (n-- > ctx->tree_count) {
348 audit_put_chunk(q->c[n]);
349 q->c[n] = NULL;
350 }
351 ctx->trees = p;
352 ctx->tree_count = count;
353#endif
354}
355
356static void free_tree_refs(struct audit_context *ctx)
357{
358 struct audit_tree_refs *p, *q;
359 for (p = ctx->first_trees; p; p = q) {
360 q = p->next;
361 kfree(p);
362 }
363}
364
365static int match_tree_refs(struct audit_context *ctx, struct audit_tree *tree)
366{
367#ifdef CONFIG_AUDIT_TREE
368 struct audit_tree_refs *p;
369 int n;
370 if (!tree)
371 return 0;
372 /* full ones */
373 for (p = ctx->first_trees; p != ctx->trees; p = p->next) {
374 for (n = 0; n < 31; n++)
375 if (audit_tree_match(p->c[n], tree))
376 return 1;
377 }
378 /* partial */
379 if (p) {
380 for (n = ctx->tree_count; n < 31; n++)
381 if (audit_tree_match(p->c[n], tree))
382 return 1;
383 }
384#endif
385 return 0;
386}
387
268/* Determine if any context name data matches a rule's watch data */ 388/* Determine if any context name data matches a rule's watch data */
269/* Compare a task_struct with an audit_rule. Return 1 on match, 0 389/* Compare a task_struct with an audit_rule. Return 1 on match, 0
270 * otherwise. */ 390 * otherwise. */
@@ -379,6 +499,10 @@ static int audit_filter_rules(struct task_struct *tsk,
379 result = (name->dev == rule->watch->dev && 499 result = (name->dev == rule->watch->dev &&
380 name->ino == rule->watch->ino); 500 name->ino == rule->watch->ino);
381 break; 501 break;
502 case AUDIT_DIR:
503 if (ctx)
504 result = match_tree_refs(ctx, rule->tree);
505 break;
382 case AUDIT_LOGINUID: 506 case AUDIT_LOGINUID:
383 result = 0; 507 result = 0;
384 if (ctx) 508 if (ctx)
@@ -727,6 +851,8 @@ static inline void audit_free_context(struct audit_context *context)
727 context->name_count, count); 851 context->name_count, count);
728 } 852 }
729 audit_free_names(context); 853 audit_free_names(context);
854 unroll_tree_refs(context, NULL, 0);
855 free_tree_refs(context);
730 audit_free_aux(context); 856 audit_free_aux(context);
731 kfree(context->filterkey); 857 kfree(context->filterkey);
732 kfree(context); 858 kfree(context);
@@ -1270,6 +1396,7 @@ void audit_syscall_exit(int valid, long return_code)
1270 tsk->audit_context = new_context; 1396 tsk->audit_context = new_context;
1271 } else { 1397 } else {
1272 audit_free_names(context); 1398 audit_free_names(context);
1399 unroll_tree_refs(context, NULL, 0);
1273 audit_free_aux(context); 1400 audit_free_aux(context);
1274 context->aux = NULL; 1401 context->aux = NULL;
1275 context->aux_pids = NULL; 1402 context->aux_pids = NULL;
@@ -1281,6 +1408,95 @@ void audit_syscall_exit(int valid, long return_code)
1281 } 1408 }
1282} 1409}
1283 1410
1411static inline void handle_one(const struct inode *inode)
1412{
1413#ifdef CONFIG_AUDIT_TREE
1414 struct audit_context *context;
1415 struct audit_tree_refs *p;
1416 struct audit_chunk *chunk;
1417 int count;
1418 if (likely(list_empty(&inode->inotify_watches)))
1419 return;
1420 context = current->audit_context;
1421 p = context->trees;
1422 count = context->tree_count;
1423 rcu_read_lock();
1424 chunk = audit_tree_lookup(inode);
1425 rcu_read_unlock();
1426 if (!chunk)
1427 return;
1428 if (likely(put_tree_ref(context, chunk)))
1429 return;
1430 if (unlikely(!grow_tree_refs(context))) {
1431 printk(KERN_WARNING "out of memory, audit has lost a tree reference");
1432 audit_set_auditable(context);
1433 audit_put_chunk(chunk);
1434 unroll_tree_refs(context, p, count);
1435 return;
1436 }
1437 put_tree_ref(context, chunk);
1438#endif
1439}
1440
1441static void handle_path(const struct dentry *dentry)
1442{
1443#ifdef CONFIG_AUDIT_TREE
1444 struct audit_context *context;
1445 struct audit_tree_refs *p;
1446 const struct dentry *d, *parent;
1447 struct audit_chunk *drop;
1448 unsigned long seq;
1449 int count;
1450
1451 context = current->audit_context;
1452 p = context->trees;
1453 count = context->tree_count;
1454retry:
1455 drop = NULL;
1456 d = dentry;
1457 rcu_read_lock();
1458 seq = read_seqbegin(&rename_lock);
1459 for(;;) {
1460 struct inode *inode = d->d_inode;
1461 if (inode && unlikely(!list_empty(&inode->inotify_watches))) {
1462 struct audit_chunk *chunk;
1463 chunk = audit_tree_lookup(inode);
1464 if (chunk) {
1465 if (unlikely(!put_tree_ref(context, chunk))) {
1466 drop = chunk;
1467 break;
1468 }
1469 }
1470 }
1471 parent = d->d_parent;
1472 if (parent == d)
1473 break;
1474 d = parent;
1475 }
1476 if (unlikely(read_seqretry(&rename_lock, seq) || drop)) { /* in this order */
1477 rcu_read_unlock();
1478 if (!drop) {
1479 /* just a race with rename */
1480 unroll_tree_refs(context, p, count);
1481 goto retry;
1482 }
1483 audit_put_chunk(drop);
1484 if (grow_tree_refs(context)) {
1485 /* OK, got more space */
1486 unroll_tree_refs(context, p, count);
1487 goto retry;
1488 }
1489 /* too bad */
1490 printk(KERN_WARNING
1491 "out of memory, audit has lost a tree reference");
1492 unroll_tree_refs(context, p, count);
1493 audit_set_auditable(context);
1494 return;
1495 }
1496 rcu_read_unlock();
1497#endif
1498}
1499
1284/** 1500/**
1285 * audit_getname - add a name to the list 1501 * audit_getname - add a name to the list
1286 * @name: name to add 1502 * @name: name to add
@@ -1407,7 +1623,7 @@ void __audit_inode(const char *name, const struct dentry *dentry)
1407{ 1623{
1408 int idx; 1624 int idx;
1409 struct audit_context *context = current->audit_context; 1625 struct audit_context *context = current->audit_context;
1410 const struct inode *inode = inode = dentry->d_inode; 1626 const struct inode *inode = dentry->d_inode;
1411 1627
1412 if (!context->in_syscall) 1628 if (!context->in_syscall)
1413 return; 1629 return;
@@ -1427,6 +1643,7 @@ void __audit_inode(const char *name, const struct dentry *dentry)
1427 idx = context->name_count - 1; 1643 idx = context->name_count - 1;
1428 context->names[idx].name = NULL; 1644 context->names[idx].name = NULL;
1429 } 1645 }
1646 handle_path(dentry);
1430 audit_copy_inode(&context->names[idx], inode); 1647 audit_copy_inode(&context->names[idx], inode);
1431} 1648}
1432 1649
@@ -1456,6 +1673,8 @@ void __audit_inode_child(const char *dname, const struct dentry *dentry,
1456 if (!context->in_syscall) 1673 if (!context->in_syscall)
1457 return; 1674 return;
1458 1675
1676 if (inode)
1677 handle_one(inode);
1459 /* determine matching parent */ 1678 /* determine matching parent */
1460 if (!dname) 1679 if (!dname)
1461 goto add_names; 1680 goto add_names;