diff options
| -rw-r--r-- | arch/mips/kernel/linux32.c | 46 | ||||
| -rw-r--r-- | fs/compat.c | 100 | ||||
| -rw-r--r-- | include/linux/compat.h | 19 |
3 files changed, 119 insertions, 46 deletions
diff --git a/arch/mips/kernel/linux32.c b/arch/mips/kernel/linux32.c index 30d433f14f93..1df544c1f966 100644 --- a/arch/mips/kernel/linux32.c +++ b/arch/mips/kernel/linux32.c | |||
| @@ -564,49 +564,3 @@ _sys32_clone(nabi_no_regargs struct pt_regs regs) | |||
| 564 | return do_fork(clone_flags, newsp, ®s, 0, | 564 | return do_fork(clone_flags, newsp, ®s, 0, |
| 565 | parent_tidptr, child_tidptr); | 565 | parent_tidptr, child_tidptr); |
| 566 | } | 566 | } |
| 567 | |||
| 568 | /* | ||
| 569 | * Implement the event wait interface for the eventpoll file. It is the kernel | ||
| 570 | * part of the user space epoll_pwait(2). | ||
| 571 | */ | ||
| 572 | asmlinkage long compat_sys_epoll_pwait(int epfd, | ||
| 573 | struct epoll_event __user *events, int maxevents, int timeout, | ||
| 574 | const compat_sigset_t __user *sigmask, size_t sigsetsize) | ||
| 575 | { | ||
| 576 | int error; | ||
| 577 | sigset_t ksigmask, sigsaved; | ||
| 578 | |||
| 579 | /* | ||
| 580 | * If the caller wants a certain signal mask to be set during the wait, | ||
| 581 | * we apply it here. | ||
| 582 | */ | ||
| 583 | if (sigmask) { | ||
| 584 | if (sigsetsize != sizeof(sigset_t)) | ||
| 585 | return -EINVAL; | ||
| 586 | if (!access_ok(VERIFY_READ, sigmask, sizeof(ksigmask))) | ||
| 587 | return -EFAULT; | ||
| 588 | if (__copy_conv_sigset_from_user(&ksigmask, sigmask)) | ||
| 589 | return -EFAULT; | ||
| 590 | sigdelsetmask(&ksigmask, sigmask(SIGKILL) | sigmask(SIGSTOP)); | ||
| 591 | sigprocmask(SIG_SETMASK, &ksigmask, &sigsaved); | ||
| 592 | } | ||
| 593 | |||
| 594 | error = sys_epoll_wait(epfd, events, maxevents, timeout); | ||
| 595 | |||
| 596 | /* | ||
| 597 | * If we changed the signal mask, we need to restore the original one. | ||
| 598 | * In case we've got a signal while waiting, we do not restore the | ||
| 599 | * signal mask yet, and we allow do_signal() to deliver the signal on | ||
| 600 | * the way back to userspace, before the signal mask is restored. | ||
| 601 | */ | ||
| 602 | if (sigmask) { | ||
| 603 | if (error == -EINTR) { | ||
| 604 | memcpy(¤t->saved_sigmask, &sigsaved, | ||
| 605 | sizeof(sigsaved)); | ||
| 606 | set_thread_flag(TIF_RESTORE_SIGMASK); | ||
| 607 | } else | ||
| 608 | sigprocmask(SIG_SETMASK, &sigsaved, NULL); | ||
| 609 | } | ||
| 610 | |||
| 611 | return error; | ||
| 612 | } | ||
diff --git a/fs/compat.c b/fs/compat.c index 0ec70e3cee0a..040a8be38a48 100644 --- a/fs/compat.c +++ b/fs/compat.c | |||
| @@ -48,6 +48,7 @@ | |||
| 48 | #include <linux/highmem.h> | 48 | #include <linux/highmem.h> |
| 49 | #include <linux/poll.h> | 49 | #include <linux/poll.h> |
| 50 | #include <linux/mm.h> | 50 | #include <linux/mm.h> |
| 51 | #include <linux/eventpoll.h> | ||
| 51 | 52 | ||
| 52 | #include <net/sock.h> /* siocdevprivate_ioctl */ | 53 | #include <net/sock.h> /* siocdevprivate_ioctl */ |
| 53 | 54 | ||
| @@ -2235,3 +2236,102 @@ long asmlinkage compat_sys_nfsservctl(int cmd, void *notused, void *notused2) | |||
| 2235 | return sys_ni_syscall(); | 2236 | return sys_ni_syscall(); |
| 2236 | } | 2237 | } |
| 2237 | #endif | 2238 | #endif |
| 2239 | |||
| 2240 | #ifdef CONFIG_EPOLL | ||
| 2241 | |||
| 2242 | #ifdef CONFIG_HAS_COMPAT_EPOLL_EVENT | ||
| 2243 | asmlinkage long compat_sys_epoll_ctl(int epfd, int op, int fd, | ||
| 2244 | struct compat_epoll_event __user *event) | ||
| 2245 | { | ||
| 2246 | long err = 0; | ||
| 2247 | struct compat_epoll_event user; | ||
| 2248 | struct epoll_event __user *kernel = NULL; | ||
| 2249 | |||
| 2250 | if (event) { | ||
| 2251 | if (copy_from_user(&user, event, sizeof(user))) | ||
| 2252 | return -EFAULT; | ||
| 2253 | kernel = compat_alloc_user_space(sizeof(struct epoll_event)); | ||
| 2254 | err |= __put_user(user.events, &kernel->events); | ||
| 2255 | err |= __put_user(user.data, &kernel->data); | ||
| 2256 | } | ||
| 2257 | |||
| 2258 | return err ? err : sys_epoll_ctl(epfd, op, fd, kernel); | ||
| 2259 | } | ||
| 2260 | |||
| 2261 | |||
| 2262 | asmlinkage long compat_sys_epoll_wait(int epfd, | ||
| 2263 | struct compat_epoll_event __user *events, | ||
| 2264 | int maxevents, int timeout) | ||
| 2265 | { | ||
| 2266 | long i, ret, err = 0; | ||
| 2267 | struct epoll_event __user *kbuf; | ||
| 2268 | struct epoll_event ev; | ||
| 2269 | |||
| 2270 | if ((maxevents <= 0) || | ||
| 2271 | (maxevents > (INT_MAX / sizeof(struct epoll_event)))) | ||
| 2272 | return -EINVAL; | ||
| 2273 | kbuf = compat_alloc_user_space(sizeof(struct epoll_event) * maxevents); | ||
| 2274 | ret = sys_epoll_wait(epfd, kbuf, maxevents, timeout); | ||
| 2275 | for (i = 0; i < ret; i++) { | ||
| 2276 | err |= __get_user(ev.events, &kbuf[i].events); | ||
| 2277 | err |= __get_user(ev.data, &kbuf[i].data); | ||
| 2278 | err |= __put_user(ev.events, &events->events); | ||
| 2279 | err |= __put_user_unaligned(ev.data, &events->data); | ||
| 2280 | events++; | ||
| 2281 | } | ||
| 2282 | |||
| 2283 | return err ? -EFAULT: ret; | ||
| 2284 | } | ||
| 2285 | #endif /* CONFIG_HAS_COMPAT_EPOLL_EVENT */ | ||
| 2286 | |||
| 2287 | #ifdef TIF_RESTORE_SIGMASK | ||
| 2288 | asmlinkage long compat_sys_epoll_pwait(int epfd, | ||
| 2289 | struct compat_epoll_event __user *events, | ||
| 2290 | int maxevents, int timeout, | ||
| 2291 | const compat_sigset_t __user *sigmask, | ||
| 2292 | compat_size_t sigsetsize) | ||
| 2293 | { | ||
| 2294 | long err; | ||
| 2295 | compat_sigset_t csigmask; | ||
| 2296 | sigset_t ksigmask, sigsaved; | ||
| 2297 | |||
| 2298 | /* | ||
| 2299 | * If the caller wants a certain signal mask to be set during the wait, | ||
| 2300 | * we apply it here. | ||
| 2301 | */ | ||
| 2302 | if (sigmask) { | ||
| 2303 | if (sigsetsize != sizeof(compat_sigset_t)) | ||
| 2304 | return -EINVAL; | ||
| 2305 | if (copy_from_user(&csigmask, sigmask, sizeof(csigmask))) | ||
| 2306 | return -EFAULT; | ||
| 2307 | sigset_from_compat(&ksigmask, &csigmask); | ||
| 2308 | sigdelsetmask(&ksigmask, sigmask(SIGKILL) | sigmask(SIGSTOP)); | ||
| 2309 | sigprocmask(SIG_SETMASK, &ksigmask, &sigsaved); | ||
| 2310 | } | ||
| 2311 | |||
| 2312 | #ifdef CONFIG_HAS_COMPAT_EPOLL_EVENT | ||
| 2313 | err = compat_sys_epoll_wait(epfd, events, maxevents, timeout); | ||
| 2314 | #else | ||
| 2315 | err = sys_epoll_wait(epfd, events, maxevents, timeout); | ||
| 2316 | #endif | ||
| 2317 | |||
| 2318 | /* | ||
| 2319 | * If we changed the signal mask, we need to restore the original one. | ||
| 2320 | * In case we've got a signal while waiting, we do not restore the | ||
| 2321 | * signal mask yet, and we allow do_signal() to deliver the signal on | ||
| 2322 | * the way back to userspace, before the signal mask is restored. | ||
| 2323 | */ | ||
| 2324 | if (sigmask) { | ||
| 2325 | if (err == -EINTR) { | ||
| 2326 | memcpy(¤t->saved_sigmask, &sigsaved, | ||
| 2327 | sizeof(sigsaved)); | ||
| 2328 | set_thread_flag(TIF_RESTORE_SIGMASK); | ||
| 2329 | } else | ||
| 2330 | sigprocmask(SIG_SETMASK, &sigsaved, NULL); | ||
| 2331 | } | ||
| 2332 | |||
| 2333 | return err; | ||
| 2334 | } | ||
| 2335 | #endif /* TIF_RESTORE_SIGMASK */ | ||
| 2336 | |||
| 2337 | #endif /* CONFIG_EPOLL */ | ||
diff --git a/include/linux/compat.h b/include/linux/compat.h index 80b17f440ec1..ccd863dd77fa 100644 --- a/include/linux/compat.h +++ b/include/linux/compat.h | |||
| @@ -234,5 +234,24 @@ asmlinkage long compat_sys_migrate_pages(compat_pid_t pid, | |||
| 234 | compat_ulong_t maxnode, const compat_ulong_t __user *old_nodes, | 234 | compat_ulong_t maxnode, const compat_ulong_t __user *old_nodes, |
| 235 | const compat_ulong_t __user *new_nodes); | 235 | const compat_ulong_t __user *new_nodes); |
| 236 | 236 | ||
| 237 | /* | ||
| 238 | * epoll (fs/eventpoll.c) compat bits follow ... | ||
| 239 | */ | ||
| 240 | #ifndef CONFIG_HAS_COMPAT_EPOLL_EVENT | ||
| 241 | struct epoll_event; | ||
| 242 | #define compat_epoll_event epoll_event | ||
| 243 | #else | ||
| 244 | asmlinkage long compat_sys_epoll_ctl(int epfd, int op, int fd, | ||
| 245 | struct compat_epoll_event __user *event); | ||
| 246 | asmlinkage long compat_sys_epoll_wait(int epfd, | ||
| 247 | struct compat_epoll_event __user *events, | ||
| 248 | int maxevents, int timeout); | ||
| 249 | #endif | ||
| 250 | asmlinkage long compat_sys_epoll_pwait(int epfd, | ||
| 251 | struct compat_epoll_event __user *events, | ||
| 252 | int maxevents, int timeout, | ||
| 253 | const compat_sigset_t __user *sigmask, | ||
| 254 | compat_size_t sigsetsize); | ||
| 255 | |||
| 237 | #endif /* CONFIG_COMPAT */ | 256 | #endif /* CONFIG_COMPAT */ |
| 238 | #endif /* _LINUX_COMPAT_H */ | 257 | #endif /* _LINUX_COMPAT_H */ |
