aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDavid Woodhouse <dwmw2@shinybook.infradead.org>2005-05-21 16:08:09 -0400
committerDavid Woodhouse <dwmw2@shinybook.infradead.org>2005-05-21 16:08:09 -0400
commitbfb4496e7239c9132d732a65cdcf3d6a7431ad1a (patch)
tree72a2068a1008a66db09ad6eebfdeb490f1a33308
parent7b5d781ce1f19fb7382d3d3fb7af48e429bed12d (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.h7
-rw-r--r--kernel/audit.c46
-rw-r--r--kernel/auditsc.c46
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) */
220extern int audit_receive_filter(int type, int pid, int uid, int seq, 220extern int audit_receive_filter(int type, int pid, int uid, int seq,
221 void *data, uid_t loginuid); 221 void *data, uid_t loginuid);
222extern int audit_get_stamp(struct audit_context *ctx, 222extern unsigned int audit_serial(void);
223 struct timespec *t, unsigned int *serial); 223extern void auditsc_get_stamp(struct audit_context *ctx,
224 struct timespec *t, unsigned int *serial);
224extern int audit_set_loginuid(struct task_struct *task, uid_t loginuid); 225extern int audit_set_loginuid(struct task_struct *task, uid_t loginuid);
225extern uid_t audit_get_loginuid(struct audit_context *ctx); 226extern uid_t audit_get_loginuid(struct audit_context *ctx);
226extern int audit_ipc_perms(unsigned long qbytes, uid_t uid, gid_t gid, mode_t mode); 227extern 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). */
615unsigned 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
630static 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). */
813static 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
1045int audit_get_stamp(struct audit_context *ctx, 1015void 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
1058int audit_set_loginuid(struct task_struct *task, uid_t loginuid) 1024int audit_set_loginuid(struct task_struct *task, uid_t loginuid)