diff options
-rw-r--r-- | include/linux/audit.h | 29 | ||||
-rw-r--r-- | kernel/auditsc.c | 117 |
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 | ||
412 | static 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. */ |
399 | static int audit_filter_rules(struct task_struct *tsk, | 434 | static 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 | ||
568 | static int audit_filter_user_rules(struct netlink_skb_parms *cb, | 602 | static 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 | } |