xref: /freebsd/sys/kern/sysv_ipc.c (revision b72029589e64e04b8f9714ad8535b723276e2e02)
19454b2d8SWarner Losh /*-
28a36da99SPedro F. Giffuni  * SPDX-License-Identifier: BSD-4-Clause
38a36da99SPedro F. Giffuni  *
43d903220SDoug Rabson  * Copyright (c) 1994 Herb Peyerl <hpeyerl@novatel.ca>
5b12c55abSRobert Watson  * Copyright (c) 2006 nCircle Network Security, Inc.
63d903220SDoug Rabson  * All rights reserved.
73d903220SDoug Rabson  *
8b12c55abSRobert Watson  * This software was developed by Robert N. M. Watson for the TrustedBSD
9b12c55abSRobert Watson  * Project under contract to nCircle Network Security, Inc.
10b12c55abSRobert Watson  *
113d903220SDoug Rabson  * Redistribution and use in source and binary forms, with or without
123d903220SDoug Rabson  * modification, are permitted provided that the following conditions
133d903220SDoug Rabson  * are met:
143d903220SDoug Rabson  * 1. Redistributions of source code must retain the above copyright
153d903220SDoug Rabson  *    notice, this list of conditions and the following disclaimer.
163d903220SDoug Rabson  * 2. Redistributions in binary form must reproduce the above copyright
173d903220SDoug Rabson  *    notice, this list of conditions and the following disclaimer in the
183d903220SDoug Rabson  *    documentation and/or other materials provided with the distribution.
193d903220SDoug Rabson  * 3. All advertising materials mentioning features or use of this software
203d903220SDoug Rabson  *    must display the following acknowledgement:
213d903220SDoug Rabson  *      This product includes software developed by Herb Peyerl.
223d903220SDoug Rabson  * 4. The name of Herb Peyerl may not be used to endorse or promote products
233d903220SDoug Rabson  *    derived from this software without specific prior written permission.
243d903220SDoug Rabson  *
253d903220SDoug Rabson  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
263d903220SDoug Rabson  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
273d903220SDoug Rabson  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
283d903220SDoug Rabson  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
293d903220SDoug Rabson  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
303d903220SDoug Rabson  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
313d903220SDoug Rabson  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
323d903220SDoug Rabson  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
333d903220SDoug Rabson  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
343d903220SDoug Rabson  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
350879ca72SPedro F. Giffuni  *
360879ca72SPedro F. Giffuni  * $NetBSD: sysv_ipc.c,v 1.9 1995/06/02 19:04:22 mycroft Exp $
373d903220SDoug Rabson  */
383d903220SDoug Rabson 
39511b67b7SGarrett Wollman #include "opt_sysvipc.h"
40511b67b7SGarrett Wollman 
413d903220SDoug Rabson #include <sys/param.h>
42cf9fa8e7SPoul-Henning Kamp #include <sys/systm.h>
4378525ce3SAlfred Perlstein #include <sys/sem.h>
4478525ce3SAlfred Perlstein #include <sys/shm.h>
4581090119SPeter Wemm #include <sys/ipc.h>
46b12c55abSRobert Watson #include <sys/priv.h>
471c308b81SPoul-Henning Kamp #include <sys/proc.h>
48b7f5d5b5SBruce Evans #include <sys/ucred.h>
4981090119SPeter Wemm 
505408c6dbSMateusz Guzik #ifndef SYSVSHM
5178525ce3SAlfred Perlstein void (*shmfork_hook)(struct proc *, struct proc *) = NULL;
523db161e0SMatthew Dillon void (*shmexit_hook)(struct vmspace *) = NULL;
53*b7202958SKonstantin Belousov void (*shmobjinfo_hook)(struct vm_object *, key_t *key,
54*b7202958SKonstantin Belousov     unsigned short *seq) = NULL;
5578525ce3SAlfred Perlstein 
5678525ce3SAlfred Perlstein /* called from kern_fork.c */
5778525ce3SAlfred Perlstein void
shmfork(struct proc * p1,struct proc * p2)58836e4b37SKonstantin Belousov shmfork(struct proc *p1, struct proc *p2)
5978525ce3SAlfred Perlstein {
6078525ce3SAlfred Perlstein 	if (shmfork_hook != NULL)
6178525ce3SAlfred Perlstein 		shmfork_hook(p1, p2);
6278525ce3SAlfred Perlstein }
6378525ce3SAlfred Perlstein 
6478525ce3SAlfred Perlstein /* called from kern_exit.c */
6578525ce3SAlfred Perlstein void
shmexit(struct vmspace * vm)663db161e0SMatthew Dillon shmexit(struct vmspace *vm)
6778525ce3SAlfred Perlstein {
6878525ce3SAlfred Perlstein 	if (shmexit_hook != NULL)
693db161e0SMatthew Dillon 		shmexit_hook(vm);
7078525ce3SAlfred Perlstein }
71*b7202958SKonstantin Belousov 
72*b7202958SKonstantin Belousov void
shmobjinfo(struct vm_object * obj,key_t * key,unsigned short * seq)73*b7202958SKonstantin Belousov shmobjinfo(struct vm_object *obj, key_t *key, unsigned short *seq)
74*b7202958SKonstantin Belousov {
75*b7202958SKonstantin Belousov 	*key = 0;	/* For non-present sysvshm.ko */
76*b7202958SKonstantin Belousov 	*seq = 0;
77*b7202958SKonstantin Belousov 	if (shmobjinfo_hook != NULL)
78*b7202958SKonstantin Belousov 		shmobjinfo_hook(obj, key, seq);
79*b7202958SKonstantin Belousov }
805408c6dbSMateusz Guzik #endif
813d903220SDoug Rabson 
823d903220SDoug Rabson /*
83857a6005SRobert Watson  * Check for IPC permission.
84857a6005SRobert Watson  *
85857a6005SRobert Watson  * Note: The MAC Framework does not require any modifications to the
86857a6005SRobert Watson  * ipcperm() function, as access control checks are performed throughout the
87857a6005SRobert Watson  * implementation of each primitive.  Those entry point calls complement the
88b12c55abSRobert Watson  * ipcperm() discertionary checks.  Unlike file system discretionary access
89b12c55abSRobert Watson  * control, the original create of an object is given the same rights as the
90b12c55abSRobert Watson  * current owner.
913d903220SDoug Rabson  */
923d903220SDoug Rabson int
ipcperm(struct thread * td,struct ipc_perm * perm,int acc_mode)93b12c55abSRobert Watson ipcperm(struct thread *td, struct ipc_perm *perm, int acc_mode)
943d903220SDoug Rabson {
95a854ed98SJohn Baldwin 	struct ucred *cred = td->td_ucred;
96b12c55abSRobert Watson 	int error, obj_mode, dac_granted, priv_granted;
973d903220SDoug Rabson 
98b12c55abSRobert Watson 	dac_granted = 0;
99b12c55abSRobert Watson 	if (cred->cr_uid == perm->cuid || cred->cr_uid == perm->uid) {
100b12c55abSRobert Watson 		obj_mode = perm->mode;
101b12c55abSRobert Watson 		dac_granted |= IPC_M;
102b12c55abSRobert Watson 	} else if (groupmember(perm->gid, cred) ||
103b12c55abSRobert Watson 	    groupmember(perm->cgid, cred)) {
104b12c55abSRobert Watson 		obj_mode = perm->mode;
105b12c55abSRobert Watson 		obj_mode <<= 3;
106ef2e1ca5SRobert Watson 	} else {
107b12c55abSRobert Watson 		obj_mode = perm->mode;
108b12c55abSRobert Watson 		obj_mode <<= 6;
109acd3428bSRobert Watson 	}
110acd3428bSRobert Watson 
111b12c55abSRobert Watson 	/*
112b12c55abSRobert Watson 	 * While the System V IPC permission model allows IPC_M to be
113b12c55abSRobert Watson 	 * granted, as part of the mode, our implementation requires
114b12c55abSRobert Watson 	 * privilege to adminster the object if not the owner or creator.
115b12c55abSRobert Watson 	 */
116b12c55abSRobert Watson #if 0
117b12c55abSRobert Watson 	if (obj_mode & IPC_M)
118b12c55abSRobert Watson 		dac_granted |= IPC_M;
119b12c55abSRobert Watson #endif
120b12c55abSRobert Watson 	if (obj_mode & IPC_R)
121b12c55abSRobert Watson 		dac_granted |= IPC_R;
122b12c55abSRobert Watson 	if (obj_mode & IPC_W)
123b12c55abSRobert Watson 		dac_granted |= IPC_W;
124b12c55abSRobert Watson 
125b12c55abSRobert Watson 	/*
126b12c55abSRobert Watson 	 * Simple case: all required rights are granted by DAC.
127b12c55abSRobert Watson 	 */
128b12c55abSRobert Watson 	if ((dac_granted & acc_mode) == acc_mode)
1299ac57410SRobert Watson 		return (0);
130b12c55abSRobert Watson 
131b12c55abSRobert Watson 	/*
132b12c55abSRobert Watson 	 * Privilege is required to satisfy the request.
133b12c55abSRobert Watson 	 */
134b12c55abSRobert Watson 	priv_granted = 0;
135b12c55abSRobert Watson 	if ((acc_mode & IPC_M) && !(dac_granted & IPC_M)) {
13632f9753cSRobert Watson 		error = priv_check(td, PRIV_IPC_ADMIN);
137b12c55abSRobert Watson 		if (error == 0)
138b12c55abSRobert Watson 			priv_granted |= IPC_M;
139b12c55abSRobert Watson 	}
140b12c55abSRobert Watson 
141b12c55abSRobert Watson 	if ((acc_mode & IPC_R) && !(dac_granted & IPC_R)) {
14232f9753cSRobert Watson 		error = priv_check(td, PRIV_IPC_READ);
143b12c55abSRobert Watson 		if (error == 0)
144b12c55abSRobert Watson 			priv_granted |= IPC_R;
145b12c55abSRobert Watson 	}
146b12c55abSRobert Watson 
147b12c55abSRobert Watson 	if ((acc_mode & IPC_W) && !(dac_granted & IPC_W)) {
14832f9753cSRobert Watson 		error = priv_check(td, PRIV_IPC_WRITE);
149b12c55abSRobert Watson 		if (error == 0)
150b12c55abSRobert Watson 			priv_granted |= IPC_W;
151b12c55abSRobert Watson 	}
152b12c55abSRobert Watson 
153b12c55abSRobert Watson 	if (((dac_granted | priv_granted) & acc_mode) == acc_mode)
154b12c55abSRobert Watson 		return (0);
155b12c55abSRobert Watson 	else
156b12c55abSRobert Watson 		return (EACCES);
1579ac57410SRobert Watson }
158b648d480SJohn Baldwin 
159b648d480SJohn Baldwin #if defined(COMPAT_FREEBSD4) || defined(COMPAT_FREEBSD5) || \
160b648d480SJohn Baldwin     defined(COMPAT_FREEBSD6) || defined(COMPAT_FREEBSD7)
161b648d480SJohn Baldwin void
ipcperm_old2new(struct ipc_perm_old * old,struct ipc_perm * new)162b648d480SJohn Baldwin ipcperm_old2new(struct ipc_perm_old *old, struct ipc_perm *new)
163b648d480SJohn Baldwin {
164b648d480SJohn Baldwin 
165b648d480SJohn Baldwin 	new->cuid = old->cuid;
166b648d480SJohn Baldwin 	new->cgid = old->cgid;
167b648d480SJohn Baldwin 	new->uid = old->uid;
168b648d480SJohn Baldwin 	new->gid = old->gid;
169b648d480SJohn Baldwin 	new->mode = old->mode;
170b648d480SJohn Baldwin 	new->seq = old->seq;
171b648d480SJohn Baldwin 	new->key = old->key;
172b648d480SJohn Baldwin }
173b648d480SJohn Baldwin 
174b648d480SJohn Baldwin void
ipcperm_new2old(struct ipc_perm * new,struct ipc_perm_old * old)175b648d480SJohn Baldwin ipcperm_new2old(struct ipc_perm *new, struct ipc_perm_old *old)
176b648d480SJohn Baldwin {
177b648d480SJohn Baldwin 
178b648d480SJohn Baldwin 	/* XXX: How to handle ID's > USHORT_MAX? */
179b648d480SJohn Baldwin 	old->cuid = new->cuid;
180b648d480SJohn Baldwin 	old->cgid = new->cgid;
181b648d480SJohn Baldwin 	old->uid = new->uid;
182b648d480SJohn Baldwin 	old->gid = new->gid;
183b648d480SJohn Baldwin 	old->mode = new->mode;
184b648d480SJohn Baldwin 	old->seq = new->seq;
185b648d480SJohn Baldwin 	old->key = new->key;
186b648d480SJohn Baldwin }
187b648d480SJohn Baldwin #endif
1884cfc39cfSKonstantin Belousov 
1894cfc39cfSKonstantin Belousov #ifdef COMPAT_FREEBSD32
1904cfc39cfSKonstantin Belousov #include <sys/mount.h>
1914cfc39cfSKonstantin Belousov #include <sys/socket.h>
1924cfc39cfSKonstantin Belousov #include <compat/freebsd32/freebsd32.h>
1934cfc39cfSKonstantin Belousov #include <compat/freebsd32/freebsd32_ipc.h>
1944cfc39cfSKonstantin Belousov #include <compat/freebsd32/freebsd32_proto.h>
1954cfc39cfSKonstantin Belousov #include <compat/freebsd32/freebsd32_signal.h>
1964cfc39cfSKonstantin Belousov #include <compat/freebsd32/freebsd32_syscall.h>
1974cfc39cfSKonstantin Belousov #include <compat/freebsd32/freebsd32_util.h>
1984cfc39cfSKonstantin Belousov 
1994cfc39cfSKonstantin Belousov #if defined(COMPAT_FREEBSD4) || defined(COMPAT_FREEBSD5) || \
2004cfc39cfSKonstantin Belousov     defined(COMPAT_FREEBSD6) || defined(COMPAT_FREEBSD7)
2014cfc39cfSKonstantin Belousov void
freebsd32_ipcperm_old_in(struct ipc_perm_old32 * ip32,struct ipc_perm * ip)2023b0cd7e5SBrooks Davis freebsd32_ipcperm_old_in(struct ipc_perm_old32 *ip32, struct ipc_perm *ip)
2034cfc39cfSKonstantin Belousov {
2044cfc39cfSKonstantin Belousov 
2054cfc39cfSKonstantin Belousov 	CP(*ip32, *ip, cuid);
2064cfc39cfSKonstantin Belousov 	CP(*ip32, *ip, cgid);
2074cfc39cfSKonstantin Belousov 	CP(*ip32, *ip, uid);
2084cfc39cfSKonstantin Belousov 	CP(*ip32, *ip, gid);
2094cfc39cfSKonstantin Belousov 	CP(*ip32, *ip, mode);
2104cfc39cfSKonstantin Belousov 	CP(*ip32, *ip, seq);
2114cfc39cfSKonstantin Belousov 	CP(*ip32, *ip, key);
2124cfc39cfSKonstantin Belousov }
2134cfc39cfSKonstantin Belousov 
2144cfc39cfSKonstantin Belousov void
freebsd32_ipcperm_old_out(struct ipc_perm * ip,struct ipc_perm_old32 * ip32)2153b0cd7e5SBrooks Davis freebsd32_ipcperm_old_out(struct ipc_perm *ip, struct ipc_perm_old32 *ip32)
2164cfc39cfSKonstantin Belousov {
2174cfc39cfSKonstantin Belousov 
2184cfc39cfSKonstantin Belousov 	CP(*ip, *ip32, cuid);
2194cfc39cfSKonstantin Belousov 	CP(*ip, *ip32, cgid);
2204cfc39cfSKonstantin Belousov 	CP(*ip, *ip32, uid);
2214cfc39cfSKonstantin Belousov 	CP(*ip, *ip32, gid);
2224cfc39cfSKonstantin Belousov 	CP(*ip, *ip32, mode);
2234cfc39cfSKonstantin Belousov 	CP(*ip, *ip32, seq);
2244cfc39cfSKonstantin Belousov 	CP(*ip, *ip32, key);
2254cfc39cfSKonstantin Belousov }
2264cfc39cfSKonstantin Belousov #endif
2274cfc39cfSKonstantin Belousov 
2284cfc39cfSKonstantin Belousov void
freebsd32_ipcperm_in(struct ipc_perm32 * ip32,struct ipc_perm * ip)2294cfc39cfSKonstantin Belousov freebsd32_ipcperm_in(struct ipc_perm32 *ip32, struct ipc_perm *ip)
2304cfc39cfSKonstantin Belousov {
2314cfc39cfSKonstantin Belousov 
2324cfc39cfSKonstantin Belousov 	CP(*ip32, *ip, cuid);
2334cfc39cfSKonstantin Belousov 	CP(*ip32, *ip, cgid);
2344cfc39cfSKonstantin Belousov 	CP(*ip32, *ip, uid);
2354cfc39cfSKonstantin Belousov 	CP(*ip32, *ip, gid);
2364cfc39cfSKonstantin Belousov 	CP(*ip32, *ip, mode);
2374cfc39cfSKonstantin Belousov 	CP(*ip32, *ip, seq);
2384cfc39cfSKonstantin Belousov 	CP(*ip32, *ip, key);
2394cfc39cfSKonstantin Belousov }
2404cfc39cfSKonstantin Belousov 
2414cfc39cfSKonstantin Belousov void
freebsd32_ipcperm_out(struct ipc_perm * ip,struct ipc_perm32 * ip32)2424cfc39cfSKonstantin Belousov freebsd32_ipcperm_out(struct ipc_perm *ip, struct ipc_perm32 *ip32)
2434cfc39cfSKonstantin Belousov {
2444cfc39cfSKonstantin Belousov 
2454cfc39cfSKonstantin Belousov 	CP(*ip, *ip32, cuid);
2464cfc39cfSKonstantin Belousov 	CP(*ip, *ip32, cgid);
2474cfc39cfSKonstantin Belousov 	CP(*ip, *ip32, uid);
2484cfc39cfSKonstantin Belousov 	CP(*ip, *ip32, gid);
2494cfc39cfSKonstantin Belousov 	CP(*ip, *ip32, mode);
2504cfc39cfSKonstantin Belousov 	CP(*ip, *ip32, seq);
2514cfc39cfSKonstantin Belousov 	CP(*ip, *ip32, key);
2524cfc39cfSKonstantin Belousov }
2534cfc39cfSKonstantin Belousov #endif
254