Blame view
fs/signalfd.c
9.13 KB
fba2afaae signal/timer/even... |
1 2 3 4 5 6 7 8 9 10 11 12 13 |
/* * 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... |
14 |
* Sat May 19, 2007: Davi E. M. Arnaut <davi@haxent.com.br> |
b3762bfc8 signalfd: retriev... |
15 |
* Retrieve multiple signals with one read() call |
b8fceee17 signalfd simplifi... |
16 17 |
* Sun Jul 15, 2007: Davide Libenzi <davidel@xmailserver.org> * Attach to the sighand only during read() and poll(). |
fba2afaae signal/timer/even... |
18 19 20 21 22 23 24 |
*/ #include <linux/file.h> #include <linux/poll.h> #include <linux/init.h> #include <linux/fs.h> #include <linux/sched.h> |
5a0e3ad6a include cleanup: ... |
25 |
#include <linux/slab.h> |
fba2afaae signal/timer/even... |
26 27 28 29 30 |
#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... |
31 |
#include <linux/syscalls.h> |
138d22b58 fs, epoll: add pr... |
32 |
#include <linux/proc_fs.h> |
7d197ed4a switch signalfd{,... |
33 |
#include <linux/compat.h> |
fba2afaae signal/timer/even... |
34 |
|
d80e731ec epoll: introduce ... |
35 36 37 |
void signalfd_cleanup(struct sighand_struct *sighand) { wait_queue_head_t *wqh = &sighand->signalfd_wqh; |
971316f05 epoll: ep_unregis... |
38 39 40 41 42 |
/* * The lockless check can race with remove_wait_queue() in progress, * but in this case its caller should run under rcu_read_lock() and * sighand_cachep is SLAB_DESTROY_BY_RCU, we can safely return. */ |
d80e731ec epoll: introduce ... |
43 44 45 46 47 48 |
if (likely(!waitqueue_active(wqh))) return; /* wait_queue_t->func(POLLFREE) should do remove_wait_queue() */ wake_up_poll(wqh, POLLHUP | POLLFREE); } |
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 57 58 59 60 61 |
return 0; } static unsigned int signalfd_poll(struct file *file, poll_table *wait) { struct signalfd_ctx *ctx = file->private_data; unsigned int events = 0; |
fba2afaae signal/timer/even... |
62 |
|
b8fceee17 signalfd simplifi... |
63 |
poll_wait(file, ¤t->sighand->signalfd_wqh, wait); |
fba2afaae signal/timer/even... |
64 |
|
b8fceee17 signalfd simplifi... |
65 66 67 68 |
spin_lock_irq(¤t->sighand->siglock); if (next_signal(¤t->pending, &ctx->sigmask) || next_signal(¤t->signal->shared_pending, &ctx->sigmask)) |
fba2afaae signal/timer/even... |
69 |
events |= POLLIN; |
b8fceee17 signalfd simplifi... |
70 |
spin_unlock_irq(¤t->sighand->siglock); |
fba2afaae signal/timer/even... |
71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 |
return events; } /* * Copied from copy_siginfo_to_user() in kernel/signal.c */ static int signalfd_copyinfo(struct signalfd_siginfo __user *uinfo, siginfo_t const *kinfo) { long err; BUILD_BUG_ON(sizeof(struct signalfd_siginfo) != 128); /* |
14e4a0f2b Fix a small numbe... |
86 |
* Unused members should be zero ... |
fba2afaae signal/timer/even... |
87 88 89 90 91 92 93 |
*/ err = __clear_user(uinfo, sizeof(*uinfo)); /* * If you change siginfo_t structure, please be sure * this code is fixed accordingly. */ |
96358de6b rename signalfd_s... |
94 95 96 |
err |= __put_user(kinfo->si_signo, &uinfo->ssi_signo); err |= __put_user(kinfo->si_errno, &uinfo->ssi_errno); err |= __put_user((short) kinfo->si_code, &uinfo->ssi_code); |
fba2afaae signal/timer/even... |
97 98 |
switch (kinfo->si_code & __SI_MASK) { case __SI_KILL: |
96358de6b rename signalfd_s... |
99 100 |
err |= __put_user(kinfo->si_pid, &uinfo->ssi_pid); err |= __put_user(kinfo->si_uid, &uinfo->ssi_uid); |
fba2afaae signal/timer/even... |
101 102 |
break; case __SI_TIMER: |
96358de6b rename signalfd_s... |
103 104 105 |
err |= __put_user(kinfo->si_tid, &uinfo->ssi_tid); err |= __put_user(kinfo->si_overrun, &uinfo->ssi_overrun); err |= __put_user((long) kinfo->si_ptr, &uinfo->ssi_ptr); |
a2a20c412 signalfd: fill in... |
106 |
err |= __put_user(kinfo->si_int, &uinfo->ssi_int); |
fba2afaae signal/timer/even... |
107 108 |
break; case __SI_POLL: |
96358de6b rename signalfd_s... |
109 110 |
err |= __put_user(kinfo->si_band, &uinfo->ssi_band); err |= __put_user(kinfo->si_fd, &uinfo->ssi_fd); |
fba2afaae signal/timer/even... |
111 112 |
break; case __SI_FAULT: |
96358de6b rename signalfd_s... |
113 |
err |= __put_user((long) kinfo->si_addr, &uinfo->ssi_addr); |
fba2afaae signal/timer/even... |
114 |
#ifdef __ARCH_SI_TRAPNO |
96358de6b rename signalfd_s... |
115 |
err |= __put_user(kinfo->si_trapno, &uinfo->ssi_trapno); |
fba2afaae signal/timer/even... |
116 |
#endif |
b8aeec341 HWPOISON/signalfd... |
117 118 119 120 121 122 123 124 125 126 |
#ifdef BUS_MCEERR_AO /* * Other callers might not initialize the si_lsb field, * so check explicitly for the right codes here. */ if (kinfo->si_code == BUS_MCEERR_AR || kinfo->si_code == BUS_MCEERR_AO) err |= __put_user((short) kinfo->si_addr_lsb, &uinfo->ssi_addr_lsb); #endif |
fba2afaae signal/timer/even... |
127 128 |
break; case __SI_CHLD: |
96358de6b rename signalfd_s... |
129 130 131 132 133 |
err |= __put_user(kinfo->si_pid, &uinfo->ssi_pid); err |= __put_user(kinfo->si_uid, &uinfo->ssi_uid); err |= __put_user(kinfo->si_status, &uinfo->ssi_status); err |= __put_user(kinfo->si_utime, &uinfo->ssi_utime); err |= __put_user(kinfo->si_stime, &uinfo->ssi_stime); |
fba2afaae signal/timer/even... |
134 135 136 |
break; case __SI_RT: /* This is not generated by the kernel as of now. */ case __SI_MESGQ: /* But this is */ |
96358de6b rename signalfd_s... |
137 138 139 |
err |= __put_user(kinfo->si_pid, &uinfo->ssi_pid); err |= __put_user(kinfo->si_uid, &uinfo->ssi_uid); err |= __put_user((long) kinfo->si_ptr, &uinfo->ssi_ptr); |
a2a20c412 signalfd: fill in... |
140 |
err |= __put_user(kinfo->si_int, &uinfo->ssi_int); |
fba2afaae signal/timer/even... |
141 |
break; |
0859ab59a signalfd: fix for... |
142 143 144 145 |
default: /* * This case catches also the signals queued by sigqueue(). */ |
96358de6b rename signalfd_s... |
146 147 |
err |= __put_user(kinfo->si_pid, &uinfo->ssi_pid); err |= __put_user(kinfo->si_uid, &uinfo->ssi_uid); |
0859ab59a signalfd: fix for... |
148 149 |
err |= __put_user((long) kinfo->si_ptr, &uinfo->ssi_ptr); err |= __put_user(kinfo->si_int, &uinfo->ssi_int); |
fba2afaae signal/timer/even... |
150 151 152 153 154 |
break; } return err ? -EFAULT: sizeof(*uinfo); } |
b3762bfc8 signalfd: retriev... |
155 156 157 158 |
static ssize_t signalfd_dequeue(struct signalfd_ctx *ctx, siginfo_t *info, int nonblock) { ssize_t ret; |
b3762bfc8 signalfd: retriev... |
159 |
DECLARE_WAITQUEUE(wait, current); |
b8fceee17 signalfd simplifi... |
160 161 |
spin_lock_irq(¤t->sighand->siglock); ret = dequeue_signal(current, &ctx->sigmask, info); |
b3762bfc8 signalfd: retriev... |
162 163 164 165 166 167 |
switch (ret) { case 0: if (!nonblock) break; ret = -EAGAIN; default: |
b8fceee17 signalfd simplifi... |
168 |
spin_unlock_irq(¤t->sighand->siglock); |
b3762bfc8 signalfd: retriev... |
169 170 |
return ret; } |
b8fceee17 signalfd simplifi... |
171 |
add_wait_queue(¤t->sighand->signalfd_wqh, &wait); |
b3762bfc8 signalfd: retriev... |
172 173 |
for (;;) { set_current_state(TASK_INTERRUPTIBLE); |
b8fceee17 signalfd simplifi... |
174 |
ret = dequeue_signal(current, &ctx->sigmask, info); |
b3762bfc8 signalfd: retriev... |
175 176 177 178 179 180 |
if (ret != 0) break; if (signal_pending(current)) { ret = -ERESTARTSYS; break; } |
b8fceee17 signalfd simplifi... |
181 |
spin_unlock_irq(¤t->sighand->siglock); |
b3762bfc8 signalfd: retriev... |
182 |
schedule(); |
b8fceee17 signalfd simplifi... |
183 |
spin_lock_irq(¤t->sighand->siglock); |
b3762bfc8 signalfd: retriev... |
184 |
} |
b8fceee17 signalfd simplifi... |
185 |
spin_unlock_irq(¤t->sighand->siglock); |
b3762bfc8 signalfd: retriev... |
186 |
|
b8fceee17 signalfd simplifi... |
187 |
remove_wait_queue(¤t->sighand->signalfd_wqh, &wait); |
b3762bfc8 signalfd: retriev... |
188 189 190 191 |
__set_current_state(TASK_RUNNING); return ret; } |
fba2afaae signal/timer/even... |
192 |
/* |
b8fceee17 signalfd simplifi... |
193 194 195 |
* 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... |
196 197 198 199 200 |
*/ 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... |
201 202 203 |
struct signalfd_siginfo __user *siginfo; int nonblock = file->f_flags & O_NONBLOCK; ssize_t ret, total = 0; |
fba2afaae signal/timer/even... |
204 |
siginfo_t info; |
fba2afaae signal/timer/even... |
205 |
|
b3762bfc8 signalfd: retriev... |
206 207 |
count /= sizeof(struct signalfd_siginfo); if (!count) |
fba2afaae signal/timer/even... |
208 |
return -EINVAL; |
fba2afaae signal/timer/even... |
209 |
|
b3762bfc8 signalfd: retriev... |
210 |
siginfo = (struct signalfd_siginfo __user *) buf; |
b3762bfc8 signalfd: retriev... |
211 212 213 214 215 216 217 218 219 220 221 |
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... |
222 |
return total ? total: ret; |
fba2afaae signal/timer/even... |
223 |
} |
138d22b58 fs, epoll: add pr... |
224 225 226 227 228 229 230 231 232 233 234 235 236 |
#ifdef CONFIG_PROC_FS static int signalfd_show_fdinfo(struct seq_file *m, struct file *f) { struct signalfd_ctx *ctx = f->private_data; sigset_t sigmask; sigmask = ctx->sigmask; signotset(&sigmask); render_sigset_t(m, "sigmask:\t", &sigmask); return 0; } #endif |
fba2afaae signal/timer/even... |
237 |
static const struct file_operations signalfd_fops = { |
138d22b58 fs, epoll: add pr... |
238 239 240 |
#ifdef CONFIG_PROC_FS .show_fdinfo = signalfd_show_fdinfo, #endif |
fba2afaae signal/timer/even... |
241 242 243 |
.release = signalfd_release, .poll = signalfd_poll, .read = signalfd_read, |
6038f373a llseek: automatic... |
244 |
.llseek = noop_llseek, |
fba2afaae signal/timer/even... |
245 |
}; |
836f92adf [CVE-2009-0029] S... |
246 247 |
SYSCALL_DEFINE4(signalfd4, int, ufd, sigset_t __user *, user_mask, size_t, sizemask, int, flags) |
fba2afaae signal/timer/even... |
248 |
{ |
fba2afaae signal/timer/even... |
249 250 |
sigset_t sigmask; struct signalfd_ctx *ctx; |
fba2afaae signal/timer/even... |
251 |
|
e38b36f32 flag parameters: ... |
252 253 254 |
/* Check the SFD_* constants for consistency. */ BUILD_BUG_ON(SFD_CLOEXEC != O_CLOEXEC); BUILD_BUG_ON(SFD_NONBLOCK != O_NONBLOCK); |
5fb5e0492 flag parameters: ... |
255 |
if (flags & ~(SFD_CLOEXEC | SFD_NONBLOCK)) |
9deb27bae flag parameters: ... |
256 |
return -EINVAL; |
fba2afaae signal/timer/even... |
257 258 |
if (sizemask != sizeof(sigset_t) || copy_from_user(&sigmask, user_mask, sizeof(sigmask))) |
f50cadaa8 tiny signalfd cle... |
259 |
return -EINVAL; |
fba2afaae signal/timer/even... |
260 261 262 263 264 265 266 |
sigdelsetmask(&sigmask, sigmask(SIGKILL) | sigmask(SIGSTOP)); signotset(&sigmask); if (ufd == -1) { ctx = kmalloc(sizeof(*ctx), GFP_KERNEL); if (!ctx) return -ENOMEM; |
fba2afaae signal/timer/even... |
267 |
ctx->sigmask = sigmask; |
fba2afaae signal/timer/even... |
268 269 270 271 272 |
/* * When we call this, the initialization must be complete, since * anon_inode_getfd() will install the fd. */ |
7d9dbca34 flag parameters: ... |
273 |
ufd = anon_inode_getfd("[signalfd]", &signalfd_fops, ctx, |
628ff7c1d anonfd: Allow mak... |
274 |
O_RDWR | (flags & (O_CLOEXEC | O_NONBLOCK))); |
2030a42ce [PATCH] sanitize ... |
275 276 |
if (ufd < 0) kfree(ctx); |
fba2afaae signal/timer/even... |
277 |
} else { |
2903ff019 switch simple cas... |
278 279 |
struct fd f = fdget(ufd); if (!f.file) |
fba2afaae signal/timer/even... |
280 |
return -EBADF; |
2903ff019 switch simple cas... |
281 282 283 |
ctx = f.file->private_data; if (f.file->f_op != &signalfd_fops) { fdput(f); |
fba2afaae signal/timer/even... |
284 285 |
return -EINVAL; } |
b8fceee17 signalfd simplifi... |
286 287 288 289 290 |
spin_lock_irq(¤t->sighand->siglock); ctx->sigmask = sigmask; spin_unlock_irq(¤t->sighand->siglock); wake_up(¤t->sighand->signalfd_wqh); |
2903ff019 switch simple cas... |
291 |
fdput(f); |
fba2afaae signal/timer/even... |
292 293 294 |
} return ufd; |
fba2afaae signal/timer/even... |
295 |
} |
9deb27bae flag parameters: ... |
296 |
|
836f92adf [CVE-2009-0029] S... |
297 298 |
SYSCALL_DEFINE3(signalfd, int, ufd, sigset_t __user *, user_mask, size_t, sizemask) |
9deb27bae flag parameters: ... |
299 300 301 |
{ return sys_signalfd4(ufd, user_mask, sizemask, 0); } |
7d197ed4a switch signalfd{,... |
302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 |
#ifdef CONFIG_COMPAT COMPAT_SYSCALL_DEFINE4(signalfd4, int, ufd, const compat_sigset_t __user *,sigmask, compat_size_t, sigsetsize, int, flags) { compat_sigset_t ss32; sigset_t tmp; sigset_t __user *ksigmask; if (sigsetsize != sizeof(compat_sigset_t)) return -EINVAL; if (copy_from_user(&ss32, sigmask, sizeof(ss32))) return -EFAULT; sigset_from_compat(&tmp, &ss32); ksigmask = compat_alloc_user_space(sizeof(sigset_t)); if (copy_to_user(ksigmask, &tmp, sizeof(sigset_t))) return -EFAULT; return sys_signalfd4(ufd, ksigmask, sizeof(sigset_t), flags); } COMPAT_SYSCALL_DEFINE3(signalfd, int, ufd, const compat_sigset_t __user *,sigmask, compat_size_t, sigsetsize) { return compat_sys_signalfd4(ufd, sigmask, sigsetsize, 0); } #endif |