1 /*
   2  * CDDL HEADER START
   3  *
   4  * The contents of this file are subject to the terms of the
   5  * Common Development and Distribution License (the "License").
   6  * You may not use this file except in compliance with the License.
   7  *
   8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
   9  * or http://www.opensolaris.org/os/licensing.
  10  * See the License for the specific language governing permissions
  11  * and limitations under the License.
  12  *
  13  * When distributing Covered Code, include this CDDL HEADER in each
  14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
  15  * If applicable, add the following below this CDDL HEADER, with the
  16  * fields enclosed by brackets "[]" replaced with your own identifying
  17  * information: Portions Copyright [yyyy] [name of copyright owner]
  18  *
  19  * CDDL HEADER END
  20  */
  21 /*
  22  * Copyright (c) 2002, 2010, Oracle and/or its affiliates. All rights reserved.
  23  * Copyright 2016, Joyent, Inc.
  24  */
  25 
  26 #ifndef _IPC_IMPL_H
  27 #define _IPC_IMPL_H
  28 
  29 #include <sys/types.h>
  30 #include <sys/ipc.h>
  31 #include <sys/mutex.h>
  32 #include <sys/ipc_rctl.h>
  33 #include <sys/project.h>
  34 #include <sys/zone.h>
  35 #include <sys/sysmacros.h>
  36 #include <sys/avl.h>
  37 #include <sys/id_space.h>
  38 #include <sys/cred.h>
  39 #include <sys/list.h>
  40 
  41 #ifdef  __cplusplus
  42 extern "C" {
  43 #endif
  44 
  45 typedef uint64_t ipc_time_t;
  46 
  47 /* For xxxctl64 */
  48 #define IPC_SET64       13      /* set options */
  49 #define IPC_STAT64      14      /* get options */
  50 
  51 /*
  52  * There are two versions of the userland ipc_perm structure:
  53  *   ipc_perm     - the version used by user applications and by the kernel
  54  *                  when the user and kernel data models match (in ipc.h)
  55  *   ipc_perm32   - the 64-bit kernel's view of a 32-bit struct ipc_perm
  56  */
  57 #if     defined(_SYSCALL32)
  58 struct ipc_perm32 {
  59         uid32_t         uid;    /* owner's user id */
  60         gid32_t         gid;    /* owner's group id */
  61         uid32_t         cuid;   /* creator's user id */
  62         gid32_t         cgid;   /* creator's group id */
  63         mode32_t        mode;   /* access modes */
  64         uint32_t        seq;    /* slot usage sequence number */
  65         key32_t         key;    /* key */
  66         int32_t         pad[4]; /* reserve area */
  67 };
  68 #endif  /* _SYSCALL32 */
  69 
  70 /*
  71  * This is the ipc_perm equivalent used in the xxxid_ds64 structures.
  72  * It, like the structures it is used in, is intended only for use in
  73  * communication between the kernel and user programs, and has the same
  74  * layout across all data models.
  75  *
  76  * The xxxid_ds64 structures rely on ipc_perm64 being a multiple of
  77  * 8 bytes so subsequent fields are 64-bit aligned on x86.
  78  */
  79 typedef struct ipc_perm64 {
  80         uid_t   ipcx_uid;       /* owner's user id */
  81         gid_t   ipcx_gid;       /* owner's group id */
  82         uid_t   ipcx_cuid;      /* creator's user id */
  83         gid_t   ipcx_cgid;      /* creator's group id */
  84         mode_t  ipcx_mode;      /* access modes */
  85         key_t   ipcx_key;       /* key */
  86         projid_t ipcx_projid;   /* allocating project id */
  87         zoneid_t ipcx_zoneid;   /* creator's zone id */
  88 } ipc_perm64_t;
  89 
  90 /*
  91  * These are versions of xxxid_ds which are intended only for use in
  92  * communication between the kernel and user programs, and therefore
  93  * have the same layout across all data models.  Omitted are all
  94  * implementation-specific fields which would be of no use to user
  95  * programs.
  96  */
  97 struct shmid_ds64 {
  98         ipc_perm64_t    shmx_perm;      /* operation permission struct */
  99         pid_t           shmx_lpid;      /* pid of last shmop */
 100         pid_t           shmx_cpid;      /* pid of creator */
 101         uint64_t        shmx_segsz;     /* size of segment in bytes */
 102         uint64_t        shmx_nattch;    /* # of attaches */
 103         uint64_t        shmx_cnattch;   /* # of ISM attaches */
 104         uint64_t        shmx_lkcnt;     /* lock count ??? */
 105         ipc_time_t      shmx_atime;     /* last shmat time */
 106         ipc_time_t      shmx_dtime;     /* last shmdt time */
 107         ipc_time_t      shmx_ctime;     /* last change time */
 108 };
 109 
 110 struct semid_ds64 {
 111         ipc_perm64_t    semx_perm;      /* operation permission struct */
 112         ushort_t        semx_nsems;     /* # of semaphores in set */
 113         ushort_t        _semx_pad[3];   /* pad to 8-byte multiple */
 114         ipc_time_t      semx_otime;     /* last semop time */
 115         ipc_time_t      semx_ctime;     /* last change time */
 116 };
 117 
 118 struct msqid_ds64 {
 119         ipc_perm64_t    msgx_perm;      /* operation permission struct */
 120         uint64_t        msgx_cbytes;    /* current # bytes on q */
 121         uint64_t        msgx_qnum;      /* # of messages on q */
 122         uint64_t        msgx_qbytes;    /* max # of bytes on q */
 123         pid_t           msgx_lspid;     /* pid of last msgsnd */
 124         pid_t           msgx_lrpid;     /* pid of last msgrcv */
 125         ipc_time_t      msgx_stime;     /* last msgsnd time */
 126         ipc_time_t      msgx_rtime;     /* last msgrcv time */
 127         ipc_time_t      msgx_ctime;     /* last change time */
 128 };
 129 
 130 #ifdef _KERNEL
 131 
 132 /*
 133  * Implementation macros
 134  */
 135 #define IPC_FREE(x)     (((x)->ipc_mode & IPC_ALLOC) == 0)
 136 
 137 #define IPC_SEQ_BITS    7
 138 #define IPC_SEQ_MASK    ((1 << IPC_SEQ_BITS) - 1)
 139 #define IPC_SEQ_SHIFT   (31 - IPC_SEQ_BITS)
 140 #define IPC_INDEX_MASK  ((1 << IPC_SEQ_SHIFT) - 1)
 141 #define IPC_SEQ(x)      ((unsigned int)(x) >> IPC_SEQ_SHIFT)
 142 #define IPC_INDEX(x)    ((unsigned int)(x) & IPC_INDEX_MASK)
 143 
 144 #define IPC_IDS_MIN     (PAGESIZE / 64)         /* starting # of entries */
 145 #define IPC_IDS_MAX     (1 << IPC_SEQ_SHIFT)      /* maximum # of entries */
 146 #define IPC_ID_INVAL    UINT_MAX
 147 
 148 #define IPC_PROJ_USAGE(p, s) \
 149         (*(rctl_qty_t *)(((char *)&p->ipc_proj->kpj_data.kpd_ipc) + \
 150         s->ipcs_rctlofs))
 151 #define IPC_ZONE_USAGE(p, s) \
 152         (*(rctl_qty_t *)(((char *)&p->ipc_zone_ref.zref_zone->zone_ipc) + \
 153         s->ipcs_rctlofs))
 154 #define IPC_LOCKED(s, o) \
 155         MUTEX_HELD(&s->ipcs_table[IPC_INDEX(o->ipc_id)].ipct_lock)
 156 
 157 /*
 158  * The kernel's ipc_perm structure.
 159  */
 160 typedef struct kipc_perm {
 161         avl_node_t ipc_avl;     /* avl node if key is non-private */
 162         list_node_t ipc_list;   /* list node in list of all ids */
 163         uint_t  ipc_ref;        /* reference count              */
 164         uid_t   ipc_uid;        /* owner's user id              */
 165         gid_t   ipc_gid;        /* owner's group id             */
 166         uid_t   ipc_cuid;       /* creator's user id            */
 167         gid_t   ipc_cgid;       /* creator's group id           */
 168         mode_t  ipc_mode;       /* access modes                 */
 169         key_t   ipc_key;        /* key                          */
 170         kproject_t *ipc_proj;   /* creator's project            */
 171         uint_t  ipc_id;         /* id                           */
 172         zoneid_t ipc_zoneid;    /* creator's zone id            */
 173         zone_ref_t ipc_zone_ref; /* reference to creator's zone */
 174 } kipc_perm_t;
 175 
 176 typedef struct ipc_slot {
 177         kmutex_t        ipct_lock;      /* bucket lock          */
 178         kipc_perm_t     *ipct_data;     /* data                 */
 179         uint_t          ipct_seq;       /* sequence number      */
 180         struct ipc_slot *ipct_chain;    /* for stale arrays     */
 181         char            ipct_pad[64 - sizeof (kmutex_t) - 3 * sizeof (void *)];
 182 } ipc_slot_t;
 183 
 184 typedef void(ipc_func_t)(kipc_perm_t *);
 185 
 186 typedef struct ipc_service {
 187         kmutex_t        ipcs_lock;      /* lock for (de)allocation, keys */
 188         avl_tree_t      ipcs_keys;      /* objects sorted by key        */
 189         ipc_slot_t      *ipcs_table;    /* table of objects             */
 190         uint_t          ipcs_tabsz;     /* size of table                */
 191         uint_t          ipcs_count;     /* # of objects allocated       */
 192         rctl_hndl_t     ipcs_proj_rctl; /* id limiting rctl handle      */
 193         rctl_hndl_t     ipcs_zone_rctl; /* id limiting rctl handle      */
 194         size_t          ipcs_rctlofs;   /* offset in kproject_data_t    */
 195         id_space_t      *ipcs_ids;      /* id space for objects         */
 196         size_t          ipcs_ssize;     /* object size (for allocation) */
 197         ipc_func_t      *ipcs_dtor;     /* object destructor            */
 198         ipc_func_t      *ipcs_rmid;     /* object removal               */
 199         list_t          ipcs_usedids;   /* list of allocated ids        */
 200         int             ipcs_atype;     /* audit type (see c2/audit.h)  */
 201 } ipc_service_t;
 202 
 203 int ipcperm_access(kipc_perm_t *, int, cred_t *);
 204 int ipcperm_set(ipc_service_t *, struct cred *, kipc_perm_t *,
 205     struct ipc_perm *, model_t);
 206 void ipcperm_stat(struct ipc_perm *, kipc_perm_t *, model_t);
 207 int ipcperm_set64(ipc_service_t *, struct cred *, kipc_perm_t *,
 208     ipc_perm64_t *);
 209 void ipcperm_stat64(ipc_perm64_t *, kipc_perm_t *);
 210 
 211 ipc_service_t *ipcs_create(const char *, rctl_hndl_t, rctl_hndl_t, size_t,
 212     ipc_func_t *, ipc_func_t *, int, size_t);
 213 void ipcs_destroy(ipc_service_t *);
 214 void ipcs_lock(ipc_service_t *);
 215 void ipcs_unlock(ipc_service_t *);
 216 
 217 kmutex_t *ipc_lock(ipc_service_t *, int);
 218 kmutex_t *ipc_relock(ipc_service_t *, int, kmutex_t *);
 219 kmutex_t *ipc_lookup(ipc_service_t *, int, kipc_perm_t **);
 220 
 221 void ipc_hold(ipc_service_t *, kipc_perm_t *);
 222 void ipc_rele(ipc_service_t *, kipc_perm_t *);
 223 void ipc_rele_locked(ipc_service_t *, kipc_perm_t *);
 224 
 225 int ipc_get(ipc_service_t *, key_t, int, kipc_perm_t **, kmutex_t **);
 226 int ipc_commit_begin(ipc_service_t *, key_t, int, kipc_perm_t *);
 227 kmutex_t *ipc_commit_end(ipc_service_t *, kipc_perm_t *);
 228 void ipc_cleanup(ipc_service_t *, kipc_perm_t *);
 229 
 230 void ipc_rmsvc(ipc_service_t *, kipc_perm_t *);
 231 int ipc_rmid(ipc_service_t *, int, cred_t *);
 232 int ipc_ids(ipc_service_t *, int *, uint_t, uint_t *);
 233 
 234 void ipc_remove_zone(ipc_service_t *, zoneid_t);
 235 
 236 #else   /* _KERNEL */
 237 
 238 int msgctl64(int, int, struct msqid_ds64 *);
 239 int semctl64(int, int, int, ...);
 240 int shmctl64(int, int, struct shmid_ds64 *);
 241 
 242 #endif  /* _KERNEL */
 243 
 244 
 245 #ifdef  __cplusplus
 246 }
 247 #endif
 248 
 249 #endif  /* _IPC_IMPL_H */