From a9ba4285aa5722a3b4d84888e78ba8adc0046b28 Mon Sep 17 00:00:00 2001 From: Kees Cook Date: Tue, 10 Jun 2014 15:40:23 -0700 Subject: [PATCH 01/14] ARM: add seccomp syscall Wires up the new seccomp syscall. Signed-off-by: Kees Cook Reviewed-by: Oleg Nesterov Conflicts: arch/arm/include/uapi/asm/unistd.h arch/arm/kernel/calls.S Signed-off-by: Lee Campbell --- arch/arm/include/asm/unistd.h | 2 +- arch/arm/include/uapi/asm/unistd.h | 6 ++++++ arch/arm/kernel/calls.S | 5 +++++ 3 files changed, 12 insertions(+), 1 deletion(-) diff --git a/arch/arm/include/asm/unistd.h b/arch/arm/include/asm/unistd.h index 141baa3f9a72..acabef1a75df 100644 --- a/arch/arm/include/asm/unistd.h +++ b/arch/arm/include/asm/unistd.h @@ -15,7 +15,7 @@ #include -#define __NR_syscalls (380) +#define __NR_syscalls (384) #define __ARM_NR_cmpxchg (__ARM_NR_BASE+0x00fff0) #define __ARCH_WANT_STAT64 diff --git a/arch/arm/include/uapi/asm/unistd.h b/arch/arm/include/uapi/asm/unistd.h index af33b44990ed..17407c92c0da 100644 --- a/arch/arm/include/uapi/asm/unistd.h +++ b/arch/arm/include/uapi/asm/unistd.h @@ -406,6 +406,12 @@ #define __NR_process_vm_writev (__NR_SYSCALL_BASE+377) #define __NR_kcmp (__NR_SYSCALL_BASE+378) #define __NR_finit_module (__NR_SYSCALL_BASE+379) +/* Reserve for later +#define __NR_sched_setattr (__NR_SYSCALL_BASE+380) +#define __NR_sched_getattr (__NR_SYSCALL_BASE+381) +#define __NR_renameat2 (__NR_SYSCALL_BASE+382) +*/ +#define __NR_seccomp (__NR_SYSCALL_BASE+383) /* * This may need to be greater than __NR_last_syscall+1 in order to diff --git a/arch/arm/kernel/calls.S b/arch/arm/kernel/calls.S index c6ca7e376773..725f844926ea 100644 --- a/arch/arm/kernel/calls.S +++ b/arch/arm/kernel/calls.S @@ -389,6 +389,11 @@ CALL(sys_process_vm_writev) CALL(sys_kcmp) CALL(sys_finit_module) +/* 380 */ CALL(sys_ni_syscall) /* reserved sys_sched_setattr */ + CALL(sys_ni_syscall) /* reserved sys_sched_getattr */ + CALL(sys_ni_syscall) /* reserved sys_renameat2 */ + CALL(sys_seccomp) + #ifndef syscalls_counted .equ syscalls_padding, ((NR_syscalls + 3) & ~3) - NR_syscalls #define syscalls_counted From 41900903483eb96602dd72e719a798c208118aad Mon Sep 17 00:00:00 2001 From: Will Deacon Date: Fri, 27 Jun 2014 17:01:47 +0100 Subject: [PATCH 02/14] ARM: 8087/1: ptrace: reload syscall number after secure_computing() check On the syscall tracing path, we call out to secure_computing() to allow seccomp to check the syscall number being attempted. As part of this, a SIGTRAP may be sent to the tracer and the syscall could be re-written by a subsequent SET_SYSCALL ptrace request. Unfortunately, this new syscall is ignored by the current code unless TIF_SYSCALL_TRACE is also set on the current thread. This patch slightly reworks the enter path of the syscall tracing code so that we always reload the syscall number from current_thread_info()->syscall after the potential ptrace traps. Acked-by: Kees Cook Tested-by: Kees Cook Signed-off-by: Will Deacon Signed-off-by: Russell King --- arch/arm/kernel/ptrace.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/arch/arm/kernel/ptrace.c b/arch/arm/kernel/ptrace.c index 03deeffd9f6d..394424b25254 100644 --- a/arch/arm/kernel/ptrace.c +++ b/arch/arm/kernel/ptrace.c @@ -916,7 +916,7 @@ enum ptrace_syscall_dir { PTRACE_SYSCALL_EXIT, }; -static int tracehook_report_syscall(struct pt_regs *regs, +static void tracehook_report_syscall(struct pt_regs *regs, enum ptrace_syscall_dir dir) { unsigned long ip; @@ -934,7 +934,6 @@ static int tracehook_report_syscall(struct pt_regs *regs, current_thread_info()->syscall = -1; regs->ARM_ip = ip; - return current_thread_info()->syscall; } asmlinkage int syscall_trace_enter(struct pt_regs *regs, int scno) @@ -946,7 +945,9 @@ asmlinkage int syscall_trace_enter(struct pt_regs *regs, int scno) return -1; if (test_thread_flag(TIF_SYSCALL_TRACE)) - scno = tracehook_report_syscall(regs, PTRACE_SYSCALL_ENTER); + tracehook_report_syscall(regs, PTRACE_SYSCALL_ENTER); + + scno = current_thread_info()->syscall; if (test_thread_flag(TIF_SYSCALL_TRACEPOINT)) trace_sys_enter(regs, scno); From 5ffb57932ec09ebc9956a1c74f703ca8389e3a90 Mon Sep 17 00:00:00 2001 From: Ruchi Kandoi Date: Tue, 14 Oct 2014 17:43:21 -0700 Subject: [PATCH 03/14] power: Avoids bogus error messages for the suspend aborts. Avoids printing bogus error message "tasks refusing to freeze", in cases where pending wakeup source caused the suspend abort. Signed-off-by: Ruchi Kandoi Change-Id: I913ad290f501b31cd536d039834c8d24c6f16928 --- kernel/power/process.c | 27 ++++++++++++++------------- 1 file changed, 14 insertions(+), 13 deletions(-) diff --git a/kernel/power/process.c b/kernel/power/process.c index fc0df8486449..d26dcb5dff87 100644 --- a/kernel/power/process.c +++ b/kernel/power/process.c @@ -82,23 +82,24 @@ static int try_to_freeze_tasks(bool user_only) do_div(elapsed_msecs64, NSEC_PER_MSEC); elapsed_msecs = elapsed_msecs64; - if (todo) { + if (wakeup) { printk("\n"); - printk(KERN_ERR "Freezing of tasks %s after %d.%03d seconds " - "(%d tasks refusing to freeze, wq_busy=%d):\n", - wakeup ? "aborted" : "failed", + printk(KERN_ERR "Freezing of tasks aborted after %d.%03d seconds", + elapsed_msecs / 1000, elapsed_msecs % 1000); + } else if (todo) { + printk("\n"); + printk(KERN_ERR "Freezing of tasks failed after %d.%03d seconds" + " (%d tasks refusing to freeze, wq_busy=%d):\n", elapsed_msecs / 1000, elapsed_msecs % 1000, todo - wq_busy, wq_busy); - if (!wakeup) { - read_lock(&tasklist_lock); - do_each_thread(g, p) { - if (p != current && !freezer_should_skip(p) - && freezing(p) && !frozen(p)) - sched_show_task(p); - } while_each_thread(g, p); - read_unlock(&tasklist_lock); - } + read_lock(&tasklist_lock); + do_each_thread(g, p) { + if (p != current && !freezer_should_skip(p) + && freezing(p) && !frozen(p)) + sched_show_task(p); + } while_each_thread(g, p); + read_unlock(&tasklist_lock); } else { printk("(elapsed %d.%03d seconds) ", elapsed_msecs / 1000, elapsed_msecs % 1000); From 13224a7d4e4e4ac6ade52deec32e9f9c28533659 Mon Sep 17 00:00:00 2001 From: Ruchi Kandoi Date: Tue, 21 Oct 2014 13:55:04 -0700 Subject: [PATCH 04/14] cpufreq: Avoid using global variable total_cpus MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The change is to compile on kernels where cpufreq stats are compiled as a module (CONFIG_CPU_FREQ_STAT=m), because total_cpus is not exported for module use. Reported-By: Emilio López Signed-off-by: Ruchi Kandoi Change-Id: I4f3c74f0fac5e8d9449655b26bf3b407b0fe4290 --- drivers/cpufreq/cpufreq_stats.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/cpufreq/cpufreq_stats.c b/drivers/cpufreq/cpufreq_stats.c index 7a2bcac3ad7f..d811f5d4b32b 100644 --- a/drivers/cpufreq/cpufreq_stats.c +++ b/drivers/cpufreq/cpufreq_stats.c @@ -282,19 +282,19 @@ static void cpufreq_stats_free_sysfs(unsigned int cpu) static void cpufreq_allstats_free(void) { - int i; + int cpu; struct all_cpufreq_stats *all_stat; sysfs_remove_file(cpufreq_global_kobject, &_attr_all_time_in_state.attr); - for (i = 0; i < total_cpus; i++) { - all_stat = per_cpu(all_cpufreq_stats, i); + for_each_possible_cpu(cpu) { + all_stat = per_cpu(all_cpufreq_stats, cpu); if (!all_stat) continue; kfree(all_stat->time_in_state); kfree(all_stat); - per_cpu(all_cpufreq_stats, i) = NULL; + per_cpu(all_cpufreq_stats, cpu) = NULL; } if (all_freq_table) { kfree(all_freq_table->freq_table); From 7af7a7d021416dfdbb30e6b31957297d484ebb97 Mon Sep 17 00:00:00 2001 From: Ruchi Kandoi Date: Wed, 29 Oct 2014 10:36:27 -0700 Subject: [PATCH 05/14] power: Adds functionality to log the last suspend abort reason. Extends the last_resume_reason to log suspend abort reason. The abort reasons will have "Abort:" appended at the start to distinguish itself from the resume reason. Signed-off-by: Ruchi Kandoi Change-Id: I3207f1844e3d87c706dfc298fb10e1c648814c5f --- drivers/base/power/main.c | 13 +++++++++++ drivers/base/power/wakeup.c | 16 +++++++++++++ drivers/base/syscore.c | 3 +++ include/linux/suspend.h | 2 +- include/linux/wakeup_reason.h | 4 +++- kernel/irq/pm.c | 7 +++++- kernel/power/process.c | 6 ++++- kernel/power/suspend.c | 19 +++++++++++++--- kernel/power/wakeup_reason.c | 42 ++++++++++++++++++++++++++++------- 9 files changed, 97 insertions(+), 15 deletions(-) diff --git a/drivers/base/power/main.c b/drivers/base/power/main.c index 6a33dd85c044..5131ad8ca17f 100644 --- a/drivers/base/power/main.c +++ b/drivers/base/power/main.c @@ -30,6 +30,7 @@ #include #include #include +#include #include "../base.h" #include "power.h" @@ -938,6 +939,7 @@ static int device_suspend_noirq(struct device *dev, pm_message_t state) static int dpm_suspend_noirq(pm_message_t state) { ktime_t starttime = ktime_get(); + char suspend_abort[MAX_SUSPEND_ABORT_LEN]; int error = 0; cpuidle_pause(); @@ -965,6 +967,9 @@ static int dpm_suspend_noirq(pm_message_t state) put_device(dev); if (pm_wakeup_pending()) { + pm_get_active_wakeup_sources(suspend_abort, + MAX_SUSPEND_ABORT_LEN); + log_suspend_abort_reason(suspend_abort); error = -EBUSY; break; } @@ -1023,6 +1028,7 @@ static int device_suspend_late(struct device *dev, pm_message_t state) static int dpm_suspend_late(pm_message_t state) { ktime_t starttime = ktime_get(); + char suspend_abort[MAX_SUSPEND_ABORT_LEN]; int error = 0; mutex_lock(&dpm_list_mtx); @@ -1048,6 +1054,9 @@ static int dpm_suspend_late(pm_message_t state) put_device(dev); if (pm_wakeup_pending()) { + pm_get_active_wakeup_sources(suspend_abort, + MAX_SUSPEND_ABORT_LEN); + log_suspend_abort_reason(suspend_abort); error = -EBUSY; break; } @@ -1115,6 +1124,7 @@ static int __device_suspend(struct device *dev, pm_message_t state, bool async) char *info = NULL; int error = 0; struct dpm_watchdog wd; + char suspend_abort[MAX_SUSPEND_ABORT_LEN]; dpm_wait_for_children(dev, async); @@ -1131,6 +1141,9 @@ static int __device_suspend(struct device *dev, pm_message_t state, bool async) pm_wakeup_event(dev, 0); if (pm_wakeup_pending()) { + pm_get_active_wakeup_sources(suspend_abort, + MAX_SUSPEND_ABORT_LEN); + log_suspend_abort_reason(suspend_abort); async_error = -EBUSY; goto Complete; } diff --git a/drivers/base/power/wakeup.c b/drivers/base/power/wakeup.c index 79715e7fa43e..bea700736f24 100644 --- a/drivers/base/power/wakeup.c +++ b/drivers/base/power/wakeup.c @@ -659,6 +659,22 @@ void pm_wakeup_event(struct device *dev, unsigned int msec) } EXPORT_SYMBOL_GPL(pm_wakeup_event); +void pm_get_active_wakeup_sources(char *pending_wakeup_source, size_t max) +{ + struct wakeup_source *ws; + int len = 0; + rcu_read_lock(); + len += snprintf(pending_wakeup_source, max, "Pending Wakeup Sources: "); + list_for_each_entry_rcu(ws, &wakeup_sources, entry) { + if (ws->active) { + len += snprintf(pending_wakeup_source + len, max, + "%s ", ws->name); + } + } + rcu_read_unlock(); +} +EXPORT_SYMBOL_GPL(pm_get_active_wakeup_sources); + static void print_active_wakeup_sources(void) { struct wakeup_source *ws; diff --git a/drivers/base/syscore.c b/drivers/base/syscore.c index e8d11b6630ee..0ab546558c4e 100644 --- a/drivers/base/syscore.c +++ b/drivers/base/syscore.c @@ -10,6 +10,7 @@ #include #include #include +#include static LIST_HEAD(syscore_ops_list); static DEFINE_MUTEX(syscore_ops_lock); @@ -73,6 +74,8 @@ int syscore_suspend(void) return 0; err_out: + log_suspend_abort_reason("System core suspend callback %pF failed", + ops->suspend); pr_err("PM: System core suspend callback %pF failed.\n", ops->suspend); list_for_each_entry_continue(ops, &syscore_ops_list, node) diff --git a/include/linux/suspend.h b/include/linux/suspend.h index d4e3f16d5e89..a34821358ae5 100644 --- a/include/linux/suspend.h +++ b/include/linux/suspend.h @@ -363,7 +363,7 @@ extern bool pm_wakeup_pending(void); extern bool pm_get_wakeup_count(unsigned int *count, bool block); extern bool pm_save_wakeup_count(unsigned int count); extern void pm_wakep_autosleep_enabled(bool set); - +extern void pm_get_active_wakeup_sources(char *pending_sources, size_t max); static inline void lock_system_sleep(void) { current->flags |= PF_FREEZER_SKIP; diff --git a/include/linux/wakeup_reason.h b/include/linux/wakeup_reason.h index 7ce50f0debc4..5f095da2c977 100644 --- a/include/linux/wakeup_reason.h +++ b/include/linux/wakeup_reason.h @@ -18,6 +18,8 @@ #ifndef _LINUX_WAKEUP_REASON_H #define _LINUX_WAKEUP_REASON_H -void log_wakeup_reason(int irq); +#define MAX_SUSPEND_ABORT_LEN 256 +void log_wakeup_reason(int irq); +void log_suspend_abort_reason(const char *fmt, ...); #endif /* _LINUX_WAKEUP_REASON_H */ diff --git a/kernel/irq/pm.c b/kernel/irq/pm.c index fe4b09cf829c..08d0916150d5 100644 --- a/kernel/irq/pm.c +++ b/kernel/irq/pm.c @@ -10,7 +10,7 @@ #include #include #include - +#include #include "internals.h" /** @@ -100,11 +100,16 @@ EXPORT_SYMBOL_GPL(resume_device_irqs); int check_wakeup_irqs(void) { struct irq_desc *desc; + char suspend_abort[MAX_SUSPEND_ABORT_LEN]; int irq; for_each_irq_desc(irq, desc) { if (irqd_is_wakeup_set(&desc->irq_data)) { if (desc->istate & IRQS_PENDING) { + log_suspend_abort_reason("Wakeup IRQ %d %s pending", + irq, + desc->action && desc->action->name ? + desc->action->name : ""); pr_info("Wakeup IRQ %d %s pending, suspend aborted\n", irq, desc->action && desc->action->name ? diff --git a/kernel/power/process.c b/kernel/power/process.c index d26dcb5dff87..86a40fa35095 100644 --- a/kernel/power/process.c +++ b/kernel/power/process.c @@ -17,7 +17,7 @@ #include #include #include - +#include /* * Timeout for stopping processes */ @@ -34,6 +34,7 @@ static int try_to_freeze_tasks(bool user_only) unsigned int elapsed_msecs; bool wakeup = false; int sleep_usecs = USEC_PER_MSEC; + char suspend_abort[MAX_SUSPEND_ABORT_LEN]; do_gettimeofday(&start); @@ -63,6 +64,9 @@ static int try_to_freeze_tasks(bool user_only) break; if (pm_wakeup_pending()) { + pm_get_active_wakeup_sources(suspend_abort, + MAX_SUSPEND_ABORT_LEN); + log_suspend_abort_reason(suspend_abort); wakeup = true; break; } diff --git a/kernel/power/suspend.c b/kernel/power/suspend.c index 454568e6c8d2..7c53fea31cba 100644 --- a/kernel/power/suspend.c +++ b/kernel/power/suspend.c @@ -27,6 +27,7 @@ #include #include #include +#include #include "power.h" @@ -147,7 +148,7 @@ static int suspend_prepare(suspend_state_t state) error = suspend_freeze_processes(); if (!error) return 0; - + log_suspend_abort_reason("One or more tasks refusing to freeze"); suspend_stats.failed_freeze++; dpm_save_failed_step(SUSPEND_FREEZE); Finish: @@ -177,7 +178,8 @@ void __attribute__ ((weak)) arch_suspend_enable_irqs(void) */ static int suspend_enter(suspend_state_t state, bool *wakeup) { - int error; + char suspend_abort[MAX_SUSPEND_ABORT_LEN]; + int error, last_dev; if (need_suspend_ops(state) && suspend_ops->prepare) { error = suspend_ops->prepare(); @@ -187,7 +189,11 @@ static int suspend_enter(suspend_state_t state, bool *wakeup) error = dpm_suspend_end(PMSG_SUSPEND); if (error) { + last_dev = suspend_stats.last_failed_dev + REC_FAILED_NUM - 1; + last_dev %= REC_FAILED_NUM; printk(KERN_ERR "PM: Some devices failed to power down\n"); + log_suspend_abort_reason("%s device failed to power down", + suspend_stats.failed_devs[last_dev]); goto Platform_finish; } @@ -212,8 +218,10 @@ static int suspend_enter(suspend_state_t state, bool *wakeup) } error = disable_nonboot_cpus(); - if (error || suspend_test(TEST_CPUS)) + if (error || suspend_test(TEST_CPUS)) { + log_suspend_abort_reason("Disabling non-boot cpus failed"); goto Enable_cpus; + } arch_suspend_disable_irqs(); BUG_ON(!irqs_disabled()); @@ -224,6 +232,10 @@ static int suspend_enter(suspend_state_t state, bool *wakeup) if (!(suspend_test(TEST_CORE) || *wakeup)) { error = suspend_ops->enter(state); events_check_enabled = false; + } else { + pm_get_active_wakeup_sources(suspend_abort, + MAX_SUSPEND_ABORT_LEN); + log_suspend_abort_reason(suspend_abort); } syscore_resume(); } @@ -271,6 +283,7 @@ int suspend_devices_and_enter(suspend_state_t state) error = dpm_suspend_start(PMSG_SUSPEND); if (error) { printk(KERN_ERR "PM: Some devices failed to suspend\n"); + log_suspend_abort_reason("Some devices failed to suspend"); goto Recover_platform; } suspend_test_finish("suspend devices"); diff --git a/kernel/power/wakeup_reason.c b/kernel/power/wakeup_reason.c index 187e4e9105fb..2aacc34ef17c 100644 --- a/kernel/power/wakeup_reason.c +++ b/kernel/power/wakeup_reason.c @@ -31,6 +31,8 @@ #define MAX_WAKEUP_REASON_IRQS 32 static int irq_list[MAX_WAKEUP_REASON_IRQS]; static int irqcount; +static bool suspend_abort; +static char abort_reason[MAX_SUSPEND_ABORT_LEN]; static struct kobject *wakeup_reason; static spinlock_t resume_reason_lock; @@ -40,14 +42,18 @@ static ssize_t last_resume_reason_show(struct kobject *kobj, struct kobj_attribu int irq_no, buf_offset = 0; struct irq_desc *desc; spin_lock(&resume_reason_lock); - for (irq_no = 0; irq_no < irqcount; irq_no++) { - desc = irq_to_desc(irq_list[irq_no]); - if (desc && desc->action && desc->action->name) - buf_offset += sprintf(buf + buf_offset, "%d %s\n", - irq_list[irq_no], desc->action->name); - else - buf_offset += sprintf(buf + buf_offset, "%d\n", - irq_list[irq_no]); + if (suspend_abort) { + buf_offset = sprintf(buf, "Abort: %s", abort_reason); + } else { + for (irq_no = 0; irq_no < irqcount; irq_no++) { + desc = irq_to_desc(irq_list[irq_no]); + if (desc && desc->action && desc->action->name) + buf_offset += sprintf(buf + buf_offset, "%d %s\n", + irq_list[irq_no], desc->action->name); + else + buf_offset += sprintf(buf + buf_offset, "%d\n", + irq_list[irq_no]); + } } spin_unlock(&resume_reason_lock); return buf_offset; @@ -89,6 +95,25 @@ void log_wakeup_reason(int irq) spin_unlock(&resume_reason_lock); } +void log_suspend_abort_reason(const char *fmt, ...) +{ + va_list args; + + spin_lock(&resume_reason_lock); + + //Suspend abort reason has already been logged. + if (suspend_abort) { + spin_unlock(&resume_reason_lock); + return; + } + + suspend_abort = true; + va_start(args, fmt); + snprintf(abort_reason, MAX_SUSPEND_ABORT_LEN, fmt, args); + va_end(args); + spin_unlock(&resume_reason_lock); +} + /* Detects a suspend and clears all the previous wake up reasons*/ static int wakeup_reason_pm_event(struct notifier_block *notifier, unsigned long pm_event, void *unused) @@ -97,6 +122,7 @@ static int wakeup_reason_pm_event(struct notifier_block *notifier, case PM_SUSPEND_PREPARE: spin_lock(&resume_reason_lock); irqcount = 0; + suspend_abort = false; spin_unlock(&resume_reason_lock); break; default: From f141171d7d56f603a43742af594b1d5549c73f34 Mon Sep 17 00:00:00 2001 From: Dmitry Shmidt Date: Fri, 31 Oct 2014 16:05:46 -0700 Subject: [PATCH 06/14] power: Add check_wakeup_reason() to verify wakeup source irq Wakeup reason is set before driver resume handlers are called. It is cleared before driver suspend handlers are called, on PM_SUSPEND_PREPARE. Change-Id: I04218c9b0c115a7877e8029c73e6679ff82e0aa4 Signed-off-by: Dmitry Shmidt --- include/linux/wakeup_reason.h | 2 ++ kernel/power/wakeup_reason.c | 19 +++++++++++++++++-- 2 files changed, 19 insertions(+), 2 deletions(-) diff --git a/include/linux/wakeup_reason.h b/include/linux/wakeup_reason.h index 5f095da2c977..ad8b76936c7f 100644 --- a/include/linux/wakeup_reason.h +++ b/include/linux/wakeup_reason.h @@ -22,4 +22,6 @@ void log_wakeup_reason(int irq); void log_suspend_abort_reason(const char *fmt, ...); +int check_wakeup_reason(int irq); + #endif /* _LINUX_WAKEUP_REASON_H */ diff --git a/kernel/power/wakeup_reason.c b/kernel/power/wakeup_reason.c index 2aacc34ef17c..085c99edca06 100644 --- a/kernel/power/wakeup_reason.c +++ b/kernel/power/wakeup_reason.c @@ -34,7 +34,7 @@ static int irqcount; static bool suspend_abort; static char abort_reason[MAX_SUSPEND_ABORT_LEN]; static struct kobject *wakeup_reason; -static spinlock_t resume_reason_lock; +static DEFINE_SPINLOCK(resume_reason_lock); static ssize_t last_resume_reason_show(struct kobject *kobj, struct kobj_attribute *attr, char *buf) @@ -95,6 +95,21 @@ void log_wakeup_reason(int irq) spin_unlock(&resume_reason_lock); } +int check_wakeup_reason(int irq) +{ + int irq_no; + int ret = false; + + spin_lock(&resume_reason_lock); + for (irq_no = 0; irq_no < irqcount; irq_no++) + if (irq_list[irq_no] == irq) { + ret = true; + break; + } + spin_unlock(&resume_reason_lock); + return ret; +} + void log_suspend_abort_reason(const char *fmt, ...) { va_list args; @@ -141,7 +156,7 @@ static struct notifier_block wakeup_reason_pm_notifier_block = { int __init wakeup_reason_init(void) { int retval; - spin_lock_init(&resume_reason_lock); + retval = register_pm_notifier(&wakeup_reason_pm_notifier_block); if (retval) printk(KERN_WARNING "[%s] failed to register PM notifier %d\n", From 2ce95507d5ce6a5d3fd7993c35667a98c2f11f3b Mon Sep 17 00:00:00 2001 From: Erik Kline Date: Tue, 28 Oct 2014 18:11:14 +0900 Subject: [PATCH 07/14] net: ipv6: Add a sysctl to make optimistic addresses useful candidates Add a sysctl that causes an interface's optimistic addresses to be considered equivalent to other non-deprecated addresses for source address selection purposes. Preferred addresses will still take precedence over optimistic addresses, subject to other ranking in the source address selection algorithm. This is useful where different interfaces are connected to different networks from different ISPs (e.g., a cell network and a home wifi network). The current behaviour complies with RFC 3484/6724, and it makes sense if the host has only one interface, or has multiple interfaces on the same network (same or cooperating administrative domain(s), but not in the multiple distinct networks case. For example, if a mobile device has an IPv6 address on an LTE network and then connects to IPv6-enabled wifi, while the wifi IPv6 address is undergoing DAD, IPv6 connections will try use the wifi default route with the LTE IPv6 address, and will get stuck until they time out. Also, because optimistic nodes can receive frames, issue an RTM_NEWADDR as soon as DAD starts (with the IFA_F_OPTIMSTIC flag appropriately set). A second RTM_NEWADDR is sent if DAD completes (the address flags have changed), otherwise an RTM_DELADDR is sent. Also: add an entry in ip-sysctl.txt for optimistic_dad. [cherry-pick of net-next 7fd2561e4ebdd070ebba6d3326c4c5b13942323f] Signed-off-by: Erik Kline Acked-by: Lorenzo Colitti Acked-by: Hannes Frederic Sowa Signed-off-by: David S. Miller Bug: 17769720 Change-Id: Ic7e50781c607e1f3a492d9ce7395946efb95c533 --- Documentation/networking/ip-sysctl.txt | 13 ++++++++ include/linux/ipv6.h | 1 + include/uapi/linux/ipv6.h | 1 + net/ipv6/addrconf.c | 46 ++++++++++++++++++++++++-- 4 files changed, 59 insertions(+), 2 deletions(-) diff --git a/Documentation/networking/ip-sysctl.txt b/Documentation/networking/ip-sysctl.txt index 6e5c7c7333bd..74b49ba13b1f 100644 --- a/Documentation/networking/ip-sysctl.txt +++ b/Documentation/networking/ip-sysctl.txt @@ -1333,6 +1333,19 @@ ndisc_notify - BOOLEAN 1 - Generate unsolicited neighbour advertisements when device is brought up or hardware address changes. +optimistic_dad - BOOLEAN + Whether to perform Optimistic Duplicate Address Detection (RFC 4429). + 0: disabled (default) + 1: enabled + +use_optimistic - BOOLEAN + If enabled, do not classify optimistic addresses as deprecated during + source address selection. Preferred addresses will still be chosen + before optimistic addresses, subject to other ranking in the source + address selection algorithm. + 0: disabled (default) + 1: enabled + icmp/*: ratelimit - INTEGER Limit the maximal rates for sending ICMPv6 packets. diff --git a/include/linux/ipv6.h b/include/linux/ipv6.h index 867833ba6bd1..76b5114e9d82 100644 --- a/include/linux/ipv6.h +++ b/include/linux/ipv6.h @@ -41,6 +41,7 @@ struct ipv6_devconf { __s32 accept_source_route; #ifdef CONFIG_IPV6_OPTIMISTIC_DAD __s32 optimistic_dad; + __s32 use_optimistic; #endif #ifdef CONFIG_IPV6_MROUTE __s32 mc_forwarding; diff --git a/include/uapi/linux/ipv6.h b/include/uapi/linux/ipv6.h index 4214fac1bf4f..e9d0f7efde3b 100644 --- a/include/uapi/linux/ipv6.h +++ b/include/uapi/linux/ipv6.h @@ -161,6 +161,7 @@ enum { DEVCONF_FORCE_TLLAO, DEVCONF_NDISC_NOTIFY, DEVCONF_ACCEPT_RA_RT_TABLE, + DEVCONF_USE_OPTIMISTIC, DEVCONF_MAX }; diff --git a/net/ipv6/addrconf.c b/net/ipv6/addrconf.c index cec8cb4d292d..e1381119a6d8 100644 --- a/net/ipv6/addrconf.c +++ b/net/ipv6/addrconf.c @@ -1174,6 +1174,9 @@ enum { #endif IPV6_SADDR_RULE_ORCHID, IPV6_SADDR_RULE_PREFIX, +#ifdef CONFIG_IPV6_OPTIMISTIC_DAD + IPV6_SADDR_RULE_NOT_OPTIMISTIC, +#endif IPV6_SADDR_RULE_MAX }; @@ -1201,6 +1204,15 @@ static inline int ipv6_saddr_preferred(int type) return 0; } +static inline bool ipv6_use_optimistic_addr(struct inet6_dev *idev) +{ +#ifdef CONFIG_IPV6_OPTIMISTIC_DAD + return idev && idev->cnf.optimistic_dad && idev->cnf.use_optimistic; +#else + return false; +#endif +} + static int ipv6_get_saddr_eval(struct net *net, struct ipv6_saddr_score *score, struct ipv6_saddr_dst *dst, @@ -1261,10 +1273,16 @@ static int ipv6_get_saddr_eval(struct net *net, score->scopedist = ret; break; case IPV6_SADDR_RULE_PREFERRED: + { /* Rule 3: Avoid deprecated and optimistic addresses */ + u8 avoid = IFA_F_DEPRECATED; + + if (!ipv6_use_optimistic_addr(score->ifa->idev)) + avoid |= IFA_F_OPTIMISTIC; ret = ipv6_saddr_preferred(score->addr_type) || - !(score->ifa->flags & (IFA_F_DEPRECATED|IFA_F_OPTIMISTIC)); + !(score->ifa->flags & avoid); break; + } #ifdef CONFIG_IPV6_MIP6 case IPV6_SADDR_RULE_HOA: { @@ -1312,6 +1330,14 @@ static int ipv6_get_saddr_eval(struct net *net, ret = score->ifa->prefix_len; score->matchlen = ret; break; +#ifdef CONFIG_IPV6_OPTIMISTIC_DAD + case IPV6_SADDR_RULE_NOT_OPTIMISTIC: + /* Optimistic addresses still have lower precedence than other + * preferred addresses. + */ + ret = !(score->ifa->flags & IFA_F_OPTIMISTIC); + break; +#endif default: ret = 0; } @@ -3245,8 +3271,15 @@ static void addrconf_dad_start(struct inet6_ifaddr *ifp) * Optimistic nodes can start receiving * Frames right away */ - if (ifp->flags & IFA_F_OPTIMISTIC) + if (ifp->flags & IFA_F_OPTIMISTIC) { ip6_ins_rt(ifp->rt); + if (ipv6_use_optimistic_addr(idev)) { + /* Because optimistic nodes can use this address, + * notify listeners. If DAD fails, RTM_DELADDR is sent. + */ + ipv6_ifa_notify(RTM_NEWADDR, ifp); + } + } addrconf_dad_kick(ifp); out: @@ -4192,6 +4225,7 @@ static inline void ipv6_store_devconf(struct ipv6_devconf *cnf, array[DEVCONF_ACCEPT_SOURCE_ROUTE] = cnf->accept_source_route; #ifdef CONFIG_IPV6_OPTIMISTIC_DAD array[DEVCONF_OPTIMISTIC_DAD] = cnf->optimistic_dad; + array[DEVCONF_USE_OPTIMISTIC] = cnf->use_optimistic; #endif #ifdef CONFIG_IPV6_MROUTE array[DEVCONF_MC_FORWARDING] = cnf->mc_forwarding; @@ -4926,6 +4960,14 @@ static struct addrconf_sysctl_table .proc_handler = proc_dointvec, }, + { + .procname = "use_optimistic", + .data = &ipv6_devconf.use_optimistic, + .maxlen = sizeof(int), + .mode = 0644, + .proc_handler = proc_dointvec, + + }, #endif #ifdef CONFIG_IPV6_MROUTE { From 9aed3d0f495e8d1c53c8041cd4f18cab81affd7b Mon Sep 17 00:00:00 2001 From: Vinod Koul Date: Mon, 16 Dec 2013 14:55:34 +0530 Subject: [PATCH 08/14] ALSA: compress: change the way sample rates are sent to kernel The usage of SNDRV_RATES is not effective as we can have rates like 12000 or some other ones used by decoders. This change the usage of this to use the raw Hz values to be sent to kernel Signed-off-by: Vinod Koul Signed-off-by: Takashi Iwai (cherry picked from commit f0e9c08065dc31210fc4cf313c4ecaa088187dc5) Signed-off-by: Yuchen Song Change-Id: Ia4c67405b9cf9aef9c641bce9b02a994939eae00 --- include/uapi/sound/compress_params.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/uapi/sound/compress_params.h b/include/uapi/sound/compress_params.h index 602dc6c45d1a..1114e380aecd 100644 --- a/include/uapi/sound/compress_params.h +++ b/include/uapi/sound/compress_params.h @@ -324,7 +324,7 @@ union snd_codec_options { /** struct snd_codec_desc - description of codec capabilities * @max_ch: Maximum number of audio channels - * @sample_rates: Sampling rates in Hz, use SNDRV_PCM_RATE_xxx for this + * @sample_rates: Sampling rates in Hz, use values like 48000 for this * @bit_rate: Indexed array containing supported bit rates * @num_bitrates: Number of valid values in bit_rate array * @rate_control: value is specified by SND_RATECONTROLMODE defines. From 083799f1d4a337e55ce9bdfaf40e4ba9ba37e0c8 Mon Sep 17 00:00:00 2001 From: Vinod Koul Date: Sat, 4 Jan 2014 16:59:11 +0530 Subject: [PATCH 09/14] ALSA: compress: remove the sample rate check commit f0e9c080 - "ALSA: compress: change the way sample rates are sent to kernel" changed the way sample rates are sent. So now we don't need to check for PCM_RATE_xxx in kernel Signed-off-by: Vinod Koul Signed-off-by: Takashi Iwai (cherry picked from commit 2aac06f787940543fb37bfdb982eb99431bc6094) Signed-off-by: Yuchen Song Change-Id: I6448d844fb31097bf33e52c23a7e38d6b089ce69 --- sound/core/compress_offload.c | 3 --- 1 file changed, 3 deletions(-) diff --git a/sound/core/compress_offload.c b/sound/core/compress_offload.c index 99db892d7299..fe399f8c18f4 100644 --- a/sound/core/compress_offload.c +++ b/sound/core/compress_offload.c @@ -490,9 +490,6 @@ static int snd_compress_check_input(struct snd_compr_params *params) if (params->codec.ch_in == 0 || params->codec.ch_out == 0) return -EINVAL; - if (!(params->codec.sample_rate & SNDRV_PCM_RATE_8000_192000)) - return -EINVAL; - return 0; } From 55fc15e33d13dd6f230fd86c6c9f9837c30b8bc6 Mon Sep 17 00:00:00 2001 From: Vinod Koul Date: Sat, 4 Jan 2014 16:59:12 +0530 Subject: [PATCH 10/14] ALSA: compress: update comment for sample rate in snd_codec Signed-off-by: Vinod Koul Signed-off-by: Takashi Iwai (cherry picked from commit d9afee6904caa7cf3c7f417f02e765db89d2b5dc) Signed-off-by: Yuchen Song Change-Id: I7608d924613611222766a898a97c856a64c2eb68 --- include/uapi/sound/compress_params.h | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/include/uapi/sound/compress_params.h b/include/uapi/sound/compress_params.h index 1114e380aecd..8c23aebc82a5 100644 --- a/include/uapi/sound/compress_params.h +++ b/include/uapi/sound/compress_params.h @@ -364,7 +364,8 @@ struct snd_codec_desc { * @ch_out: Number of output channels. In case of contradiction between * this field and the channelMode field, the channelMode field * overrides. - * @sample_rate: Audio sample rate of input data + * @sample_rate: Audio sample rate of input data in Hz, use values like 48000 + * for this. * @bit_rate: Bitrate of encoded data. May be ignored by decoders * @rate_control: Encoding rate control. See SND_RATECONTROLMODE defines. * Encoders may rely on profiles for quality levels. From 371e4108dd8b345b0144fa3ccc83d84d19918c20 Mon Sep 17 00:00:00 2001 From: Vinod Koul Date: Sat, 4 Jan 2014 16:59:13 +0530 Subject: [PATCH 11/14] ALSA: compress: update struct snd_codec_desc for sample rate Now that we don't use SNDRV_PCM_RATE_xxx bit fields for sample rate, we need to change the description to an array for describing the sample rates supported by the sink/source Signed-off-by: Vinod Koul Signed-off-by: Takashi Iwai (cherry picked from commit b8bab04829ab190f71921d4180bda438ba6124ae) Signed-off-by: Yuchen Song Change-Id: I6c2fa5a5034ec749e9d7a71c49a1108af2416848 --- include/uapi/sound/compress_params.h | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/include/uapi/sound/compress_params.h b/include/uapi/sound/compress_params.h index 8c23aebc82a5..b62b24b7f834 100644 --- a/include/uapi/sound/compress_params.h +++ b/include/uapi/sound/compress_params.h @@ -57,6 +57,7 @@ #define MAX_NUM_CODECS 32 #define MAX_NUM_CODEC_DESCRIPTORS 32 #define MAX_NUM_BITRATES 32 +#define MAX_NUM_SAMPLE_RATES 32 /* Codecs are listed linearly to allow for extensibility */ #define SND_AUDIOCODEC_PCM ((__u32) 0x00000001) @@ -346,7 +347,7 @@ union snd_codec_options { struct snd_codec_desc { __u32 max_ch; - __u32 sample_rates; + __u32 sample_rates[MAX_NUM_SAMPLE_RATES]; __u32 bit_rate[MAX_NUM_BITRATES]; __u32 num_bitrates; __u32 rate_control; From c5400a9083607af9852cf2c0ac0093a128cd3c18 Mon Sep 17 00:00:00 2001 From: Vinod Koul Date: Tue, 7 Jan 2014 21:55:42 +0530 Subject: [PATCH 12/14] ALSA: compress: add num_sample_rates in snd_codec_desc this gives ability to convey the valid values of supported rates in sample_rates array Signed-off-by: Vinod Koul Signed-off-by: Takashi Iwai (cherry picked from commit 929559be6d2c494e25bb58b730da4a78c1459e7b) Signed-off-by: Yuchen Song Change-Id: Icfbb6d272a70c0a94719613c00bac18c5a0e3f87 --- include/uapi/sound/compress_params.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/include/uapi/sound/compress_params.h b/include/uapi/sound/compress_params.h index b62b24b7f834..165e7059de75 100644 --- a/include/uapi/sound/compress_params.h +++ b/include/uapi/sound/compress_params.h @@ -326,6 +326,7 @@ union snd_codec_options { /** struct snd_codec_desc - description of codec capabilities * @max_ch: Maximum number of audio channels * @sample_rates: Sampling rates in Hz, use values like 48000 for this + * @num_sample_rates: Number of valid values in sample_rates array * @bit_rate: Indexed array containing supported bit rates * @num_bitrates: Number of valid values in bit_rate array * @rate_control: value is specified by SND_RATECONTROLMODE defines. @@ -348,6 +349,7 @@ union snd_codec_options { struct snd_codec_desc { __u32 max_ch; __u32 sample_rates[MAX_NUM_SAMPLE_RATES]; + __u32 num_sample_rates; __u32 bit_rate[MAX_NUM_BITRATES]; __u32 num_bitrates; __u32 rate_control; From 57114e95e8c4f5035c993fc74bbe94cd9573f1bb Mon Sep 17 00:00:00 2001 From: Rom Lemarchand Date: Fri, 7 Nov 2014 12:48:17 -0800 Subject: [PATCH 13/14] cgroup: refactor allow_attach function into common code move cpu_cgroup_allow_attach to a common subsys_cgroup_allow_attach. This allows any process with CAP_SYS_NICE to move tasks across cgroups if they use this function as their allow_attach handler. Bug: 18260435 Change-Id: I6bb4933d07e889d0dc39e33b4e71320c34a2c90f Signed-off-by: Rom Lemarchand --- include/linux/cgroup.h | 16 ++++++++++++++++ kernel/cgroup.c | 19 +++++++++++++++++++ kernel/sched/core.c | 19 +------------------ 3 files changed, 36 insertions(+), 18 deletions(-) diff --git a/include/linux/cgroup.h b/include/linux/cgroup.h index 8f73d835d4d5..a2bcbd2e0f9a 100644 --- a/include/linux/cgroup.h +++ b/include/linux/cgroup.h @@ -831,6 +831,17 @@ unsigned short css_id(struct cgroup_subsys_state *css); unsigned short css_depth(struct cgroup_subsys_state *css); struct cgroup_subsys_state *cgroup_css_from_dir(struct file *f, int id); +/* + * Default Android check for whether the current process is allowed to move a + * task across cgroups, either because CAP_SYS_NICE is set or because the uid + * of the calling process is the same as the moved task or because we are + * running as root. + * Returns 0 if this is allowed, or -EACCES otherwise. + */ +int subsys_cgroup_allow_attach(struct cgroup *cgrp, + struct cgroup_taskset *tset); + + #else /* !CONFIG_CGROUPS */ static inline int cgroup_init_early(void) { return 0; } @@ -854,6 +865,11 @@ static inline int cgroup_attach_task_all(struct task_struct *from, return 0; } +static inline int subsys_cgroup_allow_attach(struct cgroup *cgrp, + struct cgroup_taskset *tset) +{ + return 0; +} #endif /* !CONFIG_CGROUPS */ #endif /* _LINUX_CGROUP_H */ diff --git a/kernel/cgroup.c b/kernel/cgroup.c index 1f5338773862..8dc7ec1de429 100644 --- a/kernel/cgroup.c +++ b/kernel/cgroup.c @@ -2116,6 +2116,25 @@ static int cgroup_allow_attach(struct cgroup *cgrp, struct cgroup_taskset *tset) return 0; } +int subsys_cgroup_allow_attach(struct cgroup *cgrp, struct cgroup_taskset *tset) +{ + const struct cred *cred = current_cred(), *tcred; + struct task_struct *task; + + if (capable(CAP_SYS_NICE)) + return 0; + + cgroup_taskset_for_each(task, cgrp, tset) { + tcred = __task_cred(task); + + if (current != task && cred->euid != tcred->uid && + cred->euid != tcred->suid) + return -EACCES; + } + + return 0; +} + /* * Find the task_struct of the task to attach by vpid and pass it along to the * function to attach either it or all tasks in its threadgroup. Will lock diff --git a/kernel/sched/core.c b/kernel/sched/core.c index 014040fa3d21..d5c5c9824511 100644 --- a/kernel/sched/core.c +++ b/kernel/sched/core.c @@ -7716,23 +7716,6 @@ static void cpu_cgroup_css_offline(struct cgroup *cgrp) sched_offline_group(tg); } -static int -cpu_cgroup_allow_attach(struct cgroup *cgrp, struct cgroup_taskset *tset) -{ - const struct cred *cred = current_cred(), *tcred; - struct task_struct *task; - - cgroup_taskset_for_each(task, cgrp, tset) { - tcred = __task_cred(task); - - if ((current != task) && !capable(CAP_SYS_NICE) && - cred->euid != tcred->uid && cred->euid != tcred->suid) - return -EACCES; - } - - return 0; -} - static int cpu_cgroup_can_attach(struct cgroup *cgrp, struct cgroup_taskset *tset) { @@ -8092,7 +8075,7 @@ struct cgroup_subsys cpu_cgroup_subsys = { .css_offline = cpu_cgroup_css_offline, .can_attach = cpu_cgroup_can_attach, .attach = cpu_cgroup_attach, - .allow_attach = cpu_cgroup_allow_attach, + .allow_attach = subsys_cgroup_allow_attach, .exit = cpu_cgroup_exit, .subsys_id = cpu_cgroup_subsys_id, .base_cftypes = cpu_files, From cce78bc02ff0ea2d21e88e3438d65272b898aa35 Mon Sep 17 00:00:00 2001 From: Rom Lemarchand Date: Fri, 7 Nov 2014 09:42:40 -0800 Subject: [PATCH 14/14] memcg: add permission check Use the 'allow_attach' handler for the 'mem' cgroup to allow non-root processes to add arbitrary processes to a 'mem' cgroup if it has the CAP_SYS_NICE capability set. Bug: 18260435 Change-Id: If7d37bf90c1544024c4db53351adba6a64966250 Signed-off-by: Rom Lemarchand --- mm/memcontrol.c | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/mm/memcontrol.c b/mm/memcontrol.c index 194721839cf5..338d62a05200 100644 --- a/mm/memcontrol.c +++ b/mm/memcontrol.c @@ -6753,6 +6753,12 @@ static int mem_cgroup_can_attach(struct cgroup *cgroup, return ret; } +static int mem_cgroup_allow_attach(struct cgroup *cgroup, + struct cgroup_taskset *tset) +{ + return subsys_cgroup_allow_attach(cgroup, tset); +} + static void mem_cgroup_cancel_attach(struct cgroup *cgroup, struct cgroup_taskset *tset) { @@ -6921,6 +6927,11 @@ static int mem_cgroup_can_attach(struct cgroup *cgroup, { return 0; } +static int mem_cgroup_allow_attach(struct cgroup *cgroup, + struct cgroup_taskset *tset) +{ + return 0; +} static void mem_cgroup_cancel_attach(struct cgroup *cgroup, struct cgroup_taskset *tset) { @@ -6956,6 +6967,7 @@ struct cgroup_subsys mem_cgroup_subsys = { .can_attach = mem_cgroup_can_attach, .cancel_attach = mem_cgroup_cancel_attach, .attach = mem_cgroup_move_task, + .allow_attach = mem_cgroup_allow_attach, .bind = mem_cgroup_bind, .base_cftypes = mem_cgroup_files, .early_init = 0,