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 | |
| 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>
| -rw-r--r-- | include/uapi/linux/perf_event.h | 1 | ||||
| -rw-r--r-- | kernel/events/core.c | 12 |
2 files changed, 10 insertions, 3 deletions
diff --git a/include/uapi/linux/perf_event.h b/include/uapi/linux/perf_event.h index e1802d6153ae..ca018b4085c6 100644 --- a/include/uapi/linux/perf_event.h +++ b/include/uapi/linux/perf_event.h | |||
| @@ -724,6 +724,7 @@ enum perf_callchain_context { | |||
| 724 | #define PERF_FLAG_FD_NO_GROUP (1U << 0) | 724 | #define PERF_FLAG_FD_NO_GROUP (1U << 0) |
| 725 | #define PERF_FLAG_FD_OUTPUT (1U << 1) | 725 | #define PERF_FLAG_FD_OUTPUT (1U << 1) |
| 726 | #define PERF_FLAG_PID_CGROUP (1U << 2) /* pid=cgroup id, per-cpu mode only */ | 726 | #define PERF_FLAG_PID_CGROUP (1U << 2) /* pid=cgroup id, per-cpu mode only */ |
| 727 | #define PERF_FLAG_FD_CLOEXEC (1U << 3) /* O_CLOEXEC */ | ||
| 727 | 728 | ||
| 728 | union perf_mem_data_src { | 729 | union perf_mem_data_src { |
| 729 | __u64 val; | 730 | __u64 val; |
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; |
