1 /* $NetBSD: linux32_signal.c,v 1.6 2007/12/11 13:22:50 lukem Exp $ */ 2 3 /*- 4 * Copyright (c) 2006 Emmanuel Dreyfus, all rights reserved. 5 * 6 * Redistribution and use in source and binary forms, with or without 7 * modification, are permitted provided that the following conditions 8 * are met: 9 * 1. Redistributions of source code must retain the above copyright 10 * notice, this list of conditions and the following disclaimer. 11 * 2. Redistributions in binary form must reproduce the above copyright 12 * notice, this list of conditions and the following disclaimer in the 13 * documentation and/or other materials provided with the distribution. 14 * 3. All advertising materials mentioning features or use of this software 15 * must display the following acknowledgement: 16 * This product includes software developed by Emmanuel Dreyfus 17 * 4. The name of the author may not be used to endorse or promote 18 * products derived from this software without specific prior written 19 * permission. 20 * 21 * THIS SOFTWARE IS PROVIDED BY THE THE AUTHOR AND CONTRIBUTORS ``AS IS'' 22 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, 23 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 24 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS 25 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 26 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 27 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 28 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 29 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 30 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 31 * POSSIBILITY OF SUCH DAMAGE. 32 */ 33 34 #include <sys/cdefs.h> 35 __KERNEL_RCSID(0, "$NetBSD: linux32_signal.c,v 1.6 2007/12/11 13:22:50 lukem Exp $"); 36 37 #include <sys/param.h> 38 #include <sys/ucred.h> 39 #include <sys/signalvar.h> 40 #include <sys/lwp.h> 41 #include <sys/time.h> 42 #include <sys/proc.h> 43 44 #include <compat/netbsd32/netbsd32.h> 45 46 #include <compat/linux32/common/linux32_types.h> 47 #include <compat/linux32/common/linux32_signal.h> 48 #include <compat/linux32/linux32_syscallargs.h> 49 50 #define linux32_sigemptyset(s) memset((s), 0, sizeof(*(s))) 51 #define linux32_sigismember(s, n) ((s)->sig[((n) - 1) / LINUX32__NSIG_BPW] \ 52 & (1 << ((n) - 1) % LINUX32__NSIG_BPW)) 53 #define linux32_sigaddset(s, n) ((s)->sig[((n) - 1) / LINUX32__NSIG_BPW] \ 54 |= (1 << ((n) - 1) % LINUX32__NSIG_BPW)) 55 56 extern const int native_to_linux32_signo[]; 57 extern const int linux32_to_native_signo[]; 58 59 void 60 linux32_to_native_sigset(sigset_t *bss, const linux32_sigset_t *lss) 61 { 62 int i, newsig; 63 64 sigemptyset(bss); 65 for (i = 1; i < LINUX32__NSIG; i++) { 66 if (linux32_sigismember(lss, i)) { 67 newsig = linux32_to_native_signo[i]; 68 if (newsig) 69 sigaddset(bss, newsig); 70 } 71 } 72 } 73 74 void 75 native_to_linux32_sigset(linux32_sigset_t *lss, const sigset_t *bss) 76 { 77 int i, newsig; 78 79 linux32_sigemptyset(lss); 80 for (i = 1; i < NSIG; i++) { 81 if (sigismember(bss, i)) { 82 newsig = native_to_linux32_signo[i]; 83 if (newsig) 84 linux32_sigaddset(lss, newsig); 85 } 86 } 87 } 88 89 unsigned int 90 native_to_linux32_sigflags(const int bsf) 91 { 92 unsigned int lsf = 0; 93 if ((bsf & SA_NOCLDSTOP) != 0) 94 lsf |= LINUX32_SA_NOCLDSTOP; 95 if ((bsf & SA_NOCLDWAIT) != 0) 96 lsf |= LINUX32_SA_NOCLDWAIT; 97 if ((bsf & SA_ONSTACK) != 0) 98 lsf |= LINUX32_SA_ONSTACK; 99 if ((bsf & SA_RESTART) != 0) 100 lsf |= LINUX32_SA_RESTART; 101 if ((bsf & SA_NODEFER) != 0) 102 lsf |= LINUX32_SA_NOMASK; 103 if ((bsf & SA_RESETHAND) != 0) 104 lsf |= LINUX32_SA_ONESHOT; 105 if ((bsf & SA_SIGINFO) != 0) 106 lsf |= LINUX32_SA_SIGINFO; 107 return lsf; 108 } 109 110 int 111 linux32_to_native_sigflags(const unsigned long lsf) 112 { 113 int bsf = 0; 114 if ((lsf & LINUX32_SA_NOCLDSTOP) != 0) 115 bsf |= SA_NOCLDSTOP; 116 if ((lsf & LINUX32_SA_NOCLDWAIT) != 0) 117 bsf |= SA_NOCLDWAIT; 118 if ((lsf & LINUX32_SA_ONSTACK) != 0) 119 bsf |= SA_ONSTACK; 120 if ((lsf & LINUX32_SA_RESTART) != 0) 121 bsf |= SA_RESTART; 122 if ((lsf & LINUX32_SA_ONESHOT) != 0) 123 bsf |= SA_RESETHAND; 124 if ((lsf & LINUX32_SA_NOMASK) != 0) 125 bsf |= SA_NODEFER; 126 if ((lsf & LINUX32_SA_SIGINFO) != 0) 127 bsf |= SA_SIGINFO; 128 if ((lsf & ~LINUX32_SA_ALLBITS) != 0) { 129 #ifdef DEBUG_LINUX 130 printf("linux32_old_to_native_sigflags: " 131 "%lx extra bits ignored\n", lsf); 132 #endif 133 } 134 return bsf; 135 } 136 137 void 138 linux32_to_native_sigaction(struct sigaction *bsa, const struct linux32_sigaction *lsa) 139 { 140 bsa->sa_handler = NETBSD32PTR64(lsa->linux_sa_handler); 141 linux32_to_native_sigset(&bsa->sa_mask, &lsa->linux_sa_mask); 142 bsa->sa_flags = linux32_to_native_sigflags(lsa->linux_sa_flags); 143 } 144 145 void 146 native_to_linux32_sigaction(struct linux32_sigaction *lsa, const struct sigaction *bsa) 147 { 148 NETBSD32PTR32(lsa->linux_sa_handler, bsa->sa_handler); 149 native_to_linux32_sigset(&lsa->linux_sa_mask, &bsa->sa_mask); 150 lsa->linux_sa_flags = native_to_linux32_sigflags(bsa->sa_flags); 151 NETBSD32PTR32(lsa->linux_sa_restorer, NULL); 152 } 153 154 void 155 native_to_linux32_sigaltstack(struct linux32_sigaltstack *lss, const struct sigaltstack *bss) 156 { 157 NETBSD32PTR32(lss->ss_sp, bss->ss_sp); 158 lss->ss_size = bss->ss_size; 159 if (bss->ss_flags & SS_ONSTACK) 160 lss->ss_flags = LINUX32_SS_ONSTACK; 161 else if (bss->ss_flags & SS_DISABLE) 162 lss->ss_flags = LINUX32_SS_DISABLE; 163 else 164 lss->ss_flags = 0; 165 } 166 167 168 void 169 native_to_linux32_old_sigset(linux32_old_sigset_t *lss, const sigset_t *bss) 170 { 171 linux32_sigset_t lsnew; 172 173 native_to_linux32_sigset(&lsnew, bss); 174 175 /* convert new sigset to old sigset */ 176 *lss = lsnew.sig[0]; 177 } 178 179 void 180 linux32_old_to_native_sigset(sigset_t *bss, const linux32_old_sigset_t *lss) 181 { 182 linux32_sigset_t ls; 183 184 bzero(&ls, sizeof(ls)); 185 ls.sig[0] = *lss; 186 187 linux32_to_native_sigset(bss, &ls); 188 } 189 190 int 191 linux32_sys_rt_sigaction(struct lwp *l, void *v, register_t *retval) 192 { 193 struct linux32_sys_rt_sigaction_args /* { 194 syscallarg(int) signum; 195 syscallarg(const linux32_sigactionp_t) nsa; 196 syscallarg(linux32_sigactionp_t) osa; 197 syscallarg(netbsd32_size_t) sigsetsize; 198 } */ *uap = v; 199 struct linux32_sigaction nls32; 200 struct linux32_sigaction ols32; 201 struct sigaction ns; 202 struct sigaction os; 203 int error; 204 int sig; 205 int vers = 0; 206 void *tramp = NULL; 207 208 if (SCARG(uap, sigsetsize) != sizeof(linux32_sigset_t)) 209 return EINVAL; 210 211 if (SCARG_P32(uap, nsa) != NULL) { 212 if ((error = copyin(SCARG_P32(uap, nsa), 213 &nls32, sizeof(nls32))) != 0) 214 return error; 215 linux32_to_native_sigaction(&ns, &nls32); 216 } 217 218 sig = SCARG(uap, signum); 219 if (sig < 0 || sig >= LINUX32__NSIG) 220 return EINVAL; 221 if (sig > 0 && !linux32_to_native_signo[sig]) { 222 /* unknown signal... */ 223 os.sa_handler = SIG_IGN; 224 sigemptyset(&os.sa_mask); 225 os.sa_flags = 0; 226 } else { 227 if ((error = sigaction1(l, 228 linux32_to_native_signo[sig], 229 SCARG_P32(uap, nsa) ? &ns : NULL, 230 SCARG_P32(uap, osa) ? &os : NULL, 231 tramp, vers)) != 0) 232 return error; 233 } 234 235 if (SCARG_P32(uap, osa) != NULL) { 236 native_to_linux32_sigaction(&ols32, &os); 237 238 if ((error = copyout(&ols32, SCARG_P32(uap, osa), 239 sizeof(ols32))) != 0) 240 return error; 241 } 242 243 return 0; 244 } 245 246 int 247 linux32_sys_rt_sigprocmask(struct lwp *l, void *v, register_t *retval) 248 { 249 struct linux32_sys_rt_sigprocmask_args /* { 250 syscallarg(int) how; 251 syscallarg(const linux32_sigsetp_t) set; 252 syscallarg(linux32_sigsetp_t) oset; 253 syscallarg(netbsd32_size_t) sigsetsize; 254 } */ *uap = v; 255 struct proc *p = l->l_proc; 256 linux32_sigset_t nls32, ols32; 257 sigset_t ns, os; 258 int error; 259 int how; 260 261 if (SCARG(uap, sigsetsize) != sizeof(linux32_sigset_t)) 262 return EINVAL; 263 264 switch (SCARG(uap, how)) { 265 case LINUX32_SIG_BLOCK: 266 how = SIG_BLOCK; 267 break; 268 case LINUX32_SIG_UNBLOCK: 269 how = SIG_UNBLOCK; 270 break; 271 case LINUX32_SIG_SETMASK: 272 how = SIG_SETMASK; 273 break; 274 default: 275 return EINVAL; 276 break; 277 } 278 279 if (SCARG_P32(uap, set) != NULL) { 280 if ((error = copyin(SCARG_P32(uap, set), 281 &nls32, sizeof(nls32))) != 0) 282 return error; 283 linux32_to_native_sigset(&ns, &nls32); 284 } 285 286 mutex_enter(&p->p_smutex); 287 error = sigprocmask1(l, how, 288 SCARG_P32(uap, set) ? &ns : NULL, 289 SCARG_P32(uap, oset) ? &os : NULL); 290 mutex_exit(&p->p_smutex); 291 292 if (error != 0) 293 return error; 294 295 if (SCARG_P32(uap, oset) != NULL) { 296 native_to_linux32_sigset(&ols32, &os); 297 if ((error = copyout(&ols32, 298 SCARG_P32(uap, oset), sizeof(ols32))) != 0) 299 return error; 300 } 301 302 return 0; 303 } 304 305 int 306 linux32_sys_kill(l, v, retval) 307 struct lwp *l; 308 void *v; 309 register_t *retval; 310 { 311 struct linux32_sys_kill_args /* { 312 syscallarg(int) pid; 313 syscallarg(int) signum; 314 } */ *uap = v; 315 316 struct sys_kill_args ka; 317 int sig; 318 319 SCARG(&ka, pid) = SCARG(uap, pid); 320 sig = SCARG(uap, signum); 321 if (sig < 0 || sig >= LINUX32__NSIG) 322 return (EINVAL); 323 SCARG(&ka, signum) = linux32_to_native_signo[sig]; 324 return sys_kill(l, &ka, retval); 325 } 326 327 int 328 linux32_sys_rt_sigsuspend(l, v, retval) 329 struct lwp *l; 330 void *v; 331 register_t *retval; 332 { 333 struct linux32_sys_rt_sigsuspend_args /* { 334 syscallarg(linux32_sigsetp_t) unewset; 335 syscallarg(netbsd32_size_t) sigsetsize; 336 } */ *uap = v; 337 linux32_sigset_t lss; 338 sigset_t bss; 339 int error; 340 341 if (SCARG(uap, sigsetsize) != sizeof(linux32_sigset_t)) 342 return EINVAL; 343 344 if ((error = copyin(SCARG_P32(uap, unewset), 345 &lss, sizeof(linux32_sigset_t))) != 0) 346 return error; 347 348 linux32_to_native_sigset(&bss, &lss); 349 350 return sigsuspend1(l, &bss); 351 } 352 353 int 354 linux32_sys_signal(struct lwp *l, void *v, register_t *retval) 355 { 356 struct linux32_sys_signal_args /* { 357 syscallarg(int) signum; 358 syscallarg(linux32_handler_t) handler; 359 } */ *uap = v; 360 struct sigaction nbsa, obsa; 361 int error, sig; 362 363 *retval = -1; 364 365 sig = SCARG(uap, signum); 366 if (sig < 0 || sig >= LINUX32__NSIG) 367 return EINVAL; 368 369 nbsa.sa_handler = SCARG_P32(uap, handler); 370 sigemptyset(&nbsa.sa_mask); 371 nbsa.sa_flags = SA_RESETHAND | SA_NODEFER; 372 373 if ((error = sigaction1(l, linux32_to_native_signo[sig], 374 &nbsa, &obsa, NULL, 0)) != 0) 375 return error; 376 377 *retval = (int)(long)obsa.sa_handler; 378 return 0; 379 } 380