+ return 0;
+}
+
+/* Initialize the mutex governing access to the SysV shm subsystem */
+__private_extern__ void
+sysv_shm_lock_init( void )
+{
+ sysv_shm_subsys_lck_grp_attr = lck_grp_attr_alloc_init();
+
+ sysv_shm_subsys_lck_grp = lck_grp_alloc_init("sysv_shm_subsys_lock", sysv_shm_subsys_lck_grp_attr);
+
+ sysv_shm_subsys_lck_attr = lck_attr_alloc_init();
+ lck_mtx_init(&sysv_shm_subsys_mutex, sysv_shm_subsys_lck_grp, sysv_shm_subsys_lck_attr);
+}
+
+/* (struct sysctl_oid *oidp, void *arg1, int arg2, \
+ * struct sysctl_req *req) */
+static int
+sysctl_shminfo(__unused struct sysctl_oid *oidp, void *arg1,
+ __unused int arg2, struct sysctl_req *req)
+{
+ int error = 0;
+ int sysctl_shminfo_ret = 0;
+ int64_t saved_shmmax;
+ int64_t saved_shmmin;
+ int64_t saved_shmseg;
+ int64_t saved_shmmni;
+ int64_t saved_shmall;
+
+ error = SYSCTL_OUT(req, arg1, sizeof(int64_t));
+ if (error || req->newptr == USER_ADDR_NULL) {
+ return error;
+ }
+
+ SYSV_SHM_SUBSYS_LOCK();
+
+ /* shmmni can not be changed after SysV SHM has been initialized */
+ if (shm_inited && arg1 == &shminfo.shmmni) {
+ sysctl_shminfo_ret = EPERM;
+ goto sysctl_shminfo_out;
+ }
+ saved_shmmax = shminfo.shmmax;
+ saved_shmmin = shminfo.shmmin;
+ saved_shmseg = shminfo.shmseg;
+ saved_shmmni = shminfo.shmmni;
+ saved_shmall = shminfo.shmall;
+
+ if ((error = SYSCTL_IN(req, arg1, sizeof(int64_t))) != 0) {
+ sysctl_shminfo_ret = error;
+ goto sysctl_shminfo_out;
+ }
+
+ if (arg1 == &shminfo.shmmax) {
+ /* shmmax needs to be page-aligned */
+ if (shminfo.shmmax & PAGE_MASK_64 || shminfo.shmmax < 0) {
+ shminfo.shmmax = saved_shmmax;
+ sysctl_shminfo_ret = EINVAL;
+ goto sysctl_shminfo_out;
+ }
+ } else if (arg1 == &shminfo.shmmin) {
+ if (shminfo.shmmin < 0) {
+ shminfo.shmmin = saved_shmmin;
+ sysctl_shminfo_ret = EINVAL;
+ goto sysctl_shminfo_out;
+ }
+ } else if (arg1 == &shminfo.shmseg) {
+ /* add a sanity check - 20847256 */
+ if (shminfo.shmseg > INT32_MAX || shminfo.shmseg < 0) {
+ shminfo.shmseg = saved_shmseg;
+ sysctl_shminfo_ret = EINVAL;
+ goto sysctl_shminfo_out;
+ }
+ } else if (arg1 == &shminfo.shmmni) {
+ /* add a sanity check - 20847256 */
+ if (shminfo.shmmni > INT32_MAX || shminfo.shmmni < 0) {
+ shminfo.shmmni = saved_shmmni;
+ sysctl_shminfo_ret = EINVAL;
+ goto sysctl_shminfo_out;
+ }
+ } else if (arg1 == &shminfo.shmall) {
+ /* add a sanity check - 20847256 */
+ if (shminfo.shmall > INT32_MAX || shminfo.shmall < 0) {
+ shminfo.shmall = saved_shmall;
+ sysctl_shminfo_ret = EINVAL;
+ goto sysctl_shminfo_out;
+ }
+ }
+ sysctl_shminfo_ret = 0;
+sysctl_shminfo_out:
+ SYSV_SHM_SUBSYS_UNLOCK();
+ return sysctl_shminfo_ret;
+}
+
+static int
+IPCS_shm_sysctl(__unused struct sysctl_oid *oidp, __unused void *arg1,
+ __unused int arg2, struct sysctl_req *req)
+{
+ int error;
+ int cursor;
+ union {
+ struct user32_IPCS_command u32;
+ struct user_IPCS_command u64;
+ } ipcs = { };
+ struct user32_shmid_ds shmid_ds32 = { }; /* post conversion, 32 bit version */
+ struct user_shmid_ds shmid_ds = { }; /* 64 bit version */
+ void *shmid_dsp;
+ size_t ipcs_sz = sizeof(struct user_IPCS_command);
+ size_t shmid_ds_sz = sizeof(struct user_shmid_ds);
+ struct proc *p = current_proc();
+
+ SYSV_SHM_SUBSYS_LOCK();
+
+ if ((error = shminit())) {
+ goto ipcs_shm_sysctl_out;
+ }
+
+ if (!IS_64BIT_PROCESS(p)) {
+ ipcs_sz = sizeof(struct user32_IPCS_command);
+ shmid_ds_sz = sizeof(struct user32_shmid_ds);