diff options
author | David Woodhouse <dwmw2@shinybook.infradead.org> | 2005-05-21 16:08:09 -0400 |
---|---|---|
committer | David Woodhouse <dwmw2@shinybook.infradead.org> | 2005-05-21 16:08:09 -0400 |
commit | bfb4496e7239c9132d732a65cdcf3d6a7431ad1a (patch) | |
tree | 72a2068a1008a66db09ad6eebfdeb490f1a33308 | |
parent | 7b5d781ce1f19fb7382d3d3fb7af48e429bed12d (diff) |
AUDIT: Assign serial number to non-syscall messages
Move audit_serial() into audit.c and use it to generate serial numbers
on messages even when there is no audit context from syscall auditing.
This allows us to disambiguate audit records when more than one is
generated in the same millisecond.
Based on a patch by Steve Grubb after he observed the problem.
Signed-off-by: David Woodhouse <dwmw2@infradead.org>
-rw-r--r-- | include/linux/audit.h | 7 | ||||
-rw-r--r-- | kernel/audit.c | 46 | ||||
-rw-r--r-- | kernel/auditsc.c | 46 |
3 files changed, 52 insertions, 47 deletions
diff --git a/include/linux/audit.h b/include/linux/audit.h index 4b7caf0c6e10..3278ddf41ce6 100644 --- a/include/linux/audit.h +++ b/include/linux/audit.h | |||
@@ -219,8 +219,9 @@ extern void audit_inode(const char *name, const struct inode *inode); | |||
219 | /* Private API (for audit.c only) */ | 219 | /* Private API (for audit.c only) */ |
220 | extern int audit_receive_filter(int type, int pid, int uid, int seq, | 220 | extern int audit_receive_filter(int type, int pid, int uid, int seq, |
221 | void *data, uid_t loginuid); | 221 | void *data, uid_t loginuid); |
222 | extern int audit_get_stamp(struct audit_context *ctx, | 222 | extern unsigned int audit_serial(void); |
223 | struct timespec *t, unsigned int *serial); | 223 | extern void auditsc_get_stamp(struct audit_context *ctx, |
224 | struct timespec *t, unsigned int *serial); | ||
224 | extern int audit_set_loginuid(struct task_struct *task, uid_t loginuid); | 225 | extern int audit_set_loginuid(struct task_struct *task, uid_t loginuid); |
225 | extern uid_t audit_get_loginuid(struct audit_context *ctx); | 226 | extern uid_t audit_get_loginuid(struct audit_context *ctx); |
226 | extern int audit_ipc_perms(unsigned long qbytes, uid_t uid, gid_t gid, mode_t mode); | 227 | extern int audit_ipc_perms(unsigned long qbytes, uid_t uid, gid_t gid, mode_t mode); |
@@ -237,7 +238,7 @@ extern void audit_signal_info(int sig, struct task_struct *t); | |||
237 | #define audit_putname(n) do { ; } while (0) | 238 | #define audit_putname(n) do { ; } while (0) |
238 | #define audit_inode(n,i) do { ; } while (0) | 239 | #define audit_inode(n,i) do { ; } while (0) |
239 | #define audit_receive_filter(t,p,u,s,d,l) ({ -EOPNOTSUPP; }) | 240 | #define audit_receive_filter(t,p,u,s,d,l) ({ -EOPNOTSUPP; }) |
240 | #define audit_get_stamp(c,t,s) ({ 0; }) | 241 | #define auditsc_get_stamp(c,t,s) do { BUG(); } while (0) |
241 | #define audit_get_loginuid(c) ({ -1; }) | 242 | #define audit_get_loginuid(c) ({ -1; }) |
242 | #define audit_ipc_perms(q,u,g,m) ({ 0; }) | 243 | #define audit_ipc_perms(q,u,g,m) ({ 0; }) |
243 | #define audit_socketcall(n,a) ({ 0; }) | 244 | #define audit_socketcall(n,a) ({ 0; }) |
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); |
diff --git a/kernel/auditsc.c b/kernel/auditsc.c index 4193811d4fe1..74c2ae804ca8 100644 --- a/kernel/auditsc.c +++ b/kernel/auditsc.c | |||
@@ -795,36 +795,6 @@ void audit_free(struct task_struct *tsk) | |||
795 | audit_free_context(context); | 795 | audit_free_context(context); |
796 | } | 796 | } |
797 | 797 | ||
798 | /* Compute a serial number for the audit record. Audit records are | ||
799 | * written to user-space as soon as they are generated, so a complete | ||
800 | * audit record may be written in several pieces. The timestamp of the | ||
801 | * record and this serial number are used by the user-space tools to | ||
802 | * determine which pieces belong to the same audit record. The | ||
803 | * (timestamp,serial) tuple is unique for each syscall and is live from | ||
804 | * syscall entry to syscall exit. | ||
805 | * | ||
806 | * Atomic values are only guaranteed to be 24-bit, so we count down. | ||
807 | * | ||
808 | * NOTE: Another possibility is to store the formatted records off the | ||
809 | * audit context (for those records that have a context), and emit them | ||
810 | * all at syscall exit. However, this could delay the reporting of | ||
811 | * significant errors until syscall exit (or never, if the system | ||
812 | * halts). */ | ||
813 | static inline unsigned int audit_serial(void) | ||
814 | { | ||
815 | static atomic_t serial = ATOMIC_INIT(0xffffff); | ||
816 | unsigned int a, b; | ||
817 | |||
818 | do { | ||
819 | a = atomic_read(&serial); | ||
820 | if (atomic_dec_and_test(&serial)) | ||
821 | atomic_set(&serial, 0xffffff); | ||
822 | b = atomic_read(&serial); | ||
823 | } while (b != a - 1); | ||
824 | |||
825 | return 0xffffff - b; | ||
826 | } | ||
827 | |||
828 | /* Fill in audit context at syscall entry. This only happens if the | 798 | /* Fill in audit context at syscall entry. This only happens if the |
829 | * audit context was created when the task was created and the state or | 799 | * audit context was created when the task was created and the state or |
830 | * filters demand the audit context be built. If the state from the | 800 | * filters demand the audit context be built. If the state from the |
@@ -1042,17 +1012,13 @@ void audit_inode(const char *name, const struct inode *inode) | |||
1042 | context->names[idx].rdev = inode->i_rdev; | 1012 | context->names[idx].rdev = inode->i_rdev; |
1043 | } | 1013 | } |
1044 | 1014 | ||
1045 | int audit_get_stamp(struct audit_context *ctx, | 1015 | void auditsc_get_stamp(struct audit_context *ctx, |
1046 | struct timespec *t, unsigned int *serial) | 1016 | struct timespec *t, unsigned int *serial) |
1047 | { | 1017 | { |
1048 | if (ctx) { | 1018 | t->tv_sec = ctx->ctime.tv_sec; |
1049 | t->tv_sec = ctx->ctime.tv_sec; | 1019 | t->tv_nsec = ctx->ctime.tv_nsec; |
1050 | t->tv_nsec = ctx->ctime.tv_nsec; | 1020 | *serial = ctx->serial; |
1051 | *serial = ctx->serial; | 1021 | ctx->auditable = 1; |
1052 | ctx->auditable = 1; | ||
1053 | return 1; | ||
1054 | } | ||
1055 | return 0; | ||
1056 | } | 1022 | } |
1057 | 1023 | ||
1058 | int audit_set_loginuid(struct task_struct *task, uid_t loginuid) | 1024 | int audit_set_loginuid(struct task_struct *task, uid_t loginuid) |