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 #include <sys/param.h> 30 #include <sys/types.h> 31 #include <sys/sysmacros.h> 32 #include <sys/systm.h> 33 #include <sys/errno.h> 34 #include <sys/proc.h> 35 #include <sys/procset.h> 36 #include <sys/fault.h> 37 #include <sys/signal.h> 38 #include <sys/siginfo.h> 39 #include <sys/debug.h> 40 41 extern rctl_hndl_t rc_process_sigqueue; 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 rlim64_t sigqsz_max; 137 138 mutex_enter(&p->p_lock); 139 sigqsz_max = rctl_enforced_value(rc_process_sigqueue, 140 p->p_rctls, p); 141 mutex_exit(&p->p_lock); 142 143 /* Allocate sigqueue pool first time */ 144 sqh = sigqhdralloc(sizeof (sigqueue_t), (uint_t)sigqsz_max); 145 mutex_enter(&p->p_lock); 146 if (p->p_sigqhdr == NULL) { 147 /* hang the pool head on proc */ 148 p->p_sigqhdr = sqh; 149 } else { 150 /* another lwp allocated the pool, free ours */ 151 sigqhdrfree(sqh); 152 sqh = p->p_sigqhdr; 153 } 154 mutex_exit(&p->p_lock); 155 } 156 157 do { 158 bzero(&v, sizeof (v)); 159 v.sig = sig; 160 v.checkperm = 1; 161 v.sicode = si_code; 162 v.value.sival_ptr = value; 163 if ((error = sigqkill(pid, &v)) != EAGAIN || !block) 164 break; 165 /* block waiting for another chance to allocate a sigqueue_t */ 166 mutex_enter(&sqh->sqb_lock); 167 while (sqh->sqb_count == 0) { 168 if (!cv_wait_sig(&sqh->sqb_cv, &sqh->sqb_lock)) { 169 error = EINTR; 170 break; 171 } 172 } 173 mutex_exit(&sqh->sqb_lock); 174 } while (error == EAGAIN); 175 176 if (error) 177 return (set_errno(error)); 178 return (0); 179 } 180 181 #ifdef _SYSCALL32_IMPL 182 /* 183 * sigqueue32 - System call entry point for 32-bit callers on LP64 kernel, 184 * needed to handle the 32-bit sigvals as correctly as we can. We always 185 * assume that a 32-bit caller is passing an int. A 64-bit recipient 186 * that expects an int will therefore get it correctly. A 32-bit 187 * recipient will also get it correctly since siginfo_kto32() uses 188 * sival_int in the conversion. Since a 32-bit pointer has the same 189 * size and address in the sigval, it also converts correctly so that 190 * two 32-bit apps can exchange a pointer value. However, this means 191 * that a pointer sent by a 32-bit caller will be seen in the upper half 192 * by a 64-bit recipient, and only the upper half of a 64-bit pointer will 193 * be seen by a 32-bit recipient. This is the best solution that does 194 * not require severe hacking of the sigval union. Anyways, what it 195 * means to be sending pointers between processes with dissimilar 196 * models is unclear. 197 */ 198 int 199 sigqueue32(pid_t pid, int sig, /* union sigval32 */ caddr32_t value, 200 int si_code, int block) 201 { 202 union sigval sv; 203 204 bzero(&sv, sizeof (sv)); 205 sv.sival_int = (int)value; 206 return (sigqueue(pid, sig, sv.sival_ptr, si_code, block)); 207 } 208 #endif