xref: /freebsd/sys/kern/sysv_ipc.c (revision 0879ca728ab341bead4800d3924c0ee859b6fd98)
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.
35*0879ca72SPedro F. Giffuni  *
36*0879ca72SPedro F. Giffuni  * $NetBSD: sysv_ipc.c,v 1.9 1995/06/02 19:04:22 mycroft Exp $
373d903220SDoug Rabson  */
383d903220SDoug Rabson 
39677b542eSDavid E. O'Brien #include <sys/cdefs.h>
40677b542eSDavid E. O'Brien __FBSDID("$FreeBSD$");
41677b542eSDavid E. O'Brien 
42b648d480SJohn Baldwin #include "opt_compat.h"
43511b67b7SGarrett Wollman #include "opt_sysvipc.h"
44511b67b7SGarrett Wollman 
453d903220SDoug Rabson #include <sys/param.h>
46cf9fa8e7SPoul-Henning Kamp #include <sys/systm.h>
4778525ce3SAlfred Perlstein #include <sys/sem.h>
4878525ce3SAlfred Perlstein #include <sys/shm.h>
4981090119SPeter Wemm #include <sys/ipc.h>
50b12c55abSRobert Watson #include <sys/priv.h>
511c308b81SPoul-Henning Kamp #include <sys/proc.h>
52b7f5d5b5SBruce Evans #include <sys/ucred.h>
5381090119SPeter Wemm 
5478525ce3SAlfred Perlstein void (*shmfork_hook)(struct proc *, struct proc *) = NULL;
553db161e0SMatthew Dillon void (*shmexit_hook)(struct vmspace *) = NULL;
5678525ce3SAlfred Perlstein 
5778525ce3SAlfred Perlstein /* called from kern_fork.c */
5878525ce3SAlfred Perlstein void
5978525ce3SAlfred Perlstein shmfork(p1, p2)
6078525ce3SAlfred Perlstein 	struct proc *p1, *p2;
6178525ce3SAlfred Perlstein {
6278525ce3SAlfred Perlstein 
6378525ce3SAlfred Perlstein 	if (shmfork_hook != NULL)
6478525ce3SAlfred Perlstein 		shmfork_hook(p1, p2);
6578525ce3SAlfred Perlstein 	return;
6678525ce3SAlfred Perlstein }
6778525ce3SAlfred Perlstein 
6878525ce3SAlfred Perlstein /* called from kern_exit.c */
6978525ce3SAlfred Perlstein void
703db161e0SMatthew Dillon shmexit(struct vmspace *vm)
7178525ce3SAlfred Perlstein {
7278525ce3SAlfred Perlstein 
7378525ce3SAlfred Perlstein 	if (shmexit_hook != NULL)
743db161e0SMatthew Dillon 		shmexit_hook(vm);
7578525ce3SAlfred Perlstein 	return;
7678525ce3SAlfred Perlstein }
773d903220SDoug Rabson 
783d903220SDoug Rabson /*
79857a6005SRobert Watson  * Check for IPC permission.
80857a6005SRobert Watson  *
81857a6005SRobert Watson  * Note: The MAC Framework does not require any modifications to the
82857a6005SRobert Watson  * ipcperm() function, as access control checks are performed throughout the
83857a6005SRobert Watson  * implementation of each primitive.  Those entry point calls complement the
84b12c55abSRobert Watson  * ipcperm() discertionary checks.  Unlike file system discretionary access
85b12c55abSRobert Watson  * control, the original create of an object is given the same rights as the
86b12c55abSRobert Watson  * current owner.
873d903220SDoug Rabson  */
883d903220SDoug Rabson int
89b12c55abSRobert Watson ipcperm(struct thread *td, struct ipc_perm *perm, int acc_mode)
903d903220SDoug Rabson {
91a854ed98SJohn Baldwin 	struct ucred *cred = td->td_ucred;
92b12c55abSRobert Watson 	int error, obj_mode, dac_granted, priv_granted;
933d903220SDoug Rabson 
94b12c55abSRobert Watson 	dac_granted = 0;
95b12c55abSRobert Watson 	if (cred->cr_uid == perm->cuid || cred->cr_uid == perm->uid) {
96b12c55abSRobert Watson 		obj_mode = perm->mode;
97b12c55abSRobert Watson 		dac_granted |= IPC_M;
98b12c55abSRobert Watson 	} else if (groupmember(perm->gid, cred) ||
99b12c55abSRobert Watson 	    groupmember(perm->cgid, cred)) {
100b12c55abSRobert Watson 		obj_mode = perm->mode;
101b12c55abSRobert Watson 		obj_mode <<= 3;
102ef2e1ca5SRobert Watson 	} else {
103b12c55abSRobert Watson 		obj_mode = perm->mode;
104b12c55abSRobert Watson 		obj_mode <<= 6;
105acd3428bSRobert Watson 	}
106acd3428bSRobert Watson 
107b12c55abSRobert Watson 	/*
108b12c55abSRobert Watson 	 * While the System V IPC permission model allows IPC_M to be
109b12c55abSRobert Watson 	 * granted, as part of the mode, our implementation requires
110b12c55abSRobert Watson 	 * privilege to adminster the object if not the owner or creator.
111b12c55abSRobert Watson 	 */
112b12c55abSRobert Watson #if 0
113b12c55abSRobert Watson 	if (obj_mode & IPC_M)
114b12c55abSRobert Watson 		dac_granted |= IPC_M;
115b12c55abSRobert Watson #endif
116b12c55abSRobert Watson 	if (obj_mode & IPC_R)
117b12c55abSRobert Watson 		dac_granted |= IPC_R;
118b12c55abSRobert Watson 	if (obj_mode & IPC_W)
119b12c55abSRobert Watson 		dac_granted |= IPC_W;
120b12c55abSRobert Watson 
121b12c55abSRobert Watson 	/*
122b12c55abSRobert Watson 	 * Simple case: all required rights are granted by DAC.
123b12c55abSRobert Watson 	 */
124b12c55abSRobert Watson 	if ((dac_granted & acc_mode) == acc_mode)
1259ac57410SRobert Watson 		return (0);
126b12c55abSRobert Watson 
127b12c55abSRobert Watson 	/*
128b12c55abSRobert Watson 	 * Privilege is required to satisfy the request.
129b12c55abSRobert Watson 	 */
130b12c55abSRobert Watson 	priv_granted = 0;
131b12c55abSRobert Watson 	if ((acc_mode & IPC_M) && !(dac_granted & IPC_M)) {
13232f9753cSRobert Watson 		error = priv_check(td, PRIV_IPC_ADMIN);
133b12c55abSRobert Watson 		if (error == 0)
134b12c55abSRobert Watson 			priv_granted |= IPC_M;
135b12c55abSRobert Watson 	}
136b12c55abSRobert Watson 
137b12c55abSRobert Watson 	if ((acc_mode & IPC_R) && !(dac_granted & IPC_R)) {
13832f9753cSRobert Watson 		error = priv_check(td, PRIV_IPC_READ);
139b12c55abSRobert Watson 		if (error == 0)
140b12c55abSRobert Watson 			priv_granted |= IPC_R;
141b12c55abSRobert Watson 	}
142b12c55abSRobert Watson 
143b12c55abSRobert Watson 	if ((acc_mode & IPC_W) && !(dac_granted & IPC_W)) {
14432f9753cSRobert Watson 		error = priv_check(td, PRIV_IPC_WRITE);
145b12c55abSRobert Watson 		if (error == 0)
146b12c55abSRobert Watson 			priv_granted |= IPC_W;
147b12c55abSRobert Watson 	}
148b12c55abSRobert Watson 
149b12c55abSRobert Watson 	if (((dac_granted | priv_granted) & acc_mode) == acc_mode)
150b12c55abSRobert Watson 		return (0);
151b12c55abSRobert Watson 	else
152b12c55abSRobert Watson 		return (EACCES);
1539ac57410SRobert Watson }
154b648d480SJohn Baldwin 
155b648d480SJohn Baldwin #if defined(COMPAT_FREEBSD4) || defined(COMPAT_FREEBSD5) || \
156b648d480SJohn Baldwin     defined(COMPAT_FREEBSD6) || defined(COMPAT_FREEBSD7)
157b648d480SJohn Baldwin void
158b648d480SJohn Baldwin ipcperm_old2new(struct ipc_perm_old *old, struct ipc_perm *new)
159b648d480SJohn Baldwin {
160b648d480SJohn Baldwin 
161b648d480SJohn Baldwin 	new->cuid = old->cuid;
162b648d480SJohn Baldwin 	new->cgid = old->cgid;
163b648d480SJohn Baldwin 	new->uid = old->uid;
164b648d480SJohn Baldwin 	new->gid = old->gid;
165b648d480SJohn Baldwin 	new->mode = old->mode;
166b648d480SJohn Baldwin 	new->seq = old->seq;
167b648d480SJohn Baldwin 	new->key = old->key;
168b648d480SJohn Baldwin }
169b648d480SJohn Baldwin 
170b648d480SJohn Baldwin void
171b648d480SJohn Baldwin ipcperm_new2old(struct ipc_perm *new, struct ipc_perm_old *old)
172b648d480SJohn Baldwin {
173b648d480SJohn Baldwin 
174b648d480SJohn Baldwin 	/* XXX: How to handle ID's > USHORT_MAX? */
175b648d480SJohn Baldwin 	old->cuid = new->cuid;
176b648d480SJohn Baldwin 	old->cgid = new->cgid;
177b648d480SJohn Baldwin 	old->uid = new->uid;
178b648d480SJohn Baldwin 	old->gid = new->gid;
179b648d480SJohn Baldwin 	old->mode = new->mode;
180b648d480SJohn Baldwin 	old->seq = new->seq;
181b648d480SJohn Baldwin 	old->key = new->key;
182b648d480SJohn Baldwin }
183b648d480SJohn Baldwin #endif
1844cfc39cfSKonstantin Belousov 
1854cfc39cfSKonstantin Belousov #ifdef COMPAT_FREEBSD32
1864cfc39cfSKonstantin Belousov #include <sys/mount.h>
1874cfc39cfSKonstantin Belousov #include <sys/socket.h>
1884cfc39cfSKonstantin Belousov #include <compat/freebsd32/freebsd32.h>
1894cfc39cfSKonstantin Belousov #include <compat/freebsd32/freebsd32_ipc.h>
1904cfc39cfSKonstantin Belousov #include <compat/freebsd32/freebsd32_proto.h>
1914cfc39cfSKonstantin Belousov #include <compat/freebsd32/freebsd32_signal.h>
1924cfc39cfSKonstantin Belousov #include <compat/freebsd32/freebsd32_syscall.h>
1934cfc39cfSKonstantin Belousov #include <compat/freebsd32/freebsd32_util.h>
1944cfc39cfSKonstantin Belousov 
1954cfc39cfSKonstantin Belousov #if defined(COMPAT_FREEBSD4) || defined(COMPAT_FREEBSD5) || \
1964cfc39cfSKonstantin Belousov     defined(COMPAT_FREEBSD6) || defined(COMPAT_FREEBSD7)
1974cfc39cfSKonstantin Belousov void
1984cfc39cfSKonstantin Belousov freebsd32_ipcperm_old_in(struct ipc_perm32_old *ip32, struct ipc_perm *ip)
1994cfc39cfSKonstantin Belousov {
2004cfc39cfSKonstantin Belousov 
2014cfc39cfSKonstantin Belousov 	CP(*ip32, *ip, cuid);
2024cfc39cfSKonstantin Belousov 	CP(*ip32, *ip, cgid);
2034cfc39cfSKonstantin Belousov 	CP(*ip32, *ip, uid);
2044cfc39cfSKonstantin Belousov 	CP(*ip32, *ip, gid);
2054cfc39cfSKonstantin Belousov 	CP(*ip32, *ip, mode);
2064cfc39cfSKonstantin Belousov 	CP(*ip32, *ip, seq);
2074cfc39cfSKonstantin Belousov 	CP(*ip32, *ip, key);
2084cfc39cfSKonstantin Belousov }
2094cfc39cfSKonstantin Belousov 
2104cfc39cfSKonstantin Belousov void
2114cfc39cfSKonstantin Belousov freebsd32_ipcperm_old_out(struct ipc_perm *ip, struct ipc_perm32_old *ip32)
2124cfc39cfSKonstantin Belousov {
2134cfc39cfSKonstantin Belousov 
2144cfc39cfSKonstantin Belousov 	CP(*ip, *ip32, cuid);
2154cfc39cfSKonstantin Belousov 	CP(*ip, *ip32, cgid);
2164cfc39cfSKonstantin Belousov 	CP(*ip, *ip32, uid);
2174cfc39cfSKonstantin Belousov 	CP(*ip, *ip32, gid);
2184cfc39cfSKonstantin Belousov 	CP(*ip, *ip32, mode);
2194cfc39cfSKonstantin Belousov 	CP(*ip, *ip32, seq);
2204cfc39cfSKonstantin Belousov 	CP(*ip, *ip32, key);
2214cfc39cfSKonstantin Belousov }
2224cfc39cfSKonstantin Belousov #endif
2234cfc39cfSKonstantin Belousov 
2244cfc39cfSKonstantin Belousov void
2254cfc39cfSKonstantin Belousov freebsd32_ipcperm_in(struct ipc_perm32 *ip32, struct ipc_perm *ip)
2264cfc39cfSKonstantin Belousov {
2274cfc39cfSKonstantin Belousov 
2284cfc39cfSKonstantin Belousov 	CP(*ip32, *ip, cuid);
2294cfc39cfSKonstantin Belousov 	CP(*ip32, *ip, cgid);
2304cfc39cfSKonstantin Belousov 	CP(*ip32, *ip, uid);
2314cfc39cfSKonstantin Belousov 	CP(*ip32, *ip, gid);
2324cfc39cfSKonstantin Belousov 	CP(*ip32, *ip, mode);
2334cfc39cfSKonstantin Belousov 	CP(*ip32, *ip, seq);
2344cfc39cfSKonstantin Belousov 	CP(*ip32, *ip, key);
2354cfc39cfSKonstantin Belousov }
2364cfc39cfSKonstantin Belousov 
2374cfc39cfSKonstantin Belousov void
2384cfc39cfSKonstantin Belousov freebsd32_ipcperm_out(struct ipc_perm *ip, struct ipc_perm32 *ip32)
2394cfc39cfSKonstantin Belousov {
2404cfc39cfSKonstantin Belousov 
2414cfc39cfSKonstantin Belousov 	CP(*ip, *ip32, cuid);
2424cfc39cfSKonstantin Belousov 	CP(*ip, *ip32, cgid);
2434cfc39cfSKonstantin Belousov 	CP(*ip, *ip32, uid);
2444cfc39cfSKonstantin Belousov 	CP(*ip, *ip32, gid);
2454cfc39cfSKonstantin Belousov 	CP(*ip, *ip32, mode);
2464cfc39cfSKonstantin Belousov 	CP(*ip, *ip32, seq);
2474cfc39cfSKonstantin Belousov 	CP(*ip, *ip32, key);
2484cfc39cfSKonstantin Belousov }
2494cfc39cfSKonstantin Belousov #endif
250