]> git.saurik.com Git - apple/xnu.git/blobdiff - bsd/kern/sysv_sem.c
xnu-3789.51.2.tar.gz
[apple/xnu.git] / bsd / kern / sysv_sem.c
index 0e44029cf5fe7f87583e5979a38b0a8889c68773..ecfafb55f87293181aff77a64b13a5eab8caba59 100644 (file)
@@ -265,8 +265,8 @@ semsys(struct proc *p, struct semsys_args *uap, int32_t *retval)
 static int
 grow_semu_array(int newSize)
 {
-       register int i;
-       register struct sem_undo *newSemu;
+       int i;
+       struct sem_undo *newSemu;
 
        if (newSize <= seminfo.semmnu)
                return 1;
@@ -326,8 +326,8 @@ grow_semu_array(int newSize)
 static int
 grow_sema_array(int newSize)
 {
-       register struct semid_kernel *newSema;
-       register int i;
+       struct semid_kernel *newSema;
+       int i;
 
        if (newSize <= seminfo.semmni)
                return 0;
@@ -428,7 +428,7 @@ grow_sem_pool(int new_pool_size)
        printf("growing sem_pool array from %d to %d\n", seminfo.semmns, new_pool_size);
 #endif
        MALLOC(new_sem_pool, struct sem *, sizeof (struct sem) * new_pool_size,
-              M_SYSVSEM, M_WAITOK | M_ZERO);
+              M_SYSVSEM, M_WAITOK | M_ZERO | M_NULL);
        if (NULL == new_sem_pool) {
 #ifdef SEM_DEBUG
                printf("allocation failed.  no changes made.\n");
@@ -444,7 +444,8 @@ grow_sem_pool(int new_pool_size)
        /* Update our id structures to point to the new semaphores */
        for(i = 0; i < seminfo.semmni; i++) {
                if (sema[i].u.sem_perm.mode & SEM_ALLOC)  /* ID in use */
-                       sema[i].u.sem_base += (new_sem_pool - sem_pool);
+                       sema[i].u.sem_base = new_sem_pool + 
+                               (sema[i].u.sem_base - sem_pool);
        }
 
        sem_free = sem_pool;
@@ -471,8 +472,8 @@ grow_sem_pool(int new_pool_size)
 static int
 semu_alloc(struct proc *p)
 {
-       register int i;
-       register struct sem_undo *suptr;
+       int i;
+       struct sem_undo *suptr;
        int *supidx;
        int attempt;
 
@@ -549,9 +550,9 @@ static int
 semundo_adjust(struct proc *p, int *supidx, int semid,
        int semnum, int adjval)
 {
-       register struct sem_undo *suptr;
+       struct sem_undo *suptr;
        int suidx;
-       register struct undo *sueptr, **suepptr, *new_sueptr;
+       struct undo *sueptr, **suepptr, *new_sueptr;
        int i;
 
        /*
@@ -774,10 +775,12 @@ semctl(struct proc *p, struct semctl_args *uap, int32_t *retval)
 
                if (IS_64BIT_PROCESS(p)) {
                        struct user64_semid_ds semid_ds64;
+                       bzero(&semid_ds64, sizeof(semid_ds64));
                        semid_ds_kernelto64(&semakptr->u, &semid_ds64);
                        eval = copyout(&semid_ds64, user_arg.buf, sizeof(semid_ds64));
                } else {
                        struct user32_semid_ds semid_ds32;
+                       bzero(&semid_ds32, sizeof(semid_ds32));
                        semid_ds_kernelto32(&semakptr->u, &semid_ds32);
                        eval = copyout(&semid_ds32, user_arg.buf, sizeof(semid_ds32));
                }
@@ -853,12 +856,27 @@ semctl(struct proc *p, struct semctl_args *uap, int32_t *retval)
                        eval = EINVAL;
                        goto semctlout;
                }
+               
                /*
                 * Cast down a pointer instead of using 'val' member directly
                 * to avoid introducing endieness and a pad field into the
                 * header file.  Ugly, but it works.
                 */
-               semakptr->u.sem_base[semnum].semval = CAST_DOWN_EXPLICIT(int,user_arg.buf);
+               u_int newsemval = CAST_DOWN_EXPLICIT(u_int, user_arg.buf);
+               
+               /*
+                * The check is being performed as unsigned values to match 
+                * eventual destination
+                */ 
+               if (newsemval > (u_int)seminfo.semvmx)
+               {
+#ifdef SEM_DEBUG
+                       printf("Out of range sem value for set\n");
+#endif
+                       eval = ERANGE;
+                       goto semctlout;
+               }
+               semakptr->u.sem_base[semnum].semval = newsemval;
                semakptr->u.sem_base[semnum].sempid = p->p_pid;
                /* XXX scottl Should there be a MAC call here? */
                semundo_clear(semid, semnum);
@@ -999,8 +1017,8 @@ semget(__unused struct proc *p, struct semget_args *uap, int32_t *retval)
                sema[semid].u.sem_perm._key = key;
                sema[semid].u.sem_perm.cuid = kauth_cred_getuid(cred);
                sema[semid].u.sem_perm.uid = kauth_cred_getuid(cred);
-               sema[semid].u.sem_perm.cgid = cred->cr_gid;
-               sema[semid].u.sem_perm.gid = cred->cr_gid;
+               sema[semid].u.sem_perm.cgid = kauth_cred_getgid(cred);
+               sema[semid].u.sem_perm.gid = kauth_cred_getgid(cred);
                sema[semid].u.sem_perm.mode = (semflg & 0777) | SEM_ALLOC;
                sema[semid].u.sem_perm._seq =
                    (sema[semid].u.sem_perm._seq + 1) & 0x7fff;
@@ -1044,10 +1062,10 @@ semop(struct proc *p, struct semop_args *uap, int32_t *retval)
 {
        int semid = uap->semid;
        int nsops = uap->nsops;
-       struct sembuf sops[MAX_SOPS];
-       register struct semid_kernel *semakptr;
-       register struct sembuf *sopptr = NULL;  /* protected by 'semptr' */
-       register struct sem *semptr = NULL;     /* protected by 'if' */
+       struct sembuf sops[seminfo.semopm];
+       struct semid_kernel *semakptr;
+       struct sembuf *sopptr = NULL;   /* protected by 'semptr' */
+       struct sem *semptr = NULL;      /* protected by 'if' */
        int supidx = -1;
        int i, j, eval;
        int do_wakeup, do_undos;
@@ -1084,13 +1102,23 @@ semop(struct proc *p, struct semop_args *uap, int32_t *retval)
                goto semopout;
        }
 
-       if (nsops < 0 || nsops > MAX_SOPS) {
+       if (nsops < 0 || nsops > seminfo.semopm) {
 #ifdef SEM_DEBUG
-               printf("too many sops (max=%d, nsops=%d)\n", MAX_SOPS, nsops);
+               printf("too many sops (max=%d, nsops=%d)\n",
+                   seminfo.semopm, nsops);
 #endif
                eval = E2BIG;
                goto semopout;
        }
+       
+       /*  OK for LP64, since sizeof(struct sembuf) is currently invariant */
+       if ((eval = copyin(uap->sops, &sops, nsops * sizeof(struct sembuf))) != 0) {
+#ifdef SEM_DEBUG
+               printf("eval = %d from copyin(%08x, %08x, %ld)\n", eval,
+                   uap->sops, &sops, nsops * sizeof(struct sembuf));
+#endif
+               goto semopout;
+       }
 
 #if CONFIG_MACF
        /*
@@ -1110,15 +1138,6 @@ semop(struct proc *p, struct semop_args *uap, int32_t *retval)
                goto semopout;
 #endif
 
-       /*  OK for LP64, since sizeof(struct sembuf) is currently invariant */
-       if ((eval = copyin(uap->sops, &sops, nsops * sizeof(struct sembuf))) != 0) {
-#ifdef SEM_DEBUG
-               printf("eval = %d from copyin(%08x, %08x, %ld)\n", eval,
-                   uap->sops, &sops, nsops * sizeof(struct sembuf));
-#endif
-               goto semopout;
-       }
-
        /*
         * Loop trying to satisfy the vector of requests.
         * If we reach a point where we must wait, any requests already
@@ -1373,7 +1392,7 @@ semopout:
 void
 semexit(struct proc *p)
 {
-       register struct sem_undo *suptr = NULL;
+       struct sem_undo *suptr = NULL;
        int suidx;
        int *supidx;
        int did_something;
@@ -1454,10 +1473,7 @@ semexit(struct proc *p)
                /* Maybe we should build a list of semakptr's to wake
                 * up, finish all access to data structures, release the
                 * subsystem lock, and wake all the processes.  Something
-                * to think about.  It wouldn't buy us anything unless
-                * wakeup had the potential to block, or the syscall
-                * funnel state was changed to allow multiple threads
-                * in the BSD code at once.
+                * to think about.
                 */
 #ifdef SEM_WAKEUP
                        sem_wakeup((caddr_t)semakptr);
@@ -1539,19 +1555,19 @@ out:
 
 /* SYSCTL_NODE(_kern, KERN_SYSV, sysv, CTLFLAG_RW, 0, "SYSV"); */
 extern struct sysctl_oid_list sysctl__kern_sysv_children;
-SYSCTL_PROC(_kern_sysv, OID_AUTO, semmni, CTLTYPE_INT | CTLFLAG_RW,
+SYSCTL_PROC(_kern_sysv, OID_AUTO, semmni, CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_LOCKED,
     &limitseminfo.semmni, 0, &sysctl_seminfo ,"I","semmni");
 
-SYSCTL_PROC(_kern_sysv, OID_AUTO, semmns, CTLTYPE_INT | CTLFLAG_RW,
+SYSCTL_PROC(_kern_sysv, OID_AUTO, semmns, CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_LOCKED,
     &limitseminfo.semmns, 0, &sysctl_seminfo ,"I","semmns");
 
-SYSCTL_PROC(_kern_sysv, OID_AUTO, semmnu, CTLTYPE_INT | CTLFLAG_RW,
+SYSCTL_PROC(_kern_sysv, OID_AUTO, semmnu, CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_LOCKED,
     &limitseminfo.semmnu, 0, &sysctl_seminfo ,"I","semmnu");
 
-SYSCTL_PROC(_kern_sysv, OID_AUTO, semmsl, CTLTYPE_INT | CTLFLAG_RW,
+SYSCTL_PROC(_kern_sysv, OID_AUTO, semmsl, CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_LOCKED,
     &limitseminfo.semmsl, 0, &sysctl_seminfo ,"I","semmsl");
     
-SYSCTL_PROC(_kern_sysv, OID_AUTO, semume, CTLTYPE_INT | CTLFLAG_RW,
+SYSCTL_PROC(_kern_sysv, OID_AUTO, semume, CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_LOCKED,
     &limitseminfo.semume, 0, &sysctl_seminfo ,"I","semume");
 
 
@@ -1634,9 +1650,11 @@ IPCS_sem_sysctl(__unused struct sysctl_oid *oidp, __unused void *arg1,
                 * descriptor to a 32 bit user one.
                 */
                if (!IS_64BIT_PROCESS(p)) {
+                       bzero(&semid_ds32, sizeof(semid_ds32));
                        semid_ds_kernelto32(semid_dsp, &semid_ds32);
                        semid_dsp = &semid_ds32;
                } else {
+                       bzero(&semid_ds64, sizeof(semid_ds64));
                        semid_ds_kernelto64(semid_dsp, &semid_ds64);
                        semid_dsp = &semid_ds64;
                }
@@ -1662,7 +1680,7 @@ IPCS_sem_sysctl(__unused struct sysctl_oid *oidp, __unused void *arg1,
 }
 
 SYSCTL_DECL(_kern_sysv_ipcs);
-SYSCTL_PROC(_kern_sysv_ipcs, OID_AUTO, sem, CTLFLAG_RW|CTLFLAG_ANYBODY,
+SYSCTL_PROC(_kern_sysv_ipcs, OID_AUTO, sem, CTLFLAG_RW | CTLFLAG_ANYBODY | CTLFLAG_LOCKED,
        0, 0, IPCS_sem_sysctl,
        "S,IPCS_sem_command",
        "ipcs sem command interface");