1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License (the "License"). 6 * You may not use this file except in compliance with the License. 7 * 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9 * or http://www.opensolaris.org/os/licensing. 10 * See the License for the specific language governing permissions 11 * and limitations under the License. 12 * 13 * When distributing Covered Code, include this CDDL HEADER in each 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15 * If applicable, add the following below this CDDL HEADER, with the 16 * fields enclosed by brackets "[]" replaced with your own identifying 17 * information: Portions Copyright [yyyy] [name of copyright owner] 18 * 19 * CDDL HEADER END 20 */ 21 22 /* 23 * Copyright 2006 Sun Microsystems, Inc. All rights reserved. 24 * Use is subject to license terms. 25 */ 26 27 /* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */ 28 29 #pragma ident "%Z%%M% %I% %E% SMI" 30 31 #include <sys/param.h> 32 #include <sys/types.h> 33 #include <sys/sysmacros.h> 34 #include <sys/systm.h> 35 #include <sys/errno.h> 36 #include <sys/proc.h> 37 #include <sys/procset.h> 38 #include <sys/fault.h> 39 #include <sys/signal.h> 40 #include <sys/siginfo.h> 41 #include <sys/debug.h> 42 43 static int 44 sigqkill(pid_t pid, sigsend_t *sigsend) 45 { 46 proc_t *p; 47 int error; 48 49 if ((uint_t)sigsend->sig >= NSIG) 50 return (EINVAL); 51 52 if (pid == -1) { 53 procset_t set; 54 55 setprocset(&set, POP_AND, P_ALL, P_MYID, P_ALL, P_MYID); 56 error = sigsendset(&set, sigsend); 57 } else if (pid > 0) { 58 mutex_enter(&pidlock); 59 if ((p = prfind(pid)) == NULL || p->p_stat == SIDL) 60 error = ESRCH; 61 else { 62 error = sigsendproc(p, sigsend); 63 if (error == 0 && sigsend->perm == 0) 64 error = EPERM; 65 } 66 mutex_exit(&pidlock); 67 } else { 68 int nfound = 0; 69 pid_t pgid; 70 71 if (pid == 0) 72 pgid = ttoproc(curthread)->p_pgrp; 73 else 74 pgid = -pid; 75 76 error = 0; 77 mutex_enter(&pidlock); 78 for (p = pgfind(pgid); p && !error; p = p->p_pglink) { 79 if (p->p_stat != SIDL) { 80 nfound++; 81 error = sigsendproc(p, sigsend); 82 } 83 } 84 mutex_exit(&pidlock); 85 if (nfound == 0) 86 error = ESRCH; 87 else if (error == 0 && sigsend->perm == 0) 88 error = EPERM; 89 } 90 91 return (error); 92 } 93 94 95 /* 96 * for implementations that don't require binary compatibility, 97 * the kill system call may be made into a library call to the 98 * sigsend system call 99 */ 100 int 101 kill(pid_t pid, int sig) 102 { 103 int error; 104 sigsend_t v; 105 106 bzero(&v, sizeof (v)); 107 v.sig = sig; 108 v.checkperm = 1; 109 v.sicode = SI_USER; 110 if ((error = sigqkill(pid, &v)) != 0) 111 return (set_errno(error)); 112 return (0); 113 } 114 115 /* 116 * The handling of small unions, like the sigval argument to sigqueue, 117 * is architecture dependent. We have adopted the convention that the 118 * value itself is passed in the storage which crosses the kernel 119 * protection boundary. This procedure will accept a scalar argument, 120 * and store it in the appropriate value member of the sigsend_t structure. 121 */ 122 int 123 sigqueue(pid_t pid, int sig, /* union sigval */ void *value, 124 int si_code, int block) 125 { 126 int error; 127 sigsend_t v; 128 sigqhdr_t *sqh; 129 proc_t *p = curproc; 130 131 /* The si_code value must indicate the signal will be queued */ 132 if (pid <= 0 || !sigwillqueue(sig, si_code)) 133 return (set_errno(EINVAL)); 134 135 if ((sqh = p->p_sigqhdr) == NULL) { 136 /* Allocate sigqueue pool first time */ 137 sqh = sigqhdralloc(sizeof (sigqueue_t), _SIGQUEUE_MAX); 138 mutex_enter(&p->p_lock); 139 if (p->p_sigqhdr == NULL) { 140 /* hang the pool head on proc */ 141 p->p_sigqhdr = sqh; 142 } else { 143 /* another lwp allocated the pool, free ours */ 144 sigqhdrfree(sqh); 145 sqh = p->p_sigqhdr; 146 } 147 mutex_exit(&p->p_lock); 148 } 149 150 do { 151 bzero(&v, sizeof (v)); 152 v.sig = sig; 153 v.checkperm = 1; 154 v.sicode = si_code; 155 v.value.sival_ptr = value; 156 if ((error = sigqkill(pid, &v)) != EAGAIN || !block) 157 break; 158 /* block waiting for another chance to allocate a sigqueue_t */ 159 mutex_enter(&sqh->sqb_lock); 160 while (sqh->sqb_count == 0) { 161 if (!cv_wait_sig(&sqh->sqb_cv, &sqh->sqb_lock)) { 162 error = EINTR; 163 break; 164 } 165 } 166 mutex_exit(&sqh->sqb_lock); 167 } while (error == EAGAIN); 168 169 if (error) 170 return (set_errno(error)); 171 return (0); 172 } 173 174 #ifdef _SYSCALL32_IMPL 175 /* 176 * sigqueue32 - System call entry point for 32-bit callers on LP64 kernel, 177 * needed to handle the 32-bit sigvals as correctly as we can. We always 178 * assume that a 32-bit caller is passing an int. A 64-bit recipient 179 * that expects an int will therefore get it correctly. A 32-bit 180 * recipient will also get it correctly since siginfo_kto32() uses 181 * sival_int in the conversion. Since a 32-bit pointer has the same 182 * size and address in the sigval, it also converts correctly so that 183 * two 32-bit apps can exchange a pointer value. However, this means 184 * that a pointer sent by a 32-bit caller will be seen in the upper half 185 * by a 64-bit recipient, and only the upper half of a 64-bit pointer will 186 * be seen by a 32-bit recipient. This is the best solution that does 187 * not require severe hacking of the sigval union. Anyways, what it 188 * means to be sending pointers between processes with dissimilar 189 * models is unclear. 190 */ 191 int 192 sigqueue32(pid_t pid, int sig, /* union sigval32 */ caddr32_t value, 193 int si_code, int block) 194 { 195 union sigval sv; 196 197 bzero(&sv, sizeof (sv)); 198 sv.sival_int = (int)value; 199 return (sigqueue(pid, sig, sv.sival_ptr, si_code, block)); 200 } 201 #endif