Commit d5b454f2c40c9efd0cc113bc3220ebcb66b7c022
1 parent
351bb72259
Exists in
master
and in
4 other branches
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>
Showing 1 changed file with 10 additions and 11 deletions Side-by-side Diff
kernel/audit.c
... | ... | @@ -610,26 +610,25 @@ |
610 | 610 | * (timestamp,serial) tuple is unique for each syscall and is live from |
611 | 611 | * syscall entry to syscall exit. |
612 | 612 | * |
613 | - * Atomic values are only guaranteed to be 24-bit, so we count down. | |
614 | - * | |
615 | 613 | * NOTE: Another possibility is to store the formatted records off the |
616 | 614 | * audit context (for those records that have a context), and emit them |
617 | 615 | * all at syscall exit. However, this could delay the reporting of |
618 | 616 | * significant errors until syscall exit (or never, if the system |
619 | 617 | * halts). */ |
618 | + | |
620 | 619 | unsigned int audit_serial(void) |
621 | 620 | { |
622 | - static atomic_t serial = ATOMIC_INIT(0xffffff); | |
623 | - unsigned int a, b; | |
621 | + static spinlock_t serial_lock = SPIN_LOCK_UNLOCKED; | |
622 | + static unsigned int serial = 0; | |
624 | 623 | |
625 | - do { | |
626 | - a = atomic_read(&serial); | |
627 | - if (atomic_dec_and_test(&serial)) | |
628 | - atomic_set(&serial, 0xffffff); | |
629 | - b = atomic_read(&serial); | |
630 | - } while (b != a - 1); | |
624 | + unsigned long flags; | |
625 | + unsigned int ret; | |
631 | 626 | |
632 | - return 0xffffff - b; | |
627 | + spin_lock_irqsave(&serial_lock, flags); | |
628 | + ret = serial++; | |
629 | + spin_unlock_irqrestore(&serial_lock, flags); | |
630 | + | |
631 | + return ret; | |
633 | 632 | } |
634 | 633 | |
635 | 634 | static inline void audit_get_stamp(struct audit_context *ctx, |