Merge branch 'linux-linaro-lsk-android' of git://git.linaro.org/kernel/linux-linaro-stable into linux-linaro-lsk-android

This commit is contained in:
Mark Brown 2014-11-21 16:52:20 +00:00
commit 2cb6410ac9
72 changed files with 2331 additions and 645 deletions

View File

@ -7148,16 +7148,6 @@ S: Maintained
F: drivers/mmc/host/sdhci.*
F: drivers/mmc/host/sdhci-pltfm.[ch]
SECURE COMPUTING
M: Kees Cook <keescook@chromium.org>
T: git git://git.kernel.org/pub/scm/linux/kernel/git/kees/linux.git seccomp
S: Supported
F: kernel/seccomp.c
F: include/uapi/linux/seccomp.h
F: include/linux/seccomp.h
K: \bsecure_computing
K: \bTIF_SECCOMP\b
SECURE DIGITAL HOST CONTROLLER INTERFACE, OPEN FIRMWARE BINDINGS (SDHCI-OF)
M: Anton Vorontsov <avorontsov@ru.mvista.com>
L: linuxppc-dev@lists.ozlabs.org

View File

@ -6,6 +6,7 @@ CONFIG_ANDROID=y
CONFIG_ANDROID_BINDER_IPC=y
CONFIG_ANDROID_INTF_ALARM_DEV=y
CONFIG_ANDROID_LOW_MEMORY_KILLER=y
CONFIG_ARMV7_COMPAT=y
CONFIG_ASHMEM=y
CONFIG_BLK_DEV_DM=y
CONFIG_BLK_DEV_INITRD=y

View File

@ -22,7 +22,7 @@ config ARM
select HARDIRQS_SW_RESEND
select HAVE_ARCH_JUMP_LABEL if !XIP_KERNEL
select HAVE_ARCH_KGDB
select HAVE_ARCH_SECCOMP_FILTER if (AEABI && !OABI_COMPAT)
select HAVE_ARCH_SECCOMP_FILTER
select HAVE_ARCH_TRACEHOOK
select HAVE_BPF_JIT
select HAVE_C_RECORDMCOUNT
@ -1811,11 +1811,6 @@ config OABI_COMPAT
in memory differs between the legacy ABI and the new ARM EABI
(only for non "thumb" binaries). This option adds a tiny
overhead to all syscalls and produces a slightly larger kernel.
The seccomp filter system will not be available when this is
selected, since there is no way yet to sensibly distinguish
between calling conventions during filtering.
If you know you'll be using only pure EABI user space then you
can say N here. If this option is not selected and you attempt
to execute a legacy ABI binary then the result will be

View File

@ -59,6 +59,21 @@
#define smp_wmb() dmb(ishst)
#endif
#define smp_store_release(p, v) \
do { \
compiletime_assert_atomic_type(*p); \
smp_mb(); \
ACCESS_ONCE(*p) = (v); \
} while (0)
#define smp_load_acquire(p) \
({ \
typeof(*p) ___p1 = ACCESS_ONCE(*p); \
compiletime_assert_atomic_type(*p); \
smp_mb(); \
___p1; \
})
#define read_barrier_depends() do { } while(0)
#define smp_read_barrier_depends() do { } while(0)

View File

@ -103,8 +103,7 @@ static inline void syscall_set_arguments(struct task_struct *task,
memcpy(&regs->ARM_r0 + i, args, n * sizeof(args[0]));
}
static inline int syscall_get_arch(struct task_struct *task,
struct pt_regs *regs)
static inline int syscall_get_arch(void)
{
/* ARM tasks don't change audit architectures on the fly. */
return AUDIT_ARCH_ARM;

View File

@ -406,11 +406,11 @@
#define __NR_process_vm_writev (__NR_SYSCALL_BASE+377)
#define __NR_kcmp (__NR_SYSCALL_BASE+378)
#define __NR_finit_module (__NR_SYSCALL_BASE+379)
/* Backporting seccomp, skip a few ...
* #define __NR_sched_setattr (__NR_SYSCALL_BASE+380)
* #define __NR_sched_getattr (__NR_SYSCALL_BASE+381)
* #define __NR_renameat2 (__NR_SYSCALL_BASE+382)
*/
/* 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)
/*

View File

@ -389,10 +389,11 @@
CALL(sys_process_vm_writev)
CALL(sys_kcmp)
CALL(sys_finit_module)
/* 380 */ CALL(sys_ni_syscall) /* CALL(sys_sched_setattr) */
CALL(sys_ni_syscall) /* CALL(sys_sched_getattr) */
CALL(sys_ni_syscall) /* CALL(sys_renameat2) */
/* 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

View File

@ -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);

View File

@ -13,6 +13,7 @@ config ARM64
select ARM_GIC
select ARM_GIC_V3
select BUILDTIME_EXTABLE_SORT
select AUDIT_ARCH_COMPAT_GENERIC
select CLONE_BACKWARDS
select COMMON_CLK
select CPU_PM if (SUSPEND || CPU_IDLE)
@ -31,6 +32,8 @@ config ARM64
select HARDIRQS_SW_RESEND
select HAVE_ARCH_JUMP_LABEL
select HAVE_ARCH_KGDB
select HAVE_ARCH_AUDITSYSCALL
select HAVE_ARCH_SECCOMP_FILTER
select HAVE_ARCH_TRACEHOOK
select HAVE_C_RECORDMCOUNT
select HAVE_DEBUG_BUGVERBOSE
@ -306,6 +309,31 @@ config HOTPLUG_CPU
Say Y here to experiment with turning CPUs off and on. CPUs
can be controlled through /sys/devices/system/cpu.
config SWP_EMULATE
bool "Emulate SWP/SWPB instructions"
help
ARMv6 architecture deprecates use of the SWP/SWPB instructions. ARMv8
oblosetes the use of SWP/SWPB instructions. ARMv7 multiprocessing
extensions introduce the ability to disable these instructions,
triggering an undefined instruction exception when executed. Say Y
here to enable software emulation of these instructions for userspace
(not kernel) using LDREX/STREX. Also creates /proc/cpu/swp_emulation
for statistics.
In some older versions of glibc [<=2.8] SWP is used during futex
trylock() operations with the assumption that the code will not
be preempted. This invalid assumption may be more likely to fail
with SWP emulation enabled, leading to deadlock of the user
application.
NOTE: when accessing uncached shared regions, LDREX/STREX rely
on an external transaction monitoring block called a global
monitor to maintain update atomicity. If your system does not
implement a global monitor, this option can cause programs that
perform SWP operations to uncached memory to deadlock.
If unsure, say Y.
source kernel/Kconfig.preempt
config HZ
@ -348,6 +376,27 @@ config ARCH_WANT_HUGE_PMD_SHARE
config HAVE_ARCH_TRANSPARENT_HUGEPAGE
def_bool y
config ARMV7_COMPAT
bool "Kernel support for ARMv7 applications"
depends on COMPAT
select SWP_EMULATE
help
This option enables features that allow that ran on an ARMv7 or older
processor to continue functioning.
If you want to execute ARMv7 applications, say Y
config ARMV7_COMPAT_CPUINFO
bool "Report backwards compatible cpu features in /proc/cpuinfo"
depends on ARMV7_COMPAT
default y
help
This option makes /proc/cpuinfo list CPU features that an ARMv7 or
earlier kernel would report, but are not optional on an ARMv8 or later
processor.
If you want to execute ARMv7 applications, say Y
source "mm/Kconfig"
config FORCE_MAX_ZONEORDER
@ -355,6 +404,19 @@ config FORCE_MAX_ZONEORDER
default "14" if (ARM64_64K_PAGES && TRANSPARENT_HUGEPAGE)
default "11"
config SECCOMP
bool "Enable seccomp to safely compute untrusted bytecode"
---help---
This kernel feature is useful for number crunching applications
that may need to compute untrusted bytecode during their
execution. By using pipes or other transports made available to
the process as file descriptors supporting the read/write
syscalls, it's possible to isolate those applications in
their own address space using seccomp. Once seccomp is
enabled via prctl(PR_SET_SECCOMP), it cannot be disabled
and the task is only allowed to execute a few safe syscalls
defined by each seccomp mode.
endmenu
menu "Boot options"

View File

@ -205,6 +205,13 @@ typedef struct compat_siginfo {
compat_long_t _band; /* POLL_IN, POLL_OUT, POLL_MSG */
int _fd;
} _sigpoll;
/* SIGSYS */
struct {
compat_uptr_t _call_addr; /* calling user insn */
int _syscall; /* triggering system call number */
unsigned int _arch; /* AUDIT_ARCH_* of syscall */
} _sigsys;
} _sifields;
} compat_siginfo_t;

View File

@ -0,0 +1,231 @@
/*
* Copied from arch/arm/include/asm/opcodes.h
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*/
#ifndef __ASM_ARM_OPCODES_H
#define __ASM_ARM_OPCODES_H
#ifndef __ASSEMBLY__
#include <linux/linkage.h>
extern asmlinkage unsigned int arm_check_condition(u32 opcode, u64 psr);
#endif
#define ARM_OPCODE_CONDTEST_FAIL 0
#define ARM_OPCODE_CONDTEST_PASS 1
#define ARM_OPCODE_CONDTEST_UNCOND 2
/*
* Assembler opcode byteswap helpers.
* These are only intended for use by this header: don't use them directly,
* because they will be suboptimal in most cases.
*/
#define ___asm_opcode_swab32(x) ( \
(((x) << 24) & 0xFF000000) \
| (((x) << 8) & 0x00FF0000) \
| (((x) >> 8) & 0x0000FF00) \
| (((x) >> 24) & 0x000000FF) \
)
#define ___asm_opcode_swab16(x) ( \
(((x) << 8) & 0xFF00) \
| (((x) >> 8) & 0x00FF) \
)
#define ___asm_opcode_swahb32(x) ( \
(((x) << 8) & 0xFF00FF00) \
| (((x) >> 8) & 0x00FF00FF) \
)
#define ___asm_opcode_swahw32(x) ( \
(((x) << 16) & 0xFFFF0000) \
| (((x) >> 16) & 0x0000FFFF) \
)
#define ___asm_opcode_identity32(x) ((x) & 0xFFFFFFFF)
#define ___asm_opcode_identity16(x) ((x) & 0xFFFF)
/*
* Opcode byteswap helpers
*
* These macros help with converting instructions between a canonical integer
* format and in-memory representation, in an endianness-agnostic manner.
*
* __mem_to_opcode_*() convert from in-memory representation to canonical form.
* __opcode_to_mem_*() convert from canonical form to in-memory representation.
*
*
* Canonical instruction representation:
*
* ARM: 0xKKLLMMNN
* Thumb 16-bit: 0x0000KKLL, where KK < 0xE8
* Thumb 32-bit: 0xKKLLMMNN, where KK >= 0xE8
*
* There is no way to distinguish an ARM instruction in canonical representation
* from a Thumb instruction (just as these cannot be distinguished in memory).
* Where this distinction is important, it needs to be tracked separately.
*
* Note that values in the range 0x0000E800..0xE7FFFFFF intentionally do not
* represent any valid Thumb-2 instruction. For this range,
* __opcode_is_thumb32() and __opcode_is_thumb16() will both be false.
*
* The ___asm variants are intended only for use by this header, in situations
* involving inline assembler. For .S files, the normal __opcode_*() macros
* should do the right thing.
*/
#ifdef __ASSEMBLY__
#define ___opcode_swab32(x) ___asm_opcode_swab32(x)
#define ___opcode_swab16(x) ___asm_opcode_swab16(x)
#define ___opcode_swahb32(x) ___asm_opcode_swahb32(x)
#define ___opcode_swahw32(x) ___asm_opcode_swahw32(x)
#define ___opcode_identity32(x) ___asm_opcode_identity32(x)
#define ___opcode_identity16(x) ___asm_opcode_identity16(x)
#else /* ! __ASSEMBLY__ */
#include <linux/types.h>
#include <linux/swab.h>
#define ___opcode_swab32(x) swab32(x)
#define ___opcode_swab16(x) swab16(x)
#define ___opcode_swahb32(x) swahb32(x)
#define ___opcode_swahw32(x) swahw32(x)
#define ___opcode_identity32(x) ((u32)(x))
#define ___opcode_identity16(x) ((u16)(x))
#endif /* ! __ASSEMBLY__ */
#ifdef CONFIG_CPU_ENDIAN_BE8
#define __opcode_to_mem_arm(x) ___opcode_swab32(x)
#define __opcode_to_mem_thumb16(x) ___opcode_swab16(x)
#define __opcode_to_mem_thumb32(x) ___opcode_swahb32(x)
#define ___asm_opcode_to_mem_arm(x) ___asm_opcode_swab32(x)
#define ___asm_opcode_to_mem_thumb16(x) ___asm_opcode_swab16(x)
#define ___asm_opcode_to_mem_thumb32(x) ___asm_opcode_swahb32(x)
#else /* ! CONFIG_CPU_ENDIAN_BE8 */
#define __opcode_to_mem_arm(x) ___opcode_identity32(x)
#define __opcode_to_mem_thumb16(x) ___opcode_identity16(x)
#define ___asm_opcode_to_mem_arm(x) ___asm_opcode_identity32(x)
#define ___asm_opcode_to_mem_thumb16(x) ___asm_opcode_identity16(x)
#ifndef CONFIG_CPU_ENDIAN_BE32
/*
* On BE32 systems, using 32-bit accesses to store Thumb instructions will not
* work in all cases, due to alignment constraints. For now, a correct
* version is not provided for BE32.
*/
#define __opcode_to_mem_thumb32(x) ___opcode_swahw32(x)
#define ___asm_opcode_to_mem_thumb32(x) ___asm_opcode_swahw32(x)
#endif
#endif /* ! CONFIG_CPU_ENDIAN_BE8 */
#define __mem_to_opcode_arm(x) __opcode_to_mem_arm(x)
#define __mem_to_opcode_thumb16(x) __opcode_to_mem_thumb16(x)
#ifndef CONFIG_CPU_ENDIAN_BE32
#define __mem_to_opcode_thumb32(x) __opcode_to_mem_thumb32(x)
#endif
/* Operations specific to Thumb opcodes */
/* Instruction size checks: */
#define __opcode_is_thumb32(x) ( \
((x) & 0xF8000000) == 0xE8000000 \
|| ((x) & 0xF0000000) == 0xF0000000 \
)
#define __opcode_is_thumb16(x) ( \
((x) & 0xFFFF0000) == 0 \
&& !(((x) & 0xF800) == 0xE800 || ((x) & 0xF000) == 0xF000) \
)
/* Operations to construct or split 32-bit Thumb instructions: */
#define __opcode_thumb32_first(x) (___opcode_identity16((x) >> 16))
#define __opcode_thumb32_second(x) (___opcode_identity16(x))
#define __opcode_thumb32_compose(first, second) ( \
(___opcode_identity32(___opcode_identity16(first)) << 16) \
| ___opcode_identity32(___opcode_identity16(second)) \
)
#define ___asm_opcode_thumb32_first(x) (___asm_opcode_identity16((x) >> 16))
#define ___asm_opcode_thumb32_second(x) (___asm_opcode_identity16(x))
#define ___asm_opcode_thumb32_compose(first, second) ( \
(___asm_opcode_identity32(___asm_opcode_identity16(first)) << 16) \
| ___asm_opcode_identity32(___asm_opcode_identity16(second)) \
)
/*
* Opcode injection helpers
*
* In rare cases it is necessary to assemble an opcode which the
* assembler does not support directly, or which would normally be
* rejected because of the CFLAGS or AFLAGS used to build the affected
* file.
*
* Before using these macros, consider carefully whether it is feasible
* instead to change the build flags for your file, or whether it really
* makes sense to support old assembler versions when building that
* particular kernel feature.
*
* The macros defined here should only be used where there is no viable
* alternative.
*
*
* __inst_arm(x): emit the specified ARM opcode
* __inst_thumb16(x): emit the specified 16-bit Thumb opcode
* __inst_thumb32(x): emit the specified 32-bit Thumb opcode
*
* __inst_arm_thumb16(arm, thumb): emit either the specified arm or
* 16-bit Thumb opcode, depending on whether an ARM or Thumb-2
* kernel is being built
*
* __inst_arm_thumb32(arm, thumb): emit either the specified arm or
* 32-bit Thumb opcode, depending on whether an ARM or Thumb-2
* kernel is being built
*
*
* Note that using these macros directly is poor practice. Instead, you
* should use them to define human-readable wrapper macros to encode the
* instructions that you care about. In code which might run on ARMv7 or
* above, you can usually use the __inst_arm_thumb{16,32} macros to
* specify the ARM and Thumb alternatives at the same time. This ensures
* that the correct opcode gets emitted depending on the instruction set
* used for the kernel build.
*
* Look at opcodes-virt.h for an example of how to use these macros.
*/
#include <linux/stringify.h>
#define __inst_arm(x) ___inst_arm(___asm_opcode_to_mem_arm(x))
#define __inst_thumb32(x) ___inst_thumb32( \
___asm_opcode_to_mem_thumb16(___asm_opcode_thumb32_first(x)), \
___asm_opcode_to_mem_thumb16(___asm_opcode_thumb32_second(x)) \
)
#define __inst_thumb16(x) ___inst_thumb16(___asm_opcode_to_mem_thumb16(x))
#ifdef CONFIG_THUMB2_KERNEL
#define __inst_arm_thumb16(arm_opcode, thumb_opcode) \
__inst_thumb16(thumb_opcode)
#define __inst_arm_thumb32(arm_opcode, thumb_opcode) \
__inst_thumb32(thumb_opcode)
#else
#define __inst_arm_thumb16(arm_opcode, thumb_opcode) __inst_arm(arm_opcode)
#define __inst_arm_thumb32(arm_opcode, thumb_opcode) __inst_arm(arm_opcode)
#endif
/* Helpers for the helpers. Don't use these directly. */
#ifdef __ASSEMBLY__
#define ___inst_arm(x) .long x
#define ___inst_thumb16(x) .short x
#define ___inst_thumb32(first, second) .short first, second
#else
#define ___inst_arm(x) ".long " __stringify(x) "\n\t"
#define ___inst_thumb16(x) ".short " __stringify(x) "\n\t"
#define ___inst_thumb32(first, second) \
".short " __stringify(first) ", " __stringify(second) "\n\t"
#endif
#endif /* __ASM_ARM_OPCODES_H */

View File

@ -61,6 +61,15 @@
#define COMPAT_PT_TEXT_ADDR 0x10000
#define COMPAT_PT_DATA_ADDR 0x10004
#define COMPAT_PT_TEXT_END_ADDR 0x10008
/*
* used to skip a system call when tracer changes its number to -1
* with ptrace(PTRACE_SET_SYSCALL)
*/
#define RET_SKIP_SYSCALL -1
#define RET_SKIP_SYSCALL_TRACE -2
#define IS_SKIP_SYSCALL(no) ((int)(no & 0xffffffff) == -1)
#ifndef __ASSEMBLY__
/* sizeof(struct user) for AArch32 */
@ -178,5 +187,13 @@ extern unsigned long profile_pc(struct pt_regs *regs);
#define profile_pc(regs) instruction_pointer(regs)
#endif
/*
* True if instr is a 32-bit thumb instruction. This works if instr
* is the first or only half-word of a thumb instruction. It also works
* when instr holds all 32-bits of a wide thumb instruction if stored
* in the form (first_half<<16)|(second_half)
*/
#define is_wide_instruction(instr) ((unsigned)(instr) >= 0xe800)
#endif /* __ASSEMBLY__ */
#endif

View File

@ -0,0 +1,25 @@
/*
* arch/arm64/include/asm/seccomp.h
*
* Copyright (C) 2014 Linaro Limited
* Author: AKASHI Takahiro <takahiro.akashi <at> linaro.org>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*/
#ifndef _ASM_SECCOMP_H
#define _ASM_SECCOMP_H
#include <asm/unistd.h>
#ifdef CONFIG_COMPAT
#define __NR_seccomp_read_32 __NR_compat_read
#define __NR_seccomp_write_32 __NR_compat_write
#define __NR_seccomp_exit_32 __NR_compat_exit
#define __NR_seccomp_sigreturn_32 __NR_compat_rt_sigreturn
#endif /* CONFIG_COMPAT */
#include <asm-generic/seccomp.h>
#endif /* _ASM_SECCOMP_H */

View File

@ -16,6 +16,8 @@
#ifndef __ASM_SYSCALL_H
#define __ASM_SYSCALL_H
#include <uapi/linux/audit.h>
#include <linux/compat.h>
#include <linux/err.h>
extern const void *sys_call_table[];
@ -105,4 +107,16 @@ static inline void syscall_set_arguments(struct task_struct *task,
memcpy(&regs->regs[i], args, n * sizeof(args[0]));
}
/*
* We don't care about endianness (__AUDIT_ARCH_LE bit) here because
* AArch64 has the same system calls both on little- and big- endian.
*/
static inline int syscall_get_arch(void)
{
if (is_compat_task())
return AUDIT_ARCH_ARM;
return AUDIT_ARCH_AARCH64;
}
#endif /* __ASM_SYSCALL_H */

View File

@ -130,6 +130,10 @@ static inline struct thread_info *current_thread_info(void)
#define _TIF_SYSCALL_TRACEPOINT (1 << TIF_SYSCALL_TRACEPOINT)
#define _TIF_SECCOMP (1 << TIF_SECCOMP)
#define _TIF_FOREIGN_FPSTATE (1 << TIF_FOREIGN_FPSTATE)
#define _TIF_SYSCALL_TRACE (1 << TIF_SYSCALL_TRACE)
#define _TIF_SYSCALL_AUDIT (1 << TIF_SYSCALL_AUDIT)
#define _TIF_SYSCALL_TRACEPOINT (1 << TIF_SYSCALL_TRACEPOINT)
#define _TIF_SECCOMP (1 << TIF_SECCOMP)
#define _TIF_32BIT (1 << TIF_32BIT)
#define _TIF_WORK_MASK (_TIF_NEED_RESCHED | _TIF_SIGPENDING | \

View File

@ -18,6 +18,19 @@
#ifndef __ASM_TRAP_H
#define __ASM_TRAP_H
#include <linux/list.h>
struct undef_hook {
struct list_head node;
u32 instr_mask;
u32 instr_val;
u32 pstate_mask;
u32 pstate_val;
int (*fn)(struct pt_regs *regs, unsigned int instr);
};
void register_undef_hook(struct undef_hook *hook);
static inline int in_exception_text(unsigned long ptr)
{
extern char __exception_text_start[];

View File

@ -25,7 +25,27 @@
#define __ARCH_WANT_COMPAT_SYS_SENDFILE
#define __ARCH_WANT_SYS_FORK
#define __ARCH_WANT_SYS_VFORK
/*
* Compat syscall numbers used by the AArch64 kernel.
*/
#define __NR_compat_restart_syscall 0
#define __NR_compat_exit 1
#define __NR_compat_read 3
#define __NR_compat_write 4
#define __NR_compat_sigreturn 119
#define __NR_compat_rt_sigreturn 173
/*
* The following SVCs are ARM private.
*/
#define __ARM_NR_COMPAT_BASE 0x0f0000
#define __ARM_NR_compat_cacheflush (__ARM_NR_COMPAT_BASE+2)
#define __ARM_NR_compat_set_tls (__ARM_NR_COMPAT_BASE+5)
#define __NR_compat_syscalls 384
#endif
#define __ARCH_WANT_SYS_CLONE
#include <uapi/asm/unistd.h>

File diff suppressed because it is too large Load Diff

View File

@ -23,6 +23,7 @@
#include <asm/hwcap.h>
#define PTRACE_SET_SYSCALL 23
/*
* PSR bits

View File

@ -15,9 +15,10 @@ CFLAGS_REMOVE_return_address.o = -pg
arm64-obj-y := cputable.o debug-monitors.o entry.o irq.o fpsimd.o \
entry-fpsimd.o process.o ptrace.o setup.o signal.o \
sys.o stacktrace.o time.o traps.o io.o vdso.o \
hyp-stub.o psci.o cpu_ops.o insn.o return_address.o
hyp-stub.o psci.o cpu_ops.o insn.o return_address.o \
opcodes.o
arm64-obj-$(CONFIG_COMPAT) += sys32.o kuser32.o signal32.o \
arm64-obj-$(CONFIG_COMPAT) += sys32.o kuser32.o signal32.o \
sys_compat.o
arm64-obj-$(CONFIG_FUNCTION_TRACER) += ftrace.o entry-ftrace.o
arm64-obj-$(CONFIG_MODULES) += arm64ksyms.o module.o
@ -33,6 +34,8 @@ arm64-obj-$(CONFIG_JUMP_LABEL) += jump_label.o
arm64-obj-$(CONFIG_KGDB) += kgdb.o
arm64-obj-$(CONFIG_EFI) += efi.o efi-stub.o efi-entry.o
obj-$(CONFIG_SWP_EMULATE) += swp_emulate.o
obj-y += $(arm64-obj-y) vdso/
obj-m += $(arm64-obj-m)
head-y := head.o

View File

@ -25,9 +25,9 @@
#include <asm/asm-offsets.h>
#include <asm/errno.h>
#include <asm/esr.h>
#include <asm/ptrace.h>
#include <asm/thread_info.h>
#include <asm/unistd.h>
#include <asm/unistd32.h>
/*
* Bad Abort numbers
@ -666,6 +666,10 @@ __sys_trace:
mov x0, sp
bl syscall_trace_enter
adr lr, __sys_trace_return // return address
cmp w0, #RET_SKIP_SYSCALL_TRACE // skip syscall and tracing?
b.eq ret_to_user
cmp w0, #RET_SKIP_SYSCALL // skip syscall?
b.eq __sys_trace_return_skipped
uxtw scno, w0 // syscall number (possibly new)
mov x1, sp // pointer to regs
cmp scno, sc_nr // check upper syscall limit
@ -679,6 +683,7 @@ __sys_trace:
__sys_trace_return:
str x0, [sp] // save returned x0
__sys_trace_return_skipped: // x0 already in regs[0]
mov x0, sp
bl syscall_trace_exit
b ret_to_user

View File

@ -28,6 +28,7 @@
* See Documentation/arm/kernel_user_helpers.txt for formal definitions.
*/
#include <asm/unistd.h>
#include <asm/unistd32.h>
.align 5

View File

@ -0,0 +1,72 @@
/*
* Copied from linux/arch/arm/kernel/opcodes.c
*
* A32 condition code lookup feature moved from nwfpe/fpopcode.c
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*/
#include <linux/module.h>
#include <asm/opcodes.h>
#define ARM_OPCODE_CONDITION_UNCOND 0xf
/*
* condition code lookup table
* index into the table is test code: EQ, NE, ... LT, GT, AL, NV
*
* bit position in short is condition code: NZCV
*/
static const unsigned short cc_map[16] = {
0xF0F0, /* EQ == Z set */
0x0F0F, /* NE */
0xCCCC, /* CS == C set */
0x3333, /* CC */
0xFF00, /* MI == N set */
0x00FF, /* PL */
0xAAAA, /* VS == V set */
0x5555, /* VC */
0x0C0C, /* HI == C set && Z clear */
0xF3F3, /* LS == C clear || Z set */
0xAA55, /* GE == (N==V) */
0x55AA, /* LT == (N!=V) */
0x0A05, /* GT == (!Z && (N==V)) */
0xF5FA, /* LE == (Z || (N!=V)) */
0xFFFF, /* AL always */
0 /* NV */
};
/*
* Returns:
* ARM_OPCODE_CONDTEST_FAIL - if condition fails
* ARM_OPCODE_CONDTEST_PASS - if condition passes (including AL)
* ARM_OPCODE_CONDTEST_UNCOND - if NV condition, or separate unconditional
* opcode space from v5 onwards
*
* Code that tests whether a conditional instruction would pass its condition
* check should check that return value == ARM_OPCODE_CONDTEST_PASS.
*
* Code that tests if a condition means that the instruction would be executed
* (regardless of conditional or unconditional) should instead check that the
* return value != ARM_OPCODE_CONDTEST_FAIL.
*/
asmlinkage unsigned int arm_check_condition(u32 opcode, u64 psr)
{
u32 cc_bits = opcode >> 28;
u32 psr_cond = (u32)(psr & 0xffffffff) >> 28;
unsigned int ret;
if (cc_bits != ARM_OPCODE_CONDITION_UNCOND) {
if ((cc_map[cc_bits] >> (psr_cond)) & 1)
ret = ARM_OPCODE_CONDTEST_PASS;
else
ret = ARM_OPCODE_CONDTEST_FAIL;
} else {
ret = ARM_OPCODE_CONDTEST_UNCOND;
}
return ret;
}
EXPORT_SYMBOL_GPL(arm_check_condition);

View File

@ -161,6 +161,70 @@ void machine_restart(char *cmd)
while (1);
}
/*
* dump a block of kernel memory from around the given address
*/
static void show_data(unsigned long addr, int nbytes, const char *name)
{
int i, j;
int nlines;
u32 *p;
/*
* don't attempt to dump non-kernel addresses or
* values that are probably just small negative numbers
*/
if (addr < PAGE_OFFSET || addr > -256UL)
return;
printk("\n%s: %#lx:\n", name, addr);
/*
* round address down to a 32 bit boundary
* and always dump a multiple of 32 bytes
*/
p = (u32 *)(addr & ~(sizeof(u32) - 1));
nbytes += (addr & (sizeof(u32) - 1));
nlines = (nbytes + 31) / 32;
for (i = 0; i < nlines; i++) {
/*
* just display low 16 bits of address to keep
* each line of the dump < 80 characters
*/
printk("%04lx ", (unsigned long)p & 0xffff);
for (j = 0; j < 8; j++) {
u32 data;
if (probe_kernel_address(p, data)) {
printk(" ********");
} else {
printk(" %08x", data);
}
++p;
}
printk("\n");
}
}
static void show_extra_register_data(struct pt_regs *regs, int nbytes)
{
mm_segment_t fs;
unsigned int i;
fs = get_fs();
set_fs(KERNEL_DS);
show_data(regs->pc - nbytes, nbytes * 2, "PC");
show_data(regs->regs[30] - nbytes, nbytes * 2, "LR");
show_data(regs->sp - nbytes, nbytes * 2, "SP");
for (i = 0; i < 30; i++) {
char name[4];
snprintf(name, sizeof(name), "X%u", i);
show_data(regs->regs[i] - nbytes, nbytes * 2, name);
}
set_fs(fs);
}
void __show_regs(struct pt_regs *regs)
{
int i, top_reg;
@ -187,6 +251,8 @@ void __show_regs(struct pt_regs *regs)
if (i % 2 == 0)
printk("\n");
}
if (!user_mode(regs))
show_extra_register_data(regs, 128);
printk("\n");
}

View File

@ -19,6 +19,7 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <linux/audit.h>
#include <linux/compat.h>
#include <linux/kernel.h>
#include <linux/sched.h>
@ -26,6 +27,7 @@
#include <linux/smp.h>
#include <linux/ptrace.h>
#include <linux/user.h>
#include <linux/seccomp.h>
#include <linux/security.h>
#include <linux/init.h>
#include <linux/signal.h>
@ -39,6 +41,7 @@
#include <asm/compat.h>
#include <asm/debug-monitors.h>
#include <asm/pgtable.h>
#include <asm/syscall.h>
#include <asm/traps.h>
#include <asm/system_misc.h>
@ -1066,7 +1069,19 @@ const struct user_regset_view *task_user_regset_view(struct task_struct *task)
long arch_ptrace(struct task_struct *child, long request,
unsigned long addr, unsigned long data)
{
return ptrace_request(child, request, addr, data);
int ret;
switch (request) {
case PTRACE_SET_SYSCALL:
task_pt_regs(child)->syscallno = data;
ret = 0;
break;
default:
ret = ptrace_request(child, request, addr, data);
break;
}
return ret;
}
enum ptrace_syscall_dir {
@ -1104,6 +1119,9 @@ asmlinkage int syscall_trace_enter(struct pt_regs *regs)
if (test_thread_flag(TIF_SYSCALL_TRACEPOINT))
trace_sys_enter(regs, regs->syscallno);
audit_syscall_entry(syscall_get_arch(), regs->syscallno,
regs->orig_x0, regs->regs[1], regs->regs[2], regs->regs[3]);
return regs->syscallno;
}
@ -1112,6 +1130,8 @@ asmlinkage void syscall_trace_exit(struct pt_regs *regs)
if (test_thread_flag(TIF_SYSCALL_TRACEPOINT))
trace_sys_exit(regs, regs_return_value(regs));
audit_syscall_exit(regs);
if (test_thread_flag(TIF_SYSCALL_TRACE))
tracehook_report_syscall(regs, PTRACE_SYSCALL_EXIT);
}

View File

@ -507,9 +507,20 @@ static int c_show(struct seq_file *m, void *v)
for (i = 0; hwcap_str[i]; i++)
if (elf_hwcap & (1 << i))
seq_printf(m, "%s ", hwcap_str[i]);
#ifdef CONFIG_ARMV7_COMPAT_CPUINFO
if (is_compat_task()) {
/* Print out the non-optional ARMv8 HW capabilities */
seq_printf(m, "wp half thumb fastmult vfp edsp neon vfpv3 tlsi ");
seq_printf(m, "vfpv4 idiva idivt ");
}
#endif
seq_printf(m, "\nCPU implementer\t: 0x%02x\n", read_cpuid_id() >> 24);
seq_printf(m, "CPU architecture: AArch64\n");
seq_printf(m, "CPU architecture: %s\n",
#if IS_ENABLED(CONFIG_ARMV7_COMPAT_CPUINFO)
is_compat_task() ? "8" :
#endif
"AArch64");
seq_printf(m, "CPU variant\t: 0x%x\n", (read_cpuid_id() >> 20) & 15);
seq_printf(m, "CPU part\t: 0x%03x\n", (read_cpuid_id() >> 4) & 0xfff);
seq_printf(m, "CPU revision\t: %d\n", read_cpuid_id() & 15);

View File

@ -26,7 +26,7 @@
#include <asm/fpsimd.h>
#include <asm/signal32.h>
#include <asm/uaccess.h>
#include <asm/unistd32.h>
#include <asm/unistd.h>
struct compat_sigcontext {
/* We always set these two fields to 0 */
@ -183,6 +183,14 @@ int copy_siginfo_to_user32(compat_siginfo_t __user *to, siginfo_t *from)
err |= __put_user(from->si_uid, &to->si_uid);
err |= __put_user((compat_uptr_t)(unsigned long)from->si_ptr, &to->si_ptr);
break;
#ifdef __ARCH_SIGSYS
case __SI_SYS:
err |= __put_user((compat_uptr_t)(unsigned long)
from->si_call_addr, &to->si_call_addr);
err |= __put_user(from->si_syscall, &to->si_syscall);
err |= __put_user(from->si_arch, &to->si_arch);
break;
#endif
default: /* this is just in case for now ... */
err |= __put_user(from->si_pid, &to->si_pid);
err |= __put_user(from->si_uid, &to->si_uid);

View File

@ -0,0 +1,223 @@
/*
* Derived from from linux/arch/arm/kernel/swp_emulate.c
*
* Copyright (C) 2009 ARM Limited
* Copyright (c) 2014, NVIDIA CORPORATION. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
* Implements emulation of the SWP/SWPB instructions using load-exclusive and
* store-exclusive for processors that have them disabled (or future ones that
* might not implement them).
*
* Syntax of SWP{B} instruction: SWP{B}<c> <Rt>, <Rt2>, [<Rn>]
* Where: Rt = destination
* Rt2 = source
* Rn = address
*/
#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/proc_fs.h>
#include <linux/seq_file.h>
#include <linux/sched.h>
#include <linux/syscalls.h>
#include <linux/perf_event.h>
#include <asm/opcodes.h>
#include <asm/traps.h>
#include <asm/uaccess.h>
#include <asm/system_misc.h>
#include <linux/debugfs.h>
/*
* Error-checking SWP macros implemented using ldrex{b}/strex{b}
*/
static int swpb(u8 in, u8 *out, u8 *addr)
{
u8 _out;
int res;
int err;
do {
__asm__ __volatile__(
"0: ldxrb %w1, %4\n"
"1: stxrb %w0, %w3, %4\n"
" mov %w2, #0\n"
"2:\n"
" .section .fixup,\"ax\"\n"
" .align 2\n"
"3: mov %w2, %5\n"
" b 2b\n"
" .previous\n"
" .section __ex_table,\"a\"\n"
" .align 3\n"
" .quad 0b, 3b\n"
" .quad 1b, 3b\n"
" .previous"
: "=&r" (res), "=r" (_out), "=r" (err)
: "r" (in), "Q" (*addr), "i" (-EFAULT)
: "cc", "memory");
} while (err == 0 && res != 0);
if (err == 0)
*out = _out;
return err;
}
static int swp(u32 in, u32 *out, u32 *addr)
{
u32 _out;
int res;
int err = 0;
do {
__asm__ __volatile__(
"0: ldxr %w1, %4\n"
"1: stxr %w0, %w3, %4\n"
" mov %w2, #0\n"
"2:\n"
" .section .fixup,\"ax\"\n"
" .align 2\n"
"3: mov %w2, %5\n"
" b 2b\n"
" .previous\n"
" .section __ex_table,\"a\"\n"
" .align 3\n"
" .quad 0b, 3b\n"
" .quad 1b, 3b\n"
" .previous"
: "=&r" (res), "=r" (_out), "=r" (err)
: "r" (in), "Q" (*addr), "i" (-EFAULT)
: "cc", "memory");
} while (err == 0 && res != 0);
if (err == 0)
*out = _out;
return err;
}
/*
* Macros/defines for extracting register numbers from instruction.
*/
#define EXTRACT_REG_NUM(instruction, offset) \
(((instruction) & (0xf << (offset))) >> (offset))
#define RN_OFFSET 16
#define RT_OFFSET 12
#define RT2_OFFSET 0
/*
* Bit 22 of the instruction encoding distinguishes between
* the SWP and SWPB variants (bit set means SWPB).
*/
#define TYPE_SWPB (1 << 22)
static pid_t previous_pid;
u64 swpb_count = 0;
u64 swp_count = 0;
/*
* swp_handler logs the id of calling process, dissects the instruction, sanity
* checks the memory location, calls emulate_swpX for the actual operation and
* deals with fixup/error handling before returning
*/
static int swp_handler(struct pt_regs *regs, unsigned int instr)
{
u32 destreg, data, type;
uintptr_t address;
unsigned int res = 0;
int err;
u32 temp32;
u8 temp8;
perf_sw_event(PERF_COUNT_SW_EMULATION_FAULTS, 1, regs, regs->pc);
res = arm_check_condition(instr, regs->pstate);
switch (res) {
case ARM_OPCODE_CONDTEST_PASS:
break;
case ARM_OPCODE_CONDTEST_FAIL:
/* Condition failed - return to next instruction */
regs->pc += 4;
return 0;
case ARM_OPCODE_CONDTEST_UNCOND:
/* If unconditional encoding - not a SWP, undef */
return -EFAULT;
default:
return -EINVAL;
}
if (current->pid != previous_pid) {
pr_warn("\"%s\" (%ld) uses obsolete SWP{B} instruction\n",
current->comm, (unsigned long)current->pid);
previous_pid = current->pid;
}
address = regs->regs[EXTRACT_REG_NUM(instr, RN_OFFSET)] & 0xffffffff;
data = regs->regs[EXTRACT_REG_NUM(instr, RT2_OFFSET)];
destreg = EXTRACT_REG_NUM(instr, RT_OFFSET);
type = instr & TYPE_SWPB;
/* Check access in reasonable access range for both SWP and SWPB */
if (!access_ok(VERIFY_WRITE, (address & ~3), 4)) {
pr_debug("SWP{B} emulation: access to %p not allowed!\n",
(void *)address);
res = -EFAULT;
}
if (type == TYPE_SWPB) {
err = swpb((u8) data, &temp8, (u8 *) address);
if (err)
return err;
regs->regs[destreg] = temp8;
regs->pc += 4;
swpb_count++;
} else if (address & 0x3) {
/* SWP to unaligned address not permitted */
pr_debug("SWP instruction on unaligned pointer!\n");
return -EFAULT;
} else {
err = swp((u32) data, &temp32, (u32 *) address);
if (err)
return err;
regs->regs[destreg] = temp32;
regs->pc += 4;
swp_count++;
}
return 0;
}
/*
* Only emulate SWP/SWPB executed in ARM state/User mode.
* The kernel must be SWP free and SWP{B} does not exist in Thumb/ThumbEE.
*/
static struct undef_hook swp_hook = {
.instr_mask = 0x0fb00ff0,
.instr_val = 0x01000090,
.pstate_mask = COMPAT_PSR_MODE_MASK | COMPAT_PSR_T_BIT,
.pstate_val = COMPAT_PSR_MODE_USR,
.fn = swp_handler
};
/*
* Register handler and create status file in /proc/cpu
* Invoked as late_initcall, since not needed before init spawned.
*/
static int __init swp_emulation_init(void)
{
struct dentry *dir;
dir = debugfs_create_dir("swp_emulate", NULL);
debugfs_create_u64("swp_count", S_IRUGO | S_IWUSR, dir, &swp_count);
debugfs_create_u64("swpb_count", S_IRUGO | S_IWUSR, dir, &swpb_count);
pr_notice("Registering SWP/SWPB emulation handler\n");
register_undef_hook(&swp_hook);
return 0;
}
late_initcall(swp_emulation_init);

View File

@ -26,7 +26,7 @@
#include <linux/uaccess.h>
#include <asm/cacheflush.h>
#include <asm/unistd32.h>
#include <asm/unistd.h>
static inline void
do_compat_cache_op(unsigned long start, unsigned long end, int flags)

View File

@ -3,6 +3,7 @@
*
* Copyright (C) 1995-2009 Russell King
* Copyright (C) 2012 ARM Ltd.
* Copyright (c) 2014, NVIDIA CORPORATION. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
@ -257,15 +258,58 @@ void arm64_notify_die(const char *str, struct pt_regs *regs,
die(str, regs, err);
}
static LIST_HEAD(undef_hook);
void register_undef_hook(struct undef_hook *hook)
{
list_add(&hook->node, &undef_hook);
}
static int call_undef_hook(struct pt_regs *regs, unsigned int instr)
{
struct undef_hook *hook;
int (*fn)(struct pt_regs *regs, unsigned int instr) = NULL;
list_for_each_entry(hook, &undef_hook, node)
if ((instr & hook->instr_mask) == hook->instr_val &&
(regs->pstate & hook->pstate_mask) == hook->pstate_val)
fn = hook->fn;
return fn ? fn(regs, instr) : 1;
}
asmlinkage void __exception do_undefinstr(struct pt_regs *regs)
{
u32 instr;
siginfo_t info;
void __user *pc = (void __user *)instruction_pointer(regs);
/* check for AArch32 breakpoint instructions */
if (!aarch32_break_handler(regs))
return;
if (user_mode(regs)) {
if (compat_thumb_mode(regs)) {
if (get_user(instr, (u16 __user *)pc))
goto die_sig;
if (is_wide_instruction(instr)) {
u32 instr2;
if (get_user(instr2, (u16 __user *)pc+1))
goto die_sig;
instr <<= 16;
instr |= instr2;
}
} else if (get_user(instr, (u32 __user *)pc)) {
goto die_sig;
}
} else {
/* kernel mode */
instr = *((u32 *)pc);
}
if (call_undef_hook(regs, instr) == 0)
return;
die_sig:
if (show_unhandled_signals && unhandled_signal(current, SIGILL) &&
printk_ratelimit()) {
pr_info("%s[%d]: undefined instruction: pc=%p\n",

View File

@ -225,6 +225,20 @@ ENTRY(__cpu_setup)
ret // return to head.S
ENDPROC(__cpu_setup)
#ifdef CONFIG_ARMV7_COMPAT
/*
* n n T
* U E WT T UD US IHBS
* CE0 XWHW CZ ME TEEA S
* .... .IEE .... NEAI TE.I ..AD DEN0 ACAM
* 0011 0... 1101 ..0. ..0. 10.. .... .... < hardware reserved
* .... .100 .... 01.1 11.1 ..01 0011 1101 < software settings
*/
.type crval, #object
crval:
.word 0x030802e2 // clear
.word 0x0405d03d // set
#else
/*
* n n T
* U E WT T UD US IHBS
@ -237,3 +251,4 @@ ENDPROC(__cpu_setup)
crval:
.word 0x000802e2 // clear
.word 0x0405d11d // set
#endif

View File

@ -45,13 +45,36 @@
# define smp_rmb() rmb()
# define smp_wmb() wmb()
# define smp_read_barrier_depends() read_barrier_depends()
#else
# define smp_mb() barrier()
# define smp_rmb() barrier()
# define smp_wmb() barrier()
# define smp_read_barrier_depends() do { } while(0)
#endif
/*
* IA64 GCC turns volatile stores into st.rel and volatile loads into ld.acq no
* need for asm trickery!
*/
#define smp_store_release(p, v) \
do { \
compiletime_assert_atomic_type(*p); \
barrier(); \
ACCESS_ONCE(*p) = (v); \
} while (0)
#define smp_load_acquire(p) \
({ \
typeof(*p) ___p1 = ACCESS_ONCE(*p); \
compiletime_assert_atomic_type(*p); \
barrier(); \
___p1; \
})
/*
* XXX check on this ---I suspect what Linus really wants here is
* acquire vs release semantics but we can't discuss this stuff with

View File

@ -85,4 +85,19 @@ static inline void fence(void)
#define smp_read_barrier_depends() do { } while (0)
#define set_mb(var, value) do { var = value; smp_mb(); } while (0)
#define smp_store_release(p, v) \
do { \
compiletime_assert_atomic_type(*p); \
smp_mb(); \
ACCESS_ONCE(*p) = (v); \
} while (0)
#define smp_load_acquire(p) \
({ \
typeof(*p) ___p1 = ACCESS_ONCE(*p); \
compiletime_assert_atomic_type(*p); \
smp_mb(); \
___p1; \
})
#endif /* _ASM_METAG_BARRIER_H */

View File

@ -180,4 +180,19 @@
#define nudge_writes() mb()
#endif
#define smp_store_release(p, v) \
do { \
compiletime_assert_atomic_type(*p); \
smp_mb(); \
ACCESS_ONCE(*p) = (v); \
} while (0)
#define smp_load_acquire(p) \
({ \
typeof(*p) ___p1 = ACCESS_ONCE(*p); \
compiletime_assert_atomic_type(*p); \
smp_mb(); \
___p1; \
})
#endif /* __ASM_BARRIER_H */

View File

@ -369,22 +369,16 @@
#define __NR_process_vm_writev (__NR_Linux + 346)
#define __NR_kcmp (__NR_Linux + 347)
#define __NR_finit_module (__NR_Linux + 348)
/* Backporting seccomp, skip a few ...
* #define __NR_sched_setattr (__NR_Linux + 349)
* #define __NR_sched_getattr (__NR_Linux + 350)
* #define __NR_renameat2 (__NR_Linux + 351)
*/
#define __NR_seccomp (__NR_Linux + 352)
/*
* Offset of the last Linux o32 flavoured syscall
*/
#define __NR_Linux_syscalls 352
#define __NR_Linux_syscalls 348
#endif /* _MIPS_SIM == _MIPS_SIM_ABI32 */
#define __NR_O32_Linux 4000
#define __NR_O32_Linux_syscalls 352
#define __NR_O32_Linux_syscalls 348
#if _MIPS_SIM == _MIPS_SIM_ABI64
@ -701,22 +695,16 @@
#define __NR_kcmp (__NR_Linux + 306)
#define __NR_finit_module (__NR_Linux + 307)
#define __NR_getdents64 (__NR_Linux + 308)
/* Backporting seccomp, skip a few ...
* #define __NR_sched_setattr (__NR_Linux + 309)
* #define __NR_sched_getattr (__NR_Linux + 310)
* #define __NR_renameat2 (__NR_Linux + 311)
*/
#define __NR_seccomp (__NR_Linux + 312)
/*
* Offset of the last Linux 64-bit flavoured syscall
*/
#define __NR_Linux_syscalls 312
#define __NR_Linux_syscalls 308
#endif /* _MIPS_SIM == _MIPS_SIM_ABI64 */
#define __NR_64_Linux 5000
#define __NR_64_Linux_syscalls 312
#define __NR_64_Linux_syscalls 308
#if _MIPS_SIM == _MIPS_SIM_NABI32
@ -1037,21 +1025,15 @@
#define __NR_process_vm_writev (__NR_Linux + 310)
#define __NR_kcmp (__NR_Linux + 311)
#define __NR_finit_module (__NR_Linux + 312)
/* Backporting seccomp, skip a few ...
* #define __NR_sched_setattr (__NR_Linux + 313)
* #define __NR_sched_getattr (__NR_Linux + 314)
* #define __NR_renameat2 (__NR_Linux + 315)
*/
#define __NR_seccomp (__NR_Linux + 316)
/*
* Offset of the last N32 flavoured syscall
*/
#define __NR_Linux_syscalls 316
#define __NR_Linux_syscalls 312
#endif /* _MIPS_SIM == _MIPS_SIM_NABI32 */
#define __NR_N32_Linux 6000
#define __NR_N32_Linux_syscalls 316
#define __NR_N32_Linux_syscalls 312
#endif /* _UAPI_ASM_UNISTD_H */

View File

@ -593,12 +593,6 @@ einval: li v0, -ENOSYS
sys sys_process_vm_writev 6
sys sys_kcmp 5
sys sys_finit_module 3
/* Backporting seccomp, skip a few ... */
sys sys_ni_syscall 0 /* sys_sched_setattr */
sys sys_ni_syscall 0 /* sys_sched_getattr */ /* 4350 */
sys sys_ni_syscall 0 /* sys_renameat2 */
sys sys_seccomp 3
.endm
/* We pre-compute the number of _instruction_ bytes needed to

View File

@ -424,8 +424,4 @@ sys_call_table:
PTR sys_kcmp
PTR sys_finit_module
PTR sys_getdents64
sys sys_ni_syscall /* sys_sched_setattr */
sys sys_ni_syscall /* sys_sched_getattr */ /* 5310 */
sys sys_ni_syscall /* sys_renameat2 */
sys sys_seccomp
.size sys_call_table,.-sys_call_table

View File

@ -417,8 +417,4 @@ EXPORT(sysn32_call_table)
PTR compat_sys_process_vm_writev /* 6310 */
PTR sys_kcmp
PTR sys_finit_module
sys sys_ni_syscall /* sys_sched_setattr */
sys sys_ni_syscall /* sys_sched_getattr */
sys sys_ni_syscall /* sys_renameat2 */ /* 6315 */
sys sys_seccomp
.size sysn32_call_table,.-sysn32_call_table

View File

@ -541,8 +541,4 @@ sys_call_table:
PTR compat_sys_process_vm_writev
PTR sys_kcmp
PTR sys_finit_module
sys sys_ni_syscall /* sys_sched_setattr */
sys sys_ni_syscall /* sys_sched_getattr */ /* 4350 */
sys sys_ni_syscall /* sys_renameat2 */
sys sys_seccomp
.size sys32_call_table,.-sys32_call_table
.size sys_call_table,.-sys_call_table

View File

@ -45,11 +45,15 @@
# define SMPWMB eieio
#endif
#define __lwsync() __asm__ __volatile__ (stringify_in_c(LWSYNC) : : :"memory")
#define smp_mb() mb()
#define smp_rmb() __asm__ __volatile__ (stringify_in_c(LWSYNC) : : :"memory")
#define smp_rmb() __lwsync()
#define smp_wmb() __asm__ __volatile__ (stringify_in_c(SMPWMB) : : :"memory")
#define smp_read_barrier_depends() read_barrier_depends()
#else
#define __lwsync() barrier()
#define smp_mb() barrier()
#define smp_rmb() barrier()
#define smp_wmb() barrier()
@ -65,4 +69,19 @@
#define data_barrier(x) \
asm volatile("twi 0,%0,0; isync" : : "r" (x) : "memory");
#define smp_store_release(p, v) \
do { \
compiletime_assert_atomic_type(*p); \
__lwsync(); \
ACCESS_ONCE(*p) = (v); \
} while (0)
#define smp_load_acquire(p) \
({ \
typeof(*p) ___p1 = ACCESS_ONCE(*p); \
compiletime_assert_atomic_type(*p); \
__lwsync(); \
___p1; \
})
#endif /* _ASM_POWERPC_BARRIER_H */

View File

@ -32,4 +32,19 @@
#define set_mb(var, value) do { var = value; mb(); } while (0)
#define smp_store_release(p, v) \
do { \
compiletime_assert_atomic_type(*p); \
barrier(); \
ACCESS_ONCE(*p) = (v); \
} while (0)
#define smp_load_acquire(p) \
({ \
typeof(*p) ___p1 = ACCESS_ONCE(*p); \
compiletime_assert_atomic_type(*p); \
barrier(); \
___p1; \
})
#endif /* __ASM_BARRIER_H */

View File

@ -89,11 +89,10 @@ static inline void syscall_set_arguments(struct task_struct *task,
regs->orig_gpr2 = args[0];
}
static inline int syscall_get_arch(struct task_struct *task,
struct pt_regs *regs)
static inline int syscall_get_arch(void)
{
#ifdef CONFIG_COMPAT
if (test_tsk_thread_flag(task, TIF_31BIT))
if (test_tsk_thread_flag(current, TIF_31BIT))
return AUDIT_ARCH_S390;
#endif
return sizeof(long) == 8 ? AUDIT_ARCH_S390X : AUDIT_ARCH_S390;

View File

@ -53,4 +53,19 @@ do { __asm__ __volatile__("ba,pt %%xcc, 1f\n\t" \
#define smp_read_barrier_depends() do { } while(0)
#define smp_store_release(p, v) \
do { \
compiletime_assert_atomic_type(*p); \
barrier(); \
ACCESS_ONCE(*p) = (v); \
} while (0)
#define smp_load_acquire(p) \
({ \
typeof(*p) ___p1 = ACCESS_ONCE(*p); \
compiletime_assert_atomic_type(*p); \
barrier(); \
___p1; \
})
#endif /* !(__SPARC64_BARRIER_H) */

View File

@ -92,12 +92,53 @@
#endif
#define smp_read_barrier_depends() read_barrier_depends()
#define set_mb(var, value) do { (void)xchg(&var, value); } while (0)
#else
#else /* !SMP */
#define smp_mb() barrier()
#define smp_rmb() barrier()
#define smp_wmb() barrier()
#define smp_read_barrier_depends() do { } while (0)
#define set_mb(var, value) do { var = value; barrier(); } while (0)
#endif /* SMP */
#if defined(CONFIG_X86_OOSTORE) || defined(CONFIG_X86_PPRO_FENCE)
/*
* For either of these options x86 doesn't have a strong TSO memory
* model and we should fall back to full barriers.
*/
#define smp_store_release(p, v) \
do { \
compiletime_assert_atomic_type(*p); \
smp_mb(); \
ACCESS_ONCE(*p) = (v); \
} while (0)
#define smp_load_acquire(p) \
({ \
typeof(*p) ___p1 = ACCESS_ONCE(*p); \
compiletime_assert_atomic_type(*p); \
smp_mb(); \
___p1; \
})
#else /* regular x86 TSO memory ordering */
#define smp_store_release(p, v) \
do { \
compiletime_assert_atomic_type(*p); \
barrier(); \
ACCESS_ONCE(*p) = (v); \
} while (0)
#define smp_load_acquire(p) \
({ \
typeof(*p) ___p1 = ACCESS_ONCE(*p); \
compiletime_assert_atomic_type(*p); \
barrier(); \
___p1; \
})
#endif
/*

View File

@ -90,8 +90,7 @@ static inline void syscall_set_arguments(struct task_struct *task,
memcpy(&regs->bx + i, args, n * sizeof(args[0]));
}
static inline int syscall_get_arch(struct task_struct *task,
struct pt_regs *regs)
static inline int syscall_get_arch(void)
{
return AUDIT_ARCH_I386;
}
@ -220,8 +219,7 @@ static inline void syscall_set_arguments(struct task_struct *task,
}
}
static inline int syscall_get_arch(struct task_struct *task,
struct pt_regs *regs)
static inline int syscall_get_arch(void)
{
#ifdef CONFIG_IA32_EMULATION
/*
@ -233,7 +231,7 @@ static inline int syscall_get_arch(struct task_struct *task,
*
* x32 tasks should be considered AUDIT_ARCH_X86_64.
*/
if (task_thread_info(task)->status & TS_COMPAT)
if (task_thread_info(current)->status & TS_COMPAT)
return AUDIT_ARCH_I386;
#endif
/* Both x32 and x86_64 are considered "64-bit". */

View File

@ -357,7 +357,6 @@
348 i386 process_vm_writev sys_process_vm_writev compat_sys_process_vm_writev
349 i386 kcmp sys_kcmp
350 i386 finit_module sys_finit_module
# Backporting seccomp, skip a few ...
# 351 i386 sched_setattr sys_sched_setattr
# 352 i386 sched_getattr sys_sched_getattr
# 353 i386 renameat2 sys_renameat2

View File

@ -320,7 +320,6 @@
311 64 process_vm_writev sys_process_vm_writev
312 common kcmp sys_kcmp
313 common finit_module sys_finit_module
# Backporting seccomp, skip a few ...
# 314 common sched_setattr sys_sched_setattr
# 315 common sched_getattr sys_sched_getattr
# 316 common renameat2 sys_renameat2

View File

@ -32,6 +32,7 @@
#include <linux/cpufreq.h>
#include <linux/cpuidle.h>
#include <linux/timer.h>
#include <linux/wakeup_reason.h>
#include "../base.h"
#include "power.h"
@ -942,6 +943,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();
@ -969,6 +971,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;
}
@ -1027,6 +1032,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);
@ -1052,6 +1058,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;
}
@ -1119,6 +1128,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);
@ -1135,6 +1145,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;
}

View File

@ -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;

View File

@ -10,6 +10,7 @@
#include <linux/mutex.h>
#include <linux/module.h>
#include <linux/interrupt.h>
#include <linux/wakeup_reason.h>
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)

View File

@ -285,19 +285,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);

View File

@ -66,10 +66,10 @@
* - MS-Windows drivers sometimes emit undocumented requests.
*/
static bool rndis_multipacket_dl_disable;
module_param(rndis_multipacket_dl_disable, bool, S_IRUGO|S_IWUSR);
MODULE_PARM_DESC(rndis_multipacket_dl_disable,
"Disable RNDIS Multi-packet support in DownLink");
static unsigned int rndis_dl_max_pkt_per_xfer = 3;
module_param(rndis_dl_max_pkt_per_xfer, uint, S_IRUGO | S_IWUSR);
MODULE_PARM_DESC(rndis_dl_max_pkt_per_xfer,
"Maximum packets per transfer for DL aggregation");
static unsigned int rndis_ul_max_pkt_per_xfer = 3;
module_param(rndis_ul_max_pkt_per_xfer, uint, S_IRUGO | S_IWUSR);
@ -457,6 +457,7 @@ static void rndis_command_complete(struct usb_ep *ep, struct usb_request *req)
{
struct f_rndis *rndis = req->context;
int status;
rndis_init_msg_type *buf;
/* received RNDIS command from USB_CDC_SEND_ENCAPSULATED_COMMAND */
// spin_lock(&dev->lock);
@ -464,6 +465,21 @@ static void rndis_command_complete(struct usb_ep *ep, struct usb_request *req)
if (status < 0)
pr_err("RNDIS command error %d, %d/%d\n",
status, req->actual, req->length);
buf = (rndis_init_msg_type *)req->buf;
if (buf->MessageType == RNDIS_MSG_INIT) {
if (buf->MaxTransferSize > 2048)
rndis->port.multi_pkt_xfer = 1;
else
rndis->port.multi_pkt_xfer = 0;
pr_info("%s: MaxTransferSize: %d : Multi_pkt_txr: %s\n",
__func__, buf->MaxTransferSize,
rndis->port.multi_pkt_xfer ? "enabled" :
"disabled");
if (rndis_dl_max_pkt_per_xfer <= 1)
rndis->port.multi_pkt_xfer = 0;
}
// spin_unlock(&dev->lock);
}
@ -865,6 +881,7 @@ rndis_bind_config_vendor(struct usb_configuration *c, u8 ethaddr[ETH_ALEN],
rndis->port.wrap = rndis_add_header;
rndis->port.unwrap = rndis_rm_hdr;
rndis->port.ul_max_pkts_per_xfer = rndis_ul_max_pkt_per_xfer;
rndis->port.dl_max_pkts_per_xfer = rndis_dl_max_pkt_per_xfer;
rndis->port.func.name = "rndis";
rndis->port.func.strings = rndis_strings;

View File

@ -48,6 +48,8 @@
#define UETH__VERSION "29-May-2008"
static struct workqueue_struct *uether_wq;
struct eth_dev {
/* lock is held while accessing port_usb
*/
@ -59,18 +61,25 @@ struct eth_dev {
spinlock_t req_lock; /* guard {rx,tx}_reqs */
struct list_head tx_reqs, rx_reqs;
atomic_t tx_qlen;
unsigned tx_qlen;
/* Minimum number of TX USB request queued to UDC */
#define TX_REQ_THRESHOLD 5
int no_tx_req_used;
int tx_skb_hold_count;
u32 tx_req_bufsize;
struct sk_buff_head rx_frames;
unsigned header_len;
unsigned ul_max_pkts_per_xfer;
unsigned dl_max_pkts_per_xfer;
struct sk_buff *(*wrap)(struct gether *, struct sk_buff *skb);
int (*unwrap)(struct gether *,
struct sk_buff *skb,
struct sk_buff_head *list);
struct work_struct work;
struct work_struct rx_work;
unsigned long todo;
#define WORK_RX_MEMORY 0
@ -85,7 +94,7 @@ struct eth_dev {
#define DEFAULT_QLEN 2 /* double buffering by default */
static unsigned qmult = 5;
static unsigned qmult = 10;
module_param(qmult, uint, S_IRUGO|S_IWUSR);
MODULE_PARM_DESC(qmult, "queue length multiplier at high/super speed");
@ -259,18 +268,16 @@ rx_submit(struct eth_dev *dev, struct usb_request *req, gfp_t gfp_flags)
DBG(dev, "rx submit --> %d\n", retval);
if (skb)
dev_kfree_skb_any(skb);
spin_lock_irqsave(&dev->req_lock, flags);
list_add(&req->list, &dev->rx_reqs);
spin_unlock_irqrestore(&dev->req_lock, flags);
}
return retval;
}
static void rx_complete(struct usb_ep *ep, struct usb_request *req)
{
struct sk_buff *skb = req->context, *skb2;
struct sk_buff *skb = req->context;
struct eth_dev *dev = ep->driver_data;
int status = req->status;
bool queue = 0;
switch (status) {
@ -286,6 +293,10 @@ static void rx_complete(struct usb_ep *ep, struct usb_request *req)
status = dev->unwrap(dev->port_usb,
skb,
&dev->rx_frames);
if (status == -EINVAL)
dev->net->stats.rx_errors++;
else if (status == -EOVERFLOW)
dev->net->stats.rx_over_errors++;
} else {
dev_kfree_skb_any(skb);
status = -ENOTCONN;
@ -294,30 +305,9 @@ static void rx_complete(struct usb_ep *ep, struct usb_request *req)
} else {
skb_queue_tail(&dev->rx_frames, skb);
}
skb = NULL;
skb2 = skb_dequeue(&dev->rx_frames);
while (skb2) {
if (status < 0
|| ETH_HLEN > skb2->len
|| skb2->len > VLAN_ETH_FRAME_LEN) {
dev->net->stats.rx_errors++;
dev->net->stats.rx_length_errors++;
DBG(dev, "rx length %d\n", skb2->len);
dev_kfree_skb_any(skb2);
goto next_frame;
}
skb2->protocol = eth_type_trans(skb2, dev->net);
dev->net->stats.rx_packets++;
dev->net->stats.rx_bytes += skb2->len;
/* no buffer copies needed, unless hardware can't
* use skb buffers.
*/
status = netif_rx(skb2);
next_frame:
skb2 = skb_dequeue(&dev->rx_frames);
}
if (!status)
queue = 1;
break;
/* software-driven interface shutdown */
@ -340,22 +330,20 @@ static void rx_complete(struct usb_ep *ep, struct usb_request *req)
/* FALLTHROUGH */
default:
queue = 1;
dev_kfree_skb_any(skb);
dev->net->stats.rx_errors++;
DBG(dev, "rx status %d\n", status);
break;
}
if (skb)
dev_kfree_skb_any(skb);
if (!netif_running(dev->net)) {
clean:
spin_lock(&dev->req_lock);
list_add(&req->list, &dev->rx_reqs);
spin_unlock(&dev->req_lock);
req = NULL;
}
if (req)
rx_submit(dev, req, GFP_ATOMIC);
spin_lock(&dev->req_lock);
list_add(&req->list, &dev->rx_reqs);
spin_unlock(&dev->req_lock);
if (queue)
queue_work(uether_wq, &dev->rx_work);
}
static int prealloc(struct list_head *list, struct usb_ep *ep, unsigned n)
@ -420,16 +408,24 @@ static void rx_fill(struct eth_dev *dev, gfp_t gfp_flags)
{
struct usb_request *req;
unsigned long flags;
int req_cnt = 0;
/* fill unused rxq slots with some skb */
spin_lock_irqsave(&dev->req_lock, flags);
while (!list_empty(&dev->rx_reqs)) {
/* break the nexus of continuous completion and re-submission*/
if (++req_cnt > qlen(dev->gadget))
break;
req = container_of(dev->rx_reqs.next,
struct usb_request, list);
list_del_init(&req->list);
spin_unlock_irqrestore(&dev->req_lock, flags);
if (rx_submit(dev, req, gfp_flags) < 0) {
spin_lock_irqsave(&dev->req_lock, flags);
list_add(&req->list, &dev->rx_reqs);
spin_unlock_irqrestore(&dev->req_lock, flags);
defer_kevent(dev, WORK_RX_MEMORY);
return;
}
@ -439,6 +435,36 @@ static void rx_fill(struct eth_dev *dev, gfp_t gfp_flags)
spin_unlock_irqrestore(&dev->req_lock, flags);
}
static void process_rx_w(struct work_struct *work)
{
struct eth_dev *dev = container_of(work, struct eth_dev, rx_work);
struct sk_buff *skb;
int status = 0;
if (!dev->port_usb)
return;
while ((skb = skb_dequeue(&dev->rx_frames))) {
if (status < 0
|| ETH_HLEN > skb->len
|| skb->len > ETH_FRAME_LEN) {
dev->net->stats.rx_errors++;
dev->net->stats.rx_length_errors++;
DBG(dev, "rx length %d\n", skb->len);
dev_kfree_skb_any(skb);
continue;
}
skb->protocol = eth_type_trans(skb, dev->net);
dev->net->stats.rx_packets++;
dev->net->stats.rx_bytes += skb->len;
status = netif_rx_ni(skb);
}
if (netif_running(dev->net))
rx_fill(dev, GFP_KERNEL);
}
static void eth_work(struct work_struct *work)
{
struct eth_dev *dev = container_of(work, struct eth_dev, work);
@ -456,6 +482,11 @@ static void tx_complete(struct usb_ep *ep, struct usb_request *req)
{
struct sk_buff *skb = req->context;
struct eth_dev *dev = ep->driver_data;
struct net_device *net = dev->net;
struct usb_request *new_req;
struct usb_ep *in;
int length;
int retval;
switch (req->status) {
default:
@ -466,16 +497,74 @@ static void tx_complete(struct usb_ep *ep, struct usb_request *req)
case -ESHUTDOWN: /* disconnect etc */
break;
case 0:
dev->net->stats.tx_bytes += skb->len;
if (!req->zero)
dev->net->stats.tx_bytes += req->length-1;
else
dev->net->stats.tx_bytes += req->length;
}
dev->net->stats.tx_packets++;
spin_lock(&dev->req_lock);
list_add(&req->list, &dev->tx_reqs);
spin_unlock(&dev->req_lock);
dev_kfree_skb_any(skb);
list_add_tail(&req->list, &dev->tx_reqs);
if (dev->port_usb->multi_pkt_xfer) {
dev->no_tx_req_used--;
req->length = 0;
in = dev->port_usb->in_ep;
if (!list_empty(&dev->tx_reqs)) {
new_req = container_of(dev->tx_reqs.next,
struct usb_request, list);
list_del(&new_req->list);
spin_unlock(&dev->req_lock);
if (new_req->length > 0) {
length = new_req->length;
/* NCM requires no zlp if transfer is
* dwNtbInMaxSize */
if (dev->port_usb->is_fixed &&
length == dev->port_usb->fixed_in_len &&
(length % in->maxpacket) == 0)
new_req->zero = 0;
else
new_req->zero = 1;
/* use zlp framing on tx for strict CDC-Ether
* conformance, though any robust network rx
* path ignores extra padding. and some hardware
* doesn't like to write zlps.
*/
if (new_req->zero && !dev->zlp &&
(length % in->maxpacket) == 0) {
new_req->zero = 0;
length++;
}
new_req->length = length;
retval = usb_ep_queue(in, new_req, GFP_ATOMIC);
switch (retval) {
default:
DBG(dev, "tx queue err %d\n", retval);
break;
case 0:
spin_lock(&dev->req_lock);
dev->no_tx_req_used++;
spin_unlock(&dev->req_lock);
net->trans_start = jiffies;
}
} else {
spin_lock(&dev->req_lock);
list_add(&new_req->list, &dev->tx_reqs);
spin_unlock(&dev->req_lock);
}
} else {
spin_unlock(&dev->req_lock);
}
} else {
spin_unlock(&dev->req_lock);
dev_kfree_skb_any(skb);
}
atomic_dec(&dev->tx_qlen);
if (netif_carrier_ok(dev->net))
netif_wake_queue(dev->net);
}
@ -485,6 +574,26 @@ static inline int is_promisc(u16 cdc_filter)
return cdc_filter & USB_CDC_PACKET_TYPE_PROMISCUOUS;
}
static void alloc_tx_buffer(struct eth_dev *dev)
{
struct list_head *act;
struct usb_request *req;
dev->tx_req_bufsize = (dev->dl_max_pkts_per_xfer *
(dev->net->mtu
+ sizeof(struct ethhdr)
/* size of rndis_packet_msg_type */
+ 44
+ 22));
list_for_each(act, &dev->tx_reqs) {
req = container_of(act, struct usb_request, list);
if (!req->buf)
req->buf = kmalloc(dev->tx_req_bufsize,
GFP_ATOMIC);
}
}
static netdev_tx_t eth_start_xmit(struct sk_buff *skb,
struct net_device *net)
{
@ -511,6 +620,10 @@ static netdev_tx_t eth_start_xmit(struct sk_buff *skb,
return NETDEV_TX_OK;
}
/* Allocate memory for tx_reqs to support multi packet transfer */
if (dev->port_usb->multi_pkt_xfer && !dev->tx_req_bufsize)
alloc_tx_buffer(dev);
/* apply outgoing CDC or RNDIS filters */
if (!is_promisc(cdc_filter)) {
u8 *dest = skb->data;
@ -565,11 +678,39 @@ static netdev_tx_t eth_start_xmit(struct sk_buff *skb,
spin_unlock_irqrestore(&dev->lock, flags);
if (!skb)
goto drop;
length = skb->len;
}
req->buf = skb->data;
req->context = skb;
spin_lock_irqsave(&dev->req_lock, flags);
dev->tx_skb_hold_count++;
spin_unlock_irqrestore(&dev->req_lock, flags);
if (dev->port_usb->multi_pkt_xfer) {
memcpy(req->buf + req->length, skb->data, skb->len);
req->length = req->length + skb->len;
length = req->length;
dev_kfree_skb_any(skb);
spin_lock_irqsave(&dev->req_lock, flags);
if (dev->tx_skb_hold_count < dev->dl_max_pkts_per_xfer) {
if (dev->no_tx_req_used > TX_REQ_THRESHOLD) {
list_add(&req->list, &dev->tx_reqs);
spin_unlock_irqrestore(&dev->req_lock, flags);
goto success;
}
}
dev->no_tx_req_used++;
spin_unlock_irqrestore(&dev->req_lock, flags);
spin_lock_irqsave(&dev->lock, flags);
dev->tx_skb_hold_count = 0;
spin_unlock_irqrestore(&dev->lock, flags);
} else {
length = skb->len;
req->buf = skb->data;
req->context = skb;
}
req->complete = tx_complete;
/* NCM requires no zlp if transfer is dwNtbInMaxSize */
@ -584,17 +725,26 @@ static netdev_tx_t eth_start_xmit(struct sk_buff *skb,
* though any robust network rx path ignores extra padding.
* and some hardware doesn't like to write zlps.
*/
if (req->zero && !dev->zlp && (length % in->maxpacket) == 0)
if (req->zero && !dev->zlp && (length % in->maxpacket) == 0) {
req->zero = 0;
length++;
}
req->length = length;
/* throttle high/super speed IRQ rate back slightly */
if (gadget_is_dualspeed(dev->gadget))
req->no_interrupt = (dev->gadget->speed == USB_SPEED_HIGH ||
dev->gadget->speed == USB_SPEED_SUPER)
? ((atomic_read(&dev->tx_qlen) % qmult) != 0)
: 0;
/* throttle highspeed IRQ rate back slightly */
if (gadget_is_dualspeed(dev->gadget) &&
(dev->gadget->speed == USB_SPEED_HIGH)) {
dev->tx_qlen++;
if (dev->tx_qlen == (qmult/2)) {
req->no_interrupt = 0;
dev->tx_qlen = 0;
} else {
req->no_interrupt = 1;
}
} else {
req->no_interrupt = 0;
}
retval = usb_ep_queue(in, req, GFP_ATOMIC);
switch (retval) {
@ -603,11 +753,11 @@ static netdev_tx_t eth_start_xmit(struct sk_buff *skb,
break;
case 0:
net->trans_start = jiffies;
atomic_inc(&dev->tx_qlen);
}
if (retval) {
dev_kfree_skb_any(skb);
if (!dev->port_usb->multi_pkt_xfer)
dev_kfree_skb_any(skb);
drop:
dev->net->stats.tx_dropped++;
spin_lock_irqsave(&dev->req_lock, flags);
@ -616,6 +766,7 @@ static netdev_tx_t eth_start_xmit(struct sk_buff *skb,
list_add(&req->list, &dev->tx_reqs);
spin_unlock_irqrestore(&dev->req_lock, flags);
}
success:
return NETDEV_TX_OK;
}
@ -629,7 +780,7 @@ static void eth_start(struct eth_dev *dev, gfp_t gfp_flags)
rx_fill(dev, gfp_flags);
/* and open the tx floodgates */
atomic_set(&dev->tx_qlen, 0);
dev->tx_qlen = 0;
netif_wake_queue(dev->net);
}
@ -702,6 +853,8 @@ static int eth_stop(struct net_device *net)
/*-------------------------------------------------------------------------*/
static u8 host_ethaddr[ETH_ALEN];
/* initial value, changed by "ifconfig usb0 hw ether xx:xx:xx:xx:xx:xx" */
static char *dev_addr;
module_param(dev_addr, charp, S_IRUGO);
@ -733,6 +886,17 @@ static int get_ether_addr(const char *str, u8 *dev_addr)
return 1;
}
static int get_host_ether_addr(u8 *str, u8 *dev_addr)
{
memcpy(dev_addr, str, ETH_ALEN);
if (is_valid_ether_addr(dev_addr))
return 0;
random_ether_addr(dev_addr);
memcpy(str, dev_addr, ETH_ALEN);
return 1;
}
static const struct net_device_ops eth_netdev_ops = {
.ndo_open = eth_open,
.ndo_stop = eth_stop,
@ -775,6 +939,7 @@ struct eth_dev *gether_setup_name(struct usb_gadget *g, u8 ethaddr[ETH_ALEN],
spin_lock_init(&dev->lock);
spin_lock_init(&dev->req_lock);
INIT_WORK(&dev->work, eth_work);
INIT_WORK(&dev->rx_work, process_rx_w);
INIT_LIST_HEAD(&dev->tx_reqs);
INIT_LIST_HEAD(&dev->rx_reqs);
@ -787,9 +952,11 @@ struct eth_dev *gether_setup_name(struct usb_gadget *g, u8 ethaddr[ETH_ALEN],
if (get_ether_addr(dev_addr, net->dev_addr))
dev_warn(&g->dev,
"using random %s ethernet address\n", "self");
if (get_ether_addr(host_addr, dev->host_mac))
dev_warn(&g->dev,
"using random %s ethernet address\n", "host");
if (get_host_ether_addr(host_ethaddr, dev->host_mac))
dev_warn(&g->dev, "using random %s ethernet address\n", "host");
else
dev_warn(&g->dev, "using previous %s ethernet address\n", "host");
if (ethaddr)
memcpy(ethaddr, dev->host_mac, ETH_ALEN);
@ -888,8 +1055,12 @@ struct net_device *gether_connect(struct gether *link)
dev->unwrap = link->unwrap;
dev->wrap = link->wrap;
dev->ul_max_pkts_per_xfer = link->ul_max_pkts_per_xfer;
dev->dl_max_pkts_per_xfer = link->dl_max_pkts_per_xfer;
spin_lock(&dev->lock);
dev->tx_skb_hold_count = 0;
dev->no_tx_req_used = 0;
dev->tx_req_bufsize = 0;
dev->port_usb = link;
if (netif_running(dev->net)) {
if (link->open)
@ -933,6 +1104,7 @@ void gether_disconnect(struct gether *link)
{
struct eth_dev *dev = link->ioport;
struct usb_request *req;
struct sk_buff *skb;
WARN_ON(!dev);
if (!dev)
@ -955,6 +1127,8 @@ void gether_disconnect(struct gether *link)
list_del(&req->list);
spin_unlock(&dev->req_lock);
if (link->multi_pkt_xfer)
kfree(req->buf);
usb_ep_free_request(link->in_ep, req);
spin_lock(&dev->req_lock);
}
@ -974,6 +1148,12 @@ void gether_disconnect(struct gether *link)
spin_lock(&dev->req_lock);
}
spin_unlock(&dev->req_lock);
spin_lock(&dev->rx_frames.lock);
while ((skb = __skb_dequeue(&dev->rx_frames)))
dev_kfree_skb_any(skb);
spin_unlock(&dev->rx_frames.lock);
link->out_ep->driver_data = NULL;
link->out_ep->desc = NULL;
@ -986,3 +1166,23 @@ void gether_disconnect(struct gether *link)
dev->port_usb = NULL;
spin_unlock(&dev->lock);
}
static int __init gether_init(void)
{
uether_wq = create_singlethread_workqueue("uether");
if (!uether_wq) {
pr_err("%s: Unable to create workqueue: uether\n", __func__);
return -ENOMEM;
}
return 0;
}
module_init(gether_init);
static void __exit gether_exit(void)
{
destroy_workqueue(uether_wq);
}
module_exit(gether_exit);
MODULE_DESCRIPTION("ethernet over USB driver");
MODULE_LICENSE("GPL v2");

View File

@ -55,8 +55,7 @@ struct gether {
u32 fixed_out_len;
u32 fixed_in_len;
unsigned ul_max_pkts_per_xfer;
/* Max number of SKB packets to be used to create Multi Packet RNDIS */
#define TX_SKB_HOLD_THRESHOLD 3
unsigned dl_max_pkts_per_xfer;
bool multi_pkt_xfer;
struct sk_buff *(*wrap)(struct gether *port,
struct sk_buff *skb);

View File

@ -1239,7 +1239,7 @@ static int check_unsafe_exec(struct linux_binprm *bprm)
* This isn't strictly necessary, but it makes it harder for LSMs to
* mess up.
*/
if (current->no_new_privs)
if (task_no_new_privs(current))
bprm->unsafe |= LSM_UNSAFE_NO_NEW_PRIVS;
n_fs = 1;
@ -1286,7 +1286,7 @@ int prepare_binprm(struct linux_binprm *bprm)
bprm->cred->egid = current_egid();
if (!(bprm->file->f_path.mnt->mnt_flags & MNT_NOSUID) &&
!current->no_new_privs &&
!task_no_new_privs(current) &&
kuid_has_mapping(bprm->cred->user_ns, inode->i_uid) &&
kgid_has_mapping(bprm->cred->user_ns, inode->i_gid)) {
/* Set-uid? */

View File

@ -46,5 +46,20 @@
#define read_barrier_depends() do {} while (0)
#define smp_read_barrier_depends() do {} while (0)
#define smp_store_release(p, v) \
do { \
compiletime_assert_atomic_type(*p); \
smp_mb(); \
ACCESS_ONCE(*p) = (v); \
} while (0)
#define smp_load_acquire(p) \
({ \
typeof(*p) ___p1 = ACCESS_ONCE(*p); \
compiletime_assert_atomic_type(*p); \
smp_mb(); \
___p1; \
})
#endif /* !__ASSEMBLY__ */
#endif /* __ASM_GENERIC_BARRIER_H */

View File

@ -0,0 +1,29 @@
/*
* include/asm-generic/seccomp.h
*
* Copyright (C) 2014 Linaro Limited
* Author: AKASHI Takahiro <takahiro.akashi <at> linaro.org>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*/
#ifndef _ASM_GENERIC_SECCOMP_H
#define _ASM_GENERIC_SECCOMP_H
#include <asm-generic/unistd.h>
#if defined(CONFIG_COMPAT) && !defined(__NR_seccomp_read_32)
#define __NR_seccomp_read_32 __NR_read
#define __NR_seccomp_write_32 __NR_write
#define __NR_seccomp_exit_32 __NR_exit
#define __NR_seccomp_sigreturn_32 __NR_rt_sigreturn
#endif /* CONFIG_COMPAT && ! already defined */
#define __NR_seccomp_read __NR_read
#define __NR_seccomp_write __NR_write
#define __NR_seccomp_exit __NR_exit
#define __NR_seccomp_sigreturn __NR_rt_sigreturn
#endif /* _ASM_GENERIC_SECCOMP_H */

View File

@ -144,8 +144,6 @@ void syscall_set_arguments(struct task_struct *task, struct pt_regs *regs,
/**
* syscall_get_arch - return the AUDIT_ARCH for the current system call
* @task: task of interest, must be in system call entry tracing
* @regs: task_pt_regs() of @task
*
* Returns the AUDIT_ARCH_* based on the system call convention in use.
*
@ -155,5 +153,5 @@ void syscall_set_arguments(struct task_struct *task, struct pt_regs *regs,
* Architectures which permit CONFIG_HAVE_ARCH_SECCOMP_FILTER must
* provide an implementation of this.
*/
int syscall_get_arch(struct task_struct *task, struct pt_regs *regs);
int syscall_get_arch(void);
#endif /* _ASM_SYSCALL_H */

View File

@ -302,6 +302,11 @@ void ftrace_likely_update(struct ftrace_branch_data *f, int val, int expect);
# define __same_type(a, b) __builtin_types_compatible_p(typeof(a), typeof(b))
#endif
/* Is this type a native word size -- useful for atomic operations */
#ifndef __native_word
# define __native_word(t) (sizeof(t) == sizeof(int) || sizeof(t) == sizeof(long))
#endif
/* Compile time object size, -1 for unknown */
#ifndef __compiletime_object_size
# define __compiletime_object_size(obj) -1
@ -341,6 +346,10 @@ void ftrace_likely_update(struct ftrace_branch_data *f, int val, int expect);
#define compiletime_assert(condition, msg) \
_compiletime_assert(condition, msg, __compiletime_assert_, __LINE__)
#define compiletime_assert_atomic_type(t) \
compiletime_assert(__native_word(t), \
"Need native word sized stores/loads for atomicity.")
/*
* Prevent the compiler from merging or refetching accesses. The compiler
* is also forbidden from reordering successive instances of ACCESS_ONCE(),

View File

@ -1143,13 +1143,12 @@ struct task_struct {
* execve */
unsigned in_iowait:1;
/* task may not gain privileges */
unsigned no_new_privs:1;
/* Revert to default priority/policy when forking */
unsigned sched_reset_on_fork:1;
unsigned sched_contributes_to_load:1;
unsigned long atomic_flags; /* Flags needing atomic access. */
pid_t pid;
pid_t tgid;
@ -1716,6 +1715,19 @@ static inline void memalloc_noio_restore(unsigned int flags)
current->flags = (current->flags & ~PF_MEMALLOC_NOIO) | flags;
}
/* Per-process atomic flags. */
#define PFA_NO_NEW_PRIVS 0x00000001 /* May not gain new privileges. */
static inline bool task_no_new_privs(struct task_struct *p)
{
return test_bit(PFA_NO_NEW_PRIVS, &p->atomic_flags);
}
static inline void task_set_no_new_privs(struct task_struct *p)
{
set_bit(PFA_NO_NEW_PRIVS, &p->atomic_flags);
}
/*
* task->jobctl flags
*/

View File

@ -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;

View File

@ -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 */

View File

@ -324,6 +324,8 @@ enum {
/* distinguish syscall tables */
#define __AUDIT_ARCH_64BIT 0x80000000
#define __AUDIT_ARCH_LE 0x40000000
#define AUDIT_ARCH_AARCH64 (EM_AARCH64|__AUDIT_ARCH_64BIT|__AUDIT_ARCH_LE)
#define AUDIT_ARCH_ALPHA (EM_ALPHA|__AUDIT_ARCH_64BIT|__AUDIT_ARCH_LE)
#define AUDIT_ARCH_ARM (EM_ARM|__AUDIT_ARCH_LE)
#define AUDIT_ARCH_ARMEB (EM_ARM)

View File

@ -1126,7 +1126,7 @@ static void copy_seccomp(struct task_struct *p)
* needed because this new task is not yet running and cannot
* be racing exec.
*/
BUG_ON(!spin_is_locked(&current->sighand->siglock));
assert_spin_locked(&current->sighand->siglock);
/* Ref-count the new filter user, and assign it. */
get_seccomp_filter(current);

View File

@ -10,7 +10,7 @@
#include <linux/module.h>
#include <linux/interrupt.h>
#include <linux/syscore_ops.h>
#include <linux/wakeup_reason.h>
#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 ?

View File

@ -17,7 +17,7 @@
#include <linux/delay.h>
#include <linux/workqueue.h>
#include <linux/kmod.h>
#include <linux/wakeup_reason.h>
/*
* 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;
}
@ -82,23 +86,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);

View File

@ -27,6 +27,7 @@
#include <linux/ftrace.h>
#include <linux/rtc.h>
#include <trace/events/power.h>
#include <linux/wakeup_reason.h>
#include "power.h"
@ -139,7 +140,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:
@ -169,7 +170,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();
@ -179,7 +181,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;
}
@ -204,8 +210,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());
@ -216,6 +224,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();
}
@ -263,6 +275,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");

View File

@ -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:

View File

@ -97,7 +97,7 @@ u32 seccomp_bpf_load(int off)
if (off == BPF_DATA(nr))
return syscall_get_nr(current, regs);
if (off == BPF_DATA(arch))
return syscall_get_arch(current, regs);
return syscall_get_arch();
if (off >= BPF_DATA(args[0]) && off < BPF_DATA(args[6])) {
unsigned long value;
int arg = (off - BPF_DATA(args[0])) / sizeof(u64);
@ -204,7 +204,6 @@ static int seccomp_check_filter(struct sock_filter *filter, unsigned int flen)
static u32 seccomp_run_filters(int syscall)
{
struct seccomp_filter *f = ACCESS_ONCE(current->seccomp.filter);
struct seccomp_data sd;
u32 ret = SECCOMP_RET_ALLOW;
/* Ensure unexpected behavior doesn't result in failing open. */
@ -214,15 +213,13 @@ static u32 seccomp_run_filters(int syscall)
/* Make sure cross-thread synced filter points somewhere sane. */
smp_read_barrier_depends();
populate_seccomp_data(&sd);
/*
* All filters in the list are evaluated and the lowest BPF return
* value always takes priority (ignoring the DATA).
*/
for (; f; f = f->prev) {
u32 cur_ret = SK_RUN_FILTER(f->prog, (void *)&sd);
u32 cur_ret = sk_run_filter(NULL, f->insns);
if ((cur_ret & SECCOMP_RET_ACTION) < (ret & SECCOMP_RET_ACTION))
ret = cur_ret;
}
@ -232,7 +229,7 @@ static u32 seccomp_run_filters(int syscall)
static inline bool seccomp_may_assign_mode(unsigned long seccomp_mode)
{
BUG_ON(!spin_is_locked(&current->sighand->siglock));
assert_spin_locked(&current->sighand->siglock);
if (current->seccomp.mode && current->seccomp.mode != seccomp_mode)
return false;
@ -243,14 +240,14 @@ static inline bool seccomp_may_assign_mode(unsigned long seccomp_mode)
static inline void seccomp_assign_mode(struct task_struct *task,
unsigned long seccomp_mode)
{
BUG_ON(!spin_is_locked(&task->sighand->siglock));
assert_spin_locked(&task->sighand->siglock);
task->seccomp.mode = seccomp_mode;
/*
* Make sure TIF_SECCOMP cannot be set before the mode (and
* filter) is set.
*/
smp_mb__before_atomic();
smp_mb();
set_tsk_thread_flag(task, TIF_SECCOMP);
}
@ -282,7 +279,7 @@ static inline pid_t seccomp_can_sync_threads(void)
struct task_struct *thread, *caller;
BUG_ON(!mutex_is_locked(&current->signal->cred_guard_mutex));
BUG_ON(!spin_is_locked(&current->sighand->siglock));
assert_spin_locked(&current->sighand->siglock);
/* Validate all threads being eligible for synchronization. */
caller = current;
@ -323,7 +320,7 @@ static inline void seccomp_sync_threads(void)
struct task_struct *thread, *caller;
BUG_ON(!mutex_is_locked(&current->signal->cred_guard_mutex));
BUG_ON(!spin_is_locked(&current->sighand->siglock));
assert_spin_locked(&current->sighand->siglock);
/* Synchronize all threads. */
caller = current;
@ -372,15 +369,18 @@ static inline void seccomp_sync_threads(void)
static struct seccomp_filter *seccomp_prepare_filter(struct sock_fprog *fprog)
{
struct seccomp_filter *filter;
unsigned long fp_size;
struct sock_filter *fp;
int new_len;
unsigned long fp_size = fprog->len * sizeof(struct sock_filter);
unsigned long total_insns = fprog->len;
long ret;
if (fprog->len == 0 || fprog->len > BPF_MAXINSNS)
return ERR_PTR(-EINVAL);
BUG_ON(INT_MAX / fprog->len < sizeof(struct sock_filter));
fp_size = fprog->len * sizeof(struct sock_filter);
for (filter = current->seccomp.filter; filter; filter = filter->prev)
total_insns += filter->len + 4; /* include a 4 instr penalty */
if (total_insns > MAX_INSNS_PER_PATH)
return ERR_PTR(-ENOMEM);
/*
* Installing a seccomp filter requires that the task have
@ -388,14 +388,18 @@ static struct seccomp_filter *seccomp_prepare_filter(struct sock_fprog *fprog)
* This avoids scenarios where unprivileged tasks can affect the
* behavior of privileged children.
*/
if (!current->no_new_privs &&
if (!task_no_new_privs(current) &&
security_capable_noaudit(current_cred(), current_user_ns(),
CAP_SYS_ADMIN) != 0)
return ERR_PTR(-EACCES);
fp = kzalloc(fp_size, GFP_KERNEL|__GFP_NOWARN);
if (!fp)
return ERR_PTR(-ENOMEM);
/* Allocate a new seccomp_filter */
filter = kzalloc(sizeof(struct seccomp_filter) + fp_size,
GFP_KERNEL|__GFP_NOWARN);
if (!filter)
return ERR_PTR(-ENOMEM);;
atomic_set(&filter->usage, 1);
filter->len = fprog->len;
/* Copy the instructions from fprog. */
ret = -EFAULT;
@ -410,32 +414,12 @@ static struct seccomp_filter *seccomp_prepare_filter(struct sock_fprog *fprog)
/* Check and rewrite the fprog for seccomp use */
ret = seccomp_check_filter(filter->insns, filter->len);
if (ret)
goto free_prog;
/* Allocate a new seccomp_filter */
ret = -ENOMEM;
filter = kzalloc(sizeof(struct seccomp_filter) +
sizeof(struct sock_filter_int) * new_len,
GFP_KERNEL|__GFP_NOWARN);
if (!filter)
goto free_prog;
ret = sk_convert_filter(fp, fprog->len, filter->insnsi, &new_len);
if (ret)
goto free_filter;
kfree(fp);
atomic_set(&filter->usage, 1);
filter->len = new_len;
goto fail;
return filter;
free_filter_prog:
kfree(filter->prog);
free_filter:
fail:
kfree(filter);
free_prog:
kfree(fp);
return ERR_PTR(ret);
}
@ -482,12 +466,12 @@ static long seccomp_attach_filter(unsigned int flags,
unsigned long total_insns;
struct seccomp_filter *walker;
BUG_ON(!spin_is_locked(&current->sighand->siglock));
assert_spin_locked(&current->sighand->siglock);
/* Validate resulting filter length. */
total_insns = filter->prog->len;
total_insns = filter->len;
for (walker = current->seccomp.filter; walker; walker = walker->prev)
total_insns += walker->prog->len + 4; /* 4 instr penalty */
total_insns += walker->len + 4; /* 4 instr penalty */
if (total_insns > MAX_INSNS_PER_PATH)
return -ENOMEM;
@ -527,7 +511,6 @@ void get_seccomp_filter(struct task_struct *tsk)
static inline void seccomp_filter_free(struct seccomp_filter *filter)
{
if (filter) {
sk_filter_free(filter->prog);
kfree(filter);
}
}
@ -559,7 +542,7 @@ static void seccomp_send_sigsys(int syscall, int reason)
info.si_code = SYS_SECCOMP;
info.si_call_addr = (void __user *)KSTK_EIP(current);
info.si_errno = reason;
info.si_arch = syscall_get_arch(current, task_pt_regs(current));
info.si_arch = syscall_get_arch();
info.si_syscall = syscall;
force_sig_info(SIGSYS, &info, current);
}

View File

@ -2427,12 +2427,12 @@ SYSCALL_DEFINE5(prctl, int, option, unsigned long, arg2, unsigned long, arg3,
if (arg2 != 1 || arg3 || arg4 || arg5)
return -EINVAL;
current->no_new_privs = 1;
task_set_no_new_privs(current);
break;
case PR_GET_NO_NEW_PRIVS:
if (arg2 || arg3 || arg4 || arg5)
return -EINVAL;
return current->no_new_privs ? 1 : 0;
return task_no_new_privs(current) ? 1 : 0;
case PR_SET_VMA:
error = prctl_set_vma(arg2, arg3, arg4, arg5);
break;

View File

@ -3585,3 +3585,4 @@ int tcp_nuke_addr(struct net *net, struct sockaddr *addr)
return 0;
}
EXPORT_SYMBOL_GPL(tcp_nuke_addr);

View File

@ -629,7 +629,7 @@ int aa_change_hat(const char *hats[], int count, u64 token, bool permtest)
* There is no exception for unconfined as change_hat is not
* available.
*/
if (current->no_new_privs)
if (task_no_new_privs(current))
return -EPERM;
/* released below */
@ -780,7 +780,7 @@ int aa_change_profile(const char *ns_name, const char *hname, bool onexec,
* no_new_privs is set because this aways results in a reduction
* of permissions.
*/
if (current->no_new_privs && !unconfined(profile)) {
if (task_no_new_privs(current) && !unconfined(profile)) {
put_cred(cred);
return -EPERM;
}