diff options
author | Yann Droneaud <ydroneaud@opteya.com> | 2014-01-05 15:36:33 -0500 |
---|---|---|
committer | Ingo Molnar <mingo@kernel.org> | 2014-01-12 04:16:59 -0500 |
commit | a21b0b354d4ac39be691f51c53562e2c24443d9e (patch) | |
tree | 2625e7436b90c91966c5797f2fae3a980694d8c7 /kernel | |
parent | f228c5b882602697a1adb50d61ff688b0df1eced (diff) |
perf: Introduce a flag to enable close-on-exec in perf_event_open()
Unlike recent modern userspace API such as:
epoll_create1 (EPOLL_CLOEXEC), eventfd (EFD_CLOEXEC),
fanotify_init (FAN_CLOEXEC), inotify_init1 (IN_CLOEXEC),
signalfd (SFD_CLOEXEC), timerfd_create (TFD_CLOEXEC),
or the venerable general purpose open (O_CLOEXEC),
perf_event_open() syscall lack a flag to atomically set FD_CLOEXEC
(eg. close-on-exec) flag on file descriptor it returns to userspace.
The present patch adds a PERF_FLAG_FD_CLOEXEC flag to allow
perf_event_open() syscall to atomically set close-on-exec.
Having this flag will enable userspace to remove the file descriptor
from the list of file descriptors being inherited across exec,
without the need to call fcntl(fd, F_SETFD, FD_CLOEXEC) and the
associated race condition between the current thread and another
thread calling fork(2) then execve(2).
Links:
- Secure File Descriptor Handling (Ulrich Drepper, 2008)
http://udrepper.livejournal.com/20407.html
- Excuse me son, but your code is leaking !!! (Dan Walsh, March 2012)
http://danwalsh.livejournal.com/53603.html
- Notes in DMA buffer sharing: leak and security hole
http://git.kernel.org/cgit/linux/kernel/git/torvalds/linux.git/tree/Documentation/dma-buf-sharing.txt?id=v3.13-rc3#n428
Signed-off-by: Yann Droneaud <ydroneaud@opteya.com>
Cc: Arnaldo Carvalho de Melo <acme@ghostprotocols.net>
Cc: Al Viro <viro@zeniv.linux.org.uk>
Cc: Andrew Morton <akpm@linux-foundation.org>
Cc: Paul Mackerras <paulus@samba.org>
Cc: Linus Torvalds <torvalds@linux-foundation.org>
Signed-off-by: Peter Zijlstra <peterz@infradead.org>
Link: http://lkml.kernel.org/r/8c03f54e1598b1727c19706f3af03f98685d9fe6.1388952061.git.ydroneaud@opteya.com
Signed-off-by: Ingo Molnar <mingo@kernel.org>
Diffstat (limited to 'kernel')
-rw-r--r-- | kernel/events/core.c | 12 |
1 files changed, 9 insertions, 3 deletions
diff --git a/kernel/events/core.c b/kernel/events/core.c index c3b6c2799f34..5c8726473006 100644 --- a/kernel/events/core.c +++ b/kernel/events/core.c | |||
@@ -119,7 +119,8 @@ static int cpu_function_call(int cpu, int (*func) (void *info), void *info) | |||
119 | 119 | ||
120 | #define PERF_FLAG_ALL (PERF_FLAG_FD_NO_GROUP |\ | 120 | #define PERF_FLAG_ALL (PERF_FLAG_FD_NO_GROUP |\ |
121 | PERF_FLAG_FD_OUTPUT |\ | 121 | PERF_FLAG_FD_OUTPUT |\ |
122 | PERF_FLAG_PID_CGROUP) | 122 | PERF_FLAG_PID_CGROUP |\ |
123 | PERF_FLAG_FD_CLOEXEC) | ||
123 | 124 | ||
124 | /* | 125 | /* |
125 | * branch priv levels that need permission checks | 126 | * branch priv levels that need permission checks |
@@ -6982,6 +6983,7 @@ SYSCALL_DEFINE5(perf_event_open, | |||
6982 | int event_fd; | 6983 | int event_fd; |
6983 | int move_group = 0; | 6984 | int move_group = 0; |
6984 | int err; | 6985 | int err; |
6986 | int f_flags = O_RDWR; | ||
6985 | 6987 | ||
6986 | /* for future expandability... */ | 6988 | /* for future expandability... */ |
6987 | if (flags & ~PERF_FLAG_ALL) | 6989 | if (flags & ~PERF_FLAG_ALL) |
@@ -7010,7 +7012,10 @@ SYSCALL_DEFINE5(perf_event_open, | |||
7010 | if ((flags & PERF_FLAG_PID_CGROUP) && (pid == -1 || cpu == -1)) | 7012 | if ((flags & PERF_FLAG_PID_CGROUP) && (pid == -1 || cpu == -1)) |
7011 | return -EINVAL; | 7013 | return -EINVAL; |
7012 | 7014 | ||
7013 | event_fd = get_unused_fd(); | 7015 | if (flags & PERF_FLAG_FD_CLOEXEC) |
7016 | f_flags |= O_CLOEXEC; | ||
7017 | |||
7018 | event_fd = get_unused_fd_flags(f_flags); | ||
7014 | if (event_fd < 0) | 7019 | if (event_fd < 0) |
7015 | return event_fd; | 7020 | return event_fd; |
7016 | 7021 | ||
@@ -7132,7 +7137,8 @@ SYSCALL_DEFINE5(perf_event_open, | |||
7132 | goto err_context; | 7137 | goto err_context; |
7133 | } | 7138 | } |
7134 | 7139 | ||
7135 | event_file = anon_inode_getfile("[perf_event]", &perf_fops, event, O_RDWR); | 7140 | event_file = anon_inode_getfile("[perf_event]", &perf_fops, event, |
7141 | f_flags); | ||
7136 | if (IS_ERR(event_file)) { | 7142 | if (IS_ERR(event_file)) { |
7137 | err = PTR_ERR(event_file); | 7143 | err = PTR_ERR(event_file); |
7138 | goto err_context; | 7144 | goto err_context; |