diff options
author | 2013-11-04 19:05:54 -0500 | |
---|---|---|
committer | 2013-11-04 19:05:54 -0500 | |
commit | ee6147f8d257074979248d11bf7736e30662d0ea (patch) | |
tree | b2b086a34476f2b1ce9b283508f4f4f5275823a0 | |
parent | Grsec/PaX: 2.9.1-{2.6.32.61,3.2.52,3.11.6}-201310292050 (diff) | |
download | hardened-patchset-ee6147f8d257074979248d11bf7736e30662d0ea.tar.gz hardened-patchset-ee6147f8d257074979248d11bf7736e30662d0ea.tar.bz2 hardened-patchset-ee6147f8d257074979248d11bf7736e30662d0ea.zip |
Grsec/PaX: 2.9.1-{3.2.52,3.11.6}-20131102163520131102
-rw-r--r-- | 3.11.6/0000_README | 2 | ||||
-rw-r--r-- | 3.11.6/4420_grsecurity-2.9.1-3.11.6-201311021635.patch (renamed from 3.11.6/4420_grsecurity-2.9.1-3.11.6-201310292050.patch) | 107 | ||||
-rw-r--r-- | 3.2.52/0000_README | 2 | ||||
-rw-r--r-- | 3.2.52/4420_grsecurity-2.9.1-3.2.52-201311021628.patch (renamed from 3.2.52/4420_grsecurity-2.9.1-3.2.52-201310292049.patch) | 1688 |
4 files changed, 1690 insertions, 109 deletions
diff --git a/3.11.6/0000_README b/3.11.6/0000_README index 2489326..358a97d 100644 --- a/3.11.6/0000_README +++ b/3.11.6/0000_README @@ -2,7 +2,7 @@ README ----------------------------------------------------------------------------- Individual Patch Descriptions: ----------------------------------------------------------------------------- -Patch: 4420_grsecurity-2.9.1-3.11.6-201310292050.patch +Patch: 4420_grsecurity-2.9.1-3.11.6-201311021635.patch From: http://www.grsecurity.net Desc: hardened-sources base patch from upstream grsecurity diff --git a/3.11.6/4420_grsecurity-2.9.1-3.11.6-201310292050.patch b/3.11.6/4420_grsecurity-2.9.1-3.11.6-201311021635.patch index 020c231..306363f 100644 --- a/3.11.6/4420_grsecurity-2.9.1-3.11.6-201310292050.patch +++ b/3.11.6/4420_grsecurity-2.9.1-3.11.6-201311021635.patch @@ -46087,6 +46087,19 @@ index fcb0329..d77b7f2 100644 ret = sysfs_create_bin_file(&pdev->dev.kobj, &m48t59_nvram_attr); if (ret) +diff --git a/drivers/scsi/aacraid/linit.c b/drivers/scsi/aacraid/linit.c +index 408a42e..f0d432c 100644 +--- a/drivers/scsi/aacraid/linit.c ++++ b/drivers/scsi/aacraid/linit.c +@@ -771,6 +771,8 @@ static long aac_compat_do_ioctl(struct aac_dev *dev, unsigned cmd, unsigned long + static int aac_compat_ioctl(struct scsi_device *sdev, int cmd, void __user *arg) + { + struct aac_dev *dev = (struct aac_dev *)sdev->host->hostdata; ++ if (!capable(CAP_SYS_RAWIO)) ++ return -EPERM; + return aac_compat_do_ioctl(dev, cmd, (unsigned long)arg); + } + diff --git a/drivers/scsi/bfa/bfa_fcpim.h b/drivers/scsi/bfa/bfa_fcpim.h index e693af6..2e525b6 100644 --- a/drivers/scsi/bfa/bfa_fcpim.h @@ -47112,6 +47125,18 @@ index ee3a57f..18368c1 100644 tdev->dev = device_create(timed_output_class, NULL, MKDEV(0, tdev->index), NULL, "%s", tdev->name); if (IS_ERR(tdev->dev)) +diff --git a/drivers/staging/bcm/Bcmchar.c b/drivers/staging/bcm/Bcmchar.c +index f67a225..756b634 100644 +--- a/drivers/staging/bcm/Bcmchar.c ++++ b/drivers/staging/bcm/Bcmchar.c +@@ -1960,6 +1960,7 @@ cntrlEnd: + + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, OSAL_DBG, DBG_LVL_ALL, "Called IOCTL_BCM_GET_DEVICE_DRIVER_INFO\n"); + ++ memset(&DevInfo, 0, sizeof(DevInfo)); + DevInfo.MaxRDMBufferSize = BUFFER_4K; + DevInfo.u32DSDStartOffset = EEPROM_CALPARAM_START; + DevInfo.u32RxAlignmentCorrection = 0; diff --git a/drivers/staging/media/solo6x10/solo6x10-core.c b/drivers/staging/media/solo6x10/solo6x10-core.c index 3675020..e80d92c 100644 --- a/drivers/staging/media/solo6x10/solo6x10-core.c @@ -47203,6 +47228,20 @@ index c3a90e7..023619a 100644 #endif } +diff --git a/drivers/staging/ozwpan/ozcdev.c b/drivers/staging/ozwpan/ozcdev.c +index 374fdc3..ea5f9f3 100644 +--- a/drivers/staging/ozwpan/ozcdev.c ++++ b/drivers/staging/ozwpan/ozcdev.c +@@ -152,6 +152,9 @@ static ssize_t oz_cdev_write(struct file *filp, const char __user *buf, + struct oz_app_hdr *app_hdr; + struct oz_serial_ctx *ctx; + ++ if (count > sizeof(ei->data) - sizeof(*elt) - sizeof(*app_hdr)) ++ return -EINVAL; ++ + spin_lock_bh(&g_cdev.lock); + pd = g_cdev.active_pd; + if (pd) diff --git a/drivers/staging/rtl8712/rtl871x_io.h b/drivers/staging/rtl8712/rtl871x_io.h index dc23395..cf7e9b1 100644 --- a/drivers/staging/rtl8712/rtl871x_io.h @@ -47346,6 +47385,47 @@ index c699a30..b90a5fd 100644 pDevice->apdev->netdev_ops = &apdev_netdev_ops; pDevice->apdev->type = ARPHRD_IEEE80211; +diff --git a/drivers/staging/wlags49_h2/wl_priv.c b/drivers/staging/wlags49_h2/wl_priv.c +index c97e0e1..7e10dcd 100644 +--- a/drivers/staging/wlags49_h2/wl_priv.c ++++ b/drivers/staging/wlags49_h2/wl_priv.c +@@ -570,6 +570,7 @@ int wvlan_uil_put_info(struct uilreq *urq, struct wl_private *lp) + ltv_t *pLtv; + bool_t ltvAllocated = FALSE; + ENCSTRCT sEncryption; ++ size_t len; + + #ifdef USE_WDS + hcf_16 hcfPort = HCF_PORT_0; +@@ -686,7 +687,8 @@ int wvlan_uil_put_info(struct uilreq *urq, struct wl_private *lp) + break; + case CFG_CNF_OWN_NAME: + memset(lp->StationName, 0, sizeof(lp->StationName)); +- memcpy((void *)lp->StationName, (void *)&pLtv->u.u8[2], (size_t)pLtv->u.u16[0]); ++ len = min_t(size_t, pLtv->u.u16[0], sizeof(lp->StationName)); ++ strlcpy(lp->StationName, &pLtv->u.u8[2], len); + pLtv->u.u16[0] = CNV_INT_TO_LITTLE(pLtv->u.u16[0]); + break; + case CFG_CNF_LOAD_BALANCING: +@@ -1783,6 +1785,7 @@ int wvlan_set_station_nickname(struct net_device *dev, + { + struct wl_private *lp = wl_priv(dev); + unsigned long flags; ++ size_t len; + int ret = 0; + /*------------------------------------------------------------------------*/ + +@@ -1793,8 +1796,8 @@ int wvlan_set_station_nickname(struct net_device *dev, + wl_lock(lp, &flags); + + memset(lp->StationName, 0, sizeof(lp->StationName)); +- +- memcpy(lp->StationName, extra, wrqu->data.length); ++ len = min_t(size_t, wrqu->data.length, sizeof(lp->StationName)); ++ strlcpy(lp->StationName, extra, len); + + /* Commit the adapter parameters */ + wl_apply(lp); diff --git a/drivers/staging/zcache/tmem.h b/drivers/staging/zcache/tmem.h index d128ce2..fc1f9a1 100644 --- a/drivers/staging/zcache/tmem.h @@ -85733,6 +85813,20 @@ index e796429..6e38f9f 100644 static inline void *ptr_to_indirect(void *ptr) { +diff --git a/lib/scatterlist.c b/lib/scatterlist.c +index a685c8a..d16fa29 100644 +--- a/lib/scatterlist.c ++++ b/lib/scatterlist.c +@@ -577,7 +577,8 @@ void sg_miter_stop(struct sg_mapping_iter *miter) + miter->__offset += miter->consumed; + miter->__remaining -= miter->consumed; + +- if (miter->__flags & SG_MITER_TO_SG) ++ if ((miter->__flags & SG_MITER_TO_SG) && ++ !PageSlab(miter->page)) + flush_kernel_dcache_page(miter->page); + + if (miter->__flags & SG_MITER_ATOMIC) { diff --git a/lib/strncpy_from_user.c b/lib/strncpy_from_user.c index bb2b201..46abaf9 100644 --- a/lib/strncpy_from_user.c @@ -91613,6 +91707,19 @@ index dfa602c..3103d88 100644 if (!IS_ERR(flo)) fle->object = flo; else +diff --git a/net/core/flow_dissector.c b/net/core/flow_dissector.c +index 52d0f83..4a1d064 100644 +--- a/net/core/flow_dissector.c ++++ b/net/core/flow_dissector.c +@@ -40,7 +40,7 @@ again: + struct iphdr _iph; + ip: + iph = skb_header_pointer(skb, nhoff, sizeof(_iph), &_iph); +- if (!iph) ++ if (!iph || iph->ihl < 5) + return false; + + if (ip_is_fragment(iph)) diff --git a/net/core/iovec.c b/net/core/iovec.c index de178e4..1dabd8b 100644 --- a/net/core/iovec.c diff --git a/3.2.52/0000_README b/3.2.52/0000_README index f3e1e87..7ddab2f 100644 --- a/3.2.52/0000_README +++ b/3.2.52/0000_README @@ -126,7 +126,7 @@ Patch: 1051_linux-3.2.52.patch From: http://www.kernel.org Desc: Linux 3.2.52 -Patch: 4420_grsecurity-2.9.1-3.2.52-201310292049.patch +Patch: 4420_grsecurity-2.9.1-3.2.52-201311021628.patch From: http://www.grsecurity.net Desc: hardened-sources base patch from upstream grsecurity diff --git a/3.2.52/4420_grsecurity-2.9.1-3.2.52-201310292049.patch b/3.2.52/4420_grsecurity-2.9.1-3.2.52-201311021628.patch index e09de55..398b6be 100644 --- a/3.2.52/4420_grsecurity-2.9.1-3.2.52-201310292049.patch +++ b/3.2.52/4420_grsecurity-2.9.1-3.2.52-201311021628.patch @@ -485,6 +485,39 @@ index 1dd2c09..6f850c4 100644 $(cmd_crmodverdir) $(Q)$(MAKE) KBUILD_MODULES=$(if $(CONFIG_MODULES),1) \ $(build)=$(build-dir) $(@:.ko=.o) +diff --git a/arch/Kconfig b/arch/Kconfig +index 4b0669c..7389b35 100644 +--- a/arch/Kconfig ++++ b/arch/Kconfig +@@ -181,4 +181,28 @@ config HAVE_RCU_TABLE_FREE + config ARCH_HAVE_NMI_SAFE_CMPXCHG + bool + ++config HAVE_ARCH_SECCOMP_FILTER ++ bool ++ help ++ An arch should select this symbol if it provides all of these things: ++ - syscall_get_arch() ++ - syscall_get_arguments() ++ - syscall_rollback() ++ - syscall_set_return_value() ++ - SIGSYS siginfo_t support ++ - uses __secure_computing_int() or secure_computing() ++ - secure_computing is called from a ptrace_event()-safe context ++ - secure_computing return value is checked and a return value of -1 ++ results in the system call being skipped immediately. ++ ++config SECCOMP_FILTER ++ def_bool y ++ depends on HAVE_ARCH_SECCOMP_FILTER && SECCOMP && NET ++ help ++ Enable tasks to build secure computing environments defined ++ in terms of Berkeley Packet Filter programs which implement ++ task-defined system call filtering polices. ++ ++ See Documentation/prctl/seccomp_filter.txt for details. ++ + source "kernel/gcov/Kconfig" diff --git a/arch/alpha/include/asm/atomic.h b/arch/alpha/include/asm/atomic.h index 6f1aca7..fa956e0 100644 --- a/arch/alpha/include/asm/atomic.h @@ -8873,10 +8906,18 @@ index ad8f795..2c7eec6 100644 /* * Memory returned by kmalloc() may be used for DMA, so we must make diff --git a/arch/x86/Kconfig b/arch/x86/Kconfig -index fb2e69d..9cd4eea 100644 +index fb2e69d..27ff8ca 100644 --- a/arch/x86/Kconfig +++ b/arch/x86/Kconfig -@@ -235,7 +235,7 @@ config X86_HT +@@ -75,6 +75,7 @@ config X86 + select HAVE_BPF_JIT if (X86_64 && NET) + select CLKEVT_I8253 + select ARCH_HAVE_NMI_SAFE_CMPXCHG ++ select HAVE_ARCH_SECCOMP_FILTER + + config INSTRUCTION_DECODER + def_bool (KPROBES || PERF_EVENTS) +@@ -235,7 +236,7 @@ config X86_HT config X86_32_LAZY_GS def_bool y @@ -8885,7 +8926,7 @@ index fb2e69d..9cd4eea 100644 config ARCH_HWEIGHT_CFLAGS string -@@ -999,6 +999,7 @@ config MICROCODE_OLD_INTERFACE +@@ -999,6 +1000,7 @@ config MICROCODE_OLD_INTERFACE config X86_MSR tristate "/dev/cpu/*/msr - Model-specific register support" @@ -8893,7 +8934,7 @@ index fb2e69d..9cd4eea 100644 ---help--- This device gives privileged processes access to the x86 Model-Specific Registers (MSRs). It is a character device with -@@ -1022,7 +1023,7 @@ choice +@@ -1022,7 +1024,7 @@ choice config NOHIGHMEM bool "off" @@ -8902,7 +8943,7 @@ index fb2e69d..9cd4eea 100644 ---help--- Linux can use up to 64 Gigabytes of physical memory on x86 systems. However, the address space of 32-bit x86 processors is only 4 -@@ -1059,7 +1060,7 @@ config NOHIGHMEM +@@ -1059,7 +1061,7 @@ config NOHIGHMEM config HIGHMEM4G bool "4GB" @@ -8911,7 +8952,7 @@ index fb2e69d..9cd4eea 100644 ---help--- Select this if you have a 32-bit processor and between 1 and 4 gigabytes of physical RAM. -@@ -1113,7 +1114,7 @@ config PAGE_OFFSET +@@ -1113,7 +1115,7 @@ config PAGE_OFFSET hex default 0xB0000000 if VMSPLIT_3G_OPT default 0x80000000 if VMSPLIT_2G @@ -8920,7 +8961,7 @@ index fb2e69d..9cd4eea 100644 default 0x40000000 if VMSPLIT_1G default 0xC0000000 depends on X86_32 -@@ -1496,6 +1497,7 @@ config SECCOMP +@@ -1496,6 +1498,7 @@ config SECCOMP config CC_STACKPROTECTOR bool "Enable -fstack-protector buffer overflow detection (EXPERIMENTAL)" @@ -8928,7 +8969,7 @@ index fb2e69d..9cd4eea 100644 ---help--- This option turns on the -fstack-protector GCC feature. This feature puts, at the beginning of functions, a canary value on -@@ -1616,6 +1618,8 @@ config X86_NEED_RELOCS +@@ -1616,6 +1619,8 @@ config X86_NEED_RELOCS config PHYSICAL_ALIGN hex "Alignment value to which kernel should be aligned" if X86_32 default "0x1000000" @@ -8937,7 +8978,7 @@ index fb2e69d..9cd4eea 100644 range 0x2000 0x1000000 ---help--- This value puts the alignment restrictions on physical address -@@ -1647,9 +1651,10 @@ config HOTPLUG_CPU +@@ -1647,9 +1652,10 @@ config HOTPLUG_CPU Say N if you want to disable CPU hotplug. config COMPAT_VDSO @@ -9766,10 +9807,21 @@ index fd84387..887aa7e 100644 (unsigned long)create_aout_tables((char __user *)bprm->p, bprm); /* start thread */ diff --git a/arch/x86/ia32/ia32_signal.c b/arch/x86/ia32/ia32_signal.c -index 6557769..ef6ae89 100644 +index 6557769..dfa8ead 100644 --- a/arch/x86/ia32/ia32_signal.c +++ b/arch/x86/ia32/ia32_signal.c -@@ -169,7 +169,7 @@ asmlinkage long sys32_sigaltstack(const stack_ia32_t __user *uss_ptr, +@@ -73,6 +73,10 @@ int copy_siginfo_to_user32(compat_siginfo_t __user *to, siginfo_t *from) + switch (from->si_code >> 16) { + case __SI_FAULT >> 16: + break; ++ case __SI_SYS >> 16: ++ put_user_ex(from->si_syscall, &to->si_syscall); ++ put_user_ex(from->si_arch, &to->si_arch); ++ break; + case __SI_CHLD >> 16: + put_user_ex(from->si_utime, &to->si_utime); + put_user_ex(from->si_stime, &to->si_stime); +@@ -169,7 +173,7 @@ asmlinkage long sys32_sigaltstack(const stack_ia32_t __user *uss_ptr, } seg = get_fs(); set_fs(KERNEL_DS); @@ -9778,7 +9830,7 @@ index 6557769..ef6ae89 100644 set_fs(seg); if (ret >= 0 && uoss_ptr) { if (!access_ok(VERIFY_WRITE, uoss_ptr, sizeof(stack_ia32_t))) -@@ -370,7 +370,7 @@ static int ia32_setup_sigcontext(struct sigcontext_ia32 __user *sc, +@@ -370,7 +374,7 @@ static int ia32_setup_sigcontext(struct sigcontext_ia32 __user *sc, */ static void __user *get_sigframe(struct k_sigaction *ka, struct pt_regs *regs, size_t frame_size, @@ -9787,7 +9839,7 @@ index 6557769..ef6ae89 100644 { unsigned long sp; -@@ -391,7 +391,7 @@ static void __user *get_sigframe(struct k_sigaction *ka, struct pt_regs *regs, +@@ -391,7 +395,7 @@ static void __user *get_sigframe(struct k_sigaction *ka, struct pt_regs *regs, if (used_math()) { sp = sp - sig_xstate_ia32_size; @@ -9796,7 +9848,7 @@ index 6557769..ef6ae89 100644 if (save_i387_xstate_ia32(*fpstate) < 0) return (void __user *) -1L; } -@@ -399,7 +399,7 @@ static void __user *get_sigframe(struct k_sigaction *ka, struct pt_regs *regs, +@@ -399,7 +403,7 @@ static void __user *get_sigframe(struct k_sigaction *ka, struct pt_regs *regs, sp -= frame_size; /* Align the stack pointer according to the i386 ABI, * i.e. so that on function entry ((sp + 4) & 15) == 0. */ @@ -9805,7 +9857,7 @@ index 6557769..ef6ae89 100644 return (void __user *) sp; } -@@ -457,7 +457,7 @@ int ia32_setup_frame(int sig, struct k_sigaction *ka, +@@ -457,7 +461,7 @@ int ia32_setup_frame(int sig, struct k_sigaction *ka, * These are actually not used anymore, but left because some * gdb versions depend on them as a marker. */ @@ -9814,7 +9866,7 @@ index 6557769..ef6ae89 100644 } put_user_catch(err); if (err) -@@ -499,7 +499,7 @@ int ia32_setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info, +@@ -499,7 +503,7 @@ int ia32_setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info, 0xb8, __NR_ia32_rt_sigreturn, 0x80cd, @@ -9823,7 +9875,7 @@ index 6557769..ef6ae89 100644 }; frame = get_sigframe(ka, regs, sizeof(*frame), &fpstate); -@@ -529,16 +529,18 @@ int ia32_setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info, +@@ -529,16 +533,18 @@ int ia32_setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info, if (ka->sa.sa_flags & SA_RESTORER) restorer = ka->sa.sa_restorer; @@ -11945,6 +11997,23 @@ index a203659..9889f1c 100644 extern struct legacy_pic *legacy_pic; extern struct legacy_pic null_legacy_pic; +diff --git a/arch/x86/include/asm/ia32.h b/arch/x86/include/asm/ia32.h +index 1f7e625..541485f 100644 +--- a/arch/x86/include/asm/ia32.h ++++ b/arch/x86/include/asm/ia32.h +@@ -126,6 +126,12 @@ typedef struct compat_siginfo { + int _band; /* POLL_IN, POLL_OUT, POLL_MSG */ + int _fd; + } _sigpoll; ++ ++ struct { ++ unsigned int _call_addr; /* calling insn */ ++ int _syscall; /* triggering system call number */ ++ unsigned int _arch; /* AUDIT_ARCH_* of syscall */ ++ } _sigsys; + } _sifields; + } compat_siginfo_t; + diff --git a/arch/x86/include/asm/io.h b/arch/x86/include/asm/io.h index d8e8eef..1765f78 100644 --- a/arch/x86/include/asm/io.h @@ -13832,6 +13901,54 @@ index cb23852..2dde194 100644 asmlinkage long sys32_sysfs(int, u32, u32); asmlinkage long sys32_sched_rr_get_interval(compat_pid_t, +diff --git a/arch/x86/include/asm/syscall.h b/arch/x86/include/asm/syscall.h +index c4a348f..e2ad7ea 100644 +--- a/arch/x86/include/asm/syscall.h ++++ b/arch/x86/include/asm/syscall.h +@@ -13,6 +13,7 @@ + #ifndef _ASM_X86_SYSCALL_H + #define _ASM_X86_SYSCALL_H + ++#include <linux/audit.h> + #include <linux/sched.h> + #include <linux/err.h> + +@@ -86,6 +87,12 @@ 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) ++{ ++ return AUDIT_ARCH_I386; ++} ++ + #else /* CONFIG_X86_64 */ + + static inline void syscall_get_arguments(struct task_struct *task, +@@ -210,6 +217,22 @@ static inline void syscall_set_arguments(struct task_struct *task, + } + } + ++static inline int syscall_get_arch(struct task_struct *task, ++ struct pt_regs *regs) ++{ ++#ifdef CONFIG_IA32_EMULATION ++ /* ++ * TS_COMPAT is set for 32-bit syscall entries and then ++ * remains set until we return to user mode. ++ * ++ * TIF_IA32 tasks should always have TS_COMPAT set at ++ * system call time. ++ */ ++ if (task_thread_info(task)->status & TS_COMPAT) ++ return AUDIT_ARCH_I386; ++#endif ++ return AUDIT_ARCH_X86_64; ++} + #endif /* CONFIG_X86_32 */ + + #endif /* _ASM_X86_SYSCALL_H */ diff --git a/arch/x86/include/asm/system.h b/arch/x86/include/asm/system.h index d75adff..c0cc78b 100644 --- a/arch/x86/include/asm/system.h @@ -20676,7 +20793,7 @@ index 6a364a6..b147d11 100644 ip = *(u64 *)(fp+8); if (!in_sched_functions(ip)) diff --git a/arch/x86/kernel/ptrace.c b/arch/x86/kernel/ptrace.c -index 2dc4121..869e219 100644 +index 2dc4121..60e1086 100644 --- a/arch/x86/kernel/ptrace.c +++ b/arch/x86/kernel/ptrace.c @@ -181,14 +181,13 @@ unsigned long kernel_stack_pointer(struct pt_regs *regs) @@ -20792,7 +20909,28 @@ index 2dc4121..869e219 100644 /* * If we stepped into a sysenter/syscall insn, it trapped in * kernel mode; do_debug() cleared TF and set TIF_SINGLESTEP. -@@ -1443,6 +1451,11 @@ void syscall_trace_leave(struct pt_regs *regs) +@@ -1409,7 +1417,11 @@ long syscall_trace_enter(struct pt_regs *regs) + regs->flags |= X86_EFLAGS_TF; + + /* do the secure computing check first */ +- secure_computing(regs->orig_ax); ++ if (secure_computing(regs->orig_ax)) { ++ /* seccomp failures shouldn't expose any additional code. */ ++ ret = -1L; ++ goto out; ++ } + + if (unlikely(test_thread_flag(TIF_SYSCALL_EMU))) + ret = -1L; +@@ -1436,6 +1448,7 @@ long syscall_trace_enter(struct pt_regs *regs) + #endif + } + ++out: + return ret ?: regs->orig_ax; + } + +@@ -1443,6 +1456,11 @@ void syscall_trace_leave(struct pt_regs *regs) { bool step; @@ -42476,7 +42614,7 @@ index 2836538..30edf9d 100644 ret = sysfs_create_bin_file(&pdev->dev.kobj, &m48t59_nvram_attr); if (ret) { diff --git a/drivers/scsi/aacraid/linit.c b/drivers/scsi/aacraid/linit.c -index 705e13e..91c873c 100644 +index 705e13e..46f4afb 100644 --- a/drivers/scsi/aacraid/linit.c +++ b/drivers/scsi/aacraid/linit.c @@ -93,7 +93,7 @@ static DECLARE_PCI_DEVICE_TABLE(aac_pci_tbl) = { @@ -42488,6 +42626,15 @@ index 705e13e..91c873c 100644 #endif { 0x1028, 0x0001, 0x1028, 0x0001, 0, 0, 0 }, /* PERC 2/Si (Iguana/PERC2Si) */ { 0x1028, 0x0002, 0x1028, 0x0002, 0, 0, 1 }, /* PERC 3/Di (Opal/PERC3Di) */ +@@ -771,6 +771,8 @@ static long aac_compat_do_ioctl(struct aac_dev *dev, unsigned cmd, unsigned long + static int aac_compat_ioctl(struct scsi_device *sdev, int cmd, void __user *arg) + { + struct aac_dev *dev = (struct aac_dev *)sdev->host->hostdata; ++ if (!capable(CAP_SYS_RAWIO)) ++ return -EPERM; + return aac_compat_do_ioctl(dev, cmd, (unsigned long)arg); + } + diff --git a/drivers/scsi/aic94xx/aic94xx_init.c b/drivers/scsi/aic94xx/aic94xx_init.c index d5ff142..49c0ebb 100644 --- a/drivers/scsi/aic94xx/aic94xx_init.c @@ -43447,6 +43594,18 @@ index b2ccdea..84cde75 100644 static u8 *buf; +diff --git a/drivers/staging/bcm/Bcmchar.c b/drivers/staging/bcm/Bcmchar.c +index 2fa658e..391b768 100644 +--- a/drivers/staging/bcm/Bcmchar.c ++++ b/drivers/staging/bcm/Bcmchar.c +@@ -1932,6 +1932,7 @@ cntrlEnd: + + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, OSAL_DBG, DBG_LVL_ALL, "Called IOCTL_BCM_GET_DEVICE_DRIVER_INFO\n"); + ++ memset(&DevInfo, 0, sizeof(DevInfo)); + DevInfo.MaxRDMBufferSize = BUFFER_4K; + DevInfo.u32DSDStartOffset = EEPROM_CALPARAM_START; + DevInfo.u32RxAlignmentCorrection = 0; diff --git a/drivers/staging/gma500/power.c b/drivers/staging/gma500/power.c index 436fe97..4082570 100644 --- a/drivers/staging/gma500/power.c @@ -43809,6 +43968,59 @@ index df8ea25..47dd9c6 100644 pDevice->apdev->netdev_ops = &apdev_netdev_ops; pDevice->apdev->type = ARPHRD_IEEE80211; +diff --git a/drivers/staging/wlags49_h2/wl_priv.c b/drivers/staging/wlags49_h2/wl_priv.c +index 260d4f0..ed836c2 100644 +--- a/drivers/staging/wlags49_h2/wl_priv.c ++++ b/drivers/staging/wlags49_h2/wl_priv.c +@@ -570,6 +570,7 @@ int wvlan_uil_put_info( struct uilreq *urq, struct wl_private *lp ) + ltv_t *pLtv; + bool_t ltvAllocated = FALSE; + ENCSTRCT sEncryption; ++ size_t len; + + #ifdef USE_WDS + hcf_16 hcfPort = HCF_PORT_0; +@@ -685,9 +686,10 @@ int wvlan_uil_put_info( struct uilreq *urq, struct wl_private *lp ) + pLtv->u.u16[0] = CNV_INT_TO_LITTLE( pLtv->u.u16[0] ); + break; + case CFG_CNF_OWN_NAME: +- memset( lp->StationName, 0, sizeof( lp->StationName )); +- memcpy( (void *)lp->StationName, (void *)&pLtv->u.u8[2], (size_t)pLtv->u.u16[0]); +- pLtv->u.u16[0] = CNV_INT_TO_LITTLE( pLtv->u.u16[0] ); ++ memset(lp->StationName, 0, sizeof(lp->StationName)); ++ len = min_t(size_t, pLtv->u.u16[0], sizeof(lp->StationName)); ++ strlcpy(lp->StationName, &pLtv->u.u8[2], len); ++ pLtv->u.u16[0] = CNV_INT_TO_LITTLE(pLtv->u.u16[0]); + break; + case CFG_CNF_LOAD_BALANCING: + lp->loadBalancing = pLtv->u.u16[0]; +@@ -1798,9 +1800,10 @@ int wvlan_set_station_nickname(struct net_device *dev, + union iwreq_data *wrqu, + char *extra) + { +- struct wl_private *lp = wl_priv(dev); +- unsigned long flags; +- int ret = 0; ++ struct wl_private *lp = wl_priv(dev); ++ unsigned long flags; ++ size_t len; ++ int ret = 0; + /*------------------------------------------------------------------------*/ + + +@@ -1809,9 +1812,9 @@ int wvlan_set_station_nickname(struct net_device *dev, + + wl_lock(lp, &flags); + +- memset( lp->StationName, 0, sizeof( lp->StationName )); +- +- memcpy( lp->StationName, extra, wrqu->data.length); ++ memset(lp->StationName, 0, sizeof(lp->StationName)); ++ len = min_t(size_t, wrqu->data.length, sizeof(lp->StationName)); ++ strlcpy(lp->StationName, extra, len); + + /* Commit the adapter parameters */ + wl_apply( lp ); diff --git a/drivers/staging/zcache/tmem.c b/drivers/staging/zcache/tmem.c index 1ca66ea..76f1343 100644 --- a/drivers/staging/zcache/tmem.c @@ -51373,7 +51585,7 @@ index 451b9b8..12e5a03 100644 out_free_fd: diff --git a/fs/exec.c b/fs/exec.c -index a2d0e51..d46efb6 100644 +index a2d0e51..0d1143c 100644 --- a/fs/exec.c +++ b/fs/exec.c @@ -55,12 +55,35 @@ @@ -51760,7 +51972,21 @@ index a2d0e51..d46efb6 100644 /* Set the new mm task size. We have to do that late because it may * depend on TIF_32BIT which is only updated in flush_thread() on -@@ -1268,7 +1347,7 @@ int check_unsafe_exec(struct linux_binprm *bprm) +@@ -1259,6 +1338,13 @@ int check_unsafe_exec(struct linux_binprm *bprm) + bprm->unsafe |= LSM_UNSAFE_PTRACE; + } + ++ /* ++ * This isn't strictly necessary, but it makes it harder for LSMs to ++ * mess up. ++ */ ++ if (current->no_new_privs) ++ bprm->unsafe |= LSM_UNSAFE_NO_NEW_PRIVS; ++ + n_fs = 1; + spin_lock(&p->fs->lock); + rcu_read_lock(); +@@ -1268,7 +1354,7 @@ int check_unsafe_exec(struct linux_binprm *bprm) } rcu_read_unlock(); @@ -51769,7 +51995,17 @@ index a2d0e51..d46efb6 100644 bprm->unsafe |= LSM_UNSAFE_SHARE; } else { res = -EAGAIN; -@@ -1463,6 +1542,31 @@ int search_binary_handler(struct linux_binprm *bprm,struct pt_regs *regs) +@@ -1302,7 +1388,8 @@ int prepare_binprm(struct linux_binprm *bprm) + bprm->cred->euid = current_euid(); + bprm->cred->egid = current_egid(); + +- if (!(bprm->file->f_path.mnt->mnt_flags & MNT_NOSUID)) { ++ if (!(bprm->file->f_path.mnt->mnt_flags & MNT_NOSUID) && ++ !current->no_new_privs) { + /* Set-uid? */ + if (mode & S_ISUID) { + bprm->per_clear |= PER_CLEAR_ON_SETID; +@@ -1463,6 +1550,31 @@ int search_binary_handler(struct linux_binprm *bprm,struct pt_regs *regs) EXPORT_SYMBOL(search_binary_handler); @@ -51801,7 +52037,7 @@ index a2d0e51..d46efb6 100644 /* * sys_execve() executes a new program. */ -@@ -1471,6 +1575,11 @@ static int do_execve_common(const char *filename, +@@ -1471,6 +1583,11 @@ static int do_execve_common(const char *filename, struct user_arg_ptr envp, struct pt_regs *regs) { @@ -51813,7 +52049,7 @@ index a2d0e51..d46efb6 100644 struct linux_binprm *bprm; struct file *file; struct files_struct *displaced; -@@ -1478,6 +1587,8 @@ static int do_execve_common(const char *filename, +@@ -1478,6 +1595,8 @@ static int do_execve_common(const char *filename, int retval; const struct cred *cred = current_cred(); @@ -51822,7 +52058,7 @@ index a2d0e51..d46efb6 100644 /* * We move the actual failure in case of RLIMIT_NPROC excess from * set*uid() to execve() because too many poorly written programs -@@ -1518,12 +1629,22 @@ static int do_execve_common(const char *filename, +@@ -1518,12 +1637,22 @@ static int do_execve_common(const char *filename, if (IS_ERR(file)) goto out_unmark; @@ -51845,7 +52081,7 @@ index a2d0e51..d46efb6 100644 retval = bprm_mm_init(bprm); if (retval) goto out_file; -@@ -1540,24 +1661,70 @@ static int do_execve_common(const char *filename, +@@ -1540,24 +1669,70 @@ static int do_execve_common(const char *filename, if (retval < 0) goto out; @@ -51920,7 +52156,7 @@ index a2d0e51..d46efb6 100644 current->fs->in_exec = 0; current->in_execve = 0; acct_update_integrals(current); -@@ -1566,6 +1733,14 @@ static int do_execve_common(const char *filename, +@@ -1566,6 +1741,14 @@ static int do_execve_common(const char *filename, put_files_struct(displaced); return retval; @@ -51935,7 +52171,7 @@ index a2d0e51..d46efb6 100644 out: if (bprm->mm) { acct_arg_size(bprm, 0); -@@ -1639,7 +1814,7 @@ static int expand_corename(struct core_name *cn) +@@ -1639,7 +1822,7 @@ static int expand_corename(struct core_name *cn) { char *old_corename = cn->corename; @@ -51944,7 +52180,7 @@ index a2d0e51..d46efb6 100644 cn->corename = krealloc(old_corename, cn->size, GFP_KERNEL); if (!cn->corename) { -@@ -1736,7 +1911,7 @@ static int format_corename(struct core_name *cn, long signr) +@@ -1736,7 +1919,7 @@ static int format_corename(struct core_name *cn, long signr) int pid_in_pattern = 0; int err = 0; @@ -51953,7 +52189,7 @@ index a2d0e51..d46efb6 100644 cn->corename = kmalloc(cn->size, GFP_KERNEL); cn->used = 0; -@@ -1833,6 +2008,284 @@ out: +@@ -1833,6 +2016,284 @@ out: return ispipe; } @@ -52238,7 +52474,7 @@ index a2d0e51..d46efb6 100644 static int zap_process(struct task_struct *start, int exit_code) { struct task_struct *t; -@@ -2006,17 +2459,17 @@ static void coredump_finish(struct mm_struct *mm) +@@ -2006,17 +2467,17 @@ static void coredump_finish(struct mm_struct *mm) void set_dumpable(struct mm_struct *mm, int value) { switch (value) { @@ -52259,7 +52495,7 @@ index a2d0e51..d46efb6 100644 set_bit(MMF_DUMP_SECURELY, &mm->flags); smp_wmb(); set_bit(MMF_DUMPABLE, &mm->flags); -@@ -2029,7 +2482,7 @@ static int __get_dumpable(unsigned long mm_flags) +@@ -2029,7 +2490,7 @@ static int __get_dumpable(unsigned long mm_flags) int ret; ret = mm_flags & MMF_DUMPABLE_MASK; @@ -52268,7 +52504,7 @@ index a2d0e51..d46efb6 100644 } int get_dumpable(struct mm_struct *mm) -@@ -2044,17 +2497,17 @@ static void wait_for_dump_helpers(struct file *file) +@@ -2044,17 +2505,17 @@ static void wait_for_dump_helpers(struct file *file) pipe = file->f_path.dentry->d_inode->i_pipe; pipe_lock(pipe); @@ -52291,7 +52527,7 @@ index a2d0e51..d46efb6 100644 pipe_unlock(pipe); } -@@ -2115,7 +2568,8 @@ void do_coredump(long signr, int exit_code, struct pt_regs *regs) +@@ -2115,7 +2576,8 @@ void do_coredump(long signr, int exit_code, struct pt_regs *regs) int retval = 0; int flag = 0; int ispipe; @@ -52301,7 +52537,7 @@ index a2d0e51..d46efb6 100644 struct coredump_params cprm = { .signr = signr, .regs = regs, -@@ -2130,6 +2584,9 @@ void do_coredump(long signr, int exit_code, struct pt_regs *regs) +@@ -2130,6 +2592,9 @@ void do_coredump(long signr, int exit_code, struct pt_regs *regs) audit_core_dumps(signr); @@ -52311,7 +52547,7 @@ index a2d0e51..d46efb6 100644 binfmt = mm->binfmt; if (!binfmt || !binfmt->core_dump) goto fail; -@@ -2140,14 +2597,16 @@ void do_coredump(long signr, int exit_code, struct pt_regs *regs) +@@ -2140,14 +2605,16 @@ void do_coredump(long signr, int exit_code, struct pt_regs *regs) if (!cred) goto fail; /* @@ -52332,7 +52568,7 @@ index a2d0e51..d46efb6 100644 } retval = coredump_wait(exit_code, &core_state); -@@ -2197,7 +2656,7 @@ void do_coredump(long signr, int exit_code, struct pt_regs *regs) +@@ -2197,7 +2664,7 @@ void do_coredump(long signr, int exit_code, struct pt_regs *regs) } cprm.limit = RLIM_INFINITY; @@ -52341,7 +52577,7 @@ index a2d0e51..d46efb6 100644 if (core_pipe_limit && (core_pipe_limit < dump_count)) { printk(KERN_WARNING "Pid %d(%s) over core_pipe_limit\n", task_tgid_vnr(current), current->comm); -@@ -2224,9 +2683,19 @@ void do_coredump(long signr, int exit_code, struct pt_regs *regs) +@@ -2224,9 +2691,19 @@ void do_coredump(long signr, int exit_code, struct pt_regs *regs) } else { struct inode *inode; @@ -52361,7 +52597,7 @@ index a2d0e51..d46efb6 100644 cprm.file = filp_open(cn.corename, O_CREAT | 2 | O_NOFOLLOW | O_LARGEFILE | flag, 0600); -@@ -2267,7 +2736,7 @@ close_fail: +@@ -2267,7 +2744,7 @@ close_fail: filp_close(cprm.file, NULL); fail_dropcount: if (ispipe) @@ -52370,7 +52606,7 @@ index a2d0e51..d46efb6 100644 fail_unlock: kfree(cn.corename); fail_corename: -@@ -2286,7 +2755,7 @@ fail: +@@ -2286,7 +2763,7 @@ fail: */ int dump_write(struct file *file, const void *addr, int nr) { @@ -70045,6 +70281,93 @@ index bc00876..9aa9b1f 100644 #endif /* CONFIG_MMU */ #endif /* !__ASSEMBLY__ */ +diff --git a/include/asm-generic/siginfo.h b/include/asm-generic/siginfo.h +index 0dd4e87..af5d035 100644 +--- a/include/asm-generic/siginfo.h ++++ b/include/asm-generic/siginfo.h +@@ -90,9 +90,18 @@ typedef struct siginfo { + __ARCH_SI_BAND_T _band; /* POLL_IN, POLL_OUT, POLL_MSG */ + int _fd; + } _sigpoll; ++ ++ /* SIGSYS */ ++ struct { ++ void __user *_call_addr; /* calling user insn */ ++ int _syscall; /* triggering system call number */ ++ unsigned int _arch; /* AUDIT_ARCH_* of syscall */ ++ } _sigsys; + } _sifields; + } siginfo_t; + ++/* If the arch shares siginfo, then it has SIGSYS. */ ++#define __ARCH_SIGSYS + #endif + + /* +@@ -116,6 +125,11 @@ typedef struct siginfo { + #define si_addr_lsb _sifields._sigfault._addr_lsb + #define si_band _sifields._sigpoll._band + #define si_fd _sifields._sigpoll._fd ++#ifdef __ARCH_SIGSYS ++#define si_call_addr _sifields._sigsys._call_addr ++#define si_syscall _sifields._sigsys._syscall ++#define si_arch _sifields._sigsys._arch ++#endif + + #ifdef __KERNEL__ + #define __SI_MASK 0xffff0000u +@@ -126,6 +140,7 @@ typedef struct siginfo { + #define __SI_CHLD (4 << 16) + #define __SI_RT (5 << 16) + #define __SI_MESGQ (6 << 16) ++#define __SI_SYS (7 << 16) + #define __SI_CODE(T,N) ((T) | ((N) & 0xffff)) + #else + #define __SI_KILL 0 +@@ -135,6 +150,7 @@ typedef struct siginfo { + #define __SI_CHLD 0 + #define __SI_RT 0 + #define __SI_MESGQ 0 ++#define __SI_SYS 0 + #define __SI_CODE(T,N) (N) + #endif + +@@ -232,6 +248,12 @@ typedef struct siginfo { + #define NSIGPOLL 6 + + /* ++ * SIGSYS si_codes ++ */ ++#define SYS_SECCOMP (__SI_SYS|1) /* seccomp triggered */ ++#define NSIGSYS 1 ++ ++/* + * sigevent definitions + * + * It seems likely that SIGEV_THREAD will have to be handled from +diff --git a/include/asm-generic/syscall.h b/include/asm-generic/syscall.h +index 5c122ae..a2c13dc 100644 +--- a/include/asm-generic/syscall.h ++++ b/include/asm-generic/syscall.h +@@ -142,4 +142,18 @@ void syscall_set_arguments(struct task_struct *task, struct pt_regs *regs, + unsigned int i, unsigned int n, + const unsigned long *args); + ++/** ++ * 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. ++ * ++ * It's only valid to call this when @task is stopped on entry to a system ++ * call, due to %TIF_SYSCALL_TRACE, %TIF_SYSCALL_AUDIT, or %TIF_SECCOMP. ++ * ++ * Note, at present this function is only required with ++ * CONFIG_HAVE_ARCH_SECCOMP_FILTER. ++ */ ++int syscall_get_arch(struct task_struct *task, struct pt_regs *regs); + #endif /* _ASM_SYSCALL_H */ diff --git a/include/asm-generic/vmlinux.lds.h b/include/asm-generic/vmlinux.lds.h index b5e2e4c..6a5373e 100644 --- a/include/asm-generic/vmlinux.lds.h @@ -70207,6 +70530,18 @@ index 26c1f78..6722682 100644 /** * struct ttm_mem_global - Global memory accounting structure. +diff --git a/include/linux/Kbuild b/include/linux/Kbuild +index a3ce901..fd50c75 100644 +--- a/include/linux/Kbuild ++++ b/include/linux/Kbuild +@@ -329,6 +329,7 @@ header-y += scc.h + header-y += sched.h + header-y += screen_info.h + header-y += sdla.h ++header-y += seccomp.h + header-y += securebits.h + header-y += selinux_netlink.h + header-y += sem.h diff --git a/include/linux/a.out.h b/include/linux/a.out.h index e86dfca..40cc55f 100644 --- a/include/linux/a.out.h @@ -70248,6 +70583,40 @@ index 49a83ca..d0a847e 100644 struct atmphy_ops { int (*start)(struct atm_dev *dev); +diff --git a/include/linux/audit.h b/include/linux/audit.h +index 2f81c6f..225b4e4 100644 +--- a/include/linux/audit.h ++++ b/include/linux/audit.h +@@ -430,6 +430,7 @@ extern void audit_putname(const char *name); + extern void __audit_inode(const char *name, const struct dentry *dentry); + extern void __audit_inode_child(const struct dentry *dentry, + const struct inode *parent); ++extern void __audit_seccomp(unsigned long syscall, long signr, int code); + extern void __audit_ptrace(struct task_struct *t); + + static inline int audit_dummy_context(void) +@@ -453,6 +454,12 @@ static inline void audit_inode_child(const struct dentry *dentry, + } + void audit_core_dumps(long signr); + ++static inline void audit_seccomp(unsigned long syscall, long signr, int code) ++{ ++ if (unlikely(!audit_dummy_context())) ++ __audit_seccomp(syscall, signr, code); ++} ++ + static inline void audit_ptrace(struct task_struct *t) + { + if (unlikely(!audit_dummy_context())) +@@ -558,6 +565,8 @@ extern int audit_signals; + #define audit_inode(n,d) do { (void)(d); } while (0) + #define audit_inode_child(i,p) do { ; } while (0) + #define audit_core_dumps(i) do { ; } while (0) ++#define audit_seccomp(i,s,c) do { ; } while (0) ++#define __audit_seccomp(i,s,c) do { ; } while (0) + #define auditsc_get_stamp(c,t,s) (0) + #define audit_get_loginuid(t) (-1) + #define audit_get_sessionid(t) (-1) diff --git a/include/linux/binfmts.h b/include/linux/binfmts.h index acd8d4b..f2defe2 100644 --- a/include/linux/binfmts.h @@ -71053,18 +71422,38 @@ index 82163c4..c4b3b50 100644 extern struct kmem_cache *files_cachep; diff --git a/include/linux/filter.h b/include/linux/filter.h -index 8eeb205..d59bfa2 100644 +index 8eeb205..13d571c 100644 --- a/include/linux/filter.h +++ b/include/linux/filter.h -@@ -134,6 +134,7 @@ struct sock_fprog { /* Required for SO_ATTACH_FILTER. */ +@@ -10,6 +10,7 @@ + #ifdef __KERNEL__ + #include <linux/atomic.h> ++#include <linux/compat.h> + #endif + + /* +@@ -132,8 +133,19 @@ struct sock_fprog { /* Required for SO_ATTACH_FILTER. */ + + #ifdef __KERNEL__ + ++#ifdef CONFIG_COMPAT ++/* ++ * A struct sock_filter is architecture independent. ++ */ ++struct compat_sock_fprog { ++ u16 len; ++ compat_uptr_t filter; /* struct sock_filter * */ ++}; ++#endif ++ struct sk_buff; struct sock; +struct bpf_jit_work; struct sk_filter { -@@ -141,6 +142,9 @@ struct sk_filter +@@ -141,6 +153,9 @@ struct sk_filter unsigned int len; /* Number of filter blocks */ unsigned int (*bpf_func)(const struct sk_buff *skb, const struct sock_filter *filter); @@ -71074,6 +71463,14 @@ index 8eeb205..d59bfa2 100644 struct rcu_head rcu; struct sock_filter insns[0]; }; +@@ -228,6 +243,7 @@ enum { + BPF_S_ANC_HATYPE, + BPF_S_ANC_RXHASH, + BPF_S_ANC_CPU, ++ BPF_S_ANC_SECCOMP_LD_W, + }; + + #endif /* __KERNEL__ */ diff --git a/include/linux/fs.h b/include/linux/fs.h index a276817..ba31358 100644 --- a/include/linux/fs.h @@ -73967,6 +74364,30 @@ index b8d4ddd..bb59d8b 100644 /* * The return value from decompress routine is the length of the +diff --git a/include/linux/prctl.h b/include/linux/prctl.h +index a3baeb2..b527252 100644 +--- a/include/linux/prctl.h ++++ b/include/linux/prctl.h +@@ -102,4 +102,19 @@ + + #define PR_MCE_KILL_GET 34 + ++/* ++ * If no_new_privs is set, then operations that grant new privileges (i.e. ++ * execve) will either fail or not grant them. This affects suid/sgid, ++ * file capabilities, and LSMs. ++ * ++ * Operations that merely manipulate or drop existing privileges (setresuid, ++ * capset, etc.) will still work. Drop those privileges if you want them gone. ++ * ++ * Changing LSM security domain is considered a new privilege. So, for example, ++ * asking selinux for a specific new context (e.g. with runcon) will result ++ * in execve returning -EPERM. ++ */ ++#define PR_SET_NO_NEW_PRIVS 38 ++#define PR_GET_NO_NEW_PRIVS 39 ++ + #endif /* _LINUX_PRCTL_H */ diff --git a/include/linux/printk.h b/include/linux/printk.h index f0e22f7..82dd544 100644 --- a/include/linux/printk.h @@ -74022,10 +74443,40 @@ index 643b96c..9544c71 100644 extern const struct proc_ns_operations utsns_operations; extern const struct proc_ns_operations ipcns_operations; diff --git a/include/linux/ptrace.h b/include/linux/ptrace.h -index 800f113..12c82ec 100644 +index 800f113..13b3715 100644 --- a/include/linux/ptrace.h +++ b/include/linux/ptrace.h -@@ -129,10 +129,12 @@ extern void __ptrace_unlink(struct task_struct *child); +@@ -62,8 +62,9 @@ + #define PTRACE_O_TRACEEXEC 0x00000010 + #define PTRACE_O_TRACEVFORKDONE 0x00000020 + #define PTRACE_O_TRACEEXIT 0x00000040 ++#define PTRACE_O_TRACESECCOMP 0x00000080 + +-#define PTRACE_O_MASK 0x0000007f ++#define PTRACE_O_MASK 0x000000ff + + /* Wait extended result codes for the above trace options. */ + #define PTRACE_EVENT_FORK 1 +@@ -73,6 +74,7 @@ + #define PTRACE_EVENT_VFORK_DONE 5 + #define PTRACE_EVENT_EXIT 6 + #define PTRACE_EVENT_STOP 7 ++#define PTRACE_EVENT_SECCOMP 8 + + #include <asm/ptrace.h> + +@@ -101,8 +103,9 @@ + #define PT_TRACE_EXEC PT_EVENT_FLAG(PTRACE_EVENT_EXEC) + #define PT_TRACE_VFORK_DONE PT_EVENT_FLAG(PTRACE_EVENT_VFORK_DONE) + #define PT_TRACE_EXIT PT_EVENT_FLAG(PTRACE_EVENT_EXIT) ++#define PT_TRACE_SECCOMP PT_EVENT_FLAG(PTRACE_EVENT_SECCOMP) + +-#define PT_TRACE_MASK 0x000003f4 ++#define PT_TRACE_MASK 0x00000bf4 + + /* single stepping state bits (used on ARM and PA-RISC) */ + #define PT_SINGLESTEP_BIT 31 +@@ -129,10 +132,12 @@ extern void __ptrace_unlink(struct task_struct *child); extern void exit_ptrace(struct task_struct *tracer); #define PTRACE_MODE_READ 1 #define PTRACE_MODE_ATTACH 2 @@ -74040,7 +74491,7 @@ index 800f113..12c82ec 100644 static inline int ptrace_reparented(struct task_struct *child) { -@@ -197,9 +199,10 @@ static inline void ptrace_event(int event, unsigned long message) +@@ -197,9 +202,10 @@ static inline void ptrace_event(int event, unsigned long message) if (unlikely(ptrace_event_enabled(current, event))) { current->ptrace_message = message; ptrace_notify((event << 8) | SIGTRAP); @@ -74267,7 +74718,7 @@ index 2148b12..519b820 100644 static inline void anon_vma_merge(struct vm_area_struct *vma, diff --git a/include/linux/sched.h b/include/linux/sched.h -index 8204898..76f518d 100644 +index 8204898..070429f 100644 --- a/include/linux/sched.h +++ b/include/linux/sched.h @@ -101,6 +101,7 @@ struct bio_list; @@ -74365,7 +74816,16 @@ index 8204898..76f518d 100644 struct load_weight { unsigned long weight, inv_weight; -@@ -1341,8 +1379,8 @@ struct task_struct { +@@ -1301,6 +1339,8 @@ 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; +@@ -1341,8 +1381,8 @@ struct task_struct { struct list_head thread_group; struct completion *vfork_done; /* for vfork() */ @@ -74376,7 +74836,7 @@ index 8204898..76f518d 100644 cputime_t utime, stime, utimescaled, stimescaled; cputime_t gtime; -@@ -1358,13 +1396,6 @@ struct task_struct { +@@ -1358,13 +1398,6 @@ struct task_struct { struct task_cputime cputime_expires; struct list_head cpu_timers[3]; @@ -74390,7 +74850,7 @@ index 8204898..76f518d 100644 char comm[TASK_COMM_LEN]; /* executable name excluding path - access with [gs]et_task_comm (which lock it with task_lock()) -@@ -1381,8 +1412,16 @@ struct task_struct { +@@ -1381,8 +1414,16 @@ struct task_struct { #endif /* CPU-specific state of this task */ struct thread_struct thread; @@ -74407,7 +74867,16 @@ index 8204898..76f518d 100644 /* open file information */ struct files_struct *files; /* namespaces */ -@@ -1429,6 +1468,11 @@ struct task_struct { +@@ -1405,7 +1446,7 @@ struct task_struct { + uid_t loginuid; + unsigned int sessionid; + #endif +- seccomp_t seccomp; ++ struct seccomp seccomp; + + /* Thread group tracking */ + u32 parent_exec_id; +@@ -1429,6 +1470,11 @@ struct task_struct { struct rt_mutex_waiter *pi_blocked_on; #endif @@ -74419,7 +74888,7 @@ index 8204898..76f518d 100644 #ifdef CONFIG_DEBUG_MUTEXES /* mutex deadlock detection */ struct mutex_waiter *blocked_on; -@@ -1544,6 +1588,28 @@ struct task_struct { +@@ -1544,6 +1590,28 @@ struct task_struct { unsigned long default_timer_slack_ns; struct list_head *scm_work_list; @@ -74448,7 +74917,7 @@ index 8204898..76f518d 100644 #ifdef CONFIG_FUNCTION_GRAPH_TRACER /* Index of current stored address in ret_stack */ int curr_ret_stack; -@@ -1578,6 +1644,52 @@ struct task_struct { +@@ -1578,6 +1646,52 @@ struct task_struct { #endif }; @@ -74501,7 +74970,7 @@ index 8204898..76f518d 100644 /* Future-safe accessor for struct task_struct's cpus_allowed. */ #define tsk_cpus_allowed(tsk) (&(tsk)->cpus_allowed) -@@ -2093,7 +2205,9 @@ void yield(void); +@@ -2093,7 +2207,9 @@ void yield(void); extern struct exec_domain default_exec_domain; union thread_union { @@ -74511,7 +74980,7 @@ index 8204898..76f518d 100644 unsigned long stack[THREAD_SIZE/sizeof(long)]; }; -@@ -2126,6 +2240,7 @@ extern struct pid_namespace init_pid_ns; +@@ -2126,6 +2242,7 @@ extern struct pid_namespace init_pid_ns; */ extern struct task_struct *find_task_by_vpid(pid_t nr); @@ -74519,7 +74988,7 @@ index 8204898..76f518d 100644 extern struct task_struct *find_task_by_pid_ns(pid_t nr, struct pid_namespace *ns); -@@ -2247,6 +2362,12 @@ static inline void mmdrop(struct mm_struct * mm) +@@ -2247,6 +2364,12 @@ static inline void mmdrop(struct mm_struct * mm) extern void mmput(struct mm_struct *); /* Grab a reference to a task's mm, if it is not already going away */ extern struct mm_struct *get_task_mm(struct task_struct *task); @@ -74532,7 +75001,7 @@ index 8204898..76f518d 100644 /* Remove the current tasks stale references to the old mm_struct */ extern void mm_release(struct task_struct *, struct mm_struct *); /* Allocate a new mm structure and copy contents from tsk->mm */ -@@ -2263,7 +2384,7 @@ extern void __cleanup_sighand(struct sighand_struct *); +@@ -2263,7 +2386,7 @@ extern void __cleanup_sighand(struct sighand_struct *); extern void exit_itimers(struct signal_struct *); extern void flush_itimer_signals(void); @@ -74541,7 +75010,7 @@ index 8204898..76f518d 100644 extern void daemonize(const char *, ...); extern int allow_signal(int); -@@ -2428,9 +2549,9 @@ static inline unsigned long *end_of_stack(struct task_struct *p) +@@ -2428,9 +2551,9 @@ static inline unsigned long *end_of_stack(struct task_struct *p) #endif @@ -74567,8 +75036,154 @@ index 899fbb4..1cb4138 100644 } __attribute__((packed)); #define VIDEO_TYPE_MDA 0x10 /* Monochrome Text Display */ +diff --git a/include/linux/seccomp.h b/include/linux/seccomp.h +index cc7a4e9..306733e 100644 +--- a/include/linux/seccomp.h ++++ b/include/linux/seccomp.h +@@ -1,25 +1,89 @@ + #ifndef _LINUX_SECCOMP_H + #define _LINUX_SECCOMP_H + ++#include <linux/compiler.h> ++#include <linux/types.h> + ++ ++/* Valid values for seccomp.mode and prctl(PR_SET_SECCOMP, <mode>) */ ++#define SECCOMP_MODE_DISABLED 0 /* seccomp is not in use. */ ++#define SECCOMP_MODE_STRICT 1 /* uses hard-coded filter. */ ++#define SECCOMP_MODE_FILTER 2 /* uses user-supplied filter. */ ++ ++/* ++ * All BPF programs must return a 32-bit value. ++ * The bottom 16-bits are for optional return data. ++ * The upper 16-bits are ordered from least permissive values to most. ++ * ++ * The ordering ensures that a min_t() over composed return values always ++ * selects the least permissive choice. ++ */ ++#define SECCOMP_RET_KILL 0x00000000U /* kill the task immediately */ ++#define SECCOMP_RET_TRAP 0x00030000U /* disallow and force a SIGSYS */ ++#define SECCOMP_RET_ERRNO 0x00050000U /* returns an errno */ ++#define SECCOMP_RET_TRACE 0x7ff00000U /* pass to a tracer or disallow */ ++#define SECCOMP_RET_ALLOW 0x7fff0000U /* allow */ ++ ++/* Masks for the return value sections. */ ++#define SECCOMP_RET_ACTION 0xffff0000U ++#define SECCOMP_RET_DATA 0x0000ffffU ++ ++/** ++ * struct seccomp_data - the format the BPF program executes over. ++ * @nr: the system call number ++ * @arch: indicates system call convention as an AUDIT_ARCH_* value ++ * as defined in <linux/audit.h>. ++ * @instruction_pointer: at the time of the system call. ++ * @args: up to 6 system call arguments always stored as 64-bit values ++ * regardless of the architecture. ++ */ ++struct seccomp_data { ++ int nr; ++ __u32 arch; ++ __u64 instruction_pointer; ++ __u64 args[6]; ++}; ++ ++#ifdef __KERNEL__ + #ifdef CONFIG_SECCOMP + + #include <linux/thread_info.h> + #include <asm/seccomp.h> + +-typedef struct { int mode; } seccomp_t; ++struct seccomp_filter; ++/** ++ * struct seccomp - the state of a seccomp'ed process ++ * ++ * @mode: indicates one of the valid values above for controlled ++ * system calls available to a process. ++ * @filter: The metadata and ruleset for determining what system calls ++ * are allowed for a task. ++ * ++ * @filter must only be accessed from the context of current as there ++ * is no locking. ++ */ ++struct seccomp { ++ int mode; ++ struct seccomp_filter *filter; ++}; + +-extern void __secure_computing(int); +-static inline void secure_computing(int this_syscall) ++/* ++ * Direct callers to __secure_computing should be updated as ++ * CONFIG_HAVE_ARCH_SECCOMP_FILTER propagates. ++ */ ++extern void __secure_computing(int) __deprecated; ++extern int __secure_computing_int(int); ++static inline int secure_computing(int this_syscall) + { + if (unlikely(test_thread_flag(TIF_SECCOMP))) +- __secure_computing(this_syscall); ++ return __secure_computing_int(this_syscall); ++ return 0; + } + + extern long prctl_get_seccomp(void); +-extern long prctl_set_seccomp(unsigned long); ++extern long prctl_set_seccomp(unsigned long, char __user *); + +-static inline int seccomp_mode(seccomp_t *s) ++static inline int seccomp_mode(struct seccomp *s) + { + return s->mode; + } +@@ -28,25 +92,40 @@ static inline int seccomp_mode(seccomp_t *s) + + #include <linux/errno.h> + +-typedef struct { } seccomp_t; ++struct seccomp { }; ++struct seccomp_filter { }; + +-#define secure_computing(x) do { } while (0) ++#define secure_computing(x) 0 + + static inline long prctl_get_seccomp(void) + { + return -EINVAL; + } + +-static inline long prctl_set_seccomp(unsigned long arg2) ++static inline long prctl_set_seccomp(unsigned long arg2, char __user *arg3) + { + return -EINVAL; + } + +-static inline int seccomp_mode(seccomp_t *s) ++static inline int seccomp_mode(struct seccomp *s) + { + return 0; + } +- + #endif /* CONFIG_SECCOMP */ + ++#ifdef CONFIG_SECCOMP_FILTER ++extern void put_seccomp_filter(struct task_struct *tsk); ++extern void get_seccomp_filter(struct task_struct *tsk); ++extern u32 seccomp_bpf_load(int off); ++#else /* CONFIG_SECCOMP_FILTER */ ++static inline void put_seccomp_filter(struct task_struct *tsk) ++{ ++ return; ++} ++static inline void get_seccomp_filter(struct task_struct *tsk) ++{ ++ return; ++} ++#endif /* CONFIG_SECCOMP_FILTER */ ++#endif /* __KERNEL__ */ + #endif /* _LINUX_SECCOMP_H */ diff --git a/include/linux/security.h b/include/linux/security.h -index e8c619d..ff41b06 100644 +index e8c619d..99d0f1f 100644 --- a/include/linux/security.h +++ b/include/linux/security.h @@ -37,6 +37,7 @@ @@ -74588,7 +75203,15 @@ index e8c619d..ff41b06 100644 #ifdef CONFIG_MMU extern unsigned long mmap_min_addr; extern unsigned long dac_mmap_min_addr; -@@ -1676,6 +1675,8 @@ int security_capset(struct cred *new, const struct cred *old, +@@ -130,6 +129,7 @@ struct request_sock; + #define LSM_UNSAFE_SHARE 1 + #define LSM_UNSAFE_PTRACE 2 + #define LSM_UNSAFE_PTRACE_CAP 4 ++#define LSM_UNSAFE_NO_NEW_PRIVS 8 + + #ifdef CONFIG_MMU + /* +@@ -1676,6 +1676,8 @@ int security_capset(struct cred *new, const struct cred *old, const kernel_cap_t *permitted); int security_capable(struct user_namespace *ns, const struct cred *cred, int cap); @@ -74597,7 +75220,7 @@ index e8c619d..ff41b06 100644 int security_real_capable(struct task_struct *tsk, struct user_namespace *ns, int cap); int security_real_capable_noaudit(struct task_struct *tsk, -@@ -1880,6 +1881,12 @@ static inline int security_capable(struct user_namespace *ns, +@@ -1880,6 +1882,12 @@ static inline int security_capable(struct user_namespace *ns, return cap_capable(current, cred, ns, cap, SECURITY_CAP_AUDIT); } @@ -77495,10 +78118,18 @@ index d4bc594..efa193f 100644 return; } diff --git a/kernel/auditsc.c b/kernel/auditsc.c -index 47b7fc1..c003c33 100644 +index 47b7fc1..9af0605 100644 --- a/kernel/auditsc.c +++ b/kernel/auditsc.c -@@ -1166,8 +1166,8 @@ static void audit_log_execve_info(struct audit_context *context, +@@ -67,6 +67,7 @@ + #include <linux/syscalls.h> + #include <linux/capability.h> + #include <linux/fs_struct.h> ++#include <linux/compat.h> + + #include "audit.h" + +@@ -1166,8 +1167,8 @@ static void audit_log_execve_info(struct audit_context *context, struct audit_buffer **ab, struct audit_aux_data_execve *axi) { @@ -77509,7 +78140,7 @@ index 47b7fc1..c003c33 100644 const char __user *p; char *buf; -@@ -2118,7 +2118,7 @@ int auditsc_get_stamp(struct audit_context *ctx, +@@ -2118,7 +2119,7 @@ int auditsc_get_stamp(struct audit_context *ctx, } /* global counter which is incremented every time something logs in */ @@ -77518,7 +78149,7 @@ index 47b7fc1..c003c33 100644 /** * audit_set_loginuid - set a task's audit_context loginuid -@@ -2131,7 +2131,7 @@ static atomic_t session_id = ATOMIC_INIT(0); +@@ -2131,7 +2132,7 @@ static atomic_t session_id = ATOMIC_INIT(0); */ int audit_set_loginuid(struct task_struct *task, uid_t loginuid) { @@ -77527,6 +78158,97 @@ index 47b7fc1..c003c33 100644 struct audit_context *context = task->audit_context; if (context && context->in_syscall) { +@@ -2499,46 +2500,59 @@ void __audit_mmap_fd(int fd, int flags) + context->type = AUDIT_MMAP; + } + +-/** +- * audit_core_dumps - record information about processes that end abnormally +- * @signr: signal value +- * +- * If a process ends with a core dump, something fishy is going on and we +- * should record the event for investigation. +- */ +-void audit_core_dumps(long signr) ++static void audit_log_abend(struct audit_buffer *ab, char *reason, long signr) + { +- struct audit_buffer *ab; +- u32 sid; +- uid_t auid = audit_get_loginuid(current), uid; ++ uid_t auid, uid; + gid_t gid; +- unsigned int sessionid = audit_get_sessionid(current); ++ unsigned int sessionid; + +- if (!audit_enabled) +- return; +- +- if (signr == SIGQUIT) /* don't care for those */ +- return; +- +- ab = audit_log_start(NULL, GFP_KERNEL, AUDIT_ANOM_ABEND); ++ auid = audit_get_loginuid(current); ++ sessionid = audit_get_sessionid(current); + current_uid_gid(&uid, &gid); ++ + audit_log_format(ab, "auid=%u uid=%u gid=%u ses=%u", + auid, uid, gid, sessionid); +- security_task_getsecid(current, &sid); +- if (sid) { +- char *ctx = NULL; +- u32 len; +- +- if (security_secid_to_secctx(sid, &ctx, &len)) +- audit_log_format(ab, " ssid=%u", sid); +- else { +- audit_log_format(ab, " subj=%s", ctx); +- security_release_secctx(ctx, len); +- } +- } ++ audit_log_task_context(ab); + audit_log_format(ab, " pid=%d comm=", current->pid); + audit_log_untrustedstring(ab, current->comm); ++ audit_log_format(ab, " reason="); ++ audit_log_string(ab, reason); + audit_log_format(ab, " sig=%ld", signr); ++} ++/** ++ * audit_core_dumps - record information about processes that end abnormally ++ * @signr: signal value ++ * ++ * If a process ends with a core dump, something fishy is going on and we ++ * should record the event for investigation. ++ */ ++void audit_core_dumps(long signr) ++{ ++ struct audit_buffer *ab; ++ ++ if (!audit_enabled) ++ return; ++ ++ if (signr == SIGQUIT) /* don't care for those */ ++ return; ++ ++ ab = audit_log_start(NULL, GFP_KERNEL, AUDIT_ANOM_ABEND); ++ audit_log_abend(ab, "memory violation", signr); ++ audit_log_end(ab); ++} ++ ++void __audit_seccomp(unsigned long syscall, long signr, int code) ++{ ++ struct audit_buffer *ab; ++ ++ ab = audit_log_start(NULL, GFP_KERNEL, AUDIT_ANOM_ABEND); ++ audit_log_abend(ab, "seccomp", signr); ++ audit_log_format(ab, " syscall=%ld", syscall); ++#ifdef CONFIG_COMPAT ++ audit_log_format(ab, " compat=%d", is_compat_task()); ++#endif ++ audit_log_format(ab, " ip=0x%lx", KSTK_EIP(current)); ++ audit_log_format(ab, " code=0x%x", code); + audit_log_end(ab); + } + diff --git a/kernel/capability.c b/kernel/capability.c index b463871..59495fd 100644 --- a/kernel/capability.c @@ -78224,10 +78946,26 @@ index 234e152..0ae0243 100644 { struct signal_struct *sig = current->signal; diff --git a/kernel/fork.c b/kernel/fork.c -index ce0c182..360568a 100644 +index ce0c182..c6ec99a 100644 --- a/kernel/fork.c +++ b/kernel/fork.c -@@ -270,19 +270,24 @@ static struct task_struct *dup_task_struct(struct task_struct *orig) +@@ -34,6 +34,7 @@ + #include <linux/cgroup.h> + #include <linux/security.h> + #include <linux/hugetlb.h> ++#include <linux/seccomp.h> + #include <linux/swap.h> + #include <linux/syscalls.h> + #include <linux/jiffies.h> +@@ -168,6 +169,7 @@ void free_task(struct task_struct *tsk) + free_thread_info(tsk->stack); + rt_mutex_debug_task_free(tsk); + ftrace_graph_exit_task(tsk); ++ put_seccomp_filter(tsk); + free_task_struct(tsk); + } + EXPORT_SYMBOL(free_task); +@@ -270,19 +272,24 @@ static struct task_struct *dup_task_struct(struct task_struct *orig) } err = arch_dup_task_struct(tsk, orig); @@ -78256,7 +78994,7 @@ index ce0c182..360568a 100644 #endif /* -@@ -306,13 +311,78 @@ out: +@@ -306,13 +313,78 @@ out: } #ifdef CONFIG_MMU @@ -78339,7 +79077,7 @@ index ce0c182..360568a 100644 down_write(&oldmm->mmap_sem); flush_cache_dup_mm(oldmm); -@@ -324,8 +394,8 @@ static int dup_mmap(struct mm_struct *mm, struct mm_struct *oldmm) +@@ -324,8 +396,8 @@ static int dup_mmap(struct mm_struct *mm, struct mm_struct *oldmm) mm->locked_vm = 0; mm->mmap = NULL; mm->mmap_cache = NULL; @@ -78350,7 +79088,7 @@ index ce0c182..360568a 100644 mm->map_count = 0; cpumask_clear(mm_cpumask(mm)); mm->mm_rb = RB_ROOT; -@@ -341,63 +411,16 @@ static int dup_mmap(struct mm_struct *mm, struct mm_struct *oldmm) +@@ -341,63 +413,16 @@ static int dup_mmap(struct mm_struct *mm, struct mm_struct *oldmm) prev = NULL; for (mpnt = oldmm->mmap; mpnt; mpnt = mpnt->vm_next) { @@ -78419,7 +79157,7 @@ index ce0c182..360568a 100644 /* * Link in the new vma and copy the page table entries. -@@ -420,6 +443,31 @@ static int dup_mmap(struct mm_struct *mm, struct mm_struct *oldmm) +@@ -420,6 +445,31 @@ static int dup_mmap(struct mm_struct *mm, struct mm_struct *oldmm) if (retval) goto out; } @@ -78451,7 +79189,7 @@ index ce0c182..360568a 100644 /* a new mm has just been created */ arch_dup_mmap(oldmm, mm); retval = 0; -@@ -428,14 +476,6 @@ out: +@@ -428,14 +478,6 @@ out: flush_tlb_mm(oldmm); up_write(&oldmm->mmap_sem); return retval; @@ -78466,7 +79204,7 @@ index ce0c182..360568a 100644 } static inline int mm_alloc_pgd(struct mm_struct *mm) -@@ -647,6 +687,26 @@ struct mm_struct *get_task_mm(struct task_struct *task) +@@ -647,6 +689,26 @@ struct mm_struct *get_task_mm(struct task_struct *task) } EXPORT_SYMBOL_GPL(get_task_mm); @@ -78493,7 +79231,7 @@ index ce0c182..360568a 100644 /* Please note the differences between mmput and mm_release. * mmput is called whenever we stop holding onto a mm_struct, * error success whatever. -@@ -832,13 +892,20 @@ static int copy_fs(unsigned long clone_flags, struct task_struct *tsk) +@@ -832,13 +894,20 @@ static int copy_fs(unsigned long clone_flags, struct task_struct *tsk) spin_unlock(&fs->lock); return -EAGAIN; } @@ -78515,7 +79253,7 @@ index ce0c182..360568a 100644 return 0; } -@@ -1047,7 +1114,7 @@ static void posix_cpu_timers_init(struct task_struct *tsk) +@@ -1047,7 +1116,7 @@ static void posix_cpu_timers_init(struct task_struct *tsk) * parts of the process environment (as per the clone * flags). The actual kick-off is left to the caller. */ @@ -78524,7 +79262,15 @@ index ce0c182..360568a 100644 unsigned long stack_start, struct pt_regs *regs, unsigned long stack_size, -@@ -1104,10 +1171,13 @@ static struct task_struct *copy_process(unsigned long clone_flags, +@@ -1096,6 +1165,7 @@ static struct task_struct *copy_process(unsigned long clone_flags, + goto fork_out; + + ftrace_graph_init_task(p); ++ get_seccomp_filter(p); + + rt_mutex_init_task(p); + +@@ -1104,10 +1174,13 @@ static struct task_struct *copy_process(unsigned long clone_flags, DEBUG_LOCKS_WARN_ON(!p->softirqs_enabled); #endif retval = -EAGAIN; @@ -78540,7 +79286,7 @@ index ce0c182..360568a 100644 goto bad_fork_free; } current->flags &= ~PF_NPROC_EXCEEDED; -@@ -1341,6 +1411,11 @@ static struct task_struct *copy_process(unsigned long clone_flags, +@@ -1341,6 +1414,11 @@ static struct task_struct *copy_process(unsigned long clone_flags, goto bad_fork_free_pid; } @@ -78552,7 +79298,7 @@ index ce0c182..360568a 100644 if (clone_flags & CLONE_THREAD) { current->signal->nr_threads++; atomic_inc(¤t->signal->live); -@@ -1421,6 +1496,8 @@ bad_fork_cleanup_count: +@@ -1421,6 +1499,8 @@ bad_fork_cleanup_count: bad_fork_free: free_task(p); fork_out: @@ -78561,7 +79307,7 @@ index ce0c182..360568a 100644 return ERR_PTR(retval); } -@@ -1507,6 +1584,7 @@ long do_fork(unsigned long clone_flags, +@@ -1507,6 +1587,7 @@ long do_fork(unsigned long clone_flags, p = copy_process(clone_flags, stack_start, regs, stack_size, child_tidptr, NULL, trace); @@ -78569,7 +79315,7 @@ index ce0c182..360568a 100644 /* * Do this prior waking up the new thread - the thread pointer * might get invalid after that point, if the thread exits quickly. -@@ -1521,6 +1599,8 @@ long do_fork(unsigned long clone_flags, +@@ -1521,6 +1602,8 @@ long do_fork(unsigned long clone_flags, if (clone_flags & CLONE_PARENT_SETTID) put_user(nr, parent_tidptr); @@ -78578,7 +79324,7 @@ index ce0c182..360568a 100644 if (clone_flags & CLONE_VFORK) { p->vfork_done = &vfork; init_completion(&vfork); -@@ -1591,7 +1671,7 @@ void __init proc_caches_init(void) +@@ -1591,7 +1674,7 @@ void __init proc_caches_init(void) mm_cachep = kmem_cache_create("mm_struct", sizeof(struct mm_struct), ARCH_MIN_MMSTRUCT_ALIGN, SLAB_HWCACHE_ALIGN|SLAB_PANIC|SLAB_NOTRACK, NULL); @@ -78587,7 +79333,7 @@ index ce0c182..360568a 100644 mmap_init(); nsproxy_cache_init(); } -@@ -1630,7 +1710,7 @@ static int unshare_fs(unsigned long unshare_flags, struct fs_struct **new_fsp) +@@ -1630,7 +1713,7 @@ static int unshare_fs(unsigned long unshare_flags, struct fs_struct **new_fsp) return 0; /* don't need lock here; in the worst case we'll do useless copy */ @@ -78596,7 +79342,7 @@ index ce0c182..360568a 100644 return 0; *new_fsp = copy_fs_struct(fs); -@@ -1719,7 +1799,8 @@ SYSCALL_DEFINE1(unshare, unsigned long, unshare_flags) +@@ -1719,7 +1802,8 @@ SYSCALL_DEFINE1(unshare, unsigned long, unshare_flags) fs = current->fs; spin_lock(&fs->lock); current->fs = new_fs; @@ -80543,7 +81289,7 @@ index 76b8e77..a2930e8 100644 } diff --git a/kernel/ptrace.c b/kernel/ptrace.c -index 67fedad..32d32a04 100644 +index 67fedad..82362a6 100644 --- a/kernel/ptrace.c +++ b/kernel/ptrace.c @@ -211,7 +211,8 @@ int ptrace_check_attach(struct task_struct *child, bool ignore_state) @@ -80627,7 +81373,17 @@ index 67fedad..32d32a04 100644 return -EFAULT; copied += retval; src += retval; -@@ -719,7 +737,7 @@ int ptrace_request(struct task_struct *child, long request, +@@ -582,6 +600,9 @@ static int ptrace_setoptions(struct task_struct *child, unsigned long data) + if (data & PTRACE_O_TRACEEXIT) + child->ptrace |= PT_TRACE_EXIT; + ++ if (data & PTRACE_O_TRACESECCOMP) ++ child->ptrace |= PT_TRACE_SECCOMP; ++ + return (data & ~PTRACE_O_MASK) ? -EINVAL : 0; + } + +@@ -719,7 +740,7 @@ int ptrace_request(struct task_struct *child, long request, bool seized = child->ptrace & PT_SEIZED; int ret = -EIO; siginfo_t siginfo, *si; @@ -80636,7 +81392,7 @@ index 67fedad..32d32a04 100644 unsigned long __user *datalp = datavp; unsigned long flags; -@@ -921,14 +939,21 @@ SYSCALL_DEFINE4(ptrace, long, request, long, pid, unsigned long, addr, +@@ -921,14 +942,21 @@ SYSCALL_DEFINE4(ptrace, long, request, long, pid, unsigned long, addr, goto out; } @@ -80659,7 +81415,7 @@ index 67fedad..32d32a04 100644 goto out_put_task_struct; } -@@ -956,7 +981,7 @@ int generic_ptrace_peekdata(struct task_struct *tsk, unsigned long addr, +@@ -956,7 +984,7 @@ int generic_ptrace_peekdata(struct task_struct *tsk, unsigned long addr, copied = access_process_vm(tsk, addr, &tmp, sizeof(tmp), 0); if (copied != sizeof(tmp)) return -EIO; @@ -80668,7 +81424,7 @@ index 67fedad..32d32a04 100644 } int generic_ptrace_pokedata(struct task_struct *tsk, unsigned long addr, -@@ -1050,7 +1075,7 @@ int compat_ptrace_request(struct task_struct *child, compat_long_t request, +@@ -1050,7 +1078,7 @@ int compat_ptrace_request(struct task_struct *child, compat_long_t request, } asmlinkage long compat_sys_ptrace(compat_long_t request, compat_long_t pid, @@ -80677,7 +81433,7 @@ index 67fedad..32d32a04 100644 { struct task_struct *child; long ret; -@@ -1066,14 +1091,21 @@ asmlinkage long compat_sys_ptrace(compat_long_t request, compat_long_t pid, +@@ -1066,14 +1094,21 @@ asmlinkage long compat_sys_ptrace(compat_long_t request, compat_long_t pid, goto out; } @@ -81428,8 +82184,513 @@ index c261da7..4e5221ad 100644 { int this_cpu = smp_processor_id(); struct rq *this_rq = cpu_rq(this_cpu); +diff --git a/kernel/seccomp.c b/kernel/seccomp.c +index 57d4b13..bc84054 100644 +--- a/kernel/seccomp.c ++++ b/kernel/seccomp.c +@@ -3,15 +3,353 @@ + * + * Copyright 2004-2005 Andrea Arcangeli <andrea@cpushare.com> + * +- * This defines a simple but solid secure-computing mode. ++ * Copyright (C) 2012 Google, Inc. ++ * Will Drewry <wad@chromium.org> ++ * ++ * This defines a simple but solid secure-computing facility. ++ * ++ * Mode 1 uses a fixed list of allowed system calls. ++ * Mode 2 allows user-defined system call filters in the form ++ * of Berkeley Packet Filters/Linux Socket Filters. + */ + +-#include <linux/seccomp.h> +-#include <linux/sched.h> ++#include <linux/atomic.h> ++#include <linux/audit.h> + #include <linux/compat.h> ++#include <linux/filter.h> ++#include <linux/ptrace.h> ++#include <linux/sched.h> ++#include <linux/seccomp.h> ++#include <linux/security.h> ++#include <linux/slab.h> ++#include <linux/uaccess.h> ++ ++#ifdef CONFIG_HAVE_ARCH_SECCOMP_FILTER ++#include <asm/syscall.h> ++#endif + + /* #define SECCOMP_DEBUG 1 */ +-#define NR_SECCOMP_MODES 1 ++ ++#ifdef CONFIG_SECCOMP_FILTER ++/** ++ * struct seccomp_filter - container for seccomp BPF programs ++ * ++ * @usage: reference count to manage the object liftime. ++ * get/put helpers should be used when accessing an instance ++ * outside of a lifetime-guarded section. In general, this ++ * is only needed for handling filters shared across tasks. ++ * @prev: points to a previously installed, or inherited, filter ++ * @len: the number of instructions in the program ++ * @insns: the BPF program instructions to evaluate ++ * ++ * seccomp_filter objects are organized in a tree linked via the @prev ++ * pointer. For any task, it appears to be a singly-linked list starting ++ * with current->seccomp.filter, the most recently attached or inherited filter. ++ * However, multiple filters may share a @prev node, by way of fork(), which ++ * results in a unidirectional tree existing in memory. This is similar to ++ * how namespaces work. ++ * ++ * seccomp_filter objects should never be modified after being attached ++ * to a task_struct (other than @usage). ++ */ ++struct seccomp_filter { ++ atomic_t usage; ++ struct seccomp_filter *prev; ++ unsigned short len; /* Instruction count */ ++ struct sock_filter insns[]; ++}; ++ ++/* Limit any path through the tree to 256KB worth of instructions. */ ++#define MAX_INSNS_PER_PATH ((1 << 18) / sizeof(struct sock_filter)) ++ ++/** ++ * get_u32 - returns a u32 offset into data ++ * @data: a unsigned 64 bit value ++ * @index: 0 or 1 to return the first or second 32-bits ++ * ++ * This inline exists to hide the length of unsigned long. ++ * If a 32-bit unsigned long is passed in, it will be extended ++ * and the top 32-bits will be 0. If it is a 64-bit unsigned ++ * long, then whatever data is resident will be properly returned. ++ */ ++static inline u32 get_u32(u64 data, int index) ++{ ++ return ((u32 *)&data)[index]; ++} ++ ++/* Helper for bpf_load below. */ ++#define BPF_DATA(_name) offsetof(struct seccomp_data, _name) ++/** ++ * bpf_load: checks and returns a pointer to the requested offset ++ * @off: offset into struct seccomp_data to load from ++ * ++ * Returns the requested 32-bits of data. ++ * seccomp_chk_filter() should assure that @off is 32-bit aligned ++ * and not out of bounds. Failure to do so is a BUG. ++ */ ++u32 seccomp_bpf_load(int off) ++{ ++ struct pt_regs *regs = task_pt_regs(current); ++ if (off == BPF_DATA(nr)) ++ return syscall_get_nr(current, regs); ++ if (off == BPF_DATA(arch)) ++ return syscall_get_arch(current, regs); ++ if (off >= BPF_DATA(args[0]) && off < BPF_DATA(args[6])) { ++ unsigned long value; ++ int arg = (off - BPF_DATA(args[0])) / sizeof(u64); ++ int index = !!(off % sizeof(u64)); ++ syscall_get_arguments(current, regs, arg, 1, &value); ++ return get_u32(value, index); ++ } ++ if (off == BPF_DATA(instruction_pointer)) ++ return get_u32(KSTK_EIP(current), 0); ++ if (off == BPF_DATA(instruction_pointer) + sizeof(u32)) ++ return get_u32(KSTK_EIP(current), 1); ++ /* seccomp_chk_filter should make this impossible. */ ++ BUG(); ++} ++ ++/** ++ * seccomp_chk_filter - verify seccomp filter code ++ * @filter: filter to verify ++ * @flen: length of filter ++ * ++ * Takes a previously checked filter (by sk_chk_filter) and ++ * redirects all filter code that loads struct sk_buff data ++ * and related data through seccomp_bpf_load. It also ++ * enforces length and alignment checking of those loads. ++ * ++ * Returns 0 if the rule set is legal or -EINVAL if not. ++ */ ++static int seccomp_chk_filter(struct sock_filter *filter, unsigned int flen) ++{ ++ int pc; ++ for (pc = 0; pc < flen; pc++) { ++ struct sock_filter *ftest = &filter[pc]; ++ u16 code = ftest->code; ++ u32 k = ftest->k; ++ switch (code) { ++ case BPF_S_LD_W_ABS: ++ ftest->code = BPF_S_ANC_SECCOMP_LD_W; ++ /* 32-bit aligned and not out of bounds. */ ++ if (k >= sizeof(struct seccomp_data) || k & 3) ++ return -EINVAL; ++ continue; ++ case BPF_S_LD_W_LEN: ++ ftest->code = BPF_S_LD_IMM; ++ ftest->k = sizeof(struct seccomp_data); ++ continue; ++ case BPF_S_LDX_W_LEN: ++ ftest->code = BPF_S_LDX_IMM; ++ ftest->k = sizeof(struct seccomp_data); ++ continue; ++ /* Explicitly include allowed calls. */ ++ case BPF_S_RET_K: ++ case BPF_S_RET_A: ++ case BPF_S_ALU_ADD_K: ++ case BPF_S_ALU_ADD_X: ++ case BPF_S_ALU_SUB_K: ++ case BPF_S_ALU_SUB_X: ++ case BPF_S_ALU_MUL_K: ++ case BPF_S_ALU_MUL_X: ++ case BPF_S_ALU_DIV_X: ++ case BPF_S_ALU_AND_K: ++ case BPF_S_ALU_AND_X: ++ case BPF_S_ALU_OR_K: ++ case BPF_S_ALU_OR_X: ++ case BPF_S_ALU_LSH_K: ++ case BPF_S_ALU_LSH_X: ++ case BPF_S_ALU_RSH_K: ++ case BPF_S_ALU_RSH_X: ++ case BPF_S_ALU_NEG: ++ case BPF_S_LD_IMM: ++ case BPF_S_LDX_IMM: ++ case BPF_S_MISC_TAX: ++ case BPF_S_MISC_TXA: ++ case BPF_S_ALU_DIV_K: ++ case BPF_S_LD_MEM: ++ case BPF_S_LDX_MEM: ++ case BPF_S_ST: ++ case BPF_S_STX: ++ case BPF_S_JMP_JA: ++ case BPF_S_JMP_JEQ_K: ++ case BPF_S_JMP_JEQ_X: ++ case BPF_S_JMP_JGE_K: ++ case BPF_S_JMP_JGE_X: ++ case BPF_S_JMP_JGT_K: ++ case BPF_S_JMP_JGT_X: ++ case BPF_S_JMP_JSET_K: ++ case BPF_S_JMP_JSET_X: ++ continue; ++ default: ++ return -EINVAL; ++ } ++ } ++ return 0; ++} ++ ++/** ++ * seccomp_run_filters - evaluates all seccomp filters against @syscall ++ * @syscall: number of the current system call ++ * ++ * Returns valid seccomp BPF response codes. ++ */ ++static u32 seccomp_run_filters(int syscall) ++{ ++ struct seccomp_filter *f; ++ u32 ret = SECCOMP_RET_ALLOW; ++ ++ /* Ensure unexpected behavior doesn't result in failing open. */ ++ if (WARN_ON(current->seccomp.filter == NULL)) ++ return SECCOMP_RET_KILL; ++ ++ /* ++ * All filters are evaluated in order of youngest to oldest. The lowest ++ * BPF return value (ignoring the DATA) always takes priority. ++ */ ++ for (f = current->seccomp.filter; f; f = f->prev) { ++ u32 cur_ret = sk_run_filter(NULL, f->insns); ++ if ((cur_ret & SECCOMP_RET_ACTION) < (ret & SECCOMP_RET_ACTION)) ++ ret = cur_ret; ++ } ++ return ret; ++} ++ ++/** ++ * seccomp_attach_filter: Attaches a seccomp filter to current. ++ * @fprog: BPF program to install ++ * ++ * Returns 0 on success or an errno on failure. ++ */ ++static long seccomp_attach_filter(struct sock_fprog *fprog) ++{ ++ struct seccomp_filter *filter; ++ 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 -EINVAL; ++ ++ 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 -ENOMEM; ++ ++ /* ++ * Installing a seccomp filter requires that the task have ++ * CAP_SYS_ADMIN in its namespace or be running with no_new_privs. ++ * This avoids scenarios where unprivileged tasks can affect the ++ * behavior of privileged children. ++ */ ++ if (!current->no_new_privs && ++ security_real_capable_noaudit(current, current_user_ns(), ++ CAP_SYS_ADMIN) != 0) ++ return -EACCES; ++ ++ /* Allocate a new seccomp_filter */ ++ filter = kzalloc(sizeof(struct seccomp_filter) + fp_size, GFP_KERNEL); ++ if (!filter) ++ return -ENOMEM; ++ atomic_set(&filter->usage, 1); ++ filter->len = fprog->len; ++ ++ /* Copy the instructions from fprog. */ ++ ret = -EFAULT; ++ if (copy_from_user(filter->insns, fprog->filter, fp_size)) ++ goto fail; ++ ++ /* Check and rewrite the fprog via the skb checker */ ++ ret = sk_chk_filter(filter->insns, filter->len); ++ if (ret) ++ goto fail; ++ ++ /* Check and rewrite the fprog for seccomp use */ ++ ret = seccomp_chk_filter(filter->insns, filter->len); ++ if (ret) ++ goto fail; ++ ++ /* ++ * If there is an existing filter, make it the prev and don't drop its ++ * task reference. ++ */ ++ filter->prev = current->seccomp.filter; ++ current->seccomp.filter = filter; ++ return 0; ++fail: ++ kfree(filter); ++ return ret; ++} ++ ++/** ++ * seccomp_attach_user_filter - attaches a user-supplied sock_fprog ++ * @user_filter: pointer to the user data containing a sock_fprog. ++ * ++ * Returns 0 on success and non-zero otherwise. ++ */ ++long seccomp_attach_user_filter(char __user *user_filter) ++{ ++ struct sock_fprog fprog; ++ long ret = -EFAULT; ++ ++#ifdef CONFIG_COMPAT ++ if (is_compat_task()) { ++ struct compat_sock_fprog fprog32; ++ if (copy_from_user(&fprog32, user_filter, sizeof(fprog32))) ++ goto out; ++ fprog.len = fprog32.len; ++ fprog.filter = compat_ptr(fprog32.filter); ++ } else /* falls through to the if below. */ ++#endif ++ if (copy_from_user(&fprog, user_filter, sizeof(fprog))) ++ goto out; ++ ret = seccomp_attach_filter(&fprog); ++out: ++ return ret; ++} ++ ++/* get_seccomp_filter - increments the reference count of the filter on @tsk */ ++void get_seccomp_filter(struct task_struct *tsk) ++{ ++ struct seccomp_filter *orig = tsk->seccomp.filter; ++ if (!orig) ++ return; ++ /* Reference count is bounded by the number of total processes. */ ++ atomic_inc(&orig->usage); ++} ++ ++/* put_seccomp_filter - decrements the ref count of tsk->seccomp.filter */ ++void put_seccomp_filter(struct task_struct *tsk) ++{ ++ struct seccomp_filter *orig = tsk->seccomp.filter; ++ /* Clean up single-reference branches iteratively. */ ++ while (orig && atomic_dec_and_test(&orig->usage)) { ++ struct seccomp_filter *freeme = orig; ++ orig = orig->prev; ++ kfree(freeme); ++ } ++} ++ ++/** ++ * seccomp_send_sigsys - signals the task to allow in-process syscall emulation ++ * @syscall: syscall number to send to userland ++ * @reason: filter-supplied reason code to send to userland (via si_errno) ++ * ++ * Forces a SIGSYS with a code of SYS_SECCOMP and related sigsys info. ++ */ ++static void seccomp_send_sigsys(int syscall, int reason) ++{ ++ struct siginfo info; ++ memset(&info, 0, sizeof(info)); ++ info.si_signo = SIGSYS; ++ 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_syscall = syscall; ++ force_sig_info(SIGSYS, &info, current); ++} ++#endif /* CONFIG_SECCOMP_FILTER */ + + /* + * Secure computing mode 1 allows only read/write/exit/sigreturn. +@@ -32,11 +370,21 @@ static int mode1_syscalls_32[] = { + + void __secure_computing(int this_syscall) + { ++ /* Filter calls should never use this function. */ ++ BUG_ON(current->seccomp.mode == SECCOMP_MODE_FILTER); ++ __secure_computing_int(this_syscall); ++} ++ ++int __secure_computing_int(int this_syscall) ++{ + int mode = current->seccomp.mode; +- int * syscall; ++ int exit_sig = 0; ++ int *syscall; ++ u32 ret = SECCOMP_RET_KILL; ++ int data; + + switch (mode) { +- case 1: ++ case SECCOMP_MODE_STRICT: + syscall = mode1_syscalls; + #ifdef CONFIG_COMPAT + if (is_compat_task()) +@@ -44,9 +392,44 @@ void __secure_computing(int this_syscall) + #endif + do { + if (*syscall == this_syscall) +- return; ++ return 0; + } while (*++syscall); ++ exit_sig = SIGKILL; + break; ++#ifdef CONFIG_SECCOMP_FILTER ++ case SECCOMP_MODE_FILTER: ++ ret = seccomp_run_filters(this_syscall); ++ data = ret & SECCOMP_RET_DATA; ++ switch (ret & SECCOMP_RET_ACTION) { ++ case SECCOMP_RET_ERRNO: ++ /* Set the low-order 16-bits as a errno. */ ++ syscall_set_return_value(current, task_pt_regs(current), ++ -data, 0); ++ goto skip; ++ case SECCOMP_RET_TRAP: ++ /* Show the handler the original registers. */ ++ syscall_rollback(current, task_pt_regs(current)); ++ /* Let the filter pass back 16 bits of data. */ ++ seccomp_send_sigsys(this_syscall, data); ++ goto skip; ++ case SECCOMP_RET_TRACE: ++ /* Skip these calls if there is no tracer. */ ++ if (!ptrace_event_enabled(current, PTRACE_EVENT_SECCOMP)) ++ goto skip; ++ /* Allow the BPF to provide the event message */ ++ ptrace_event(PTRACE_EVENT_SECCOMP, data); ++ if (fatal_signal_pending(current)) ++ break; ++ return 0; ++ case SECCOMP_RET_ALLOW: ++ return 0; ++ case SECCOMP_RET_KILL: ++ default: ++ break; ++ } ++ exit_sig = SIGSYS; ++ break; ++#endif + default: + BUG(); + } +@@ -54,7 +437,11 @@ void __secure_computing(int this_syscall) + #ifdef SECCOMP_DEBUG + dump_stack(); + #endif +- do_exit(SIGKILL); ++ __audit_seccomp(this_syscall, exit_sig, ret); ++ do_exit(exit_sig); ++skip: ++ audit_seccomp(this_syscall, exit_sig, ret); ++ return -1; + } + + long prctl_get_seccomp(void) +@@ -62,25 +449,48 @@ long prctl_get_seccomp(void) + return current->seccomp.mode; + } + +-long prctl_set_seccomp(unsigned long seccomp_mode) ++/** ++ * prctl_set_seccomp: configures current->seccomp.mode ++ * @seccomp_mode: requested mode to use ++ * @filter: optional struct sock_fprog for use with SECCOMP_MODE_FILTER ++ * ++ * This function may be called repeatedly with a @seccomp_mode of ++ * SECCOMP_MODE_FILTER to install additional filters. Every filter ++ * successfully installed will be evaluated (in reverse order) for each system ++ * call the task makes. ++ * ++ * Once current->seccomp.mode is non-zero, it may not be changed. ++ * ++ * Returns 0 on success or -EINVAL on failure. ++ */ ++long prctl_set_seccomp(unsigned long seccomp_mode, char __user *filter) + { +- long ret; ++ long ret = -EINVAL; + +- /* can set it only once to be even more secure */ +- ret = -EPERM; +- if (unlikely(current->seccomp.mode)) ++ if (current->seccomp.mode && ++ current->seccomp.mode != seccomp_mode) + goto out; + +- ret = -EINVAL; +- if (seccomp_mode && seccomp_mode <= NR_SECCOMP_MODES) { +- current->seccomp.mode = seccomp_mode; +- set_thread_flag(TIF_SECCOMP); ++ switch (seccomp_mode) { ++ case SECCOMP_MODE_STRICT: ++ ret = 0; + #ifdef TIF_NOTSC + disable_TSC(); + #endif +- ret = 0; ++ break; ++#ifdef CONFIG_SECCOMP_FILTER ++ case SECCOMP_MODE_FILTER: ++ ret = seccomp_attach_user_filter(filter); ++ if (ret) ++ goto out; ++ break; ++#endif ++ default: ++ goto out; + } + +- out: ++ current->seccomp.mode = seccomp_mode; ++ set_thread_flag(TIF_SECCOMP); ++out: + return ret; + } diff --git a/kernel/signal.c b/kernel/signal.c -index 3ecf574..7b5d245 100644 +index 3ecf574..0541e21 100644 --- a/kernel/signal.c +++ b/kernel/signal.c @@ -45,12 +45,12 @@ static struct kmem_cache *sigqueue_cachep; @@ -81456,6 +82717,15 @@ index 3ecf574..7b5d245 100644 handler = sig_handler(t, sig); +@@ -159,7 +159,7 @@ void recalc_sigpending(void) + + #define SYNCHRONOUS_MASK \ + (sigmask(SIGSEGV) | sigmask(SIGBUS) | sigmask(SIGILL) | \ +- sigmask(SIGTRAP) | sigmask(SIGFPE)) ++ sigmask(SIGTRAP) | sigmask(SIGFPE) | sigmask(SIGSYS)) + + int next_signal(struct sigpending *pending, sigset_t *mask) + { @@ -364,6 +364,9 @@ __sigqueue_alloc(int sig, struct task_struct *t, gfp_t flags, int override_rlimi atomic_inc(&user->sigpending); rcu_read_unlock(); @@ -81538,7 +82808,21 @@ index 3ecf574..7b5d245 100644 return ret; } -@@ -2765,7 +2788,15 @@ do_send_specific(pid_t tgid, pid_t pid, int sig, struct siginfo *info) +@@ -2631,6 +2654,13 @@ int copy_siginfo_to_user(siginfo_t __user *to, siginfo_t *from) + err |= __put_user(from->si_uid, &to->si_uid); + err |= __put_user(from->si_ptr, &to->si_ptr); + break; ++#ifdef __ARCH_SIGSYS ++ case __SI_SYS: ++ err |= __put_user(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); +@@ -2765,7 +2795,15 @@ do_send_specific(pid_t tgid, pid_t pid, int sig, struct siginfo *info) int error = -ESRCH; rcu_read_lock(); @@ -81681,7 +82965,7 @@ index 2f194e9..2c05ea9 100644 .priority = 10, }; diff --git a/kernel/sys.c b/kernel/sys.c -index 9d557df..691558c 100644 +index 9d557df..b2a5319 100644 --- a/kernel/sys.c +++ b/kernel/sys.c @@ -158,6 +158,12 @@ static int set_one_prio(struct task_struct *p, int niceval, int error) @@ -81852,6 +83136,32 @@ index 9d557df..691558c 100644 error = -EINVAL; break; } +@@ -1808,7 +1851,7 @@ SYSCALL_DEFINE5(prctl, int, option, unsigned long, arg2, unsigned long, arg3, + error = prctl_get_seccomp(); + break; + case PR_SET_SECCOMP: +- error = prctl_set_seccomp(arg2); ++ error = prctl_set_seccomp(arg2, (char __user *)arg3); + break; + case PR_GET_TSC: + error = GET_TSC_CTL(arg2); +@@ -1868,6 +1911,16 @@ SYSCALL_DEFINE5(prctl, int, option, unsigned long, arg2, unsigned long, arg3, + else + error = PR_MCE_KILL_DEFAULT; + break; ++ case PR_SET_NO_NEW_PRIVS: ++ if (arg2 != 1 || arg3 || arg4 || arg5) ++ return -EINVAL; ++ ++ current->no_new_privs = 1; ++ break; ++ case PR_GET_NO_NEW_PRIVS: ++ if (arg2 || arg3 || arg4 || arg5) ++ return -EINVAL; ++ return current->no_new_privs ? 1 : 0; + default: + error = -EINVAL; + break; diff --git a/kernel/sysctl.c b/kernel/sysctl.c index ea7ec7f..798623e 100644 --- a/kernel/sysctl.c @@ -83724,6 +85034,20 @@ index d9df745..e73c2fe 100644 static inline void *ptr_to_indirect(void *ptr) { +diff --git a/lib/scatterlist.c b/lib/scatterlist.c +index 4ceb05d..2ffcb3c 100644 +--- a/lib/scatterlist.c ++++ b/lib/scatterlist.c +@@ -419,7 +419,8 @@ void sg_miter_stop(struct sg_mapping_iter *miter) + if (miter->addr) { + miter->__offset += miter->consumed; + +- if (miter->__flags & SG_MITER_TO_SG) ++ if ((miter->__flags & SG_MITER_TO_SG) && ++ !PageSlab(miter->page)) + flush_kernel_dcache_page(miter->page); + + if (miter->__flags & SG_MITER_ATOMIC) { diff --git a/lib/vsprintf.c b/lib/vsprintf.c index d74c317..1170419 100644 --- a/lib/vsprintf.c @@ -89809,7 +91133,7 @@ index f78f898..d7aa843 100644 if (__rtnl_register(PF_CAN, RTM_GETROUTE, NULL, cgw_dump_jobs, NULL)) { diff --git a/net/compat.c b/net/compat.c -index 8c979cc..2b1960c 100644 +index 8c979cc..453a165 100644 --- a/net/compat.c +++ b/net/compat.c @@ -71,9 +71,11 @@ int get_compat_msghdr(struct msghdr *kmsg, struct compat_msghdr __user *umsg) @@ -89887,7 +91211,22 @@ index 8c979cc..2b1960c 100644 int fdmax = (kmsg->msg_controllen - sizeof(struct compat_cmsghdr)) / sizeof(int); int fdnum = scm->fp->count; struct file **fp = scm->fp->fp; -@@ -370,7 +372,7 @@ static int do_set_sock_timeout(struct socket *sock, int level, +@@ -326,14 +328,6 @@ void scm_detach_fds_compat(struct msghdr *kmsg, struct scm_cookie *scm) + __scm_destroy(scm); + } + +-/* +- * A struct sock_filter is architecture independent. +- */ +-struct compat_sock_fprog { +- u16 len; +- compat_uptr_t filter; /* struct sock_filter * */ +-}; +- + static int do_set_attach_filter(struct socket *sock, int level, int optname, + char __user *optval, unsigned int optlen) + { +@@ -370,7 +364,7 @@ static int do_set_sock_timeout(struct socket *sock, int level, return -EFAULT; old_fs = get_fs(); set_fs(KERNEL_DS); @@ -89896,7 +91235,7 @@ index 8c979cc..2b1960c 100644 set_fs(old_fs); return err; -@@ -431,7 +433,7 @@ static int do_get_sock_timeout(struct socket *sock, int level, int optname, +@@ -431,7 +425,7 @@ static int do_get_sock_timeout(struct socket *sock, int level, int optname, len = sizeof(ktime); old_fs = get_fs(); set_fs(KERNEL_DS); @@ -89905,7 +91244,7 @@ index 8c979cc..2b1960c 100644 set_fs(old_fs); if (!err) { -@@ -566,7 +568,7 @@ int compat_mc_setsockopt(struct sock *sock, int level, int optname, +@@ -566,7 +560,7 @@ int compat_mc_setsockopt(struct sock *sock, int level, int optname, case MCAST_JOIN_GROUP: case MCAST_LEAVE_GROUP: { @@ -89914,7 +91253,7 @@ index 8c979cc..2b1960c 100644 struct group_req __user *kgr = compat_alloc_user_space(sizeof(struct group_req)); u32 interface; -@@ -587,7 +589,7 @@ int compat_mc_setsockopt(struct sock *sock, int level, int optname, +@@ -587,7 +581,7 @@ int compat_mc_setsockopt(struct sock *sock, int level, int optname, case MCAST_BLOCK_SOURCE: case MCAST_UNBLOCK_SOURCE: { @@ -89923,7 +91262,7 @@ index 8c979cc..2b1960c 100644 struct group_source_req __user *kgsr = compat_alloc_user_space( sizeof(struct group_source_req)); u32 interface; -@@ -608,7 +610,7 @@ int compat_mc_setsockopt(struct sock *sock, int level, int optname, +@@ -608,7 +602,7 @@ int compat_mc_setsockopt(struct sock *sock, int level, int optname, } case MCAST_MSFILTER: { @@ -89932,7 +91271,7 @@ index 8c979cc..2b1960c 100644 struct group_filter __user *kgf; u32 interface, fmode, numsrc; -@@ -646,7 +648,7 @@ int compat_mc_getsockopt(struct sock *sock, int level, int optname, +@@ -646,7 +640,7 @@ int compat_mc_getsockopt(struct sock *sock, int level, int optname, char __user *optval, int __user *optlen, int (*getsockopt)(struct sock *, int, int, char __user *, int __user *)) { @@ -89941,7 +91280,7 @@ index 8c979cc..2b1960c 100644 struct group_filter __user *kgf; int __user *koptlen; u32 interface, fmode, numsrc; -@@ -799,7 +801,7 @@ asmlinkage long compat_sys_socketcall(int call, u32 __user *args) +@@ -799,7 +793,7 @@ asmlinkage long compat_sys_socketcall(int call, u32 __user *args) if (call < SYS_SOCKET || call > SYS_SENDMMSG) return -EINVAL; @@ -90150,6 +91489,30 @@ index 2367246..4a0a677 100644 if (copy_to_user(useraddr, &dump, sizeof(dump))) { ret = -EFAULT; goto out; +diff --git a/net/core/filter.c b/net/core/filter.c +index 5dea452..d775edc 100644 +--- a/net/core/filter.c ++++ b/net/core/filter.c +@@ -39,6 +39,7 @@ + #include <linux/filter.h> + #include <linux/reciprocal_div.h> + #include <linux/ratelimit.h> ++#include <linux/seccomp.h> + + /* No hurry in this branch */ + static void *__load_pointer(const struct sk_buff *skb, int k, unsigned int size) +@@ -350,6 +351,11 @@ load_b: + A = 0; + continue; + } ++#ifdef CONFIG_SECCOMP_FILTER ++ case BPF_S_ANC_SECCOMP_LD_W: ++ A = seccomp_bpf_load(fentry->k); ++ continue; ++#endif + default: + WARN_RATELIMIT(1, "Unknown code:%u jt:%u tf:%u k:%u\n", + fentry->code, fentry->jt, diff --git a/net/core/flow.c b/net/core/flow.c index e318c7e..168b1d0 100644 --- a/net/core/flow.c @@ -98042,6 +99405,73 @@ index 69ddb47..be0f0f9 100644 error = aafs_create(".load", 0640, &aa_fs_profile_load); if (error) goto error; +diff --git a/security/apparmor/domain.c b/security/apparmor/domain.c +index c1e18ba..7316d77 100644 +--- a/security/apparmor/domain.c ++++ b/security/apparmor/domain.c +@@ -395,6 +395,11 @@ int apparmor_bprm_set_creds(struct linux_binprm *bprm) + new_profile = find_attach(ns, &ns->base.profiles, name); + if (!new_profile) + goto cleanup; ++ /* ++ * NOTE: Domain transitions from unconfined are allowed ++ * even when no_new_privs is set because this aways results ++ * in a further reduction of permissions. ++ */ + goto apply; + } + +@@ -455,6 +460,16 @@ int apparmor_bprm_set_creds(struct linux_binprm *bprm) + /* fail exec */ + error = -EACCES; + ++ /* ++ * Policy has specified a domain transition, if no_new_privs then ++ * fail the exec. ++ */ ++ if (bprm->unsafe & LSM_UNSAFE_NO_NEW_PRIVS) { ++ aa_put_profile(new_profile); ++ error = -EPERM; ++ goto cleanup; ++ } ++ + if (!new_profile) + goto audit; + +@@ -609,6 +624,14 @@ int aa_change_hat(const char *hats[], int count, u64 token, bool permtest) + const char *target = NULL, *info = NULL; + int error = 0; + ++ /* ++ * Fail explicitly requested domain transitions if no_new_privs. ++ * There is no exception for unconfined as change_hat is not ++ * available. ++ */ ++ if (current->no_new_privs) ++ return -EPERM; ++ + /* released below */ + cred = get_current_cred(); + cxt = cred->security; +@@ -750,6 +773,18 @@ int aa_change_profile(const char *ns_name, const char *hname, bool onexec, + cxt = cred->security; + profile = aa_cred_profile(cred); + ++ /* ++ * Fail explicitly requested domain transitions if no_new_privs ++ * and not unconfined. ++ * Domain transitions from unconfined are allowed even when ++ * no_new_privs is set because this aways results in a reduction ++ * of permissions. ++ */ ++ if (current->no_new_privs && !unconfined(profile)) { ++ put_cred(cred); ++ return -EPERM; ++ } ++ + if (ns_name) { + /* released below */ + ns = aa_find_namespace(profile->ns, ns_name); diff --git a/security/apparmor/include/apparmorfs.h b/security/apparmor/include/apparmorfs.h index cb1e93a..14f955c 100644 --- a/security/apparmor/include/apparmorfs.h @@ -98574,7 +100004,7 @@ index 741dd13..ee8043e 100644 profile->file.dfa = unpack_dfa(e); if (IS_ERR(profile->file.dfa)) { diff --git a/security/commoncap.c b/security/commoncap.c -index 12440ee..e16cba1 100644 +index 12440ee..2ec6d88 100644 --- a/security/commoncap.c +++ b/security/commoncap.c @@ -29,6 +29,7 @@ @@ -98640,7 +100070,27 @@ index 12440ee..e16cba1 100644 /* * Attempt to get the on-exec apply capability sets for an executable file from * its xattrs and, if present, apply them to the proposed credentials being -@@ -585,6 +625,9 @@ int cap_bprm_secureexec(struct linux_binprm *bprm) +@@ -521,14 +561,17 @@ skip: + + + /* Don't let someone trace a set[ug]id/setpcap binary with the revised +- * credentials unless they have the appropriate permit ++ * credentials unless they have the appropriate permit. ++ * ++ * In addition, if NO_NEW_PRIVS, then ensure we get no new privs. + */ + if ((new->euid != old->uid || + new->egid != old->gid || + !cap_issubset(new->cap_permitted, old->cap_permitted)) && + bprm->unsafe & ~LSM_UNSAFE_PTRACE_CAP) { + /* downgrade; they get no more than they had, and maybe less */ +- if (!capable(CAP_SETUID)) { ++ if (!capable(CAP_SETUID) || ++ (bprm->unsafe & LSM_UNSAFE_NO_NEW_PRIVS)) { + new->euid = new->uid; + new->egid = new->gid; + } +@@ -585,6 +628,9 @@ int cap_bprm_secureexec(struct linux_binprm *bprm) { const struct cred *cred = current_cred(); @@ -98981,7 +100431,7 @@ index dca1c22..4fa4591 100644 lock = &avc_cache.slots_lock[hvalue]; diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c -index 1126c10..3684fc7 100644 +index 1126c10..e2dad6b 100644 --- a/security/selinux/hooks.c +++ b/security/selinux/hooks.c @@ -94,8 +94,6 @@ @@ -98993,7 +100443,31 @@ index 1126c10..3684fc7 100644 /* SECMARK reference count */ static atomic_t selinux_secmark_refcount = ATOMIC_INIT(0); -@@ -5449,7 +5447,7 @@ static int selinux_key_getsecurity(struct key *key, char **_buffer) +@@ -2000,6 +1998,13 @@ static int selinux_bprm_set_creds(struct linux_binprm *bprm) + new_tsec->sid = old_tsec->exec_sid; + /* Reset exec SID on execve. */ + new_tsec->exec_sid = 0; ++ ++ /* ++ * Minimize confusion: if no_new_privs and a transition is ++ * explicitly requested, then fail the exec. ++ */ ++ if (bprm->unsafe & LSM_UNSAFE_NO_NEW_PRIVS) ++ return -EPERM; + } else { + /* Check for a default transition on this program. */ + rc = security_transition_sid(old_tsec->sid, isec->sid, +@@ -2012,7 +2017,8 @@ static int selinux_bprm_set_creds(struct linux_binprm *bprm) + COMMON_AUDIT_DATA_INIT(&ad, PATH); + ad.u.path = bprm->file->f_path; + +- if (bprm->file->f_path.mnt->mnt_flags & MNT_NOSUID) ++ if ((bprm->file->f_path.mnt->mnt_flags & MNT_NOSUID) || ++ (bprm->unsafe & LSM_UNSAFE_NO_NEW_PRIVS)) + new_tsec->sid = old_tsec->sid; + + if (new_tsec->sid == old_tsec->sid) { +@@ -5449,7 +5455,7 @@ static int selinux_key_getsecurity(struct key *key, char **_buffer) #endif @@ -99002,7 +100476,7 @@ index 1126c10..3684fc7 100644 .name = "selinux", .ptrace_access_check = selinux_ptrace_access_check, -@@ -5795,6 +5793,9 @@ static void selinux_nf_ip_exit(void) +@@ -5795,6 +5801,9 @@ static void selinux_nf_ip_exit(void) #ifdef CONFIG_SECURITY_SELINUX_DISABLE static int selinux_disabled; @@ -99012,7 +100486,7 @@ index 1126c10..3684fc7 100644 int selinux_disable(void) { if (ss_initialized) { -@@ -5812,7 +5813,9 @@ int selinux_disable(void) +@@ -5812,7 +5821,9 @@ int selinux_disable(void) selinux_disabled = 1; selinux_enabled = 0; |