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