The Design and Implementation of the FreeBSD Operating System, Second Edition
Now available: The Design and Implementation of the FreeBSD Operating System (Second Edition)


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]

FreeBSD/Linux Kernel Cross Reference
sys/kern/uipc_sem.c

Version: -  FREEBSD  -  FREEBSD-13-STABLE  -  FREEBSD-13-0  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  l41  -  OPENBSD  -  linux-2.6  -  MK84  -  PLAN9  -  xnu-8792 
SearchContext: -  none  -  3  -  10 

    1 /*-
    2  * Copyright (c) 2002 Alfred Perlstein <alfred@FreeBSD.org>
    3  * Copyright (c) 2003-2005 SPARTA, Inc.
    4  * Copyright (c) 2005 Robert N. M. Watson
    5  * All rights reserved.
    6  *
    7  * This software was developed for the FreeBSD Project in part by Network
    8  * Associates Laboratories, the Security Research Division of Network
    9  * Associates, Inc. under DARPA/SPAWAR contract N66001-01-C-8035 ("CBOSS"),
   10  * as part of the DARPA CHATS research program.
   11  *
   12  * Redistribution and use in source and binary forms, with or without
   13  * modification, are permitted provided that the following conditions
   14  * are met:
   15  * 1. Redistributions of source code must retain the above copyright
   16  *    notice, this list of conditions and the following disclaimer.
   17  * 2. Redistributions in binary form must reproduce the above copyright
   18  *    notice, this list of conditions and the following disclaimer in the
   19  *    documentation and/or other materials provided with the distribution.
   20  *
   21  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
   22  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   23  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
   24  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
   25  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
   26  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
   27  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
   28  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
   29  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
   30  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   31  * SUCH DAMAGE.
   32  */
   33 
   34 #include <sys/cdefs.h>
   35 __FBSDID("$FreeBSD: releng/11.1/sys/kern/uipc_sem.c 297976 2016-04-14 17:07:26Z jamie $");
   36 
   37 #include "opt_compat.h"
   38 #include "opt_posix.h"
   39 
   40 #include <sys/param.h>
   41 #include <sys/capsicum.h>
   42 #include <sys/condvar.h>
   43 #include <sys/fcntl.h>
   44 #include <sys/file.h>
   45 #include <sys/filedesc.h>
   46 #include <sys/fnv_hash.h>
   47 #include <sys/jail.h>
   48 #include <sys/kernel.h>
   49 #include <sys/ksem.h>
   50 #include <sys/lock.h>
   51 #include <sys/malloc.h>
   52 #include <sys/module.h>
   53 #include <sys/mutex.h>
   54 #include <sys/priv.h>
   55 #include <sys/proc.h>
   56 #include <sys/posix4.h>
   57 #include <sys/_semaphore.h>
   58 #include <sys/stat.h>
   59 #include <sys/syscall.h>
   60 #include <sys/syscallsubr.h>
   61 #include <sys/sysctl.h>
   62 #include <sys/sysent.h>
   63 #include <sys/sysproto.h>
   64 #include <sys/systm.h>
   65 #include <sys/sx.h>
   66 #include <sys/user.h>
   67 #include <sys/vnode.h>
   68 
   69 #include <security/mac/mac_framework.h>
   70 
   71 FEATURE(p1003_1b_semaphores, "POSIX P1003.1B semaphores support");
   72 /*
   73  * TODO
   74  *
   75  * - Resource limits?
   76  * - Replace global sem_lock with mtx_pool locks?
   77  * - Add a MAC check_create() hook for creating new named semaphores.
   78  */
   79 
   80 #ifndef SEM_MAX
   81 #define SEM_MAX 30
   82 #endif
   83 
   84 #ifdef SEM_DEBUG
   85 #define DP(x)   printf x
   86 #else
   87 #define DP(x)
   88 #endif
   89 
   90 struct ksem_mapping {
   91         char            *km_path;
   92         Fnv32_t         km_fnv;
   93         struct ksem     *km_ksem;
   94         LIST_ENTRY(ksem_mapping) km_link;
   95 };
   96 
   97 static MALLOC_DEFINE(M_KSEM, "ksem", "semaphore file descriptor");
   98 static LIST_HEAD(, ksem_mapping) *ksem_dictionary;
   99 static struct sx ksem_dict_lock;
  100 static struct mtx ksem_count_lock;
  101 static struct mtx sem_lock;
  102 static u_long ksem_hash;
  103 static int ksem_dead;
  104 
  105 #define KSEM_HASH(fnv)  (&ksem_dictionary[(fnv) & ksem_hash])
  106 
  107 static int nsems = 0;
  108 SYSCTL_DECL(_p1003_1b);
  109 SYSCTL_INT(_p1003_1b, OID_AUTO, nsems, CTLFLAG_RD, &nsems, 0,
  110     "Number of active kernel POSIX semaphores");
  111 
  112 static int      kern_sem_wait(struct thread *td, semid_t id, int tryflag,
  113                     struct timespec *abstime);
  114 static int      ksem_access(struct ksem *ks, struct ucred *ucred);
  115 static struct ksem *ksem_alloc(struct ucred *ucred, mode_t mode,
  116                     unsigned int value);
  117 static int      ksem_create(struct thread *td, const char *path,
  118                     semid_t *semidp, mode_t mode, unsigned int value,
  119                     int flags, int compat32);
  120 static void     ksem_drop(struct ksem *ks);
  121 static int      ksem_get(struct thread *td, semid_t id, cap_rights_t *rightsp,
  122     struct file **fpp);
  123 static struct ksem *ksem_hold(struct ksem *ks);
  124 static void     ksem_insert(char *path, Fnv32_t fnv, struct ksem *ks);
  125 static struct ksem *ksem_lookup(char *path, Fnv32_t fnv);
  126 static void     ksem_module_destroy(void);
  127 static int      ksem_module_init(void);
  128 static int      ksem_remove(char *path, Fnv32_t fnv, struct ucred *ucred);
  129 static int      sem_modload(struct module *module, int cmd, void *arg);
  130 
  131 static fo_stat_t        ksem_stat;
  132 static fo_close_t       ksem_closef;
  133 static fo_chmod_t       ksem_chmod;
  134 static fo_chown_t       ksem_chown;
  135 static fo_fill_kinfo_t  ksem_fill_kinfo;
  136 
  137 /* File descriptor operations. */
  138 static struct fileops ksem_ops = {
  139         .fo_read = invfo_rdwr,
  140         .fo_write = invfo_rdwr,
  141         .fo_truncate = invfo_truncate,
  142         .fo_ioctl = invfo_ioctl,
  143         .fo_poll = invfo_poll,
  144         .fo_kqfilter = invfo_kqfilter,
  145         .fo_stat = ksem_stat,
  146         .fo_close = ksem_closef,
  147         .fo_chmod = ksem_chmod,
  148         .fo_chown = ksem_chown,
  149         .fo_sendfile = invfo_sendfile,
  150         .fo_fill_kinfo = ksem_fill_kinfo,
  151         .fo_flags = DFLAG_PASSABLE
  152 };
  153 
  154 FEATURE(posix_sem, "POSIX semaphores");
  155 
  156 static int
  157 ksem_stat(struct file *fp, struct stat *sb, struct ucred *active_cred,
  158     struct thread *td)
  159 {
  160         struct ksem *ks;
  161 #ifdef MAC
  162         int error;
  163 #endif
  164 
  165         ks = fp->f_data;
  166 
  167 #ifdef MAC
  168         error = mac_posixsem_check_stat(active_cred, fp->f_cred, ks);
  169         if (error)
  170                 return (error);
  171 #endif
  172         
  173         /*
  174          * Attempt to return sanish values for fstat() on a semaphore
  175          * file descriptor.
  176          */
  177         bzero(sb, sizeof(*sb));
  178 
  179         mtx_lock(&sem_lock);
  180         sb->st_atim = ks->ks_atime;
  181         sb->st_ctim = ks->ks_ctime;
  182         sb->st_mtim = ks->ks_mtime;
  183         sb->st_birthtim = ks->ks_birthtime;
  184         sb->st_uid = ks->ks_uid;
  185         sb->st_gid = ks->ks_gid;
  186         sb->st_mode = S_IFREG | ks->ks_mode;            /* XXX */
  187         mtx_unlock(&sem_lock);
  188 
  189         return (0);
  190 }
  191 
  192 static int
  193 ksem_chmod(struct file *fp, mode_t mode, struct ucred *active_cred,
  194     struct thread *td)
  195 {
  196         struct ksem *ks;
  197         int error;
  198 
  199         error = 0;
  200         ks = fp->f_data;
  201         mtx_lock(&sem_lock);
  202 #ifdef MAC
  203         error = mac_posixsem_check_setmode(active_cred, ks, mode);
  204         if (error != 0)
  205                 goto out;
  206 #endif
  207         error = vaccess(VREG, ks->ks_mode, ks->ks_uid, ks->ks_gid, VADMIN,
  208             active_cred, NULL);
  209         if (error != 0)
  210                 goto out;
  211         ks->ks_mode = mode & ACCESSPERMS;
  212 out:
  213         mtx_unlock(&sem_lock);
  214         return (error);
  215 }
  216 
  217 static int
  218 ksem_chown(struct file *fp, uid_t uid, gid_t gid, struct ucred *active_cred,
  219     struct thread *td)
  220 {
  221         struct ksem *ks;
  222         int error;
  223 
  224         error = 0;
  225         ks = fp->f_data;
  226         mtx_lock(&sem_lock);
  227 #ifdef MAC
  228         error = mac_posixsem_check_setowner(active_cred, ks, uid, gid);
  229         if (error != 0)
  230                 goto out;
  231 #endif
  232         if (uid == (uid_t)-1)
  233                 uid = ks->ks_uid;
  234         if (gid == (gid_t)-1)
  235                  gid = ks->ks_gid;
  236         if (((uid != ks->ks_uid && uid != active_cred->cr_uid) ||
  237             (gid != ks->ks_gid && !groupmember(gid, active_cred))) &&
  238             (error = priv_check_cred(active_cred, PRIV_VFS_CHOWN, 0)))
  239                 goto out;
  240         ks->ks_uid = uid;
  241         ks->ks_gid = gid;
  242 out:
  243         mtx_unlock(&sem_lock);
  244         return (error);
  245 }
  246 
  247 static int
  248 ksem_closef(struct file *fp, struct thread *td)
  249 {
  250         struct ksem *ks;
  251 
  252         ks = fp->f_data;
  253         fp->f_data = NULL;
  254         ksem_drop(ks);
  255 
  256         return (0);
  257 }
  258 
  259 static int
  260 ksem_fill_kinfo(struct file *fp, struct kinfo_file *kif, struct filedesc *fdp)
  261 {
  262         const char *path, *pr_path;
  263         struct ksem *ks;
  264         size_t pr_pathlen;
  265 
  266         kif->kf_type = KF_TYPE_SEM;
  267         ks = fp->f_data;
  268         mtx_lock(&sem_lock);
  269         kif->kf_un.kf_sem.kf_sem_value = ks->ks_value;
  270         kif->kf_un.kf_sem.kf_sem_mode = S_IFREG | ks->ks_mode;  /* XXX */
  271         mtx_unlock(&sem_lock);
  272         if (ks->ks_path != NULL) {
  273                 sx_slock(&ksem_dict_lock);
  274                 if (ks->ks_path != NULL) {
  275                         path = ks->ks_path;
  276                         pr_path = curthread->td_ucred->cr_prison->pr_path;
  277                         if (strcmp(pr_path, "/") != 0) {
  278                                 /* Return the jail-rooted pathname. */
  279                                 pr_pathlen = strlen(pr_path);
  280                                 if (strncmp(path, pr_path, pr_pathlen) == 0 &&
  281                                     path[pr_pathlen] == '/')
  282                                         path += pr_pathlen;
  283                         }
  284                         strlcpy(kif->kf_path, path, sizeof(kif->kf_path));
  285                 }
  286                 sx_sunlock(&ksem_dict_lock);
  287         }
  288         return (0);
  289 }
  290 
  291 /*
  292  * ksem object management including creation and reference counting
  293  * routines.
  294  */
  295 static struct ksem *
  296 ksem_alloc(struct ucred *ucred, mode_t mode, unsigned int value)
  297 {
  298         struct ksem *ks;
  299 
  300         mtx_lock(&ksem_count_lock);
  301         if (nsems == p31b_getcfg(CTL_P1003_1B_SEM_NSEMS_MAX) || ksem_dead) {
  302                 mtx_unlock(&ksem_count_lock);
  303                 return (NULL);
  304         }
  305         nsems++;
  306         mtx_unlock(&ksem_count_lock);
  307         ks = malloc(sizeof(*ks), M_KSEM, M_WAITOK | M_ZERO);
  308         ks->ks_uid = ucred->cr_uid;
  309         ks->ks_gid = ucred->cr_gid;
  310         ks->ks_mode = mode;
  311         ks->ks_value = value;
  312         cv_init(&ks->ks_cv, "ksem");
  313         vfs_timestamp(&ks->ks_birthtime);
  314         ks->ks_atime = ks->ks_mtime = ks->ks_ctime = ks->ks_birthtime;
  315         refcount_init(&ks->ks_ref, 1);
  316 #ifdef MAC
  317         mac_posixsem_init(ks);
  318         mac_posixsem_create(ucred, ks);
  319 #endif
  320 
  321         return (ks);
  322 }
  323 
  324 static struct ksem *
  325 ksem_hold(struct ksem *ks)
  326 {
  327 
  328         refcount_acquire(&ks->ks_ref);
  329         return (ks);
  330 }
  331 
  332 static void
  333 ksem_drop(struct ksem *ks)
  334 {
  335 
  336         if (refcount_release(&ks->ks_ref)) {
  337 #ifdef MAC
  338                 mac_posixsem_destroy(ks);
  339 #endif
  340                 cv_destroy(&ks->ks_cv);
  341                 free(ks, M_KSEM);
  342                 mtx_lock(&ksem_count_lock);
  343                 nsems--;
  344                 mtx_unlock(&ksem_count_lock);
  345         }
  346 }
  347 
  348 /*
  349  * Determine if the credentials have sufficient permissions for read
  350  * and write access.
  351  */
  352 static int
  353 ksem_access(struct ksem *ks, struct ucred *ucred)
  354 {
  355         int error;
  356 
  357         error = vaccess(VREG, ks->ks_mode, ks->ks_uid, ks->ks_gid,
  358             VREAD | VWRITE, ucred, NULL);
  359         if (error)
  360                 error = priv_check_cred(ucred, PRIV_SEM_WRITE, 0);
  361         return (error);
  362 }
  363 
  364 /*
  365  * Dictionary management.  We maintain an in-kernel dictionary to map
  366  * paths to semaphore objects.  We use the FNV hash on the path to
  367  * store the mappings in a hash table.
  368  */
  369 static struct ksem *
  370 ksem_lookup(char *path, Fnv32_t fnv)
  371 {
  372         struct ksem_mapping *map;
  373 
  374         LIST_FOREACH(map, KSEM_HASH(fnv), km_link) {
  375                 if (map->km_fnv != fnv)
  376                         continue;
  377                 if (strcmp(map->km_path, path) == 0)
  378                         return (map->km_ksem);
  379         }
  380 
  381         return (NULL);
  382 }
  383 
  384 static void
  385 ksem_insert(char *path, Fnv32_t fnv, struct ksem *ks)
  386 {
  387         struct ksem_mapping *map;
  388 
  389         map = malloc(sizeof(struct ksem_mapping), M_KSEM, M_WAITOK);
  390         map->km_path = path;
  391         map->km_fnv = fnv;
  392         map->km_ksem = ksem_hold(ks);
  393         ks->ks_path = path;
  394         LIST_INSERT_HEAD(KSEM_HASH(fnv), map, km_link);
  395 }
  396 
  397 static int
  398 ksem_remove(char *path, Fnv32_t fnv, struct ucred *ucred)
  399 {
  400         struct ksem_mapping *map;
  401         int error;
  402 
  403         LIST_FOREACH(map, KSEM_HASH(fnv), km_link) {
  404                 if (map->km_fnv != fnv)
  405                         continue;
  406                 if (strcmp(map->km_path, path) == 0) {
  407 #ifdef MAC
  408                         error = mac_posixsem_check_unlink(ucred, map->km_ksem);
  409                         if (error)
  410                                 return (error);
  411 #endif
  412                         error = ksem_access(map->km_ksem, ucred);
  413                         if (error)
  414                                 return (error);
  415                         map->km_ksem->ks_path = NULL;
  416                         LIST_REMOVE(map, km_link);
  417                         ksem_drop(map->km_ksem);
  418                         free(map->km_path, M_KSEM);
  419                         free(map, M_KSEM);
  420                         return (0);
  421                 }
  422         }
  423 
  424         return (ENOENT);
  425 }
  426 
  427 static int
  428 ksem_create_copyout_semid(struct thread *td, semid_t *semidp, int fd,
  429     int compat32)
  430 {
  431         semid_t semid;
  432 #ifdef COMPAT_FREEBSD32
  433         int32_t semid32;
  434 #endif
  435         void *ptr;
  436         size_t ptrs;
  437 
  438 #ifdef COMPAT_FREEBSD32
  439         if (compat32) {
  440                 semid32 = fd;
  441                 ptr = &semid32;
  442                 ptrs = sizeof(semid32);
  443         } else {
  444 #endif
  445                 semid = fd;
  446                 ptr = &semid;
  447                 ptrs = sizeof(semid);
  448                 compat32 = 0; /* silence gcc */
  449 #ifdef COMPAT_FREEBSD32
  450         }
  451 #endif
  452 
  453         return (copyout(ptr, semidp, ptrs));
  454 }
  455 
  456 /* Other helper routines. */
  457 static int
  458 ksem_create(struct thread *td, const char *name, semid_t *semidp, mode_t mode,
  459     unsigned int value, int flags, int compat32)
  460 {
  461         struct filedesc *fdp;
  462         struct ksem *ks;
  463         struct file *fp;
  464         char *path;
  465         const char *pr_path;
  466         size_t pr_pathlen;
  467         Fnv32_t fnv;
  468         int error, fd;
  469 
  470         if (value > SEM_VALUE_MAX)
  471                 return (EINVAL);
  472 
  473         fdp = td->td_proc->p_fd;
  474         mode = (mode & ~fdp->fd_cmask) & ACCESSPERMS;
  475         error = falloc(td, &fp, &fd, O_CLOEXEC);
  476         if (error) {
  477                 if (name == NULL)
  478                         error = ENOSPC;
  479                 return (error);
  480         }
  481 
  482         /*
  483          * Go ahead and copyout the file descriptor now.  This is a bit
  484          * premature, but it is a lot easier to handle errors as opposed
  485          * to later when we've possibly created a new semaphore, etc.
  486          */
  487         error = ksem_create_copyout_semid(td, semidp, fd, compat32);
  488         if (error) {
  489                 fdclose(td, fp, fd);
  490                 fdrop(fp, td);
  491                 return (error);
  492         }
  493 
  494         if (name == NULL) {
  495                 /* Create an anonymous semaphore. */
  496                 ks = ksem_alloc(td->td_ucred, mode, value);
  497                 if (ks == NULL)
  498                         error = ENOSPC;
  499                 else
  500                         ks->ks_flags |= KS_ANONYMOUS;
  501         } else {
  502                 path = malloc(MAXPATHLEN, M_KSEM, M_WAITOK);
  503                 pr_path = td->td_ucred->cr_prison->pr_path;
  504 
  505                 /* Construct a full pathname for jailed callers. */
  506                 pr_pathlen = strcmp(pr_path, "/") == 0 ? 0
  507                     : strlcpy(path, pr_path, MAXPATHLEN);
  508                 error = copyinstr(name, path + pr_pathlen,
  509                     MAXPATHLEN - pr_pathlen, NULL);
  510 
  511                 /* Require paths to start with a '/' character. */
  512                 if (error == 0 && path[pr_pathlen] != '/')
  513                         error = EINVAL;
  514                 if (error) {
  515                         fdclose(td, fp, fd);
  516                         fdrop(fp, td);
  517                         free(path, M_KSEM);
  518                         return (error);
  519                 }
  520 
  521                 fnv = fnv_32_str(path, FNV1_32_INIT);
  522                 sx_xlock(&ksem_dict_lock);
  523                 ks = ksem_lookup(path, fnv);
  524                 if (ks == NULL) {
  525                         /* Object does not exist, create it if requested. */
  526                         if (flags & O_CREAT) {
  527                                 ks = ksem_alloc(td->td_ucred, mode, value);
  528                                 if (ks == NULL)
  529                                         error = ENFILE;
  530                                 else {
  531                                         ksem_insert(path, fnv, ks);
  532                                         path = NULL;
  533                                 }
  534                         } else
  535                                 error = ENOENT;
  536                 } else {
  537                         /*
  538                          * Object already exists, obtain a new
  539                          * reference if requested and permitted.
  540                          */
  541                         if ((flags & (O_CREAT | O_EXCL)) ==
  542                             (O_CREAT | O_EXCL))
  543                                 error = EEXIST;
  544                         else {
  545 #ifdef MAC
  546                                 error = mac_posixsem_check_open(td->td_ucred,
  547                                     ks);
  548                                 if (error == 0)
  549 #endif
  550                                 error = ksem_access(ks, td->td_ucred);
  551                         }
  552                         if (error == 0)
  553                                 ksem_hold(ks);
  554 #ifdef INVARIANTS
  555                         else
  556                                 ks = NULL;
  557 #endif
  558                 }
  559                 sx_xunlock(&ksem_dict_lock);
  560                 if (path)
  561                         free(path, M_KSEM);
  562         }
  563 
  564         if (error) {
  565                 KASSERT(ks == NULL, ("ksem_create error with a ksem"));
  566                 fdclose(td, fp, fd);
  567                 fdrop(fp, td);
  568                 return (error);
  569         }
  570         KASSERT(ks != NULL, ("ksem_create w/o a ksem"));
  571 
  572         finit(fp, FREAD | FWRITE, DTYPE_SEM, ks, &ksem_ops);
  573 
  574         fdrop(fp, td);
  575 
  576         return (0);
  577 }
  578 
  579 static int
  580 ksem_get(struct thread *td, semid_t id, cap_rights_t *rightsp,
  581     struct file **fpp)
  582 {
  583         struct ksem *ks;
  584         struct file *fp;
  585         int error;
  586 
  587         error = fget(td, id, rightsp, &fp);
  588         if (error)
  589                 return (EINVAL);
  590         if (fp->f_type != DTYPE_SEM) {
  591                 fdrop(fp, td);
  592                 return (EINVAL);
  593         }
  594         ks = fp->f_data;
  595         if (ks->ks_flags & KS_DEAD) {
  596                 fdrop(fp, td);
  597                 return (EINVAL);
  598         }
  599         *fpp = fp;
  600         return (0);
  601 }
  602 
  603 /* System calls. */
  604 #ifndef _SYS_SYSPROTO_H_
  605 struct ksem_init_args {
  606         unsigned int    value;
  607         semid_t         *idp;
  608 };
  609 #endif
  610 int
  611 sys_ksem_init(struct thread *td, struct ksem_init_args *uap)
  612 {
  613 
  614         return (ksem_create(td, NULL, uap->idp, S_IRWXU | S_IRWXG, uap->value,
  615             0, 0));
  616 }
  617 
  618 #ifndef _SYS_SYSPROTO_H_
  619 struct ksem_open_args {
  620         char            *name;
  621         int             oflag;
  622         mode_t          mode;
  623         unsigned int    value;
  624         semid_t         *idp;   
  625 };
  626 #endif
  627 int
  628 sys_ksem_open(struct thread *td, struct ksem_open_args *uap)
  629 {
  630 
  631         DP((">>> ksem_open start, pid=%d\n", (int)td->td_proc->p_pid));
  632 
  633         if ((uap->oflag & ~(O_CREAT | O_EXCL)) != 0)
  634                 return (EINVAL);
  635         return (ksem_create(td, uap->name, uap->idp, uap->mode, uap->value,
  636             uap->oflag, 0));
  637 }
  638 
  639 #ifndef _SYS_SYSPROTO_H_
  640 struct ksem_unlink_args {
  641         char            *name;
  642 };
  643 #endif
  644 int
  645 sys_ksem_unlink(struct thread *td, struct ksem_unlink_args *uap)
  646 {
  647         char *path;
  648         const char *pr_path;
  649         size_t pr_pathlen;
  650         Fnv32_t fnv;
  651         int error;
  652 
  653         path = malloc(MAXPATHLEN, M_TEMP, M_WAITOK);
  654         pr_path = td->td_ucred->cr_prison->pr_path;
  655         pr_pathlen = strcmp(pr_path, "/") == 0 ? 0
  656             : strlcpy(path, pr_path, MAXPATHLEN);
  657         error = copyinstr(uap->name, path + pr_pathlen, MAXPATHLEN - pr_pathlen,
  658             NULL);
  659         if (error) {
  660                 free(path, M_TEMP);
  661                 return (error);
  662         }
  663 
  664         fnv = fnv_32_str(path, FNV1_32_INIT);
  665         sx_xlock(&ksem_dict_lock);
  666         error = ksem_remove(path, fnv, td->td_ucred);
  667         sx_xunlock(&ksem_dict_lock);
  668         free(path, M_TEMP);
  669 
  670         return (error);
  671 }
  672 
  673 #ifndef _SYS_SYSPROTO_H_
  674 struct ksem_close_args {
  675         semid_t         id;
  676 };
  677 #endif
  678 int
  679 sys_ksem_close(struct thread *td, struct ksem_close_args *uap)
  680 {
  681         cap_rights_t rights;
  682         struct ksem *ks;
  683         struct file *fp;
  684         int error;
  685 
  686         /* No capability rights required to close a semaphore. */
  687         error = ksem_get(td, uap->id, cap_rights_init(&rights), &fp);
  688         if (error)
  689                 return (error);
  690         ks = fp->f_data;
  691         if (ks->ks_flags & KS_ANONYMOUS) {
  692                 fdrop(fp, td);
  693                 return (EINVAL);
  694         }
  695         error = kern_close(td, uap->id);
  696         fdrop(fp, td);
  697         return (error);
  698 }
  699 
  700 #ifndef _SYS_SYSPROTO_H_
  701 struct ksem_post_args {
  702         semid_t id;
  703 };
  704 #endif
  705 int
  706 sys_ksem_post(struct thread *td, struct ksem_post_args *uap)
  707 {
  708         cap_rights_t rights;
  709         struct file *fp;
  710         struct ksem *ks;
  711         int error;
  712 
  713         error = ksem_get(td, uap->id,
  714             cap_rights_init(&rights, CAP_SEM_POST), &fp);
  715         if (error)
  716                 return (error);
  717         ks = fp->f_data;
  718 
  719         mtx_lock(&sem_lock);
  720 #ifdef MAC
  721         error = mac_posixsem_check_post(td->td_ucred, fp->f_cred, ks);
  722         if (error)
  723                 goto err;
  724 #endif
  725         if (ks->ks_value == SEM_VALUE_MAX) {
  726                 error = EOVERFLOW;
  727                 goto err;
  728         }
  729         ++ks->ks_value;
  730         if (ks->ks_waiters > 0)
  731                 cv_signal(&ks->ks_cv);
  732         error = 0;
  733         vfs_timestamp(&ks->ks_ctime);
  734 err:
  735         mtx_unlock(&sem_lock);
  736         fdrop(fp, td);
  737         return (error);
  738 }
  739 
  740 #ifndef _SYS_SYSPROTO_H_
  741 struct ksem_wait_args {
  742         semid_t         id;
  743 };
  744 #endif
  745 int
  746 sys_ksem_wait(struct thread *td, struct ksem_wait_args *uap)
  747 {
  748 
  749         return (kern_sem_wait(td, uap->id, 0, NULL));
  750 }
  751 
  752 #ifndef _SYS_SYSPROTO_H_
  753 struct ksem_timedwait_args {
  754         semid_t         id;
  755         const struct timespec *abstime;
  756 };
  757 #endif
  758 int
  759 sys_ksem_timedwait(struct thread *td, struct ksem_timedwait_args *uap)
  760 {
  761         struct timespec abstime;
  762         struct timespec *ts;
  763         int error;
  764 
  765         /*
  766          * We allow a null timespec (wait forever).
  767          */
  768         if (uap->abstime == NULL)
  769                 ts = NULL;
  770         else {
  771                 error = copyin(uap->abstime, &abstime, sizeof(abstime));
  772                 if (error != 0)
  773                         return (error);
  774                 if (abstime.tv_nsec >= 1000000000 || abstime.tv_nsec < 0)
  775                         return (EINVAL);
  776                 ts = &abstime;
  777         }
  778         return (kern_sem_wait(td, uap->id, 0, ts));
  779 }
  780 
  781 #ifndef _SYS_SYSPROTO_H_
  782 struct ksem_trywait_args {
  783         semid_t         id;
  784 };
  785 #endif
  786 int
  787 sys_ksem_trywait(struct thread *td, struct ksem_trywait_args *uap)
  788 {
  789 
  790         return (kern_sem_wait(td, uap->id, 1, NULL));
  791 }
  792 
  793 static int
  794 kern_sem_wait(struct thread *td, semid_t id, int tryflag,
  795     struct timespec *abstime)
  796 {
  797         struct timespec ts1, ts2;
  798         struct timeval tv;
  799         cap_rights_t rights;
  800         struct file *fp;
  801         struct ksem *ks;
  802         int error;
  803 
  804         DP((">>> kern_sem_wait entered! pid=%d\n", (int)td->td_proc->p_pid));
  805         error = ksem_get(td, id, cap_rights_init(&rights, CAP_SEM_WAIT), &fp);
  806         if (error)
  807                 return (error);
  808         ks = fp->f_data;
  809         mtx_lock(&sem_lock);
  810         DP((">>> kern_sem_wait critical section entered! pid=%d\n",
  811             (int)td->td_proc->p_pid));
  812 #ifdef MAC
  813         error = mac_posixsem_check_wait(td->td_ucred, fp->f_cred, ks);
  814         if (error) {
  815                 DP(("kern_sem_wait mac failed\n"));
  816                 goto err;
  817         }
  818 #endif
  819         DP(("kern_sem_wait value = %d, tryflag %d\n", ks->ks_value, tryflag));
  820         vfs_timestamp(&ks->ks_atime);
  821         while (ks->ks_value == 0) {
  822                 ks->ks_waiters++;
  823                 if (tryflag != 0)
  824                         error = EAGAIN;
  825                 else if (abstime == NULL)
  826                         error = cv_wait_sig(&ks->ks_cv, &sem_lock);
  827                 else {
  828                         for (;;) {
  829                                 ts1 = *abstime;
  830                                 getnanotime(&ts2);
  831                                 timespecsub(&ts1, &ts2);
  832                                 TIMESPEC_TO_TIMEVAL(&tv, &ts1);
  833                                 if (tv.tv_sec < 0) {
  834                                         error = ETIMEDOUT;
  835                                         break;
  836                                 }
  837                                 error = cv_timedwait_sig(&ks->ks_cv,
  838                                     &sem_lock, tvtohz(&tv));
  839                                 if (error != EWOULDBLOCK)
  840                                         break;
  841                         }
  842                 }
  843                 ks->ks_waiters--;
  844                 if (error)
  845                         goto err;
  846         }
  847         ks->ks_value--;
  848         DP(("kern_sem_wait value post-decrement = %d\n", ks->ks_value));
  849         error = 0;
  850 err:
  851         mtx_unlock(&sem_lock);
  852         fdrop(fp, td);
  853         DP(("<<< kern_sem_wait leaving, pid=%d, error = %d\n",
  854             (int)td->td_proc->p_pid, error));
  855         return (error);
  856 }
  857 
  858 #ifndef _SYS_SYSPROTO_H_
  859 struct ksem_getvalue_args {
  860         semid_t         id;
  861         int             *val;
  862 };
  863 #endif
  864 int
  865 sys_ksem_getvalue(struct thread *td, struct ksem_getvalue_args *uap)
  866 {
  867         cap_rights_t rights;
  868         struct file *fp;
  869         struct ksem *ks;
  870         int error, val;
  871 
  872         error = ksem_get(td, uap->id,
  873             cap_rights_init(&rights, CAP_SEM_GETVALUE), &fp);
  874         if (error)
  875                 return (error);
  876         ks = fp->f_data;
  877 
  878         mtx_lock(&sem_lock);
  879 #ifdef MAC
  880         error = mac_posixsem_check_getvalue(td->td_ucred, fp->f_cred, ks);
  881         if (error) {
  882                 mtx_unlock(&sem_lock);
  883                 fdrop(fp, td);
  884                 return (error);
  885         }
  886 #endif
  887         val = ks->ks_value;
  888         vfs_timestamp(&ks->ks_atime);
  889         mtx_unlock(&sem_lock);
  890         fdrop(fp, td);
  891         error = copyout(&val, uap->val, sizeof(val));
  892         return (error);
  893 }
  894 
  895 #ifndef _SYS_SYSPROTO_H_
  896 struct ksem_destroy_args {
  897         semid_t         id;
  898 };
  899 #endif
  900 int
  901 sys_ksem_destroy(struct thread *td, struct ksem_destroy_args *uap)
  902 {
  903         cap_rights_t rights;
  904         struct file *fp;
  905         struct ksem *ks;
  906         int error;
  907 
  908         /* No capability rights required to close a semaphore. */
  909         error = ksem_get(td, uap->id, cap_rights_init(&rights), &fp);
  910         if (error)
  911                 return (error);
  912         ks = fp->f_data;
  913         if (!(ks->ks_flags & KS_ANONYMOUS)) {
  914                 fdrop(fp, td);
  915                 return (EINVAL);
  916         }
  917         mtx_lock(&sem_lock);
  918         if (ks->ks_waiters != 0) {
  919                 mtx_unlock(&sem_lock);
  920                 error = EBUSY;
  921                 goto err;
  922         }
  923         ks->ks_flags |= KS_DEAD;
  924         mtx_unlock(&sem_lock);
  925 
  926         error = kern_close(td, uap->id);
  927 err:
  928         fdrop(fp, td);
  929         return (error);
  930 }
  931 
  932 static struct syscall_helper_data ksem_syscalls[] = {
  933         SYSCALL_INIT_HELPER(ksem_init),
  934         SYSCALL_INIT_HELPER(ksem_open),
  935         SYSCALL_INIT_HELPER(ksem_unlink),
  936         SYSCALL_INIT_HELPER(ksem_close),
  937         SYSCALL_INIT_HELPER(ksem_post),
  938         SYSCALL_INIT_HELPER(ksem_wait),
  939         SYSCALL_INIT_HELPER(ksem_timedwait),
  940         SYSCALL_INIT_HELPER(ksem_trywait),
  941         SYSCALL_INIT_HELPER(ksem_getvalue),
  942         SYSCALL_INIT_HELPER(ksem_destroy),
  943         SYSCALL_INIT_LAST
  944 };
  945 
  946 #ifdef COMPAT_FREEBSD32
  947 #include <compat/freebsd32/freebsd32.h>
  948 #include <compat/freebsd32/freebsd32_proto.h>
  949 #include <compat/freebsd32/freebsd32_signal.h>
  950 #include <compat/freebsd32/freebsd32_syscall.h>
  951 #include <compat/freebsd32/freebsd32_util.h>
  952 
  953 int
  954 freebsd32_ksem_init(struct thread *td, struct freebsd32_ksem_init_args *uap)
  955 {
  956 
  957         return (ksem_create(td, NULL, uap->idp, S_IRWXU | S_IRWXG, uap->value,
  958             0, 1));
  959 }
  960 
  961 int
  962 freebsd32_ksem_open(struct thread *td, struct freebsd32_ksem_open_args *uap)
  963 {
  964 
  965         if ((uap->oflag & ~(O_CREAT | O_EXCL)) != 0)
  966                 return (EINVAL);
  967         return (ksem_create(td, uap->name, uap->idp, uap->mode, uap->value,
  968             uap->oflag, 1));
  969 }
  970 
  971 int
  972 freebsd32_ksem_timedwait(struct thread *td,
  973     struct freebsd32_ksem_timedwait_args *uap)
  974 {
  975         struct timespec32 abstime32;
  976         struct timespec *ts, abstime;
  977         int error;
  978 
  979         /*
  980          * We allow a null timespec (wait forever).
  981          */
  982         if (uap->abstime == NULL)
  983                 ts = NULL;
  984         else {
  985                 error = copyin(uap->abstime, &abstime32, sizeof(abstime32));
  986                 if (error != 0)
  987                         return (error);
  988                 CP(abstime32, abstime, tv_sec);
  989                 CP(abstime32, abstime, tv_nsec);
  990                 if (abstime.tv_nsec >= 1000000000 || abstime.tv_nsec < 0)
  991                         return (EINVAL);
  992                 ts = &abstime;
  993         }
  994         return (kern_sem_wait(td, uap->id, 0, ts));
  995 }
  996 
  997 static struct syscall_helper_data ksem32_syscalls[] = {
  998         SYSCALL32_INIT_HELPER(freebsd32_ksem_init),
  999         SYSCALL32_INIT_HELPER(freebsd32_ksem_open),
 1000         SYSCALL32_INIT_HELPER_COMPAT(ksem_unlink),
 1001         SYSCALL32_INIT_HELPER_COMPAT(ksem_close),
 1002         SYSCALL32_INIT_HELPER_COMPAT(ksem_post),
 1003         SYSCALL32_INIT_HELPER_COMPAT(ksem_wait),
 1004         SYSCALL32_INIT_HELPER(freebsd32_ksem_timedwait),
 1005         SYSCALL32_INIT_HELPER_COMPAT(ksem_trywait),
 1006         SYSCALL32_INIT_HELPER_COMPAT(ksem_getvalue),
 1007         SYSCALL32_INIT_HELPER_COMPAT(ksem_destroy),
 1008         SYSCALL_INIT_LAST
 1009 };
 1010 #endif
 1011 
 1012 static int
 1013 ksem_module_init(void)
 1014 {
 1015         int error;
 1016 
 1017         mtx_init(&sem_lock, "sem", NULL, MTX_DEF);
 1018         mtx_init(&ksem_count_lock, "ksem count", NULL, MTX_DEF);
 1019         sx_init(&ksem_dict_lock, "ksem dictionary");
 1020         ksem_dictionary = hashinit(1024, M_KSEM, &ksem_hash);
 1021         p31b_setcfg(CTL_P1003_1B_SEMAPHORES, 200112L);
 1022         p31b_setcfg(CTL_P1003_1B_SEM_NSEMS_MAX, SEM_MAX);
 1023         p31b_setcfg(CTL_P1003_1B_SEM_VALUE_MAX, SEM_VALUE_MAX);
 1024 
 1025         error = syscall_helper_register(ksem_syscalls, SY_THR_STATIC_KLD);
 1026         if (error)
 1027                 return (error);
 1028 #ifdef COMPAT_FREEBSD32
 1029         error = syscall32_helper_register(ksem32_syscalls, SY_THR_STATIC_KLD);
 1030         if (error)
 1031                 return (error);
 1032 #endif
 1033         return (0);
 1034 }
 1035 
 1036 static void
 1037 ksem_module_destroy(void)
 1038 {
 1039 
 1040 #ifdef COMPAT_FREEBSD32
 1041         syscall32_helper_unregister(ksem32_syscalls);
 1042 #endif
 1043         syscall_helper_unregister(ksem_syscalls);
 1044 
 1045         p31b_setcfg(CTL_P1003_1B_SEMAPHORES, 0);
 1046         hashdestroy(ksem_dictionary, M_KSEM, ksem_hash);
 1047         sx_destroy(&ksem_dict_lock);
 1048         mtx_destroy(&ksem_count_lock);
 1049         mtx_destroy(&sem_lock);
 1050         p31b_unsetcfg(CTL_P1003_1B_SEM_VALUE_MAX);
 1051         p31b_unsetcfg(CTL_P1003_1B_SEM_NSEMS_MAX);
 1052 }
 1053 
 1054 static int
 1055 sem_modload(struct module *module, int cmd, void *arg)
 1056 {
 1057         int error = 0;
 1058 
 1059         switch (cmd) {
 1060         case MOD_LOAD:
 1061                 error = ksem_module_init();
 1062                 if (error)
 1063                         ksem_module_destroy();
 1064                 break;
 1065 
 1066         case MOD_UNLOAD:
 1067                 mtx_lock(&ksem_count_lock);
 1068                 if (nsems != 0) {
 1069                         error = EOPNOTSUPP;
 1070                         mtx_unlock(&ksem_count_lock);
 1071                         break;
 1072                 }
 1073                 ksem_dead = 1;
 1074                 mtx_unlock(&ksem_count_lock);
 1075                 ksem_module_destroy();
 1076                 break;
 1077 
 1078         case MOD_SHUTDOWN:
 1079                 break;
 1080         default:
 1081                 error = EINVAL;
 1082                 break;
 1083         }
 1084         return (error);
 1085 }
 1086 
 1087 static moduledata_t sem_mod = {
 1088         "sem",
 1089         &sem_modload,
 1090         NULL
 1091 };
 1092 
 1093 DECLARE_MODULE(sem, sem_mod, SI_SUB_SYSV_SEM, SI_ORDER_FIRST);
 1094 MODULE_VERSION(sem, 1);

Cache object: f9be7fbb68064b22a2383244d02a09e4


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]


This page is part of the FreeBSD/Linux Linux Kernel Cross-Reference, and was automatically generated using a modified version of the LXR engine.