]>
Commit | Line | Data |
---|---|---|
1c79356b | 1 | /* |
2d21ac55 | 2 | * Copyright (c) 2000-2007 Apple Inc. All rights reserved. |
5d5c5d0d | 3 | * |
2d21ac55 | 4 | * @APPLE_OSREFERENCE_LICENSE_HEADER_START@ |
1c79356b | 5 | * |
2d21ac55 A |
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. | |
8f6c56a5 | 14 | * |
2d21ac55 A |
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 | |
8f6c56a5 A |
20 | * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, |
21 | * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, | |
2d21ac55 A |
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. | |
8f6c56a5 | 25 | * |
2d21ac55 | 26 | * @APPLE_OSREFERENCE_LICENSE_HEADER_END@ |
1c79356b A |
27 | */ |
28 | /* | |
29 | * Copyright (c) 1990, 1996-1998 Apple Computer, Inc. | |
30 | * All Rights Reserved. | |
31 | */ | |
32 | /* | |
9bccf70c | 33 | * posix_shm.c : Support for POSIX semaphore APIs |
1c79356b A |
34 | * |
35 | * File: posix_sem.c | |
36 | * Author: Ananthakrishna Ramesh | |
37 | * | |
38 | * HISTORY | |
39 | * 2-Sep-1999 A.Ramesh | |
40 | * Created for MacOSX | |
41 | * | |
42 | */ | |
2d21ac55 A |
43 | /* |
44 | * NOTICE: This file was modified by SPARTA, Inc. in 2005 to introduce | |
45 | * support for mandatory and extensible security protections. This notice | |
46 | * is included in support of clause 2.2 (b) of the Apple Public License, | |
47 | * Version 2.0. | |
48 | */ | |
1c79356b A |
49 | |
50 | #include <sys/cdefs.h> | |
51 | #include <sys/param.h> | |
52 | #include <sys/systm.h> | |
53 | #include <sys/kernel.h> | |
91447636 | 54 | #include <sys/file_internal.h> |
1c79356b A |
55 | #include <sys/filedesc.h> |
56 | #include <sys/stat.h> | |
91447636 A |
57 | #include <sys/proc_internal.h> |
58 | #include <sys/kauth.h> | |
1c79356b A |
59 | #include <sys/mount.h> |
60 | #include <sys/namei.h> | |
61 | #include <sys/vnode.h> | |
62 | #include <sys/ioctl.h> | |
63 | #include <sys/tty.h> | |
64 | #include <sys/malloc.h> | |
65 | #include <sys/semaphore.h> | |
91447636 | 66 | #include <sys/sysproto.h> |
0c530ab8 | 67 | #include <sys/proc_info.h> |
e5568f75 | 68 | |
2d21ac55 A |
69 | #if CONFIG_MACF |
70 | #include <sys/vnode_internal.h> | |
71 | #include <security/mac_framework.h> | |
72 | #endif | |
73 | ||
e5568f75 A |
74 | #include <bsm/audit_kernel.h> |
75 | ||
1c79356b A |
76 | #include <mach/mach_types.h> |
77 | #include <mach/vm_prot.h> | |
78 | #include <mach/semaphore.h> | |
79 | #include <mach/sync_policy.h> | |
91447636 A |
80 | #include <mach/task.h> |
81 | #include <kern/kern_types.h> | |
1c79356b A |
82 | #include <kern/task.h> |
83 | #include <kern/clock.h> | |
84 | #include <mach/kern_return.h> | |
85 | ||
91447636 A |
86 | |
87 | #define f_flag f_fglob->fg_flag | |
88 | #define f_type f_fglob->fg_type | |
89 | #define f_msgcount f_fglob->fg_msgcount | |
90 | #define f_cred f_fglob->fg_cred | |
91 | #define f_ops f_fglob->fg_ops | |
92 | #define f_offset f_fglob->fg_offset | |
93 | #define f_data f_fglob->fg_data | |
1c79356b A |
94 | #define PSEMNAMLEN 31 /* maximum name segment length we bother with */ |
95 | ||
96 | struct pseminfo { | |
97 | unsigned int psem_flags; | |
98 | unsigned int psem_usecount; | |
99 | mode_t psem_mode; | |
100 | uid_t psem_uid; | |
101 | gid_t psem_gid; | |
102 | char psem_name[PSEMNAMLEN + 1]; /* segment name */ | |
91447636 | 103 | semaphore_t psem_semobject; |
2d21ac55 A |
104 | proc_t sem_proc; |
105 | struct label * psem_label; | |
1c79356b A |
106 | }; |
107 | #define PSEMINFO_NULL (struct pseminfo *)0 | |
108 | ||
109 | #define PSEM_NONE 1 | |
110 | #define PSEM_DEFINED 2 | |
111 | #define PSEM_ALLOCATED 4 | |
112 | #define PSEM_MAPPED 8 | |
113 | #define PSEM_INUSE 0x10 | |
114 | #define PSEM_REMOVED 0x20 | |
115 | #define PSEM_INCREATE 0x40 | |
116 | #define PSEM_INDELETE 0x80 | |
117 | ||
118 | struct psemcache { | |
119 | LIST_ENTRY(psemcache) psem_hash; /* hash chain */ | |
120 | struct pseminfo *pseminfo; /* vnode the name refers to */ | |
121 | int psem_nlen; /* length of name */ | |
122 | char psem_name[PSEMNAMLEN + 1]; /* segment name */ | |
123 | }; | |
124 | #define PSEMCACHE_NULL (struct psemcache *)0 | |
125 | ||
126 | struct psemstats { | |
127 | long goodhits; /* hits that we can really use */ | |
128 | long neghits; /* negative hits that we can use */ | |
129 | long badhits; /* hits we must drop */ | |
130 | long falsehits; /* hits with id mismatch */ | |
131 | long miss; /* misses */ | |
132 | long longnames; /* long names that ignore cache */ | |
133 | }; | |
134 | ||
135 | struct psemname { | |
136 | char *psem_nameptr; /* pointer to looked up name */ | |
137 | long psem_namelen; /* length of looked up component */ | |
138 | u_long psem_hash; /* hash value of looked up name */ | |
139 | }; | |
140 | ||
141 | struct psemnode { | |
142 | struct pseminfo *pinfo; | |
143 | #if DIAGNOSTIC | |
144 | unsigned int readcnt; | |
145 | unsigned int writecnt; | |
146 | #endif | |
147 | }; | |
148 | #define PSEMNODE_NULL (struct psemnode *)0 | |
149 | ||
150 | ||
151 | #define PSEMHASH(pnp) \ | |
152 | (&psemhashtbl[(pnp)->psem_hash & psemhash]) | |
153 | LIST_HEAD(psemhashhead, psemcache) *psemhashtbl; /* Hash Table */ | |
154 | u_long psemhash; /* size of hash table - 1 */ | |
155 | long psemnument; /* number of cache entries allocated */ | |
91447636 A |
156 | long posix_sem_max = 10000; /* tunable for max POSIX semaphores */ |
157 | /* 10000 limits to ~1M of memory */ | |
2d21ac55 A |
158 | SYSCTL_NODE(_kern, KERN_POSIX, posix, CTLFLAG_RW|CTLFLAG_LOCKED, 0, "Posix"); |
159 | SYSCTL_NODE(_kern_posix, OID_AUTO, sem, CTLFLAG_RW|CTLFLAG_LOCKED, 0, "Semaphores"); | |
91447636 A |
160 | SYSCTL_INT (_kern_posix_sem, OID_AUTO, max, CTLFLAG_RW, &posix_sem_max, 0, "max"); |
161 | ||
1c79356b A |
162 | struct psemstats psemstats; /* cache effectiveness statistics */ |
163 | ||
91447636 A |
164 | static int psem_access(struct pseminfo *pinfo, int mode, kauth_cred_t cred); |
165 | static int psem_cache_search(struct pseminfo **, | |
166 | struct psemname *, struct psemcache **); | |
167 | static int psem_delete(struct pseminfo * pinfo); | |
1c79356b | 168 | |
91447636 | 169 | static int psem_read (struct fileproc *fp, struct uio *uio, |
2d21ac55 | 170 | int flags, vfs_context_t ctx); |
91447636 | 171 | static int psem_write (struct fileproc *fp, struct uio *uio, |
2d21ac55 | 172 | int flags, vfs_context_t ctx); |
91447636 | 173 | static int psem_ioctl (struct fileproc *fp, u_long com, |
2d21ac55 A |
174 | caddr_t data, vfs_context_t ctx); |
175 | static int psem_select (struct fileproc *fp, int which, void *wql, vfs_context_t ctx); | |
176 | static int psem_closefile (struct fileglob *fp, vfs_context_t ctx); | |
1c79356b | 177 | |
2d21ac55 | 178 | static int psem_kqfilter (struct fileproc *fp, struct knote *kn, vfs_context_t ctx); |
55e303ae | 179 | |
1c79356b | 180 | struct fileops psemops = |
2d21ac55 | 181 | { psem_read, psem_write, psem_ioctl, psem_select, psem_closefile, psem_kqfilter, NULL }; |
91447636 A |
182 | |
183 | ||
184 | static lck_grp_t *psx_sem_subsys_lck_grp; | |
185 | static lck_grp_attr_t *psx_sem_subsys_lck_grp_attr; | |
186 | static lck_attr_t *psx_sem_subsys_lck_attr; | |
187 | static lck_mtx_t psx_sem_subsys_mutex; | |
188 | ||
189 | #define PSEM_SUBSYS_LOCK() lck_mtx_lock(& psx_sem_subsys_mutex) | |
190 | #define PSEM_SUBSYS_UNLOCK() lck_mtx_unlock(& psx_sem_subsys_mutex) | |
191 | ||
192 | ||
193 | static int psem_cache_add(struct pseminfo *psemp, struct psemname *pnp, struct psemcache *pcp); | |
194 | /* Initialize the mutex governing access to the posix sem subsystem */ | |
195 | __private_extern__ void | |
196 | psem_lock_init( void ) | |
197 | { | |
198 | ||
199 | psx_sem_subsys_lck_grp_attr = lck_grp_attr_alloc_init(); | |
91447636 A |
200 | |
201 | psx_sem_subsys_lck_grp = lck_grp_alloc_init("posix shared memory", psx_sem_subsys_lck_grp_attr); | |
202 | ||
203 | psx_sem_subsys_lck_attr = lck_attr_alloc_init(); | |
91447636 A |
204 | lck_mtx_init(& psx_sem_subsys_mutex, psx_sem_subsys_lck_grp, psx_sem_subsys_lck_attr); |
205 | } | |
1c79356b A |
206 | |
207 | /* | |
208 | * Lookup an entry in the cache | |
209 | * | |
210 | * | |
211 | * status of -1 is returned if matches | |
212 | * If the lookup determines that the name does not exist | |
213 | * (negative cacheing), a status of ENOENT is returned. If the lookup | |
214 | * fails, a status of zero is returned. | |
215 | */ | |
216 | ||
9bccf70c | 217 | static int |
2d21ac55 A |
218 | psem_cache_search(struct pseminfo **psemp, struct psemname *pnp, |
219 | struct psemcache **pcache) | |
1c79356b | 220 | { |
91447636 A |
221 | struct psemcache *pcp, *nnp; |
222 | struct psemhashhead *pcpp; | |
1c79356b A |
223 | |
224 | if (pnp->psem_namelen > PSEMNAMLEN) { | |
225 | psemstats.longnames++; | |
226 | return (0); | |
227 | } | |
228 | ||
229 | pcpp = PSEMHASH(pnp); | |
230 | for (pcp = pcpp->lh_first; pcp != 0; pcp = nnp) { | |
231 | nnp = pcp->psem_hash.le_next; | |
232 | if (pcp->psem_nlen == pnp->psem_namelen && | |
233 | !bcmp(pcp->psem_name, pnp->psem_nameptr, (u_int)pcp-> psem_nlen)) | |
234 | break; | |
235 | } | |
236 | ||
237 | if (pcp == 0) { | |
238 | psemstats.miss++; | |
239 | return (0); | |
240 | } | |
241 | ||
242 | /* We found a "positive" match, return the vnode */ | |
243 | if (pcp->pseminfo) { | |
244 | psemstats.goodhits++; | |
245 | /* TOUCH(ncp); */ | |
246 | *psemp = pcp->pseminfo; | |
247 | *pcache = pcp; | |
248 | return (-1); | |
249 | } | |
250 | ||
251 | /* | |
252 | * We found a "negative" match, ENOENT notifies client of this match. | |
253 | * The nc_vpid field records whether this is a whiteout. | |
254 | */ | |
255 | psemstats.neghits++; | |
256 | return (ENOENT); | |
257 | } | |
258 | ||
259 | /* | |
260 | * Add an entry to the cache. | |
261 | */ | |
9bccf70c | 262 | static int |
91447636 | 263 | psem_cache_add(struct pseminfo *psemp, struct psemname *pnp, struct psemcache *pcp) |
1c79356b | 264 | { |
91447636 | 265 | struct psemhashhead *pcpp; |
1c79356b A |
266 | struct pseminfo *dpinfo; |
267 | struct psemcache *dpcp; | |
268 | ||
269 | #if DIAGNOSTIC | |
2d21ac55 | 270 | if (pnp->psem_namelen > PSEMNAMLEN) |
1c79356b A |
271 | panic("cache_enter: name too long"); |
272 | #endif | |
273 | ||
91447636 | 274 | |
1c79356b A |
275 | /* if the entry has already been added by some one else return */ |
276 | if (psem_cache_search(&dpinfo, pnp, &dpcp) == -1) { | |
1c79356b A |
277 | return(EEXIST); |
278 | } | |
91447636 A |
279 | if (psemnument >= posix_sem_max) |
280 | return(ENOSPC); | |
1c79356b | 281 | psemnument++; |
1c79356b A |
282 | /* |
283 | * Fill in cache info, if vp is NULL this is a "negative" cache entry. | |
284 | * For negative entries, we have to record whether it is a whiteout. | |
285 | * the whiteout flag is stored in the nc_vpid field which is | |
286 | * otherwise unused. | |
287 | */ | |
288 | pcp->pseminfo = psemp; | |
289 | pcp->psem_nlen = pnp->psem_namelen; | |
290 | bcopy(pnp->psem_nameptr, pcp->psem_name, (unsigned)pcp->psem_nlen); | |
291 | pcpp = PSEMHASH(pnp); | |
292 | #if DIAGNOSTIC | |
293 | { | |
91447636 | 294 | struct psemcache *p; |
1c79356b A |
295 | |
296 | for (p = pcpp->lh_first; p != 0; p = p->psem_hash.le_next) | |
297 | if (p == pcp) | |
298 | panic("psem:cache_enter duplicate"); | |
299 | } | |
300 | #endif | |
301 | LIST_INSERT_HEAD(pcpp, pcp, psem_hash); | |
302 | return(0); | |
303 | } | |
304 | ||
305 | /* | |
306 | * Name cache initialization, from vfs_init() when we are booting | |
307 | */ | |
308 | void | |
91447636 | 309 | psem_cache_init(void) |
1c79356b | 310 | { |
2d21ac55 | 311 | psemhashtbl = hashinit(posix_sem_max / 2, M_SHM, &psemhash); |
1c79356b A |
312 | } |
313 | ||
9bccf70c | 314 | static void |
91447636 | 315 | psem_cache_delete(struct psemcache *pcp) |
9bccf70c A |
316 | { |
317 | #if DIAGNOSTIC | |
318 | if (pcp->psem_hash.le_prev == 0) | |
319 | panic("psem namecache purge le_prev"); | |
320 | if (pcp->psem_hash.le_next == pcp) | |
321 | panic("namecache purge le_next"); | |
322 | #endif /* DIAGNOSTIC */ | |
323 | LIST_REMOVE(pcp, psem_hash); | |
2d21ac55 | 324 | pcp->psem_hash.le_prev = NULL; |
9bccf70c A |
325 | psemnument--; |
326 | } | |
327 | ||
91447636 | 328 | #if NOT_USED |
1c79356b A |
329 | /* |
330 | * Invalidate a all entries to particular vnode. | |
331 | * | |
332 | * We actually just increment the v_id, that will do it. The entries will | |
333 | * be purged by lookup as they get found. If the v_id wraps around, we | |
334 | * need to ditch the entire cache, to avoid confusion. No valid vnode will | |
335 | * ever have (v_id == 0). | |
336 | */ | |
91447636 | 337 | static void |
1c79356b A |
338 | psem_cache_purge(void) |
339 | { | |
340 | struct psemcache *pcp; | |
341 | struct psemhashhead *pcpp; | |
342 | ||
343 | for (pcpp = &psemhashtbl[psemhash]; pcpp >= psemhashtbl; pcpp--) { | |
91447636 | 344 | while ( (pcp = pcpp->lh_first) ) |
1c79356b A |
345 | psem_cache_delete(pcp); |
346 | } | |
347 | } | |
91447636 | 348 | #endif /* NOT_USED */ |
1c79356b A |
349 | |
350 | int | |
2d21ac55 | 351 | sem_open(proc_t p, struct sem_open_args *uap, user_addr_t *retval) |
1c79356b | 352 | { |
91447636 A |
353 | struct fileproc *fp; |
354 | size_t i; | |
355 | struct fileproc *nfp; | |
356 | int indx, error; | |
1c79356b A |
357 | struct psemname nd; |
358 | struct pseminfo *pinfo; | |
2d21ac55 | 359 | struct psemcache *pcp = NULL; /* protected by !incache */ |
1c79356b A |
360 | char * pnbuf; |
361 | char * nameptr; | |
362 | char * cp; | |
363 | size_t pathlen, plen; | |
364 | int fmode ; | |
365 | int cmode = uap->mode; | |
366 | int value = uap->value; | |
367 | int incache = 0; | |
368 | struct psemnode * pnode = PSEMNODE_NULL; | |
369 | struct psemcache * pcache = PSEMCACHE_NULL; | |
370 | kern_return_t kret = KERN_SUCCESS; | |
371 | int pinfo_alloc = 0; | |
372 | ||
e5568f75 A |
373 | AUDIT_ARG(fflags, uap->oflag); |
374 | AUDIT_ARG(mode, uap->mode); | |
375 | AUDIT_ARG(value, uap->value); | |
91447636 | 376 | |
1c79356b A |
377 | pinfo = PSEMINFO_NULL; |
378 | ||
91447636 A |
379 | MALLOC_ZONE(pnbuf, caddr_t, MAXPATHLEN, M_NAMEI, M_WAITOK); |
380 | if (pnbuf == NULL) | |
381 | return(ENOSPC); | |
382 | ||
1c79356b | 383 | pathlen = MAXPATHLEN; |
91447636 | 384 | error = copyinstr(uap->name, pnbuf, MAXPATHLEN, &pathlen); |
1c79356b A |
385 | if (error) { |
386 | goto bad; | |
387 | } | |
e5568f75 | 388 | AUDIT_ARG(text, pnbuf); |
91447636 | 389 | if ( (pathlen > PSEMNAMLEN) ) { |
1c79356b A |
390 | error = ENAMETOOLONG; |
391 | goto bad; | |
392 | } | |
393 | ||
1c79356b A |
394 | #ifdef PSXSEM_NAME_RESTRICT |
395 | nameptr = pnbuf; | |
396 | if (*nameptr == '/') { | |
397 | while (*(nameptr++) == '/') { | |
398 | plen--; | |
399 | error = EINVAL; | |
400 | goto bad; | |
401 | } | |
402 | } else { | |
403 | error = EINVAL; | |
404 | goto bad; | |
405 | } | |
406 | #endif /* PSXSEM_NAME_RESTRICT */ | |
407 | ||
408 | plen = pathlen; | |
409 | nameptr = pnbuf; | |
410 | nd.psem_nameptr = nameptr; | |
411 | nd.psem_namelen = plen; | |
2d21ac55 | 412 | nd.psem_hash = 0; |
1c79356b A |
413 | |
414 | for (cp = nameptr, i=1; *cp != 0 && i <= plen; i++, cp++) { | |
415 | nd.psem_hash += (unsigned char)*cp * i; | |
416 | } | |
417 | ||
91447636 | 418 | PSEM_SUBSYS_LOCK(); |
1c79356b A |
419 | error = psem_cache_search(&pinfo, &nd, &pcache); |
420 | ||
421 | if (error == ENOENT) { | |
91447636 | 422 | PSEM_SUBSYS_UNLOCK(); |
1c79356b A |
423 | error = EINVAL; |
424 | goto bad; | |
425 | ||
426 | } | |
427 | if (!error) { | |
428 | incache = 0; | |
429 | } else | |
430 | incache = 1; | |
431 | fmode = FFLAGS(uap->oflag); | |
432 | ||
91447636 | 433 | PSEM_SUBSYS_UNLOCK(); |
2d21ac55 | 434 | error = falloc(p, &nfp, &indx, vfs_context_current()); |
91447636 | 435 | if (error) |
1c79356b | 436 | goto bad; |
1c79356b | 437 | |
91447636 | 438 | PSEM_SUBSYS_LOCK(); |
1c79356b A |
439 | fp = nfp; |
440 | cmode &= ALLPERMS; | |
441 | ||
442 | if (((fmode & (O_CREAT | O_EXCL))==(O_CREAT | O_EXCL)) && incache) { | |
443 | /* sem exists and opened O_EXCL */ | |
444 | #if notyet | |
445 | if (pinfo->psem_flags & PSEM_INDELETE) { | |
446 | } | |
447 | #endif | |
e5568f75 | 448 | AUDIT_ARG(posix_ipc_perm, pinfo->psem_uid, |
91447636 A |
449 | pinfo->psem_gid, pinfo->psem_mode); |
450 | PSEM_SUBSYS_UNLOCK(); | |
1c79356b A |
451 | error = EEXIST; |
452 | goto bad1; | |
453 | } | |
454 | if (((fmode & (O_CREAT | O_EXCL))== O_CREAT) && incache) { | |
455 | /* As per POSIX, O_CREAT has no effect */ | |
456 | fmode &= ~O_CREAT; | |
457 | } | |
458 | ||
91447636 | 459 | if ( (fmode & O_CREAT) ) { |
2d21ac55 | 460 | if((value < 0) || (value > SEM_VALUE_MAX)) { |
91447636 | 461 | PSEM_SUBSYS_UNLOCK(); |
1c79356b A |
462 | error = EINVAL; |
463 | goto bad1; | |
464 | } | |
91447636 A |
465 | PSEM_SUBSYS_UNLOCK(); |
466 | MALLOC(pinfo, struct pseminfo *, sizeof(struct pseminfo), M_SHM, M_WAITOK|M_ZERO); | |
467 | if (pinfo == NULL) { | |
468 | error = ENOSPC; | |
469 | goto bad1; | |
470 | } | |
2d21ac55 A |
471 | #if CONFIG_MACF |
472 | mac_posixsem_label_init(pinfo); | |
473 | #endif | |
91447636 A |
474 | PSEM_SUBSYS_LOCK(); |
475 | ||
1c79356b A |
476 | pinfo_alloc = 1; |
477 | pinfo->psem_flags = PSEM_DEFINED | PSEM_INCREATE; | |
478 | pinfo->psem_usecount = 1; | |
479 | pinfo->psem_mode = cmode; | |
91447636 A |
480 | pinfo->psem_uid = kauth_cred_getuid(kauth_cred_get()); |
481 | pinfo->psem_gid = kauth_cred_get()->cr_gid; | |
0c530ab8 A |
482 | bcopy(pnbuf, &pinfo->psem_name[0], PSEMNAMLEN); |
483 | pinfo->psem_name[PSEMNAMLEN]= 0; | |
91447636 | 484 | PSEM_SUBSYS_UNLOCK(); |
1c79356b A |
485 | kret = semaphore_create(kernel_task, &pinfo->psem_semobject, |
486 | SYNC_POLICY_FIFO, value); | |
487 | if(kret != KERN_SUCCESS) | |
488 | goto bad3; | |
91447636 | 489 | PSEM_SUBSYS_LOCK(); |
1c79356b A |
490 | pinfo->psem_flags &= ~PSEM_DEFINED; |
491 | pinfo->psem_flags |= PSEM_ALLOCATED; | |
492 | pinfo->sem_proc = p; | |
2d21ac55 A |
493 | #if CONFIG_MACF |
494 | error = mac_posixsem_check_create(kauth_cred_get(), nameptr); | |
495 | if (error) { | |
496 | PSEM_SUBSYS_UNLOCK(); | |
497 | goto bad2; | |
498 | } | |
499 | mac_posixsem_label_associate(kauth_cred_get(), pinfo, nameptr); | |
500 | #endif | |
1c79356b A |
501 | } else { |
502 | /* semaphore should exist as it is without O_CREAT */ | |
503 | if (!incache) { | |
91447636 | 504 | PSEM_SUBSYS_UNLOCK(); |
1c79356b A |
505 | error = ENOENT; |
506 | goto bad1; | |
507 | } | |
508 | if( pinfo->psem_flags & PSEM_INDELETE) { | |
91447636 | 509 | PSEM_SUBSYS_UNLOCK(); |
1c79356b A |
510 | error = ENOENT; |
511 | goto bad1; | |
512 | } | |
e5568f75 | 513 | AUDIT_ARG(posix_ipc_perm, pinfo->psem_uid, |
91447636 | 514 | pinfo->psem_gid, pinfo->psem_mode); |
2d21ac55 A |
515 | #if CONFIG_MACF |
516 | error = mac_posixsem_check_open(kauth_cred_get(), pinfo); | |
517 | if (error) { | |
518 | PSEM_SUBSYS_UNLOCK(); | |
519 | goto bad1; | |
520 | } | |
521 | #endif | |
91447636 A |
522 | if ( (error = psem_access(pinfo, fmode, kauth_cred_get())) ) { |
523 | PSEM_SUBSYS_UNLOCK(); | |
1c79356b | 524 | goto bad1; |
91447636 | 525 | } |
1c79356b | 526 | } |
91447636 A |
527 | PSEM_SUBSYS_UNLOCK(); |
528 | MALLOC(pnode, struct psemnode *, sizeof(struct psemnode), M_SHM, M_WAITOK|M_ZERO); | |
529 | if (pnode == NULL) { | |
530 | error = ENOSPC; | |
531 | goto bad1; | |
532 | } | |
533 | if (!incache) { | |
534 | /* | |
535 | * We allocate a new entry if we are less than the maximum | |
536 | * allowed and the one at the front of the LRU list is in use. | |
537 | * Otherwise we use the one at the front of the LRU list. | |
538 | */ | |
539 | MALLOC(pcp, struct psemcache *, sizeof(struct psemcache), M_SHM, M_WAITOK|M_ZERO); | |
540 | if (pcp == NULL) { | |
541 | error = ENOMEM; | |
542 | goto bad2; | |
543 | } | |
1c79356b | 544 | |
91447636 A |
545 | } |
546 | PSEM_SUBSYS_LOCK(); | |
1c79356b | 547 | if (!incache) { |
91447636 A |
548 | if ( (error = psem_cache_add(pinfo, &nd, pcp)) ) { |
549 | PSEM_SUBSYS_UNLOCK(); | |
550 | FREE(pcp, M_SHM); | |
551 | goto bad2; | |
1c79356b A |
552 | } |
553 | } | |
554 | pinfo->psem_flags &= ~PSEM_INCREATE; | |
555 | pinfo->psem_usecount++; | |
556 | pnode->pinfo = pinfo; | |
91447636 A |
557 | PSEM_SUBSYS_UNLOCK(); |
558 | ||
559 | proc_fdlock(p); | |
55e303ae | 560 | fp->f_flag = fmode & FMASK; |
1c79356b A |
561 | fp->f_type = DTYPE_PSXSEM; |
562 | fp->f_ops = &psemops; | |
563 | fp->f_data = (caddr_t)pnode; | |
6601e61a | 564 | procfdtbl_releasefd(p, indx, NULL); |
91447636 A |
565 | fp_drop(p, indx, fp, 1); |
566 | proc_fdunlock(p); | |
567 | ||
568 | *retval = CAST_USER_ADDR_T(indx); | |
55e303ae | 569 | FREE_ZONE(pnbuf, MAXPATHLEN, M_NAMEI); |
1c79356b A |
570 | return (0); |
571 | ||
572 | bad3: | |
573 | switch (kret) { | |
574 | case KERN_RESOURCE_SHORTAGE: | |
575 | error = ENOMEM; | |
2d21ac55 | 576 | break; |
1c79356b A |
577 | case KERN_PROTECTION_FAILURE: |
578 | error = EACCES; | |
2d21ac55 | 579 | break; |
1c79356b A |
580 | default: |
581 | error = EINVAL; | |
582 | } | |
583 | goto bad1; | |
584 | bad2: | |
91447636 | 585 | FREE(pnode, M_SHM); |
1c79356b | 586 | bad1: |
2d21ac55 A |
587 | if (pinfo_alloc) { |
588 | #if CONFIG_MACF | |
589 | mac_posixsem_label_destroy(pinfo); | |
590 | #endif | |
91447636 | 591 | FREE(pinfo, M_SHM); |
2d21ac55 | 592 | } |
91447636 | 593 | fp_free(p, indx, nfp); |
1c79356b | 594 | bad: |
55e303ae | 595 | FREE_ZONE(pnbuf, MAXPATHLEN, M_NAMEI); |
1c79356b A |
596 | return (error); |
597 | } | |
598 | ||
91447636 A |
599 | /* |
600 | * XXX This code is repeated in several places | |
601 | */ | |
602 | static int | |
603 | psem_access(struct pseminfo *pinfo, int mode, kauth_cred_t cred) | |
1c79356b A |
604 | { |
605 | mode_t mask; | |
91447636 | 606 | int is_member; |
1c79356b A |
607 | |
608 | /* Otherwise, user id 0 always gets access. */ | |
91447636 | 609 | if (!suser(cred, NULL)) |
1c79356b A |
610 | return (0); |
611 | ||
612 | mask = 0; | |
613 | ||
614 | /* Otherwise, check the owner. */ | |
91447636 | 615 | if (kauth_cred_getuid(cred) == pinfo->psem_uid) { |
1c79356b A |
616 | if (mode & FREAD) |
617 | mask |= S_IRUSR; | |
618 | if (mode & FWRITE) | |
619 | mask |= S_IWUSR; | |
620 | return ((pinfo->psem_mode & mask) == mask ? 0 : EACCES); | |
621 | } | |
622 | ||
623 | /* Otherwise, check the groups. */ | |
91447636 A |
624 | if (kauth_cred_ismember_gid(cred, pinfo->psem_gid, &is_member) == 0 && is_member) { |
625 | if (mode & FREAD) | |
626 | mask |= S_IRGRP; | |
627 | if (mode & FWRITE) | |
628 | mask |= S_IWGRP; | |
629 | return ((pinfo->psem_mode & mask) == mask ? 0 : EACCES); | |
630 | } | |
1c79356b A |
631 | |
632 | /* Otherwise, check everyone else. */ | |
633 | if (mode & FREAD) | |
634 | mask |= S_IROTH; | |
635 | if (mode & FWRITE) | |
636 | mask |= S_IWOTH; | |
637 | return ((pinfo->psem_mode & mask) == mask ? 0 : EACCES); | |
638 | } | |
639 | ||
1c79356b | 640 | int |
2d21ac55 | 641 | sem_unlink(__unused proc_t p, struct sem_unlink_args *uap, __unused register_t *retval) |
1c79356b | 642 | { |
91447636 | 643 | size_t i; |
1c79356b A |
644 | int error=0; |
645 | struct psemname nd; | |
646 | struct pseminfo *pinfo; | |
1c79356b A |
647 | char * pnbuf; |
648 | char * nameptr; | |
649 | char * cp; | |
650 | size_t pathlen, plen; | |
1c79356b | 651 | int incache = 0; |
1c79356b | 652 | struct psemcache *pcache = PSEMCACHE_NULL; |
1c79356b A |
653 | |
654 | pinfo = PSEMINFO_NULL; | |
655 | ||
91447636 A |
656 | MALLOC_ZONE(pnbuf, caddr_t, MAXPATHLEN, M_NAMEI, M_WAITOK); |
657 | if (pnbuf == NULL) { | |
658 | return(ENOSPC); /* XXX non-standard */ | |
659 | } | |
1c79356b | 660 | pathlen = MAXPATHLEN; |
91447636 | 661 | error = copyinstr(uap->name, pnbuf, MAXPATHLEN, &pathlen); |
1c79356b A |
662 | if (error) { |
663 | goto bad; | |
664 | } | |
e5568f75 | 665 | AUDIT_ARG(text, pnbuf); |
1c79356b A |
666 | if (pathlen > PSEMNAMLEN) { |
667 | error = ENAMETOOLONG; | |
668 | goto bad; | |
669 | } | |
670 | ||
671 | ||
672 | #ifdef PSXSEM_NAME_RESTRICT | |
673 | nameptr = pnbuf; | |
674 | if (*nameptr == '/') { | |
675 | while (*(nameptr++) == '/') { | |
676 | plen--; | |
677 | error = EINVAL; | |
678 | goto bad; | |
679 | } | |
680 | } else { | |
681 | error = EINVAL; | |
682 | goto bad; | |
683 | } | |
684 | #endif /* PSXSEM_NAME_RESTRICT */ | |
685 | ||
686 | plen = pathlen; | |
687 | nameptr = pnbuf; | |
688 | nd.psem_nameptr = nameptr; | |
689 | nd.psem_namelen = plen; | |
690 | nd. psem_hash =0; | |
691 | ||
692 | for (cp = nameptr, i=1; *cp != 0 && i <= plen; i++, cp++) { | |
693 | nd.psem_hash += (unsigned char)*cp * i; | |
694 | } | |
695 | ||
91447636 | 696 | PSEM_SUBSYS_LOCK(); |
1c79356b A |
697 | error = psem_cache_search(&pinfo, &nd, &pcache); |
698 | ||
699 | if (error == ENOENT) { | |
91447636 | 700 | PSEM_SUBSYS_UNLOCK(); |
1c79356b A |
701 | error = EINVAL; |
702 | goto bad; | |
703 | ||
704 | } | |
705 | if (!error) { | |
91447636 | 706 | PSEM_SUBSYS_UNLOCK(); |
1c79356b A |
707 | error = EINVAL; |
708 | goto bad; | |
709 | } else | |
710 | incache = 1; | |
2d21ac55 A |
711 | #if CONFIG_MACF |
712 | error = mac_posixsem_check_unlink(kauth_cred_get(), pinfo, nameptr); | |
713 | if (error) { | |
714 | PSEM_SUBSYS_UNLOCK(); | |
715 | goto bad; | |
716 | } | |
717 | #endif | |
91447636 A |
718 | if ( (error = psem_access(pinfo, pinfo->psem_mode, kauth_cred_get())) ) { |
719 | PSEM_SUBSYS_UNLOCK(); | |
1c79356b | 720 | goto bad; |
91447636 | 721 | } |
1c79356b A |
722 | |
723 | if ((pinfo->psem_flags & (PSEM_DEFINED | PSEM_ALLOCATED))==0) { | |
91447636 | 724 | PSEM_SUBSYS_UNLOCK(); |
2d21ac55 A |
725 | error = EINVAL; |
726 | goto bad; | |
1c79356b A |
727 | } |
728 | ||
91447636 A |
729 | if ( (pinfo->psem_flags & PSEM_INDELETE) ) { |
730 | PSEM_SUBSYS_UNLOCK(); | |
1c79356b A |
731 | error = 0; |
732 | goto bad; | |
733 | } | |
91447636 | 734 | |
e5568f75 A |
735 | AUDIT_ARG(posix_ipc_perm, pinfo->psem_uid, pinfo->psem_gid, |
736 | pinfo->psem_mode); | |
737 | ||
1c79356b A |
738 | pinfo->psem_flags |= PSEM_INDELETE; |
739 | pinfo->psem_usecount--; | |
740 | ||
741 | if (!pinfo->psem_usecount) { | |
742 | psem_delete(pinfo); | |
91447636 | 743 | FREE(pinfo,M_SHM); |
1c79356b A |
744 | } else |
745 | pinfo->psem_flags |= PSEM_REMOVED; | |
746 | ||
747 | psem_cache_delete(pcache); | |
91447636 A |
748 | PSEM_SUBSYS_UNLOCK(); |
749 | FREE(pcache, M_SHM); | |
1c79356b A |
750 | error = 0; |
751 | bad: | |
55e303ae | 752 | FREE_ZONE(pnbuf, MAXPATHLEN, M_NAMEI); |
1c79356b A |
753 | return (error); |
754 | } | |
755 | ||
1c79356b | 756 | int |
2d21ac55 | 757 | sem_close(proc_t p, struct sem_close_args *uap, __unused register_t *retval) |
1c79356b | 758 | { |
91447636 A |
759 | int fd = CAST_DOWN(int,uap->sem); |
760 | struct fileproc *fp; | |
1c79356b A |
761 | int error = 0; |
762 | ||
e5568f75 | 763 | AUDIT_ARG(fd, fd); /* XXX This seems wrong; uap->sem is a pointer */ |
91447636 A |
764 | |
765 | proc_fdlock(p); | |
766 | error = fp_lookup(p,fd, &fp, 1); | |
767 | if (error) { | |
768 | proc_fdunlock(p); | |
1c79356b | 769 | return(error); |
91447636 | 770 | } |
2d21ac55 | 771 | fileproc_drain(p, fp); |
91447636 A |
772 | fdrelse(p, fd); |
773 | error = closef_locked(fp, fp->f_fglob, p); | |
774 | FREE_ZONE(fp, sizeof *fp, M_FILEPROC); | |
775 | proc_fdunlock(p); | |
776 | return(error); | |
1c79356b A |
777 | } |
778 | ||
1c79356b | 779 | int |
2d21ac55 A |
780 | sem_wait(proc_t p, struct sem_wait_args *uap, register_t *retval) |
781 | { | |
782 | __pthread_testcancel(1); | |
783 | return(sem_wait_nocancel(p, (struct sem_wait_nocancel_args *)uap, retval)); | |
784 | } | |
785 | ||
786 | int | |
787 | sem_wait_nocancel(proc_t p, struct sem_wait_nocancel_args *uap, __unused register_t *retval) | |
1c79356b | 788 | { |
91447636 A |
789 | int fd = CAST_DOWN(int,uap->sem); |
790 | struct fileproc *fp; | |
1c79356b A |
791 | struct pseminfo * pinfo; |
792 | struct psemnode * pnode ; | |
793 | kern_return_t kret; | |
794 | int error; | |
795 | ||
91447636 A |
796 | error = fp_getfpsem(p, fd, &fp, &pnode); |
797 | if (error) | |
1c79356b | 798 | return (error); |
91447636 A |
799 | if (((pnode = (struct psemnode *)fp->f_data)) == PSEMNODE_NULL ) { |
800 | error = EINVAL; | |
801 | goto out; | |
802 | } | |
803 | PSEM_SUBSYS_LOCK(); | |
804 | if ((pinfo = pnode->pinfo) == PSEMINFO_NULL) { | |
805 | PSEM_SUBSYS_UNLOCK(); | |
806 | error = EINVAL; | |
807 | goto out; | |
808 | } | |
1c79356b A |
809 | if ((pinfo->psem_flags & (PSEM_DEFINED | PSEM_ALLOCATED)) |
810 | != PSEM_ALLOCATED) { | |
91447636 A |
811 | PSEM_SUBSYS_UNLOCK(); |
812 | error = EINVAL; | |
813 | goto out; | |
1c79356b | 814 | } |
2d21ac55 A |
815 | #if CONFIG_MACF |
816 | error = mac_posixsem_check_wait(kauth_cred_get(), pinfo); | |
817 | if (error) { | |
818 | PSEM_SUBSYS_UNLOCK(); | |
819 | goto out; | |
820 | } | |
821 | #endif | |
91447636 | 822 | PSEM_SUBSYS_UNLOCK(); |
1c79356b A |
823 | kret = semaphore_wait(pinfo->psem_semobject); |
824 | switch (kret) { | |
825 | case KERN_INVALID_ADDRESS: | |
826 | case KERN_PROTECTION_FAILURE: | |
91447636 A |
827 | error = EACCES; |
828 | break; | |
1c79356b A |
829 | case KERN_ABORTED: |
830 | case KERN_OPERATION_TIMED_OUT: | |
91447636 A |
831 | error = EINTR; |
832 | break; | |
1c79356b | 833 | case KERN_SUCCESS: |
91447636 A |
834 | error = 0; |
835 | break; | |
1c79356b | 836 | default: |
91447636 A |
837 | error = EINVAL; |
838 | break; | |
1c79356b | 839 | } |
91447636 A |
840 | out: |
841 | fp_drop(p, fd, fp, 0); | |
842 | return(error); | |
1c79356b | 843 | |
91447636 | 844 | } |
1c79356b A |
845 | |
846 | int | |
2d21ac55 | 847 | sem_trywait(proc_t p, struct sem_trywait_args *uap, __unused register_t *retval) |
1c79356b | 848 | { |
91447636 A |
849 | int fd = CAST_DOWN(int,uap->sem); |
850 | struct fileproc *fp; | |
1c79356b A |
851 | struct pseminfo * pinfo; |
852 | struct psemnode * pnode ; | |
853 | kern_return_t kret; | |
854 | mach_timespec_t wait_time; | |
855 | int error; | |
856 | ||
91447636 A |
857 | error = fp_getfpsem(p, fd, &fp, &pnode); |
858 | if (error) | |
1c79356b | 859 | return (error); |
91447636 A |
860 | if (((pnode = (struct psemnode *)fp->f_data)) == PSEMNODE_NULL ) { |
861 | error = EINVAL; | |
862 | goto out; | |
863 | } | |
864 | PSEM_SUBSYS_LOCK(); | |
865 | if ((pinfo = pnode->pinfo) == PSEMINFO_NULL) { | |
866 | PSEM_SUBSYS_UNLOCK(); | |
867 | error = EINVAL; | |
868 | goto out; | |
869 | } | |
1c79356b A |
870 | if ((pinfo->psem_flags & (PSEM_DEFINED | PSEM_ALLOCATED)) |
871 | != PSEM_ALLOCATED) { | |
91447636 A |
872 | PSEM_SUBSYS_UNLOCK(); |
873 | error = EINVAL; | |
874 | goto out; | |
1c79356b | 875 | } |
2d21ac55 A |
876 | #if CONFIG_MACF |
877 | error = mac_posixsem_check_wait(kauth_cred_get(), pinfo); | |
878 | if (error) { | |
879 | PSEM_SUBSYS_UNLOCK(); | |
880 | goto out; | |
881 | } | |
882 | #endif | |
91447636 | 883 | PSEM_SUBSYS_UNLOCK(); |
1c79356b A |
884 | wait_time.tv_sec = 0; |
885 | wait_time.tv_nsec = 0; | |
886 | ||
887 | kret = semaphore_timedwait(pinfo->psem_semobject, MACH_TIMESPEC_ZERO); | |
888 | switch (kret) { | |
889 | case KERN_INVALID_ADDRESS: | |
890 | case KERN_PROTECTION_FAILURE: | |
91447636 A |
891 | error = EINVAL; |
892 | break; | |
1c79356b | 893 | case KERN_ABORTED: |
91447636 A |
894 | error = EINTR; |
895 | break; | |
1c79356b | 896 | case KERN_OPERATION_TIMED_OUT: |
91447636 A |
897 | error = EAGAIN; |
898 | break; | |
1c79356b | 899 | case KERN_SUCCESS: |
91447636 A |
900 | error = 0; |
901 | break; | |
1c79356b | 902 | default: |
91447636 A |
903 | error = EINVAL; |
904 | break; | |
1c79356b | 905 | } |
91447636 A |
906 | out: |
907 | fp_drop(p, fd, fp, 0); | |
908 | return(error); | |
1c79356b A |
909 | } |
910 | ||
1c79356b | 911 | int |
2d21ac55 | 912 | sem_post(proc_t p, struct sem_post_args *uap, __unused register_t *retval) |
1c79356b | 913 | { |
91447636 A |
914 | int fd = CAST_DOWN(int,uap->sem); |
915 | struct fileproc *fp; | |
1c79356b A |
916 | struct pseminfo * pinfo; |
917 | struct psemnode * pnode ; | |
918 | kern_return_t kret; | |
919 | int error; | |
920 | ||
91447636 A |
921 | error = fp_getfpsem(p, fd, &fp, &pnode); |
922 | if (error) | |
1c79356b | 923 | return (error); |
91447636 A |
924 | if (((pnode = (struct psemnode *)fp->f_data)) == PSEMNODE_NULL ) { |
925 | error = EINVAL; | |
926 | goto out; | |
927 | } | |
928 | PSEM_SUBSYS_LOCK(); | |
929 | if ((pinfo = pnode->pinfo) == PSEMINFO_NULL) { | |
930 | PSEM_SUBSYS_UNLOCK(); | |
931 | error = EINVAL; | |
932 | goto out; | |
933 | } | |
1c79356b A |
934 | if ((pinfo->psem_flags & (PSEM_DEFINED | PSEM_ALLOCATED)) |
935 | != PSEM_ALLOCATED) { | |
91447636 A |
936 | PSEM_SUBSYS_UNLOCK(); |
937 | error = EINVAL; | |
938 | goto out; | |
1c79356b | 939 | } |
2d21ac55 A |
940 | #if CONFIG_MACF |
941 | error = mac_posixsem_check_post(kauth_cred_get(), pinfo); | |
942 | if (error) { | |
943 | PSEM_SUBSYS_UNLOCK(); | |
944 | goto out; | |
945 | } | |
946 | #endif | |
91447636 | 947 | PSEM_SUBSYS_UNLOCK(); |
1c79356b A |
948 | kret = semaphore_signal(pinfo->psem_semobject); |
949 | switch (kret) { | |
950 | case KERN_INVALID_ADDRESS: | |
951 | case KERN_PROTECTION_FAILURE: | |
91447636 A |
952 | error = EINVAL; |
953 | break; | |
1c79356b A |
954 | case KERN_ABORTED: |
955 | case KERN_OPERATION_TIMED_OUT: | |
91447636 A |
956 | error = EINTR; |
957 | break; | |
1c79356b | 958 | case KERN_SUCCESS: |
91447636 A |
959 | error = 0; |
960 | break; | |
1c79356b | 961 | default: |
91447636 A |
962 | error = EINVAL; |
963 | break; | |
1c79356b | 964 | } |
91447636 A |
965 | out: |
966 | fp_drop(p, fd, fp, 0); | |
967 | return(error); | |
1c79356b A |
968 | } |
969 | ||
1c79356b | 970 | int |
2d21ac55 | 971 | sem_init(__unused proc_t p, __unused struct sem_init_args *uap, __unused register_t *retval) |
1c79356b A |
972 | { |
973 | return(ENOSYS); | |
974 | } | |
975 | ||
1c79356b | 976 | int |
2d21ac55 | 977 | sem_destroy(__unused proc_t p, __unused struct sem_destroy_args *uap, __unused register_t *retval) |
1c79356b A |
978 | { |
979 | return(ENOSYS); | |
980 | } | |
981 | ||
1c79356b | 982 | int |
2d21ac55 | 983 | sem_getvalue(__unused proc_t p, __unused struct sem_getvalue_args *uap, __unused register_t *retval) |
1c79356b A |
984 | { |
985 | return(ENOSYS); | |
986 | } | |
987 | ||
9bccf70c | 988 | static int |
2d21ac55 | 989 | psem_close(struct psemnode *pnode, __unused int flags) |
1c79356b A |
990 | { |
991 | int error=0; | |
2d21ac55 | 992 | struct pseminfo *pinfo; |
1c79356b | 993 | |
91447636 A |
994 | PSEM_SUBSYS_LOCK(); |
995 | if ((pinfo = pnode->pinfo) == PSEMINFO_NULL){ | |
996 | PSEM_SUBSYS_UNLOCK(); | |
1c79356b | 997 | return(EINVAL); |
91447636 | 998 | } |
1c79356b A |
999 | |
1000 | if ((pinfo->psem_flags & PSEM_ALLOCATED) != PSEM_ALLOCATED) { | |
91447636 | 1001 | PSEM_SUBSYS_UNLOCK(); |
1c79356b A |
1002 | return(EINVAL); |
1003 | } | |
1004 | #if DIAGNOSTIC | |
1005 | if(!pinfo->psem_usecount) { | |
1006 | kprintf("negative usecount in psem_close\n"); | |
1007 | } | |
1008 | #endif /* DIAGNOSTIC */ | |
1009 | pinfo->psem_usecount--; | |
1010 | ||
1011 | if ((pinfo->psem_flags & PSEM_REMOVED) && !pinfo->psem_usecount) { | |
91447636 A |
1012 | PSEM_SUBSYS_UNLOCK(); |
1013 | /* lock dropped as only semaphore is destroyed here */ | |
1c79356b | 1014 | error = psem_delete(pinfo); |
91447636 A |
1015 | FREE(pinfo,M_SHM); |
1016 | } else { | |
1017 | PSEM_SUBSYS_UNLOCK(); | |
1c79356b | 1018 | } |
91447636 A |
1019 | /* subsystem lock is dropped when we get here */ |
1020 | FREE(pnode, M_SHM); | |
1c79356b A |
1021 | return (error); |
1022 | } | |
1023 | ||
9bccf70c | 1024 | static int |
2d21ac55 | 1025 | psem_closefile(struct fileglob *fg, __unused vfs_context_t ctx) |
9bccf70c | 1026 | { |
91447636 | 1027 | int error; |
9bccf70c | 1028 | |
2d21ac55 A |
1029 | /* |
1030 | * Not locked as psem_close is called only from here and is locked | |
1031 | * properly | |
1032 | */ | |
1033 | error = psem_close(((struct psemnode *)fg->fg_data), fg->fg_flag); | |
91447636 A |
1034 | |
1035 | return(error); | |
9bccf70c A |
1036 | } |
1037 | ||
91447636 | 1038 | static int |
1c79356b A |
1039 | psem_delete(struct pseminfo * pinfo) |
1040 | { | |
1041 | kern_return_t kret; | |
1042 | ||
1043 | kret = semaphore_destroy(kernel_task, pinfo->psem_semobject); | |
2d21ac55 A |
1044 | #if CONFIG_MACF |
1045 | mac_posixsem_label_destroy(pinfo); | |
1046 | #endif | |
1c79356b A |
1047 | |
1048 | switch (kret) { | |
1049 | case KERN_INVALID_ADDRESS: | |
1050 | case KERN_PROTECTION_FAILURE: | |
1051 | return (EINVAL); | |
1052 | case KERN_ABORTED: | |
1053 | case KERN_OPERATION_TIMED_OUT: | |
1054 | return (EINTR); | |
1055 | case KERN_SUCCESS: | |
1056 | return(0); | |
1057 | default: | |
1058 | return (EINVAL); | |
1059 | } | |
1c79356b A |
1060 | } |
1061 | ||
9bccf70c | 1062 | static int |
91447636 | 1063 | psem_read(__unused struct fileproc *fp, __unused struct uio *uio, |
2d21ac55 | 1064 | __unused int flags, __unused vfs_context_t ctx) |
1c79356b | 1065 | { |
91447636 | 1066 | return(ENOTSUP); |
1c79356b | 1067 | } |
9bccf70c A |
1068 | |
1069 | static int | |
91447636 | 1070 | psem_write(__unused struct fileproc *fp, __unused struct uio *uio, |
2d21ac55 | 1071 | __unused int flags, __unused vfs_context_t ctx) |
1c79356b | 1072 | { |
91447636 | 1073 | return(ENOTSUP); |
1c79356b | 1074 | } |
9bccf70c A |
1075 | |
1076 | static int | |
91447636 | 1077 | psem_ioctl(__unused struct fileproc *fp, __unused u_long com, |
2d21ac55 | 1078 | __unused caddr_t data, __unused vfs_context_t ctx) |
1c79356b | 1079 | { |
91447636 | 1080 | return(ENOTSUP); |
1c79356b | 1081 | } |
9bccf70c A |
1082 | |
1083 | static int | |
91447636 | 1084 | psem_select(__unused struct fileproc *fp, __unused int which, |
2d21ac55 | 1085 | __unused void *wql, __unused vfs_context_t ctx) |
1c79356b | 1086 | { |
91447636 | 1087 | return(ENOTSUP); |
1c79356b | 1088 | } |
55e303ae A |
1089 | |
1090 | static int | |
91447636 | 1091 | psem_kqfilter(__unused struct fileproc *fp, __unused struct knote *kn, |
2d21ac55 | 1092 | __unused vfs_context_t ctx) |
55e303ae | 1093 | { |
91447636 | 1094 | return (ENOTSUP); |
55e303ae A |
1095 | } |
1096 | ||
0c530ab8 A |
1097 | int |
1098 | fill_pseminfo(struct psemnode *pnode, struct psem_info * info) | |
1099 | { | |
2d21ac55 A |
1100 | struct pseminfo *pinfo; |
1101 | struct vinfo_stat *sb; | |
0c530ab8 A |
1102 | |
1103 | PSEM_SUBSYS_LOCK(); | |
1104 | if ((pinfo = pnode->pinfo) == PSEMINFO_NULL){ | |
1105 | PSEM_SUBSYS_UNLOCK(); | |
1106 | return(EINVAL); | |
1107 | } | |
1108 | ||
1109 | #if 0 | |
1110 | if ((pinfo->psem_flags & PSEM_ALLOCATED) != PSEM_ALLOCATED) { | |
1111 | PSEM_SUBSYS_UNLOCK(); | |
1112 | return(EINVAL); | |
1113 | } | |
1114 | #endif | |
1115 | ||
1116 | sb = &info->psem_stat; | |
2d21ac55 | 1117 | bzero(sb, sizeof(struct vinfo_stat)); |
0c530ab8 | 1118 | |
2d21ac55 A |
1119 | sb->vst_mode = pinfo->psem_mode; |
1120 | sb->vst_uid = pinfo->psem_uid; | |
1121 | sb->vst_gid = pinfo->psem_gid; | |
1122 | sb->vst_size = pinfo->psem_usecount; | |
0c530ab8 A |
1123 | bcopy(&pinfo->psem_name[0], &info->psem_name[0], PSEMNAMLEN+1); |
1124 | ||
1125 | PSEM_SUBSYS_UNLOCK(); | |
1126 | return(0); | |
1127 | } | |
1128 | ||
2d21ac55 A |
1129 | #if CONFIG_MACF |
1130 | void | |
1131 | psem_label_associate(struct fileproc *fp, struct vnode *vp, vfs_context_t ctx) | |
1132 | { | |
1133 | struct psemnode *pnode; | |
1134 | struct pseminfo *psem; | |
1135 | ||
1136 | PSEM_SUBSYS_LOCK(); | |
1137 | pnode = (struct psemnode *)fp->f_fglob->fg_data; | |
1138 | if (pnode != NULL) { | |
1139 | psem = pnode->pinfo; | |
1140 | if (psem != NULL) | |
1141 | mac_posixsem_vnode_label_associate( | |
1142 | vfs_context_ucred(ctx), psem, psem->psem_label, | |
1143 | vp, vp->v_label); | |
1144 | } | |
1145 | PSEM_SUBSYS_UNLOCK(); | |
1146 | } | |
1147 | #endif | |
1148 |