diff options
author | Kevin Hilman <khilman@linaro.org> | 2015-10-13 16:29:43 -0700 |
---|---|---|
committer | Kevin Hilman <khilman@linaro.org> | 2015-10-13 16:29:43 -0700 |
commit | 974070b95b0c8ff6ef0d62109c16aea160cf3c7c (patch) | |
tree | 71da351fb8feb8698f2295e4a4a7def9a4623a81 /fs/coredump.c | |
parent | 4d869de174c78ae29ca91b41581367c8092d933d (diff) | |
parent | f5552cd830e58c46dffae3617b3ce0c839771981 (diff) |
Merge branch 'linux-3.10.y' of git://git.kernel.org/pub/scm/linux/kernel/git/stable/linux-stable into linux-linaro-lsk-v3.10lsk-v3.10-15.10
* 'linux-3.10.y' of git://git.kernel.org/pub/scm/linux/kernel/git/stable/linux-stable: (77 commits)
Linux 3.10.90
Revert "iio: bmg160: IIO_BUFFER and IIO_TRIGGERED_BUFFER are required"
vfs: Remove incorrect debugging WARN in prepend_path
fib_rules: fix fib rule dumps across multiple skbs
sctp: fix race on protocol/netns initialization
net/ipv6: Correct PIM6 mrt_lock handling
ipv6: fix exthdrs offload registration in out_rt path
usbnet: Get EVENT_NO_RUNTIME_PM bit before it is cleared
ip6_gre: release cached dst on tunnel removal
rds: fix an integer overflow test in rds_info_getsockopt()
netlink: don't hold mutex in rcu callback when releasing mmapd ring
inet: frags: fix defragmented packet's IP header for af_packet
bonding: fix destruction of bond with devices different from arphrd_ether
ipv6: lock socket in ip6_datagram_connect()
isdn/gigaset: reset tty->receive_room when attaching ser_gigaset
bridge: mdb: fix double add notification
net: Fix skb_set_peeked use-after-free bug
net: Fix skb csum races when peeking
net: Clone skb before setting peeked flag
net: call rcu_read_lock early in process_backlog
...
Diffstat (limited to 'fs/coredump.c')
-rw-r--r-- | fs/coredump.c | 38 |
1 files changed, 32 insertions, 6 deletions
diff --git a/fs/coredump.c b/fs/coredump.c index 1d402ce5b72f..4f03b2b50375 100644 --- a/fs/coredump.c +++ b/fs/coredump.c @@ -491,10 +491,10 @@ void do_coredump(siginfo_t *siginfo) const struct cred *old_cred; struct cred *cred; int retval = 0; - int flag = 0; int ispipe; struct files_struct *displaced; - bool need_nonrelative = false; + /* require nonrelative corefile path and be extra careful */ + bool need_suid_safe = false; bool core_dumped = false; static atomic_t core_dump_count = ATOMIC_INIT(0); struct coredump_params cprm = { @@ -528,9 +528,8 @@ void do_coredump(siginfo_t *siginfo) */ if (__get_dumpable(cprm.mm_flags) == SUID_DUMP_ROOT) { /* Setuid core dump mode */ - flag = O_EXCL; /* Stop rewrite attacks */ cred->fsuid = GLOBAL_ROOT_UID; /* Dump root private */ - need_nonrelative = true; + need_suid_safe = true; } retval = coredump_wait(siginfo->si_signo, &core_state); @@ -611,7 +610,7 @@ void do_coredump(siginfo_t *siginfo) if (cprm.limit < binfmt->min_coredump) goto fail_unlock; - if (need_nonrelative && cn.corename[0] != '/') { + if (need_suid_safe && cn.corename[0] != '/') { printk(KERN_WARNING "Pid %d(%s) can only dump core "\ "to fully qualified path!\n", task_tgid_vnr(current), current->comm); @@ -619,8 +618,35 @@ void do_coredump(siginfo_t *siginfo) goto fail_unlock; } + /* + * Unlink the file if it exists unless this is a SUID + * binary - in that case, we're running around with root + * privs and don't want to unlink another user's coredump. + */ + if (!need_suid_safe) { + mm_segment_t old_fs; + + old_fs = get_fs(); + set_fs(KERNEL_DS); + /* + * If it doesn't exist, that's fine. If there's some + * other problem, we'll catch it at the filp_open(). + */ + (void) sys_unlink((const char __user *)cn.corename); + set_fs(old_fs); + } + + /* + * There is a race between unlinking and creating the + * file, but if that causes an EEXIST here, that's + * fine - another process raced with us while creating + * the corefile, and the other process won. To userspace, + * what matters is that at least one of the two processes + * writes its coredump successfully, not which one. + */ cprm.file = filp_open(cn.corename, - O_CREAT | 2 | O_NOFOLLOW | O_LARGEFILE | flag, + O_CREAT | 2 | O_NOFOLLOW | + O_LARGEFILE | O_EXCL, 0600); if (IS_ERR(cprm.file)) goto fail_unlock; |