mirror of
https://github.com/torvalds/linux.git
synced 2026-06-08 14:42:37 +02:00
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:
commit
2cb6410ac9
10
MAINTAINERS
10
MAINTAINERS
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
||||
|
|
|
|||
|
|
@ -103,8 +103,7 @@ static inline void syscall_set_arguments(struct task_struct *task,
|
|||
memcpy(®s->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;
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
||||
/*
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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"
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
||||
|
|
|
|||
231
arch/arm64/include/asm/opcodes.h
Normal file
231
arch/arm64/include/asm/opcodes.h
Normal 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 */
|
||||
|
|
@ -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
|
||||
|
|
|
|||
25
arch/arm64/include/asm/seccomp.h
Normal file
25
arch/arm64/include/asm/seccomp.h
Normal 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 */
|
||||
|
|
@ -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(®s->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 */
|
||||
|
|
|
|||
|
|
@ -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 | \
|
||||
|
|
|
|||
|
|
@ -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[];
|
||||
|
|
|
|||
|
|
@ -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
|
|
@ -23,6 +23,7 @@
|
|||
|
||||
#include <asm/hwcap.h>
|
||||
|
||||
#define PTRACE_SET_SYSCALL 23
|
||||
|
||||
/*
|
||||
* PSR bits
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -28,6 +28,7 @@
|
|||
* See Documentation/arm/kernel_user_helpers.txt for formal definitions.
|
||||
*/
|
||||
|
||||
#include <asm/unistd.h>
|
||||
#include <asm/unistd32.h>
|
||||
|
||||
.align 5
|
||||
|
|
|
|||
72
arch/arm64/kernel/opcodes.c
Normal file
72
arch/arm64/kernel/opcodes.c
Normal 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);
|
||||
|
|
@ -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");
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
223
arch/arm64/kernel/swp_emulate.c
Normal file
223
arch/arm64/kernel/swp_emulate.c
Normal 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);
|
||||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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",
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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 */
|
||||
|
|
|
|||
|
|
@ -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 */
|
||||
|
|
|
|||
|
|
@ -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 */
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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 */
|
||||
|
|
|
|||
|
|
@ -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 */
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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) */
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
||||
/*
|
||||
|
|
|
|||
|
|
@ -90,8 +90,7 @@ static inline void syscall_set_arguments(struct task_struct *task,
|
|||
memcpy(®s->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". */
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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");
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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? */
|
||||
|
|
|
|||
|
|
@ -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 */
|
||||
|
|
|
|||
29
include/asm-generic/seccomp.h
Normal file
29
include/asm-generic/seccomp.h
Normal 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 */
|
||||
|
||||
|
|
@ -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 */
|
||||
|
|
|
|||
|
|
@ -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(),
|
||||
|
|
|
|||
|
|
@ -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
|
||||
*/
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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 */
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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(¤t->sighand->siglock));
|
||||
assert_spin_locked(¤t->sighand->siglock);
|
||||
|
||||
/* Ref-count the new filter user, and assign it. */
|
||||
get_seccomp_filter(current);
|
||||
|
|
|
|||
|
|
@ -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 ?
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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");
|
||||
|
|
|
|||
|
|
@ -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:
|
||||
|
|
|
|||
|
|
@ -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(¤t->sighand->siglock));
|
||||
assert_spin_locked(¤t->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(¤t->signal->cred_guard_mutex));
|
||||
BUG_ON(!spin_is_locked(¤t->sighand->siglock));
|
||||
assert_spin_locked(¤t->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(¤t->signal->cred_guard_mutex));
|
||||
BUG_ON(!spin_is_locked(¤t->sighand->siglock));
|
||||
assert_spin_locked(¤t->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(¤t->sighand->siglock));
|
||||
assert_spin_locked(¤t->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);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -3585,3 +3585,4 @@ int tcp_nuke_addr(struct net *net, struct sockaddr *addr)
|
|||
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(tcp_nuke_addr);
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user