xref: /xnu-11417.140.69/bsd/kern/sysv_ipc.c (revision 43a90889846e00bfb5cf1d255cdc0a701a1e05a4)
1 /*
2  * Copyright (c) 2000 Apple Computer, Inc. All rights reserved.
3  *
4  * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
5  *
6  * This file contains Original Code and/or Modifications of Original Code
7  * as defined in and that are subject to the Apple Public Source License
8  * Version 2.0 (the 'License'). You may not use this file except in
9  * compliance with the License. The rights granted to you under the License
10  * may not be used to create, or enable the creation or redistribution of,
11  * unlawful or unlicensed copies of an Apple operating system, or to
12  * circumvent, violate, or enable the circumvention or violation of, any
13  * terms of an Apple operating system software license agreement.
14  *
15  * Please obtain a copy of the License at
16  * http://www.opensource.apple.com/apsl/ and read it before using this file.
17  *
18  * The Original Code and all software distributed under the License are
19  * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
20  * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
21  * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
22  * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
23  * Please see the License for the specific language governing rights and
24  * limitations under the License.
25  *
26  * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
27  */
28 /*	$NetBSD: sysv_ipc.c,v 1.7 1994/06/29 06:33:11 cgd Exp $	*/
29 
30 /*
31  * Copyright (c) 1994 Herb Peyerl <[email protected]>
32  * All rights reserved.
33  *
34  * Redistribution and use in source and binary forms, with or without
35  * modification, are permitted provided that the following conditions
36  * are met:
37  * 1. Redistributions of source code must retain the above copyright
38  *    notice, this list of conditions and the following disclaimer.
39  * 2. Redistributions in binary form must reproduce the above copyright
40  *    notice, this list of conditions and the following disclaimer in the
41  *    documentation and/or other materials provided with the distribution.
42  * 3. All advertising materials mentioning features or use of this software
43  *    must display the following acknowledgement:
44  *      This product includes software developed by Herb Peyerl.
45  * 4. The name of Herb Peyerl may not be used to endorse or promote products
46  *    derived from this software without specific prior written permission.
47  *
48  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
49  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
50  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
51  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
52  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
53  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
54  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
55  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
56  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
57  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
58  */
59 
60 
61 #include <sys/param.h>
62 #include <sys/ipc.h>
63 #include <sys/stat.h>   /* mode constants */
64 #include <sys/ucred.h>
65 #include <sys/kauth.h>
66 
67 
68 /*
69  * Check for ipc permission
70  */
71 
72 
73 /*
74  * ipc_perm
75  *
76  *	perm->mode			mode of the object
77  *	mode				mode bits we want to test
78  *
79  * Returns:	0			Success
80  *		EPERM
81  *		EACCES
82  *
83  * Notes:	The IPC_M bit is special, in that it may only be granted to
84  *		root, the creating user, or the owning user.
85  *
86  *		This code does not use posix_cred_access() because of the
87  *		need to check both creator and owner separately when we are
88  *		considering a rights grant.  Because of this, we need to do
89  *		two evaluations when the values are inequal, which can lead
90  *		us to defeat the callout avoidance optimization.  So we do
91  *		the work here, inline.  This is less than optimal for any
92  *		future work involving opacity of of POSIX credentials.
93  *
94  *		Setting up the mode_owner / mode_group / mode_world implicitly
95  *		masks the IPC_M bit off.  This is intentional.
96  *
97  *		See the posix_cred_access() implementation for algorithm
98  *		information.
99  */
100 int
ipcperm(kauth_cred_t cred,struct ipc_perm * perm,int mode_req)101 ipcperm(kauth_cred_t cred, struct ipc_perm *perm, int mode_req)
102 {
103 	uid_t   uid = kauth_cred_getuid(cred);  /* avoid multiple calls */
104 	int     want_mod_controlinfo = (mode_req & IPC_M);
105 	int     is_member;
106 	mode_t  mode_owner = (perm->mode & S_IRWXU);
107 	mode_t  mode_group = (mode_t)((perm->mode & S_IRWXG) << 3);
108 	mode_t  mode_world = (mode_t)((perm->mode & S_IRWXO) << 6);
109 
110 	/* Grant all rights to super user */
111 	if (!suser(cred, (u_short *)NULL)) {
112 		return 0;
113 	}
114 
115 	/* Grant or deny rights based on ownership */
116 	if (uid == perm->cuid || uid == perm->uid) {
117 		if (want_mod_controlinfo) {
118 			return 0;
119 		}
120 
121 		return (mode_req & mode_owner) == mode_req ? 0 : EACCES;
122 	} else {
123 		/* everyone else who wants to modify control info is denied */
124 		if (want_mod_controlinfo) {
125 			return EPERM;
126 		}
127 	}
128 
129 	/*
130 	 * Combined group and world rights check, if no owner rights; positive
131 	 * asssertion of gid/cgid equality avoids an extra callout in the
132 	 * common case.
133 	 */
134 	if ((mode_req & mode_group & mode_world) == mode_req) {
135 		return 0;
136 	} else {
137 		if ((mode_req & mode_group) != mode_req) {
138 			if ((!kauth_cred_ismember_gid(cred, perm->gid, &is_member) && is_member) &&
139 			    ((perm->gid == perm->cgid) ||
140 			    (!kauth_cred_ismember_gid(cred, perm->cgid, &is_member) && is_member))) {
141 				return EACCES;
142 			} else {
143 				if ((mode_req & mode_world) != mode_req) {
144 					return EACCES;
145 				} else {
146 					return 0;
147 				}
148 			}
149 		} else {
150 			if ((!kauth_cred_ismember_gid(cred, perm->gid, &is_member) && is_member) ||
151 			    ((perm->gid != perm->cgid) &&
152 			    (!kauth_cred_ismember_gid(cred, perm->cgid, &is_member) && is_member))) {
153 				return 0;
154 			} else {
155 				if ((mode_req & mode_world) != mode_req) {
156 					return EACCES;
157 				} else {
158 					return 0;
159 				}
160 			}
161 		}
162 	}
163 }
164