1 /*- 2 * Copyright (c) 1994-1995 S�ren Schmidt 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer 10 * in this position and unchanged. 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. The name of the author may not be used to endorse or promote products 15 * derived from this software withough specific prior written permission 16 * 17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 18 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 19 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 20 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 21 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 22 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 23 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 24 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 26 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27 * 28 * $FreeBSD$ 29 */ 30 31 #include <sys/param.h> 32 #include <sys/systm.h> 33 #include <sys/sysproto.h> 34 #include <sys/proc.h> 35 #include <sys/signalvar.h> 36 37 #include <machine/../linux/linux.h> 38 #include <machine/../linux/linux_proto.h> 39 #include <compat/linux/linux_signal.h> 40 #include <compat/linux/linux_util.h> 41 42 void 43 linux_to_bsd_sigset(linux_sigset_t *lss, sigset_t *bss) 44 { 45 int b, l; 46 47 SIGEMPTYSET(*bss); 48 bss->__bits[0] = lss->__bits[0] & ~((1U << LINUX_SIGTBLSZ) - 1); 49 bss->__bits[1] = lss->__bits[1]; 50 for (l = 1; l <= LINUX_SIGTBLSZ; l++) { 51 if (LINUX_SIGISMEMBER(*lss, l)) { 52 b = linux_to_bsd_signal[_SIG_IDX(l)]; 53 if (b) 54 SIGADDSET(*bss, b); 55 } 56 } 57 } 58 59 static void 60 bsd_to_linux_sigset(sigset_t *bss, linux_sigset_t *lss) 61 { 62 int b, l; 63 64 LINUX_SIGEMPTYSET(*lss); 65 lss->__bits[0] = bss->__bits[0] & ~((1U << LINUX_SIGTBLSZ) - 1); 66 lss->__bits[1] = bss->__bits[1]; 67 for (b = 1; b <= LINUX_SIGTBLSZ; b++) { 68 if (SIGISMEMBER(*bss, b)) { 69 l = bsd_to_linux_signal[_SIG_IDX(b)]; 70 if (l) 71 LINUX_SIGADDSET(*lss, l); 72 } 73 } 74 } 75 76 static void 77 linux_to_bsd_sigaction(linux_sigaction_t *lsa, struct sigaction *bsa) 78 { 79 80 linux_to_bsd_sigset(&lsa->lsa_mask, &bsa->sa_mask); 81 bsa->sa_handler = lsa->lsa_handler; 82 bsa->sa_flags = 0; 83 if (lsa->lsa_flags & LINUX_SA_NOCLDSTOP) 84 bsa->sa_flags |= SA_NOCLDSTOP; 85 if (lsa->lsa_flags & LINUX_SA_NOCLDWAIT) 86 bsa->sa_flags |= SA_NOCLDWAIT; 87 if (lsa->lsa_flags & LINUX_SA_SIGINFO) 88 bsa->sa_flags |= SA_SIGINFO; 89 if (lsa->lsa_flags & LINUX_SA_ONSTACK) 90 bsa->sa_flags |= SA_ONSTACK; 91 if (lsa->lsa_flags & LINUX_SA_RESTART) 92 bsa->sa_flags |= SA_RESTART; 93 if (lsa->lsa_flags & LINUX_SA_ONESHOT) 94 bsa->sa_flags |= SA_RESETHAND; 95 if (lsa->lsa_flags & LINUX_SA_NOMASK) 96 bsa->sa_flags |= SA_NODEFER; 97 } 98 99 static void 100 bsd_to_linux_sigaction(struct sigaction *bsa, linux_sigaction_t *lsa) 101 { 102 103 bsd_to_linux_sigset(&bsa->sa_mask, &lsa->lsa_mask); 104 lsa->lsa_handler = bsa->sa_handler; 105 lsa->lsa_restorer = NULL; /* unsupported */ 106 lsa->lsa_flags = 0; 107 if (bsa->sa_flags & SA_NOCLDSTOP) 108 lsa->lsa_flags |= LINUX_SA_NOCLDSTOP; 109 if (bsa->sa_flags & SA_NOCLDWAIT) 110 lsa->lsa_flags |= LINUX_SA_NOCLDWAIT; 111 if (bsa->sa_flags & SA_SIGINFO) 112 lsa->lsa_flags |= LINUX_SA_SIGINFO; 113 if (bsa->sa_flags & SA_ONSTACK) 114 lsa->lsa_flags |= LINUX_SA_ONSTACK; 115 if (bsa->sa_flags & SA_RESTART) 116 lsa->lsa_flags |= LINUX_SA_RESTART; 117 if (bsa->sa_flags & SA_RESETHAND) 118 lsa->lsa_flags |= LINUX_SA_ONESHOT; 119 if (bsa->sa_flags & SA_NODEFER) 120 lsa->lsa_flags |= LINUX_SA_NOMASK; 121 } 122 123 int 124 linux_do_sigaction(struct proc *p, int linux_sig, linux_sigaction_t *linux_nsa, 125 linux_sigaction_t *linux_osa) 126 { 127 struct sigaction *nsa, *osa; 128 struct sigaction_args sa_args; 129 int error; 130 caddr_t sg = stackgap_init(); 131 132 if (linux_sig <= 0 || linux_sig > LINUX_NSIG) 133 return (EINVAL); 134 135 if (linux_osa != NULL) 136 osa = stackgap_alloc(&sg, sizeof(struct sigaction)); 137 else 138 osa = NULL; 139 140 if (linux_nsa != NULL) { 141 nsa = stackgap_alloc(&sg, sizeof(struct sigaction)); 142 linux_to_bsd_sigaction(linux_nsa, nsa); 143 } 144 else 145 nsa = NULL; 146 147 if (linux_sig <= LINUX_SIGTBLSZ) 148 sa_args.sig = linux_to_bsd_signal[_SIG_IDX(linux_sig)]; 149 else 150 sa_args.sig = linux_sig; 151 152 sa_args.act = nsa; 153 sa_args.oact = osa; 154 error = sigaction(p, &sa_args); 155 if (error) 156 return (error); 157 158 if (linux_osa != NULL) 159 bsd_to_linux_sigaction(osa, linux_osa); 160 161 return (0); 162 } 163 164 int 165 linux_signal(struct proc *p, struct linux_signal_args *args) 166 { 167 linux_sigaction_t nsa, osa; 168 int error; 169 170 #ifdef DEBUG 171 printf("Linux-emul(%ld): signal(%d, %p)\n", 172 (long)p->p_pid, args->sig, (void *)args->handler); 173 #endif 174 175 nsa.lsa_handler = args->handler; 176 nsa.lsa_flags = LINUX_SA_ONESHOT | LINUX_SA_NOMASK; 177 LINUX_SIGEMPTYSET(nsa.lsa_mask); 178 179 error = linux_do_sigaction(p, args->sig, &nsa, &osa); 180 p->p_retval[0] = (int)osa.lsa_handler; 181 182 return (error); 183 } 184 185 int 186 linux_rt_sigaction(struct proc *p, struct linux_rt_sigaction_args *args) 187 { 188 linux_sigaction_t nsa, osa; 189 int error; 190 191 #ifdef DEBUG 192 printf("Linux-emul(%ld): rt_sigaction(%d, %p, %p, %d)\n", 193 (long)p->p_pid, args->sig, (void *)args->act, 194 (void *)args->oact, args->sigsetsize); 195 #endif 196 197 if (args->sigsetsize != sizeof(linux_sigset_t)) 198 return (EINVAL); 199 200 if (args->act != NULL) { 201 error = copyin(args->act, &nsa, sizeof(linux_sigaction_t)); 202 if (error) 203 return (error); 204 } 205 206 error = linux_do_sigaction(p, args->sig, 207 args->act ? &nsa : NULL, 208 args->oact ? &osa : NULL); 209 210 if (args->oact != NULL && !error) { 211 error = copyout(&osa, args->oact, sizeof(linux_sigaction_t)); 212 } 213 214 return (error); 215 } 216 217 static int 218 linux_do_sigprocmask(struct proc *p, int how, linux_sigset_t *new, 219 linux_sigset_t *old) 220 { 221 int error, s; 222 sigset_t mask; 223 224 error = 0; 225 p->p_retval[0] = 0; 226 227 if (old != NULL) 228 bsd_to_linux_sigset(&p->p_sigmask, old); 229 230 if (new != NULL) { 231 linux_to_bsd_sigset(new, &mask); 232 233 s = splhigh(); 234 235 switch (how) { 236 case LINUX_SIG_BLOCK: 237 SIGSETOR(p->p_sigmask, mask); 238 SIG_CANTMASK(p->p_sigmask); 239 break; 240 case LINUX_SIG_UNBLOCK: 241 SIGSETNAND(p->p_sigmask, mask); 242 break; 243 case LINUX_SIG_SETMASK: 244 p->p_sigmask = mask; 245 SIG_CANTMASK(p->p_sigmask); 246 break; 247 default: 248 error = EINVAL; 249 break; 250 } 251 252 splx(s); 253 } 254 255 return (error); 256 } 257 258 int 259 linux_sigprocmask(struct proc *p, struct linux_sigprocmask_args *args) 260 { 261 linux_osigset_t mask; 262 linux_sigset_t set, oset; 263 int error; 264 265 #ifdef DEBUG 266 printf("Linux-emul(%d): sigprocmask(%d, *, *)\n", p->p_pid, args->how); 267 #endif 268 269 if (args->mask != NULL) { 270 error = copyin(args->mask, &mask, sizeof(linux_osigset_t)); 271 if (error) 272 return (error); 273 LINUX_SIGEMPTYSET(set); 274 set.__bits[0] = mask; 275 } 276 277 error = linux_do_sigprocmask(p, args->how, 278 args->mask ? &set : NULL, 279 args->omask ? &oset : NULL); 280 281 if (args->omask != NULL && !error) { 282 mask = oset.__bits[0]; 283 error = copyout(&mask, args->omask, sizeof(linux_osigset_t)); 284 } 285 286 return (error); 287 } 288 289 int 290 linux_rt_sigprocmask(struct proc *p, struct linux_rt_sigprocmask_args *args) 291 { 292 linux_sigset_t set, oset; 293 int error; 294 295 #ifdef DEBUG 296 printf("Linux-emul(%ld): rt_sigprocmask(%d, %p, %p, %d)\n", 297 (long)p->p_pid, args->how, (void *)args->mask, 298 (void *)args->omask, args->sigsetsize); 299 #endif 300 301 if (args->sigsetsize != sizeof(linux_sigset_t)) 302 return EINVAL; 303 304 if (args->mask != NULL) { 305 error = copyin(args->mask, &set, sizeof(linux_sigset_t)); 306 if (error) 307 return (error); 308 } 309 310 error = linux_do_sigprocmask(p, args->how, 311 args->mask ? &set : NULL, 312 args->omask ? &oset : NULL); 313 314 if (args->omask != NULL && !error) { 315 error = copyout(&oset, args->omask, sizeof(linux_sigset_t)); 316 } 317 318 return (error); 319 } 320 321 int 322 linux_siggetmask(struct proc *p, struct linux_siggetmask_args *args) 323 { 324 linux_sigset_t mask; 325 326 #ifdef DEBUG 327 printf("Linux-emul(%d): siggetmask()\n", p->p_pid); 328 #endif 329 330 bsd_to_linux_sigset(&p->p_sigmask, &mask); 331 p->p_retval[0] = mask.__bits[0]; 332 return (0); 333 } 334 335 int 336 linux_sigsetmask(struct proc *p, struct linux_sigsetmask_args *args) 337 { 338 linux_sigset_t lset; 339 sigset_t bset; 340 int s; 341 342 #ifdef DEBUG 343 printf("Linux-emul(%ld): sigsetmask(%08lx)\n", 344 (long)p->p_pid, (unsigned long)args->mask); 345 #endif 346 347 bsd_to_linux_sigset(&p->p_sigmask, &lset); 348 p->p_retval[0] = lset.__bits[0]; 349 LINUX_SIGEMPTYSET(lset); 350 lset.__bits[0] = args->mask; 351 linux_to_bsd_sigset(&lset, &bset); 352 s = splhigh(); 353 p->p_sigmask = bset; 354 SIG_CANTMASK(p->p_sigmask); 355 splx(s); 356 return (0); 357 } 358 359 int 360 linux_sigpending(struct proc *p, struct linux_sigpending_args *args) 361 { 362 sigset_t bset; 363 linux_sigset_t lset; 364 linux_osigset_t mask; 365 366 #ifdef DEBUG 367 printf("Linux-emul(%d): sigpending(*)\n", p->p_pid); 368 #endif 369 370 bset = p->p_siglist; 371 SIGSETAND(bset, p->p_sigmask); 372 bsd_to_linux_sigset(&bset, &lset); 373 mask = lset.__bits[0]; 374 return (copyout(&mask, args->mask, sizeof(mask))); 375 } 376 377 int 378 linux_kill(struct proc *p, struct linux_kill_args *args) 379 { 380 struct kill_args /* { 381 int pid; 382 int signum; 383 } */ tmp; 384 385 #ifdef DEBUG 386 printf("Linux-emul(%d): kill(%d, %d)\n", 387 p->p_pid, args->pid, args->signum); 388 #endif 389 390 /* 391 * Allow signal 0 as a means to check for privileges 392 */ 393 if (args->signum < 0 || args->signum > LINUX_NSIG) 394 return EINVAL; 395 396 if (args->signum > 0 && args->signum <= LINUX_SIGTBLSZ) 397 tmp.signum = linux_to_bsd_signal[_SIG_IDX(args->signum)]; 398 else 399 tmp.signum = args->signum; 400 401 tmp.pid = args->pid; 402 return (kill(p, &tmp)); 403 } 404