aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDustin Kirkland <dustin.kirkland@us.ibm.com>2005-11-03 10:41:46 -0500
committerAl Viro <viro@zeniv.linux.org.uk>2006-03-20 14:08:53 -0500
commitb63862f46547487388e582e8ac9083830d34f058 (patch)
tree5aa0173c02535fdd9dfe302e9c8a8a225091ed56
parentb0dd25a8263dde3c30b0d7d72a8bd92d7ba0e3f5 (diff)
[PATCH] Filter rule comparators
Currently, audit only supports the "=" and "!=" operators in the -F filter rules. This patch reworks the support for "=" and "!=", and adds support for ">", ">=", "<", and "<=". This turned out to be a pretty clean, and simply process. I ended up using the high order bits of the "field", as suggested by Steve and Amy. This allowed for no changes whatsoever to the netlink communications. See the documentation within the patch in the include/linux/audit.h area, where there is a table that explains the reasoning of the bitmask assignments clearly. The patch adds a new function, audit_comparator(left, op, right). This function will perform the specified comparison (op, which defaults to "==" for backward compatibility) between two values (left and right). If the negate bit is on, it will negate whatever that result was. This value is returned. Signed-off-by: Dustin Kirkland <dustin.kirkland@us.ibm.com> Signed-off-by: David Woodhouse <dwmw2@infradead.org>
-rw-r--r--include/linux/audit.h29
-rw-r--r--kernel/auditsc.c117
2 files changed, 103 insertions, 43 deletions
diff --git a/include/linux/audit.h b/include/linux/audit.h
index da3c01955f3d..2408cb77899c 100644
--- a/include/linux/audit.h
+++ b/include/linux/audit.h
@@ -98,6 +98,13 @@
98#define AUDIT_WORD(nr) ((__u32)((nr)/32)) 98#define AUDIT_WORD(nr) ((__u32)((nr)/32))
99#define AUDIT_BIT(nr) (1 << ((nr) - AUDIT_WORD(nr)*32)) 99#define AUDIT_BIT(nr) (1 << ((nr) - AUDIT_WORD(nr)*32))
100 100
101/* This bitmask is used to validate user input. It represents all bits that
102 * are currently used in an audit field constant understood by the kernel.
103 * If you are adding a new #define AUDIT_<whatever>, please ensure that
104 * AUDIT_UNUSED_BITS is updated if need be. */
105#define AUDIT_UNUSED_BITS 0x0FFFFC00
106
107
101/* Rule fields */ 108/* Rule fields */
102 /* These are useful when checking the 109 /* These are useful when checking the
103 * task structure at task creation time 110 * task structure at task creation time
@@ -128,8 +135,28 @@
128#define AUDIT_ARG2 (AUDIT_ARG0+2) 135#define AUDIT_ARG2 (AUDIT_ARG0+2)
129#define AUDIT_ARG3 (AUDIT_ARG0+3) 136#define AUDIT_ARG3 (AUDIT_ARG0+3)
130 137
131#define AUDIT_NEGATE 0x80000000 138#define AUDIT_NEGATE 0x80000000
132 139
140/* These are the supported operators.
141 * 4 2 1
142 * = > <
143 * -------
144 * 0 0 0 0 nonsense
145 * 0 0 1 1 <
146 * 0 1 0 2 >
147 * 0 1 1 3 !=
148 * 1 0 0 4 =
149 * 1 0 1 5 <=
150 * 1 1 0 6 >=
151 * 1 1 1 7 all operators
152 */
153#define AUDIT_LESS_THAN 0x10000000
154#define AUDIT_GREATER_THAN 0x20000000
155#define AUDIT_NOT_EQUAL 0x30000000
156#define AUDIT_EQUAL 0x40000000
157#define AUDIT_LESS_THAN_OR_EQUAL (AUDIT_LESS_THAN|AUDIT_EQUAL)
158#define AUDIT_GREATER_THAN_OR_EQUAL (AUDIT_GREATER_THAN|AUDIT_EQUAL)
159#define AUDIT_OPERATORS (AUDIT_EQUAL|AUDIT_NOT_EQUAL)
133 160
134/* Status symbols */ 161/* Status symbols */
135 /* Mask values */ 162 /* Mask values */
diff --git a/kernel/auditsc.c b/kernel/auditsc.c
index 51a4f58a4d81..95076fa12202 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 (C) 2005 IBM Corporation
5 * All Rights Reserved. 6 * All Rights Reserved.
6 * 7 *
7 * This program is free software; you can redistribute it and/or modify 8 * This program is free software; you can redistribute it and/or modify
@@ -27,6 +28,9 @@
27 * this file -- see entry.S) is based on a GPL'd patch written by 28 * this file -- see entry.S) is based on a GPL'd patch written by
28 * okir@suse.de and Copyright 2003 SuSE Linux AG. 29 * okir@suse.de and Copyright 2003 SuSE Linux AG.
29 * 30 *
31 * The support of additional filter rules compares (>, <, >=, <=) was
32 * added by Dustin Kirkland <dustin.kirkland@us.ibm.com>, 2005.
33 *
30 */ 34 */
31 35
32#include <linux/init.h> 36#include <linux/init.h>
@@ -252,6 +256,7 @@ static inline int audit_add_rule(struct audit_rule *rule,
252 struct list_head *list) 256 struct list_head *list)
253{ 257{
254 struct audit_entry *entry; 258 struct audit_entry *entry;
259 int i;
255 260
256 /* Do not use the _rcu iterator here, since this is the only 261 /* Do not use the _rcu iterator here, since this is the only
257 * addition routine. */ 262 * addition routine. */
@@ -261,6 +266,16 @@ static inline int audit_add_rule(struct audit_rule *rule,
261 } 266 }
262 } 267 }
263 268
269 for (i = 0; i < rule->field_count; i++) {
270 if (rule->fields[i] & AUDIT_UNUSED_BITS)
271 return -EINVAL;
272 if ( rule->fields[i] & AUDIT_NEGATE )
273 rule->fields[i] |= AUDIT_NOT_EQUAL;
274 else if ( (rule->fields[i] & AUDIT_OPERATORS) == 0 )
275 rule->fields[i] |= AUDIT_EQUAL;
276 rule->fields[i] &= (~AUDIT_NEGATE);
277 }
278
264 if (!(entry = kmalloc(sizeof(*entry), GFP_KERNEL))) 279 if (!(entry = kmalloc(sizeof(*entry), GFP_KERNEL)))
265 return -ENOMEM; 280 return -ENOMEM;
266 if (audit_copy_rule(&entry->rule, rule)) { 281 if (audit_copy_rule(&entry->rule, rule)) {
@@ -394,6 +409,26 @@ int audit_receive_filter(int type, int pid, int uid, int seq, void *data,
394 return err; 409 return err;
395} 410}
396 411
412static int audit_comparator(const u32 left, const u32 op, const u32 right)
413{
414 switch (op) {
415 case AUDIT_EQUAL:
416 return (left == right);
417 case AUDIT_NOT_EQUAL:
418 return (left != right);
419 case AUDIT_LESS_THAN:
420 return (left < right);
421 case AUDIT_LESS_THAN_OR_EQUAL:
422 return (left <= right);
423 case AUDIT_GREATER_THAN:
424 return (left > right);
425 case AUDIT_GREATER_THAN_OR_EQUAL:
426 return (left >= right);
427 default:
428 return -EINVAL;
429 }
430}
431
397/* Compare a task_struct with an audit_rule. Return 1 on match, 0 432/* Compare a task_struct with an audit_rule. Return 1 on match, 0
398 * otherwise. */ 433 * otherwise. */
399static int audit_filter_rules(struct task_struct *tsk, 434static int audit_filter_rules(struct task_struct *tsk,
@@ -404,62 +439,63 @@ static int audit_filter_rules(struct task_struct *tsk,
404 int i, j; 439 int i, j;
405 440
406 for (i = 0; i < rule->field_count; i++) { 441 for (i = 0; i < rule->field_count; i++) {
407 u32 field = rule->fields[i] & ~AUDIT_NEGATE; 442 u32 field = rule->fields[i] & ~AUDIT_OPERATORS;
443 u32 op = rule->fields[i] & AUDIT_OPERATORS;
408 u32 value = rule->values[i]; 444 u32 value = rule->values[i];
409 int result = 0; 445 int result = 0;
410 446
411 switch (field) { 447 switch (field) {
412 case AUDIT_PID: 448 case AUDIT_PID:
413 result = (tsk->pid == value); 449 result = audit_comparator(tsk->pid, op, value);
414 break; 450 break;
415 case AUDIT_UID: 451 case AUDIT_UID:
416 result = (tsk->uid == value); 452 result = audit_comparator(tsk->uid, op, value);
417 break; 453 break;
418 case AUDIT_EUID: 454 case AUDIT_EUID:
419 result = (tsk->euid == value); 455 result = audit_comparator(tsk->euid, op, value);
420 break; 456 break;
421 case AUDIT_SUID: 457 case AUDIT_SUID:
422 result = (tsk->suid == value); 458 result = audit_comparator(tsk->suid, op, value);
423 break; 459 break;
424 case AUDIT_FSUID: 460 case AUDIT_FSUID:
425 result = (tsk->fsuid == value); 461 result = audit_comparator(tsk->fsuid, op, value);
426 break; 462 break;
427 case AUDIT_GID: 463 case AUDIT_GID:
428 result = (tsk->gid == value); 464 result = audit_comparator(tsk->gid, op, value);
429 break; 465 break;
430 case AUDIT_EGID: 466 case AUDIT_EGID:
431 result = (tsk->egid == value); 467 result = audit_comparator(tsk->egid, op, value);
432 break; 468 break;
433 case AUDIT_SGID: 469 case AUDIT_SGID:
434 result = (tsk->sgid == value); 470 result = audit_comparator(tsk->sgid, op, value);
435 break; 471 break;
436 case AUDIT_FSGID: 472 case AUDIT_FSGID:
437 result = (tsk->fsgid == value); 473 result = audit_comparator(tsk->fsgid, op, value);
438 break; 474 break;
439 case AUDIT_PERS: 475 case AUDIT_PERS:
440 result = (tsk->personality == value); 476 result = audit_comparator(tsk->personality, op, value);
441 break; 477 break;
442 case AUDIT_ARCH: 478 case AUDIT_ARCH:
443 if (ctx) 479 if (ctx)
444 result = (ctx->arch == value); 480 result = audit_comparator(ctx->arch, op, value);
445 break; 481 break;
446 482
447 case AUDIT_EXIT: 483 case AUDIT_EXIT:
448 if (ctx && ctx->return_valid) 484 if (ctx && ctx->return_valid)
449 result = (ctx->return_code == value); 485 result = audit_comparator(ctx->return_code, op, value);
450 break; 486 break;
451 case AUDIT_SUCCESS: 487 case AUDIT_SUCCESS:
452 if (ctx && ctx->return_valid) { 488 if (ctx && ctx->return_valid) {
453 if (value) 489 if (value)
454 result = (ctx->return_valid == AUDITSC_SUCCESS); 490 result = audit_comparator(ctx->return_valid, op, AUDITSC_SUCCESS);
455 else 491 else
456 result = (ctx->return_valid == AUDITSC_FAILURE); 492 result = audit_comparator(ctx->return_valid, op, AUDITSC_FAILURE);
457 } 493 }
458 break; 494 break;
459 case AUDIT_DEVMAJOR: 495 case AUDIT_DEVMAJOR:
460 if (ctx) { 496 if (ctx) {
461 for (j = 0; j < ctx->name_count; j++) { 497 for (j = 0; j < ctx->name_count; j++) {
462 if (MAJOR(ctx->names[j].dev)==value) { 498 if (audit_comparator(MAJOR(ctx->names[j].dev), op, value)) {
463 ++result; 499 ++result;
464 break; 500 break;
465 } 501 }
@@ -469,7 +505,7 @@ static int audit_filter_rules(struct task_struct *tsk,
469 case AUDIT_DEVMINOR: 505 case AUDIT_DEVMINOR:
470 if (ctx) { 506 if (ctx) {
471 for (j = 0; j < ctx->name_count; j++) { 507 for (j = 0; j < ctx->name_count; j++) {
472 if (MINOR(ctx->names[j].dev)==value) { 508 if (audit_comparator(MINOR(ctx->names[j].dev), op, value)) {
473 ++result; 509 ++result;
474 break; 510 break;
475 } 511 }
@@ -479,7 +515,7 @@ static int audit_filter_rules(struct task_struct *tsk,
479 case AUDIT_INODE: 515 case AUDIT_INODE:
480 if (ctx) { 516 if (ctx) {
481 for (j = 0; j < ctx->name_count; j++) { 517 for (j = 0; j < ctx->name_count; j++) {
482 if (ctx->names[j].ino == value) { 518 if (audit_comparator(ctx->names[j].ino, op, value)) {
483 ++result; 519 ++result;
484 break; 520 break;
485 } 521 }
@@ -489,19 +525,17 @@ static int audit_filter_rules(struct task_struct *tsk,
489 case AUDIT_LOGINUID: 525 case AUDIT_LOGINUID:
490 result = 0; 526 result = 0;
491 if (ctx) 527 if (ctx)
492 result = (ctx->loginuid == value); 528 result = audit_comparator(ctx->loginuid, op, value);
493 break; 529 break;
494 case AUDIT_ARG0: 530 case AUDIT_ARG0:
495 case AUDIT_ARG1: 531 case AUDIT_ARG1:
496 case AUDIT_ARG2: 532 case AUDIT_ARG2:
497 case AUDIT_ARG3: 533 case AUDIT_ARG3:
498 if (ctx) 534 if (ctx)
499 result = (ctx->argv[field-AUDIT_ARG0]==value); 535 result = audit_comparator(ctx->argv[field-AUDIT_ARG0], op, value);
500 break; 536 break;
501 } 537 }
502 538
503 if (rule->fields[i] & AUDIT_NEGATE)
504 result = !result;
505 if (!result) 539 if (!result)
506 return 0; 540 return 0;
507 } 541 }
@@ -550,49 +584,48 @@ static enum audit_state audit_filter_syscall(struct task_struct *tsk,
550 584
551 rcu_read_lock(); 585 rcu_read_lock();
552 if (!list_empty(list)) { 586 if (!list_empty(list)) {
553 int word = AUDIT_WORD(ctx->major); 587 int word = AUDIT_WORD(ctx->major);
554 int bit = AUDIT_BIT(ctx->major); 588 int bit = AUDIT_BIT(ctx->major);
555 589
556 list_for_each_entry_rcu(e, list, list) { 590 list_for_each_entry_rcu(e, list, list) {
557 if ((e->rule.mask[word] & bit) == bit 591 if ((e->rule.mask[word] & bit) == bit
558 && audit_filter_rules(tsk, &e->rule, ctx, &state)) { 592 && audit_filter_rules(tsk, &e->rule, ctx, &state)) {
559 rcu_read_unlock(); 593 rcu_read_unlock();
560 return state; 594 return state;
561 } 595 }
562 } 596 }
563 } 597 }
564 rcu_read_unlock(); 598 rcu_read_unlock();
565 return AUDIT_BUILD_CONTEXT; 599 return AUDIT_BUILD_CONTEXT;
566} 600}
567 601
568static int audit_filter_user_rules(struct netlink_skb_parms *cb, 602static int audit_filter_user_rules(struct netlink_skb_parms *cb,
569 struct audit_rule *rule, 603 struct audit_rule *rule,
570 enum audit_state *state) 604 enum audit_state *state)
571{ 605{
572 int i; 606 int i;
573 607
574 for (i = 0; i < rule->field_count; i++) { 608 for (i = 0; i < rule->field_count; i++) {
575 u32 field = rule->fields[i] & ~AUDIT_NEGATE; 609 u32 field = rule->fields[i] & ~AUDIT_OPERATORS;
610 u32 op = rule->fields[i] & AUDIT_OPERATORS;
576 u32 value = rule->values[i]; 611 u32 value = rule->values[i];
577 int result = 0; 612 int result = 0;
578 613
579 switch (field) { 614 switch (field) {
580 case AUDIT_PID: 615 case AUDIT_PID:
581 result = (cb->creds.pid == value); 616 result = audit_comparator(cb->creds.pid, op, value);
582 break; 617 break;
583 case AUDIT_UID: 618 case AUDIT_UID:
584 result = (cb->creds.uid == value); 619 result = audit_comparator(cb->creds.uid, op, value);
585 break; 620 break;
586 case AUDIT_GID: 621 case AUDIT_GID:
587 result = (cb->creds.gid == value); 622 result = audit_comparator(cb->creds.gid, op, value);
588 break; 623 break;
589 case AUDIT_LOGINUID: 624 case AUDIT_LOGINUID:
590 result = (cb->loginuid == value); 625 result = audit_comparator(cb->loginuid, op, value);
591 break; 626 break;
592 } 627 }
593 628
594 if (rule->fields[i] & AUDIT_NEGATE)
595 result = !result;
596 if (!result) 629 if (!result)
597 return 0; 630 return 0;
598 } 631 }