Blame view
fs/signalfd.c
9 KB
b24413180 License cleanup: ... |
1 |
// SPDX-License-Identifier: GPL-2.0 |
fba2afaae signal/timer/even... |
2 3 4 5 6 7 8 9 10 11 12 13 14 |
/* * fs/signalfd.c * * Copyright (C) 2003 Linus Torvalds * * Mon Mar 5, 2007: Davide Libenzi <davidel@xmailserver.org> * Changed ->read() to return a siginfo strcture instead of signal number. * Fixed locking in ->poll(). * Added sighand-detach notification. * Added fd re-use in sys_signalfd() syscall. * Now using anonymous inode source. * Thanks to Oleg Nesterov for useful code review and suggestions. * More comments and suggestions from Arnd Bergmann. |
b8fceee17 signalfd simplifi... |
15 |
* Sat May 19, 2007: Davi E. M. Arnaut <davi@haxent.com.br> |
b3762bfc8 signalfd: retriev... |
16 |
* Retrieve multiple signals with one read() call |
b8fceee17 signalfd simplifi... |
17 18 |
* Sun Jul 15, 2007: Davide Libenzi <davidel@xmailserver.org> * Attach to the sighand only during read() and poll(). |
fba2afaae signal/timer/even... |
19 20 21 22 23 24 25 |
*/ #include <linux/file.h> #include <linux/poll.h> #include <linux/init.h> #include <linux/fs.h> #include <linux/sched.h> |
5a0e3ad6a include cleanup: ... |
26 |
#include <linux/slab.h> |
fba2afaae signal/timer/even... |
27 28 29 30 31 |
#include <linux/kernel.h> #include <linux/signal.h> #include <linux/list.h> #include <linux/anon_inodes.h> #include <linux/signalfd.h> |
7ec37dfd4 fs/signalfd.c sho... |
32 |
#include <linux/syscalls.h> |
138d22b58 fs, epoll: add pr... |
33 |
#include <linux/proc_fs.h> |
7d197ed4a switch signalfd{,... |
34 |
#include <linux/compat.h> |
fba2afaae signal/timer/even... |
35 |
|
d80e731ec epoll: introduce ... |
36 37 38 |
void signalfd_cleanup(struct sighand_struct *sighand) { wait_queue_head_t *wqh = &sighand->signalfd_wqh; |
971316f05 epoll: ep_unregis... |
39 40 41 |
/* * The lockless check can race with remove_wait_queue() in progress, * but in this case its caller should run under rcu_read_lock() and |
5f0d5a3ae mm: Rename SLAB_D... |
42 |
* sighand_cachep is SLAB_TYPESAFE_BY_RCU, we can safely return. |
971316f05 epoll: ep_unregis... |
43 |
*/ |
d80e731ec epoll: introduce ... |
44 45 |
if (likely(!waitqueue_active(wqh))) return; |
ac6424b98 sched/wait: Renam... |
46 |
/* wait_queue_entry_t->func(POLLFREE) should do remove_wait_queue() */ |
a9a08845e vfs: do bulk POLL... |
47 |
wake_up_poll(wqh, EPOLLHUP | POLLFREE); |
d80e731ec epoll: introduce ... |
48 |
} |
fba2afaae signal/timer/even... |
49 |
struct signalfd_ctx { |
fba2afaae signal/timer/even... |
50 |
sigset_t sigmask; |
fba2afaae signal/timer/even... |
51 |
}; |
fba2afaae signal/timer/even... |
52 53 |
static int signalfd_release(struct inode *inode, struct file *file) { |
b8fceee17 signalfd simplifi... |
54 |
kfree(file->private_data); |
fba2afaae signal/timer/even... |
55 56 |
return 0; } |
076ccb76e fs: annotate ->po... |
57 |
static __poll_t signalfd_poll(struct file *file, poll_table *wait) |
fba2afaae signal/timer/even... |
58 59 |
{ struct signalfd_ctx *ctx = file->private_data; |
076ccb76e fs: annotate ->po... |
60 |
__poll_t events = 0; |
fba2afaae signal/timer/even... |
61 |
|
b8fceee17 signalfd simplifi... |
62 |
poll_wait(file, ¤t->sighand->signalfd_wqh, wait); |
fba2afaae signal/timer/even... |
63 |
|
b8fceee17 signalfd simplifi... |
64 65 66 67 |
spin_lock_irq(¤t->sighand->siglock); if (next_signal(¤t->pending, &ctx->sigmask) || next_signal(¤t->signal->shared_pending, &ctx->sigmask)) |
a9a08845e vfs: do bulk POLL... |
68 |
events |= EPOLLIN; |
b8fceee17 signalfd simplifi... |
69 |
spin_unlock_irq(¤t->sighand->siglock); |
fba2afaae signal/timer/even... |
70 71 72 73 74 75 76 77 |
return events; } /* * Copied from copy_siginfo_to_user() in kernel/signal.c */ static int signalfd_copyinfo(struct signalfd_siginfo __user *uinfo, |
ae7795bc6 signal: Distingui... |
78 |
kernel_siginfo_t const *kinfo) |
fba2afaae signal/timer/even... |
79 |
{ |
5611f55ee signal/signalfd: ... |
80 |
struct signalfd_siginfo new; |
fba2afaae signal/timer/even... |
81 82 83 84 |
BUILD_BUG_ON(sizeof(struct signalfd_siginfo) != 128); /* |
14e4a0f2b Fix a small numbe... |
85 |
* Unused members should be zero ... |
fba2afaae signal/timer/even... |
86 |
*/ |
5611f55ee signal/signalfd: ... |
87 |
memset(&new, 0, sizeof(new)); |
fba2afaae signal/timer/even... |
88 89 90 91 92 |
/* * If you change siginfo_t structure, please be sure * this code is fixed accordingly. */ |
5611f55ee signal/signalfd: ... |
93 94 95 |
new.ssi_signo = kinfo->si_signo; new.ssi_errno = kinfo->si_errno; new.ssi_code = kinfo->si_code; |
cc731525f signal: Remove ke... |
96 97 |
switch (siginfo_layout(kinfo->si_signo, kinfo->si_code)) { case SIL_KILL: |
5611f55ee signal/signalfd: ... |
98 99 |
new.ssi_pid = kinfo->si_pid; new.ssi_uid = kinfo->si_uid; |
fba2afaae signal/timer/even... |
100 |
break; |
cc731525f signal: Remove ke... |
101 |
case SIL_TIMER: |
5611f55ee signal/signalfd: ... |
102 103 104 105 |
new.ssi_tid = kinfo->si_tid; new.ssi_overrun = kinfo->si_overrun; new.ssi_ptr = (long) kinfo->si_ptr; new.ssi_int = kinfo->si_int; |
fba2afaae signal/timer/even... |
106 |
break; |
cc731525f signal: Remove ke... |
107 |
case SIL_POLL: |
5611f55ee signal/signalfd: ... |
108 109 |
new.ssi_band = kinfo->si_band; new.ssi_fd = kinfo->si_fd; |
fba2afaae signal/timer/even... |
110 |
break; |
31931c93d signal: Extend si... |
111 112 113 114 115 116 117 118 119 |
case SIL_FAULT_BNDERR: case SIL_FAULT_PKUERR: /* * Fall through to the SIL_FAULT case. Both SIL_FAULT_BNDERR * and SIL_FAULT_PKUERR are only generated by faults that * deliver them synchronously to userspace. In case someone * injects one of these signals and signalfd catches it treat * it as SIL_FAULT. */ |
cc731525f signal: Remove ke... |
120 |
case SIL_FAULT: |
5611f55ee signal/signalfd: ... |
121 |
new.ssi_addr = (long) kinfo->si_addr; |
fba2afaae signal/timer/even... |
122 |
#ifdef __ARCH_SI_TRAPNO |
5611f55ee signal/signalfd: ... |
123 |
new.ssi_trapno = kinfo->si_trapno; |
fba2afaae signal/timer/even... |
124 |
#endif |
31931c93d signal: Extend si... |
125 126 127 128 129 130 131 |
break; case SIL_FAULT_MCEERR: new.ssi_addr = (long) kinfo->si_addr; #ifdef __ARCH_SI_TRAPNO new.ssi_trapno = kinfo->si_trapno; #endif new.ssi_addr_lsb = (short) kinfo->si_addr_lsb; |
fba2afaae signal/timer/even... |
132 |
break; |
cc731525f signal: Remove ke... |
133 |
case SIL_CHLD: |
5611f55ee signal/signalfd: ... |
134 135 136 137 138 |
new.ssi_pid = kinfo->si_pid; new.ssi_uid = kinfo->si_uid; new.ssi_status = kinfo->si_status; new.ssi_utime = kinfo->si_utime; new.ssi_stime = kinfo->si_stime; |
fba2afaae signal/timer/even... |
139 |
break; |
cc731525f signal: Remove ke... |
140 |
case SIL_RT: |
0859ab59a signalfd: fix for... |
141 142 143 |
/* * This case catches also the signals queued by sigqueue(). */ |
5611f55ee signal/signalfd: ... |
144 145 146 147 |
new.ssi_pid = kinfo->si_pid; new.ssi_uid = kinfo->si_uid; new.ssi_ptr = (long) kinfo->si_ptr; new.ssi_int = kinfo->si_int; |
fba2afaae signal/timer/even... |
148 |
break; |
76b7f6707 signal/signalfd: ... |
149 150 151 152 153 |
case SIL_SYS: new.ssi_call_addr = (long) kinfo->si_call_addr; new.ssi_syscall = kinfo->si_syscall; new.ssi_arch = kinfo->si_arch; break; |
fba2afaae signal/timer/even... |
154 |
} |
5611f55ee signal/signalfd: ... |
155 156 157 158 |
if (copy_to_user(uinfo, &new, sizeof(struct signalfd_siginfo))) return -EFAULT; return sizeof(*uinfo); |
fba2afaae signal/timer/even... |
159 |
} |
ae7795bc6 signal: Distingui... |
160 |
static ssize_t signalfd_dequeue(struct signalfd_ctx *ctx, kernel_siginfo_t *info, |
b3762bfc8 signalfd: retriev... |
161 162 163 |
int nonblock) { ssize_t ret; |
b3762bfc8 signalfd: retriev... |
164 |
DECLARE_WAITQUEUE(wait, current); |
b8fceee17 signalfd simplifi... |
165 166 |
spin_lock_irq(¤t->sighand->siglock); ret = dequeue_signal(current, &ctx->sigmask, info); |
b3762bfc8 signalfd: retriev... |
167 168 169 170 171 |
switch (ret) { case 0: if (!nonblock) break; ret = -EAGAIN; |
0a4c92657 fs: mark expected... |
172 |
/* fall through */ |
b3762bfc8 signalfd: retriev... |
173 |
default: |
b8fceee17 signalfd simplifi... |
174 |
spin_unlock_irq(¤t->sighand->siglock); |
b3762bfc8 signalfd: retriev... |
175 176 |
return ret; } |
b8fceee17 signalfd simplifi... |
177 |
add_wait_queue(¤t->sighand->signalfd_wqh, &wait); |
b3762bfc8 signalfd: retriev... |
178 179 |
for (;;) { set_current_state(TASK_INTERRUPTIBLE); |
b8fceee17 signalfd simplifi... |
180 |
ret = dequeue_signal(current, &ctx->sigmask, info); |
b3762bfc8 signalfd: retriev... |
181 182 183 184 185 186 |
if (ret != 0) break; if (signal_pending(current)) { ret = -ERESTARTSYS; break; } |
b8fceee17 signalfd simplifi... |
187 |
spin_unlock_irq(¤t->sighand->siglock); |
b3762bfc8 signalfd: retriev... |
188 |
schedule(); |
b8fceee17 signalfd simplifi... |
189 |
spin_lock_irq(¤t->sighand->siglock); |
b3762bfc8 signalfd: retriev... |
190 |
} |
b8fceee17 signalfd simplifi... |
191 |
spin_unlock_irq(¤t->sighand->siglock); |
b3762bfc8 signalfd: retriev... |
192 |
|
b8fceee17 signalfd simplifi... |
193 |
remove_wait_queue(¤t->sighand->signalfd_wqh, &wait); |
b3762bfc8 signalfd: retriev... |
194 195 196 197 |
__set_current_state(TASK_RUNNING); return ret; } |
fba2afaae signal/timer/even... |
198 |
/* |
b8fceee17 signalfd simplifi... |
199 200 201 |
* Returns a multiple of the size of a "struct signalfd_siginfo", or a negative * error code. The "count" parameter must be at least the size of a * "struct signalfd_siginfo". |
fba2afaae signal/timer/even... |
202 203 204 205 206 |
*/ static ssize_t signalfd_read(struct file *file, char __user *buf, size_t count, loff_t *ppos) { struct signalfd_ctx *ctx = file->private_data; |
b3762bfc8 signalfd: retriev... |
207 208 209 |
struct signalfd_siginfo __user *siginfo; int nonblock = file->f_flags & O_NONBLOCK; ssize_t ret, total = 0; |
ae7795bc6 signal: Distingui... |
210 |
kernel_siginfo_t info; |
fba2afaae signal/timer/even... |
211 |
|
b3762bfc8 signalfd: retriev... |
212 213 |
count /= sizeof(struct signalfd_siginfo); if (!count) |
fba2afaae signal/timer/even... |
214 |
return -EINVAL; |
fba2afaae signal/timer/even... |
215 |
|
b3762bfc8 signalfd: retriev... |
216 |
siginfo = (struct signalfd_siginfo __user *) buf; |
b3762bfc8 signalfd: retriev... |
217 218 219 220 221 222 223 224 225 226 227 |
do { ret = signalfd_dequeue(ctx, &info, nonblock); if (unlikely(ret <= 0)) break; ret = signalfd_copyinfo(siginfo, &info); if (ret < 0) break; siginfo++; total += ret; nonblock = 1; } while (--count); |
b8fceee17 signalfd simplifi... |
228 |
return total ? total: ret; |
fba2afaae signal/timer/even... |
229 |
} |
138d22b58 fs, epoll: add pr... |
230 |
#ifdef CONFIG_PROC_FS |
a3816ab0e fs: Convert show_... |
231 |
static void signalfd_show_fdinfo(struct seq_file *m, struct file *f) |
138d22b58 fs, epoll: add pr... |
232 233 234 235 236 237 238 |
{ struct signalfd_ctx *ctx = f->private_data; sigset_t sigmask; sigmask = ctx->sigmask; signotset(&sigmask); render_sigset_t(m, "sigmask:\t", &sigmask); |
138d22b58 fs, epoll: add pr... |
239 240 |
} #endif |
fba2afaae signal/timer/even... |
241 |
static const struct file_operations signalfd_fops = { |
138d22b58 fs, epoll: add pr... |
242 243 244 |
#ifdef CONFIG_PROC_FS .show_fdinfo = signalfd_show_fdinfo, #endif |
fba2afaae signal/timer/even... |
245 246 247 |
.release = signalfd_release, .poll = signalfd_poll, .read = signalfd_read, |
6038f373a llseek: automatic... |
248 |
.llseek = noop_llseek, |
fba2afaae signal/timer/even... |
249 |
}; |
5ed0127fc signalfd: lift si... |
250 |
static int do_signalfd4(int ufd, sigset_t *mask, int flags) |
fba2afaae signal/timer/even... |
251 |
{ |
fba2afaae signal/timer/even... |
252 |
struct signalfd_ctx *ctx; |
fba2afaae signal/timer/even... |
253 |
|
e38b36f32 flag parameters: ... |
254 255 256 |
/* Check the SFD_* constants for consistency. */ BUILD_BUG_ON(SFD_CLOEXEC != O_CLOEXEC); BUILD_BUG_ON(SFD_NONBLOCK != O_NONBLOCK); |
5fb5e0492 flag parameters: ... |
257 |
if (flags & ~(SFD_CLOEXEC | SFD_NONBLOCK)) |
9deb27bae flag parameters: ... |
258 |
return -EINVAL; |
5ed0127fc signalfd: lift si... |
259 260 |
sigdelsetmask(mask, sigmask(SIGKILL) | sigmask(SIGSTOP)); signotset(mask); |
fba2afaae signal/timer/even... |
261 262 263 264 265 |
if (ufd == -1) { ctx = kmalloc(sizeof(*ctx), GFP_KERNEL); if (!ctx) return -ENOMEM; |
5ed0127fc signalfd: lift si... |
266 |
ctx->sigmask = *mask; |
fba2afaae signal/timer/even... |
267 268 269 270 271 |
/* * When we call this, the initialization must be complete, since * anon_inode_getfd() will install the fd. */ |
7d9dbca34 flag parameters: ... |
272 |
ufd = anon_inode_getfd("[signalfd]", &signalfd_fops, ctx, |
628ff7c1d anonfd: Allow mak... |
273 |
O_RDWR | (flags & (O_CLOEXEC | O_NONBLOCK))); |
2030a42ce [PATCH] sanitize ... |
274 275 |
if (ufd < 0) kfree(ctx); |
fba2afaae signal/timer/even... |
276 |
} else { |
2903ff019 switch simple cas... |
277 278 |
struct fd f = fdget(ufd); if (!f.file) |
fba2afaae signal/timer/even... |
279 |
return -EBADF; |
2903ff019 switch simple cas... |
280 281 282 |
ctx = f.file->private_data; if (f.file->f_op != &signalfd_fops) { fdput(f); |
fba2afaae signal/timer/even... |
283 284 |
return -EINVAL; } |
b8fceee17 signalfd simplifi... |
285 |
spin_lock_irq(¤t->sighand->siglock); |
5ed0127fc signalfd: lift si... |
286 |
ctx->sigmask = *mask; |
b8fceee17 signalfd simplifi... |
287 288 289 |
spin_unlock_irq(¤t->sighand->siglock); wake_up(¤t->sighand->signalfd_wqh); |
2903ff019 switch simple cas... |
290 |
fdput(f); |
fba2afaae signal/timer/even... |
291 292 293 |
} return ufd; |
fba2afaae signal/timer/even... |
294 |
} |
9deb27bae flag parameters: ... |
295 |
|
52fb6db0f fs: add do_signal... |
296 297 298 |
SYSCALL_DEFINE4(signalfd4, int, ufd, sigset_t __user *, user_mask, size_t, sizemask, int, flags) { |
5ed0127fc signalfd: lift si... |
299 300 301 302 303 304 |
sigset_t mask; if (sizemask != sizeof(sigset_t) || copy_from_user(&mask, user_mask, sizeof(mask))) return -EINVAL; return do_signalfd4(ufd, &mask, flags); |
52fb6db0f fs: add do_signal... |
305 |
} |
836f92adf [CVE-2009-0029] S... |
306 307 |
SYSCALL_DEFINE3(signalfd, int, ufd, sigset_t __user *, user_mask, size_t, sizemask) |
9deb27bae flag parameters: ... |
308 |
{ |
5ed0127fc signalfd: lift si... |
309 310 311 312 313 314 |
sigset_t mask; if (sizemask != sizeof(sigset_t) || copy_from_user(&mask, user_mask, sizeof(mask))) return -EINVAL; return do_signalfd4(ufd, &mask, 0); |
9deb27bae flag parameters: ... |
315 |
} |
7d197ed4a switch signalfd{,... |
316 317 |
#ifdef CONFIG_COMPAT |
570484bfe fs: add do_compat... |
318 |
static long do_compat_signalfd4(int ufd, |
5ed0127fc signalfd: lift si... |
319 |
const compat_sigset_t __user *user_mask, |
570484bfe fs: add do_compat... |
320 |
compat_size_t sigsetsize, int flags) |
7d197ed4a switch signalfd{,... |
321 |
{ |
5ed0127fc signalfd: lift si... |
322 |
sigset_t mask; |
7d197ed4a switch signalfd{,... |
323 324 325 |
if (sigsetsize != sizeof(compat_sigset_t)) return -EINVAL; |
5ed0127fc signalfd: lift si... |
326 |
if (get_compat_sigset(&mask, user_mask)) |
7d197ed4a switch signalfd{,... |
327 |
return -EFAULT; |
5ed0127fc signalfd: lift si... |
328 |
return do_signalfd4(ufd, &mask, flags); |
7d197ed4a switch signalfd{,... |
329 |
} |
570484bfe fs: add do_compat... |
330 |
COMPAT_SYSCALL_DEFINE4(signalfd4, int, ufd, |
5ed0127fc signalfd: lift si... |
331 |
const compat_sigset_t __user *, user_mask, |
570484bfe fs: add do_compat... |
332 333 334 |
compat_size_t, sigsetsize, int, flags) { |
5ed0127fc signalfd: lift si... |
335 |
return do_compat_signalfd4(ufd, user_mask, sigsetsize, flags); |
570484bfe fs: add do_compat... |
336 |
} |
7d197ed4a switch signalfd{,... |
337 |
COMPAT_SYSCALL_DEFINE3(signalfd, int, ufd, |
5ed0127fc signalfd: lift si... |
338 |
const compat_sigset_t __user *, user_mask, |
7d197ed4a switch signalfd{,... |
339 340 |
compat_size_t, sigsetsize) { |
5ed0127fc signalfd: lift si... |
341 |
return do_compat_signalfd4(ufd, user_mask, sigsetsize, 0); |
7d197ed4a switch signalfd{,... |
342 343 |
} #endif |