diff options
Diffstat (limited to 'kernel')
-rw-r--r-- | kernel/audit.c | 6 | ||||
-rw-r--r-- | kernel/audit.h | 1 | ||||
-rw-r--r-- | kernel/auditfilter.c | 37 | ||||
-rw-r--r-- | kernel/auditsc.c | 51 | ||||
-rw-r--r-- | kernel/futex.c | 84 | ||||
-rw-r--r-- | kernel/panic.c | 2 | ||||
-rw-r--r-- | kernel/power/Kconfig | 6 | ||||
-rw-r--r-- | kernel/spinlock.c | 2 |
8 files changed, 108 insertions, 81 deletions
diff --git a/kernel/audit.c b/kernel/audit.c index 0a36091e..963fd15 100644 --- a/kernel/audit.c +++ b/kernel/audit.c @@ -1028,6 +1028,9 @@ void audit_log_hex(struct audit_buffer *ab, const unsigned char *buf, struct sk_buff *skb; static const unsigned char *hex = "0123456789ABCDEF"; + if (!ab) + return; + BUG_ON(!ab->skb); skb = ab->skb; avail = skb_tailroom(skb); @@ -1060,6 +1063,9 @@ static void audit_log_n_string(struct audit_buffer *ab, size_t slen, unsigned char *ptr; struct sk_buff *skb; + if (!ab) + return; + BUG_ON(!ab->skb); skb = ab->skb; avail = skb_tailroom(skb); diff --git a/kernel/audit.h b/kernel/audit.h index 6aa33b8..a337023 100644 --- a/kernel/audit.h +++ b/kernel/audit.h @@ -104,6 +104,7 @@ static inline int audit_hash_ino(u32 ino) return (ino & (AUDIT_INODE_BUCKETS-1)); } +extern int audit_match_class(int class, unsigned syscall); extern int audit_comparator(const u32 left, const u32 op, const u32 right); extern int audit_compare_dname_path(const char *dname, const char *path, int *dirlen); diff --git a/kernel/auditfilter.c b/kernel/auditfilter.c index 6a9a5c5a..a44879b 100644 --- a/kernel/auditfilter.c +++ b/kernel/auditfilter.c @@ -302,6 +302,15 @@ int __init audit_register_class(int class, unsigned *list) return 0; } +int audit_match_class(int class, unsigned syscall) +{ + if (unlikely(syscall >= AUDIT_BITMASK_SIZE * sizeof(__u32))) + return 0; + if (unlikely(class >= AUDIT_SYSCALL_CLASSES || !classes[class])) + return 0; + return classes[class][AUDIT_WORD(syscall)] & AUDIT_BIT(syscall); +} + /* Common user-space to kernel rule translation. */ static inline struct audit_entry *audit_to_entry_common(struct audit_rule *rule) { @@ -404,6 +413,7 @@ static struct audit_entry *audit_rule_to_entry(struct audit_rule *rule) case AUDIT_PERS: case AUDIT_ARCH: case AUDIT_MSGTYPE: + case AUDIT_PPID: case AUDIT_DEVMAJOR: case AUDIT_DEVMINOR: case AUDIT_EXIT: @@ -413,6 +423,10 @@ static struct audit_entry *audit_rule_to_entry(struct audit_rule *rule) case AUDIT_ARG2: case AUDIT_ARG3: break; + case AUDIT_PERM: + if (f->val & ~15) + goto exit_free; + break; case AUDIT_INODE: err = audit_to_inode(&entry->rule, f); if (err) @@ -567,6 +581,10 @@ static struct audit_entry *audit_data_to_entry(struct audit_rule_data *data, entry->rule.buflen += f->val; entry->rule.filterkey = str; break; + case AUDIT_PERM: + if (f->val & ~15) + goto exit_free; + break; default: goto exit_free; } @@ -913,7 +931,7 @@ static void audit_update_watch(struct audit_parent *parent, } ab = audit_log_start(NULL, GFP_KERNEL, AUDIT_CONFIG_CHANGE); - audit_log_format(ab, "audit updated rules specifying watch="); + audit_log_format(ab, "audit updated rules specifying path="); audit_log_untrustedstring(ab, owatch->path); audit_log_format(ab, " with dev=%u ino=%lu\n", dev, ino); audit_log_end(ab); @@ -936,19 +954,28 @@ static void audit_remove_parent_watches(struct audit_parent *parent) struct audit_watch *w, *nextw; struct audit_krule *r, *nextr; struct audit_entry *e; + struct audit_buffer *ab; mutex_lock(&audit_filter_mutex); parent->flags |= AUDIT_PARENT_INVALID; list_for_each_entry_safe(w, nextw, &parent->watches, wlist) { list_for_each_entry_safe(r, nextr, &w->rules, rlist) { e = container_of(r, struct audit_entry, rule); + + ab = audit_log_start(NULL, GFP_KERNEL, AUDIT_CONFIG_CHANGE); + audit_log_format(ab, "audit implicitly removed rule path="); + audit_log_untrustedstring(ab, w->path); + if (r->filterkey) { + audit_log_format(ab, " key="); + audit_log_untrustedstring(ab, r->filterkey); + } else + audit_log_format(ab, " key=(null)"); + audit_log_format(ab, " list=%d", r->listnr); + audit_log_end(ab); + list_del(&r->rlist); list_del_rcu(&e->list); call_rcu(&e->rcu, audit_free_rule_rcu); - - audit_log(NULL, GFP_KERNEL, AUDIT_CONFIG_CHANGE, - "audit implicitly removed rule from list=%d\n", - AUDIT_FILTER_EXIT); } audit_remove_watch(w); } diff --git a/kernel/auditsc.c b/kernel/auditsc.c index efc1b74..1bd8827 100644 --- a/kernel/auditsc.c +++ b/kernel/auditsc.c @@ -209,6 +209,54 @@ struct audit_context { #endif }; +#define ACC_MODE(x) ("\004\002\006\006"[(x)&O_ACCMODE]) +static inline int open_arg(int flags, int mask) +{ + int n = ACC_MODE(flags); + if (flags & (O_TRUNC | O_CREAT)) + n |= AUDIT_PERM_WRITE; + return n & mask; +} + +static int audit_match_perm(struct audit_context *ctx, int mask) +{ + unsigned n = ctx->major; + switch (audit_classify_syscall(ctx->arch, n)) { + case 0: /* native */ + if ((mask & AUDIT_PERM_WRITE) && + audit_match_class(AUDIT_CLASS_WRITE, n)) + return 1; + if ((mask & AUDIT_PERM_READ) && + audit_match_class(AUDIT_CLASS_READ, n)) + return 1; + if ((mask & AUDIT_PERM_ATTR) && + audit_match_class(AUDIT_CLASS_CHATTR, n)) + return 1; + return 0; + case 1: /* 32bit on biarch */ + if ((mask & AUDIT_PERM_WRITE) && + audit_match_class(AUDIT_CLASS_WRITE_32, n)) + return 1; + if ((mask & AUDIT_PERM_READ) && + audit_match_class(AUDIT_CLASS_READ_32, n)) + return 1; + if ((mask & AUDIT_PERM_ATTR) && + audit_match_class(AUDIT_CLASS_CHATTR_32, n)) + return 1; + return 0; + case 2: /* open */ + return mask & ACC_MODE(ctx->argv[1]); + case 3: /* openat */ + return mask & ACC_MODE(ctx->argv[2]); + case 4: /* socketcall */ + return ((mask & AUDIT_PERM_WRITE) && ctx->argv[0] == SYS_BIND); + case 5: /* execve */ + return mask & AUDIT_PERM_EXEC; + default: + return 0; + } +} + /* Determine if any context name data matches a rule's watch data */ /* Compare a task_struct with an audit_rule. Return 1 on match, 0 * otherwise. */ @@ -397,6 +445,9 @@ static int audit_filter_rules(struct task_struct *tsk, /* ignore this field for filtering */ result = 1; break; + case AUDIT_PERM: + result = audit_match_perm(ctx, f->val); + break; } if (!result) diff --git a/kernel/futex.c b/kernel/futex.c index b9b8aea..9d260e8 100644 --- a/kernel/futex.c +++ b/kernel/futex.c @@ -1120,9 +1120,10 @@ static int futex_wait(u32 __user *uaddr, u32 val, unsigned long time) * if there are waiters then it will block, it does PI, etc. (Due to * races the kernel might see a 0 value of the futex too.) */ -static int do_futex_lock_pi(u32 __user *uaddr, int detect, int trylock, - struct hrtimer_sleeper *to) +static int futex_lock_pi(u32 __user *uaddr, int detect, unsigned long sec, + long nsec, int trylock) { + struct hrtimer_sleeper timeout, *to = NULL; struct task_struct *curr = current; struct futex_hash_bucket *hb; u32 uval, newval, curval; @@ -1132,6 +1133,13 @@ static int do_futex_lock_pi(u32 __user *uaddr, int detect, int trylock, if (refill_pi_state_cache()) return -ENOMEM; + if (sec != MAX_SCHEDULE_TIMEOUT) { + to = &timeout; + hrtimer_init(&to->timer, CLOCK_REALTIME, HRTIMER_ABS); + hrtimer_init_sleeper(to, current); + to->timer.expires = ktime_set(sec, nsec); + } + q.pi_state = NULL; retry: down_read(&curr->mm->mmap_sem); @@ -1307,7 +1315,7 @@ static int do_futex_lock_pi(u32 __user *uaddr, int detect, int trylock, if (!detect && ret == -EDEADLK && 0) force_sig(SIGKILL, current); - return ret; + return ret != -EINTR ? ret : -ERESTARTNOINTR; out_unlock_release_sem: queue_unlock(&q, hb); @@ -1342,76 +1350,6 @@ static int do_futex_lock_pi(u32 __user *uaddr, int detect, int trylock, } /* - * Restart handler - */ -static long futex_lock_pi_restart(struct restart_block *restart) -{ - struct hrtimer_sleeper timeout, *to = NULL; - int ret; - - restart->fn = do_no_restart_syscall; - - if (restart->arg2 || restart->arg3) { - to = &timeout; - hrtimer_init(&to->timer, CLOCK_REALTIME, HRTIMER_ABS); - hrtimer_init_sleeper(to, current); - to->timer.expires.tv64 = ((u64)restart->arg1 << 32) | - (u64) restart->arg0; - } - - pr_debug("lock_pi restart: %p, %d (%d)\n", - (u32 __user *)restart->arg0, current->pid); - - ret = do_futex_lock_pi((u32 __user *)restart->arg0, restart->arg1, - 0, to); - - if (ret != -EINTR) - return ret; - - restart->fn = futex_lock_pi_restart; - - /* The other values are filled in */ - return -ERESTART_RESTARTBLOCK; -} - -/* - * Called from the syscall entry below. - */ -static int futex_lock_pi(u32 __user *uaddr, int detect, unsigned long sec, - long nsec, int trylock) -{ - struct hrtimer_sleeper timeout, *to = NULL; - struct restart_block *restart; - int ret; - - if (sec != MAX_SCHEDULE_TIMEOUT) { - to = &timeout; - hrtimer_init(&to->timer, CLOCK_REALTIME, HRTIMER_ABS); - hrtimer_init_sleeper(to, current); - to->timer.expires = ktime_set(sec, nsec); - } - - ret = do_futex_lock_pi(uaddr, detect, trylock, to); - - if (ret != -EINTR) - return ret; - - pr_debug("lock_pi interrupted: %p, %d (%d)\n", uaddr, current->pid); - - restart = ¤t_thread_info()->restart_block; - restart->fn = futex_lock_pi_restart; - restart->arg0 = (unsigned long) uaddr; - restart->arg1 = detect; - if (to) { - restart->arg2 = to->timer.expires.tv64 & 0xFFFFFFFF; - restart->arg3 = to->timer.expires.tv64 >> 32; - } else - restart->arg2 = restart->arg3 = 0; - - return -ERESTART_RESTARTBLOCK; -} - -/* * Userspace attempted a TID -> 0 atomic transition, and failed. * This is the in-kernel slowpath: we look up the PI state (if any), * and do the rt-mutex unlock. diff --git a/kernel/panic.c b/kernel/panic.c index 9b8dcfd..8010b9b 100644 --- a/kernel/panic.c +++ b/kernel/panic.c @@ -173,7 +173,7 @@ const char *print_tainted(void) void add_taint(unsigned flag) { - debug_locks_off(); /* can't trust the integrity of the kernel anymore */ + debug_locks = 0; /* can't trust the integrity of the kernel anymore */ tainted |= flag; } EXPORT_SYMBOL(add_taint); diff --git a/kernel/power/Kconfig b/kernel/power/Kconfig index ae44a70..619ecab 100644 --- a/kernel/power/Kconfig +++ b/kernel/power/Kconfig @@ -56,7 +56,7 @@ config PM_TRACE config SOFTWARE_SUSPEND bool "Software Suspend" - depends on PM && SWAP && (X86 && (!SMP || SUSPEND_SMP)) || ((FRV || PPC32) && !SMP) + depends on PM && SWAP && ((X86 && (!SMP || SUSPEND_SMP) && !X86_PAE) || ((FRV || PPC32) && !SMP)) ---help--- Enable the possibility of suspending the machine. It doesn't need ACPI or APM. @@ -78,6 +78,10 @@ config SOFTWARE_SUSPEND For more information take a look at <file:Documentation/power/swsusp.txt>. + (For now, swsusp is incompatible with PAE aka HIGHMEM_64G on i386. + we need identity mapping for resume to work, and that is trivial + to get with 4MB pages, but less than trivial on PAE). + config PM_STD_PARTITION string "Default resume partition" depends on SOFTWARE_SUSPEND diff --git a/kernel/spinlock.c b/kernel/spinlock.c index bfd6ad9..fb524b0 100644 --- a/kernel/spinlock.c +++ b/kernel/spinlock.c @@ -72,7 +72,7 @@ EXPORT_SYMBOL(_write_trylock); * not re-enabled during lock-acquire (which the preempt-spin-ops do): */ #if !defined(CONFIG_PREEMPT) || !defined(CONFIG_SMP) || \ - defined(CONFIG_PROVE_LOCKING) + defined(CONFIG_DEBUG_LOCK_ALLOC) void __lockfunc _read_lock(rwlock_t *lock) { |