summaryrefslogtreecommitdiffstats
path: root/kernel/audit.c
diff options
context:
space:
mode:
authorDavid Woodhouse <dwmw2@shinybook.infradead.org>2005-07-15 13:56:03 +0200
committerDavid Woodhouse <dwmw2@shinybook.infradead.org>2005-07-15 13:56:03 +0200
commitd5b454f2c40c9efd0cc113bc3220ebcb66b7c022 (patch)
treea8aaa30e003c9dcc07840c217760f92e4fab430a /kernel/audit.c
parentAUDIT: Fix compile error in audit_filter_syscall (diff)
downloadlinux-d5b454f2c40c9efd0cc113bc3220ebcb66b7c022.tar.xz
linux-d5b454f2c40c9efd0cc113bc3220ebcb66b7c022.zip
AUDIT: Fix livelock in audit_serial().
The tricks with atomic_t were bizarre. Just do it sensibly instead. Signed-off-by: David Woodhouse <dwmw2@infradead.org>
Diffstat (limited to 'kernel/audit.c')
-rw-r--r--kernel/audit.c21
1 files changed, 10 insertions, 11 deletions
diff --git a/kernel/audit.c b/kernel/audit.c
index 518a833b676a..27ffcf363f8d 100644
--- a/kernel/audit.c
+++ b/kernel/audit.c
@@ -610,26 +610,25 @@ err:
* (timestamp,serial) tuple is unique for each syscall and is live from
* syscall entry to syscall exit.
*
- * Atomic values are only guaranteed to be 24-bit, so we count down.
- *
* NOTE: Another possibility is to store the formatted records off the
* audit context (for those records that have a context), and emit them
* all at syscall exit. However, this could delay the reporting of
* significant errors until syscall exit (or never, if the system
* halts). */
+
unsigned int audit_serial(void)
{
- static atomic_t serial = ATOMIC_INIT(0xffffff);
- unsigned int a, b;
+ static spinlock_t serial_lock = SPIN_LOCK_UNLOCKED;
+ static unsigned int serial = 0;
+
+ unsigned long flags;
+ unsigned int ret;
- do {
- a = atomic_read(&serial);
- if (atomic_dec_and_test(&serial))
- atomic_set(&serial, 0xffffff);
- b = atomic_read(&serial);
- } while (b != a - 1);
+ spin_lock_irqsave(&serial_lock, flags);
+ ret = serial++;
+ spin_unlock_irqrestore(&serial_lock, flags);
- return 0xffffff - b;
+ return ret;
}
static inline void audit_get_stamp(struct audit_context *ctx,