1 /* $NetBSD: linux32_signal.c,v 1.4 2007/03/18 21:38:32 dsl 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 #include <sys/param.h> 34 #include <sys/ucred.h> 35 #include <sys/signalvar.h> 36 #include <sys/lwp.h> 37 #include <sys/time.h> 38 #include <sys/proc.h> 39 40 #include <compat/netbsd32/netbsd32.h> 41 42 #include <compat/linux32/common/linux32_types.h> 43 #include <compat/linux32/common/linux32_signal.h> 44 #include <compat/linux32/linux32_syscallargs.h> 45 46 #define linux32_sigemptyset(s) memset((s), 0, sizeof(*(s))) 47 #define linux32_sigismember(s, n) ((s)->sig[((n) - 1) / LINUX32__NSIG_BPW] \ 48 & (1 << ((n) - 1) % LINUX32__NSIG_BPW)) 49 #define linux32_sigaddset(s, n) ((s)->sig[((n) - 1) / LINUX32__NSIG_BPW] \ 50 |= (1 << ((n) - 1) % LINUX32__NSIG_BPW)) 51 52 extern const int native_to_linux32_signo[]; 53 extern const int linux32_to_native_signo[]; 54 55 void 56 linux32_to_native_sigset(bss, lss) 57 sigset_t *bss; 58 const linux32_sigset_t *lss; 59 { 60 int i, newsig; 61 62 sigemptyset(bss); 63 for (i = 1; i < LINUX32__NSIG; i++) { 64 if (linux32_sigismember(lss, i)) { 65 newsig = linux32_to_native_signo[i]; 66 if (newsig) 67 sigaddset(bss, newsig); 68 } 69 } 70 } 71 72 void 73 native_to_linux32_sigset(lss, bss) 74 linux32_sigset_t *lss; 75 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(bsf) 91 const int bsf; 92 { 93 unsigned int lsf = 0; 94 if ((bsf & SA_NOCLDSTOP) != 0) 95 lsf |= LINUX32_SA_NOCLDSTOP; 96 if ((bsf & SA_NOCLDWAIT) != 0) 97 lsf |= LINUX32_SA_NOCLDWAIT; 98 if ((bsf & SA_ONSTACK) != 0) 99 lsf |= LINUX32_SA_ONSTACK; 100 if ((bsf & SA_RESTART) != 0) 101 lsf |= LINUX32_SA_RESTART; 102 if ((bsf & SA_NODEFER) != 0) 103 lsf |= LINUX32_SA_NOMASK; 104 if ((bsf & SA_RESETHAND) != 0) 105 lsf |= LINUX32_SA_ONESHOT; 106 if ((bsf & SA_SIGINFO) != 0) 107 lsf |= LINUX32_SA_SIGINFO; 108 return lsf; 109 } 110 111 int 112 linux32_to_native_sigflags(lsf) 113 const unsigned long lsf; 114 { 115 int bsf = 0; 116 if ((lsf & LINUX32_SA_NOCLDSTOP) != 0) 117 bsf |= SA_NOCLDSTOP; 118 if ((lsf & LINUX32_SA_NOCLDWAIT) != 0) 119 bsf |= SA_NOCLDWAIT; 120 if ((lsf & LINUX32_SA_ONSTACK) != 0) 121 bsf |= SA_ONSTACK; 122 if ((lsf & LINUX32_SA_RESTART) != 0) 123 bsf |= SA_RESTART; 124 if ((lsf & LINUX32_SA_ONESHOT) != 0) 125 bsf |= SA_RESETHAND; 126 if ((lsf & LINUX32_SA_NOMASK) != 0) 127 bsf |= SA_NODEFER; 128 if ((lsf & LINUX32_SA_SIGINFO) != 0) 129 bsf |= SA_SIGINFO; 130 if ((lsf & ~LINUX32_SA_ALLBITS) != 0) { 131 #ifdef DEBUG_LINUX 132 printf("linux32_old_to_native_sigflags: " 133 "%lx extra bits ignored\n", lsf); 134 #endif 135 } 136 return bsf; 137 } 138 139 void 140 linux32_to_native_sigaction(bsa, lsa) 141 struct sigaction *bsa; 142 const struct linux32_sigaction *lsa; 143 { 144 bsa->sa_handler = NETBSD32PTR64(lsa->linux_sa_handler); 145 linux32_to_native_sigset(&bsa->sa_mask, &lsa->linux_sa_mask); 146 bsa->sa_flags = linux32_to_native_sigflags(lsa->linux_sa_flags); 147 } 148 149 void 150 native_to_linux32_sigaction(lsa, bsa) 151 struct linux32_sigaction *lsa; 152 const struct sigaction *bsa; 153 { 154 NETBSD32PTR32(lsa->linux_sa_handler, bsa->sa_handler); 155 native_to_linux32_sigset(&lsa->linux_sa_mask, &bsa->sa_mask); 156 lsa->linux_sa_flags = native_to_linux32_sigflags(bsa->sa_flags); 157 NETBSD32PTR32(lsa->linux_sa_restorer, NULL); 158 } 159 160 void 161 native_to_linux32_sigaltstack(lss, bss) 162 struct linux32_sigaltstack *lss; 163 const struct sigaltstack *bss; 164 { 165 NETBSD32PTR32(lss->ss_sp, bss->ss_sp); 166 lss->ss_size = bss->ss_size; 167 if (bss->ss_flags & SS_ONSTACK) 168 lss->ss_flags = LINUX32_SS_ONSTACK; 169 else if (bss->ss_flags & SS_DISABLE) 170 lss->ss_flags = LINUX32_SS_DISABLE; 171 else 172 lss->ss_flags = 0; 173 } 174 175 176 void 177 native_to_linux32_old_sigset(lss, bss) 178 linux32_old_sigset_t *lss; 179 const sigset_t *bss; 180 { 181 linux32_sigset_t lsnew; 182 183 native_to_linux32_sigset(&lsnew, bss); 184 185 /* convert new sigset to old sigset */ 186 *lss = lsnew.sig[0]; 187 } 188 189 void 190 linux32_old_to_native_sigset(bss, lss) 191 sigset_t *bss; 192 const linux32_old_sigset_t *lss; 193 { 194 linux32_sigset_t ls; 195 196 bzero(&ls, sizeof(ls)); 197 ls.sig[0] = *lss; 198 199 linux32_to_native_sigset(bss, &ls); 200 } 201 202 int 203 linux32_sys_rt_sigaction(l, v, retval) 204 struct lwp *l; 205 void *v; 206 register_t *retval; 207 { 208 struct linux32_sys_rt_sigaction_args /* { 209 syscallarg(int) signum; 210 syscallarg(const linux32_sigactionp_t) nsa; 211 syscallarg(linux32_sigactionp_t) osa; 212 syscallarg(netbsd32_size_t) sigsetsize; 213 } */ *uap = v; 214 struct linux32_sigaction nls32; 215 struct linux32_sigaction ols32; 216 struct sigaction ns; 217 struct sigaction os; 218 int error; 219 int sig; 220 int vers = 0; 221 void *tramp = NULL; 222 223 if (SCARG(uap, sigsetsize) != sizeof(linux32_sigset_t)) 224 return EINVAL; 225 226 if (SCARG_P32(uap, nsa) != NULL) { 227 if ((error = copyin(SCARG_P32(uap, nsa), 228 &nls32, sizeof(nls32))) != 0) 229 return error; 230 linux32_to_native_sigaction(&ns, &nls32); 231 } 232 233 sig = SCARG(uap, signum); 234 if (sig < 0 || sig >= LINUX32__NSIG) 235 return EINVAL; 236 if (sig > 0 && !linux32_to_native_signo[sig]) { 237 /* unknown signal... */ 238 os.sa_handler = SIG_IGN; 239 sigemptyset(&os.sa_mask); 240 os.sa_flags = 0; 241 } else { 242 if ((error = sigaction1(l, 243 linux32_to_native_signo[sig], 244 SCARG_P32(uap, nsa) ? &ns : NULL, 245 SCARG_P32(uap, osa) ? &os : NULL, 246 tramp, vers)) != 0) 247 return error; 248 } 249 250 if (SCARG_P32(uap, osa) != NULL) { 251 native_to_linux32_sigaction(&ols32, &os); 252 253 if ((error = copyout(&ols32, SCARG_P32(uap, osa), 254 sizeof(ols32))) != 0) 255 return error; 256 } 257 258 return 0; 259 } 260 261 int 262 linux32_sys_rt_sigprocmask(l, v, retval) 263 struct lwp *l; 264 void *v; 265 register_t *retval; 266 { 267 struct linux32_sys_rt_sigprocmask_args /* { 268 syscallarg(int) how; 269 syscallarg(const linux32_sigsetp_t) set; 270 syscallarg(linux32_sigsetp_t) oset; 271 syscallarg(netbsd32_size_t) sigsetsize; 272 } */ *uap = v; 273 struct proc *p = l->l_proc; 274 linux32_sigset_t nls32, ols32; 275 sigset_t ns, os; 276 int error; 277 int how; 278 279 if (SCARG(uap, sigsetsize) != sizeof(linux32_sigset_t)) 280 return EINVAL; 281 282 switch (SCARG(uap, how)) { 283 case LINUX32_SIG_BLOCK: 284 how = SIG_BLOCK; 285 break; 286 case LINUX32_SIG_UNBLOCK: 287 how = SIG_UNBLOCK; 288 break; 289 case LINUX32_SIG_SETMASK: 290 how = SIG_SETMASK; 291 break; 292 default: 293 return EINVAL; 294 break; 295 } 296 297 if (SCARG_P32(uap, set) != NULL) { 298 if ((error = copyin(SCARG_P32(uap, set), 299 &nls32, sizeof(nls32))) != 0) 300 return error; 301 linux32_to_native_sigset(&ns, &nls32); 302 } 303 304 mutex_enter(&p->p_smutex); 305 error = sigprocmask1(l, how, 306 SCARG_P32(uap, set) ? &ns : NULL, 307 SCARG_P32(uap, oset) ? &os : NULL); 308 mutex_exit(&p->p_smutex); 309 310 if (error != 0) 311 return error; 312 313 if (SCARG_P32(uap, oset) != NULL) { 314 native_to_linux32_sigset(&ols32, &os); 315 if ((error = copyout(&ols32, 316 SCARG_P32(uap, oset), sizeof(ols32))) != 0) 317 return error; 318 } 319 320 return 0; 321 } 322 323 int 324 linux32_sys_kill(l, v, retval) 325 struct lwp *l; 326 void *v; 327 register_t *retval; 328 { 329 struct linux32_sys_kill_args /* { 330 syscallarg(int) pid; 331 syscallarg(int) signum; 332 } */ *uap = v; 333 334 struct sys_kill_args ka; 335 int sig; 336 337 SCARG(&ka, pid) = SCARG(uap, pid); 338 sig = SCARG(uap, signum); 339 if (sig < 0 || sig >= LINUX32__NSIG) 340 return (EINVAL); 341 SCARG(&ka, signum) = linux32_to_native_signo[sig]; 342 return sys_kill(l, &ka, retval); 343 } 344 345 int 346 linux32_sys_rt_sigsuspend(l, v, retval) 347 struct lwp *l; 348 void *v; 349 register_t *retval; 350 { 351 struct linux32_sys_rt_sigsuspend_args /* { 352 syscallarg(linux32_sigsetp_t) unewset; 353 syscallarg(netbsd32_size_t) sigsetsize; 354 } */ *uap = v; 355 linux32_sigset_t lss; 356 sigset_t bss; 357 int error; 358 359 if (SCARG(uap, sigsetsize) != sizeof(linux32_sigset_t)) 360 return EINVAL; 361 362 if ((error = copyin(SCARG_P32(uap, unewset), 363 &lss, sizeof(linux32_sigset_t))) != 0) 364 return error; 365 366 linux32_to_native_sigset(&bss, &lss); 367 368 return sigsuspend1(l, &bss); 369 } 370 371 int 372 linux32_sys_signal(l, v, retval) 373 struct lwp *l; 374 void *v; 375 register_t *retval; 376 { 377 struct linux32_sys_signal_args /* { 378 syscallarg(int) signum; 379 syscallarg(linux32_handler_t) handler; 380 } */ *uap = v; 381 struct sigaction nbsa, obsa; 382 int error, sig; 383 384 *retval = -1; 385 386 sig = SCARG(uap, signum); 387 if (sig < 0 || sig >= LINUX32__NSIG) 388 return EINVAL; 389 390 nbsa.sa_handler = SCARG_P32(uap, handler); 391 sigemptyset(&nbsa.sa_mask); 392 nbsa.sa_flags = SA_RESETHAND | SA_NODEFER; 393 394 if ((error = sigaction1(l, linux32_to_native_signo[sig], 395 &nbsa, &obsa, NULL, 0)) != 0) 396 return error; 397 398 *retval = (int)(long)obsa.sa_handler; 399 return 0; 400 } 401