diff options
Diffstat (limited to 'kernel/audit.c')
-rw-r--r-- | kernel/audit.c | 46 |
1 files changed, 42 insertions, 4 deletions
diff --git a/kernel/audit.c b/kernel/audit.c index f0a003acf621..35306f4369e7 100644 --- a/kernel/audit.c +++ b/kernel/audit.c | |||
@@ -597,6 +597,47 @@ err: | |||
597 | return NULL; | 597 | return NULL; |
598 | } | 598 | } |
599 | 599 | ||
600 | /* Compute a serial number for the audit record. Audit records are | ||
601 | * written to user-space as soon as they are generated, so a complete | ||
602 | * audit record may be written in several pieces. The timestamp of the | ||
603 | * record and this serial number are used by the user-space tools to | ||
604 | * determine which pieces belong to the same audit record. The | ||
605 | * (timestamp,serial) tuple is unique for each syscall and is live from | ||
606 | * syscall entry to syscall exit. | ||
607 | * | ||
608 | * Atomic values are only guaranteed to be 24-bit, so we count down. | ||
609 | * | ||
610 | * NOTE: Another possibility is to store the formatted records off the | ||
611 | * audit context (for those records that have a context), and emit them | ||
612 | * all at syscall exit. However, this could delay the reporting of | ||
613 | * significant errors until syscall exit (or never, if the system | ||
614 | * halts). */ | ||
615 | unsigned int audit_serial(void) | ||
616 | { | ||
617 | static atomic_t serial = ATOMIC_INIT(0xffffff); | ||
618 | unsigned int a, b; | ||
619 | |||
620 | do { | ||
621 | a = atomic_read(&serial); | ||
622 | if (atomic_dec_and_test(&serial)) | ||
623 | atomic_set(&serial, 0xffffff); | ||
624 | b = atomic_read(&serial); | ||
625 | } while (b != a - 1); | ||
626 | |||
627 | return 0xffffff - b; | ||
628 | } | ||
629 | |||
630 | static inline void audit_get_stamp(struct audit_context *ctx, | ||
631 | struct timespec *t, unsigned int *serial) | ||
632 | { | ||
633 | if (ctx) | ||
634 | auditsc_get_stamp(ctx, t, serial); | ||
635 | else { | ||
636 | *t = CURRENT_TIME; | ||
637 | *serial = audit_serial(); | ||
638 | } | ||
639 | } | ||
640 | |||
600 | /* Obtain an audit buffer. This routine does locking to obtain the | 641 | /* Obtain an audit buffer. This routine does locking to obtain the |
601 | * audit buffer, but then no locking is required for calls to | 642 | * audit buffer, but then no locking is required for calls to |
602 | * audit_log_*format. If the tsk is a task that is currently in a | 643 | * audit_log_*format. If the tsk is a task that is currently in a |
@@ -630,10 +671,7 @@ struct audit_buffer *audit_log_start(struct audit_context *ctx, int type) | |||
630 | return NULL; | 671 | return NULL; |
631 | } | 672 | } |
632 | 673 | ||
633 | if (!audit_get_stamp(ab->ctx, &t, &serial)) { | 674 | audit_get_stamp(ab->ctx, &t, &serial); |
634 | t = CURRENT_TIME; | ||
635 | serial = 0; | ||
636 | } | ||
637 | 675 | ||
638 | audit_log_format(ab, "audit(%lu.%03lu:%u): ", | 676 | audit_log_format(ab, "audit(%lu.%03lu:%u): ", |
639 | t.tv_sec, t.tv_nsec/1000000, serial); | 677 | t.tv_sec, t.tv_nsec/1000000, serial); |