]> git.kernelconcepts.de Git - karo-tx-linux.git/blobdiff - ipc/sem.c
ipc: add missing container_of()s for randstruct
[karo-tx-linux.git] / ipc / sem.c
index fff8337ebab3e33d69090502c6a1b05969ece147..38371e93bfa5c4f101e264b46eab6a19f2f02404 100644 (file)
--- a/ipc/sem.c
+++ b/ipc/sem.c
@@ -260,11 +260,11 @@ static void merge_queues(struct sem_array *sma)
 
 static void sem_rcu_free(struct rcu_head *head)
 {
-       struct ipc_rcu *p = container_of(head, struct ipc_rcu, rcu);
-       struct sem_array *sma = ipc_rcu_to_struct(p);
+       struct kern_ipc_perm *p = container_of(head, struct kern_ipc_perm, rcu);
+       struct sem_array *sma = container_of(p, struct sem_array, sem_perm);
 
        security_sem_free(sma);
-       ipc_rcu_free(head);
+       kvfree(sma);
 }
 
 /*
@@ -438,7 +438,7 @@ static inline struct sem_array *sem_obtain_object_check(struct ipc_namespace *ns
 static inline void sem_lock_and_putref(struct sem_array *sma)
 {
        sem_lock(sma, NULL, -1);
-       ipc_rcu_putref(sma, sem_rcu_free);
+       ipc_rcu_putref(&sma->sem_perm, sem_rcu_free);
 }
 
 static inline void sem_rmid(struct ipc_namespace *ns, struct sem_array *s)
@@ -446,6 +446,24 @@ static inline void sem_rmid(struct ipc_namespace *ns, struct sem_array *s)
        ipc_rmid(&sem_ids(ns), &s->sem_perm);
 }
 
+static struct sem_array *sem_alloc(size_t nsems)
+{
+       struct sem_array *sma;
+       size_t size;
+
+       if (nsems > (INT_MAX - sizeof(*sma)) / sizeof(sma->sems[0]))
+               return NULL;
+
+       size = sizeof(*sma) + nsems * sizeof(sma->sems[0]);
+       sma = kvmalloc(size, GFP_KERNEL);
+       if (unlikely(!sma))
+               return NULL;
+
+       memset(sma, 0, size);
+
+       return sma;
+}
+
 /**
  * newary - Create a new semaphore set
  * @ns: namespace
@@ -455,10 +473,8 @@ static inline void sem_rmid(struct ipc_namespace *ns, struct sem_array *s)
  */
 static int newary(struct ipc_namespace *ns, struct ipc_params *params)
 {
-       int id;
        int retval;
        struct sem_array *sma;
-       int size;
        key_t key = params->key;
        int nsems = params->u.nsems;
        int semflg = params->flg;
@@ -469,20 +485,17 @@ static int newary(struct ipc_namespace *ns, struct ipc_params *params)
        if (ns->used_sems + nsems > ns->sc_semmns)
                return -ENOSPC;
 
-       size = sizeof(*sma) + nsems * sizeof(sma->sems[0]);
-       sma = ipc_rcu_alloc(size);
+       sma = sem_alloc(nsems);
        if (!sma)
                return -ENOMEM;
 
-       memset(sma, 0, size);
-
        sma->sem_perm.mode = (semflg & S_IRWXUGO);
        sma->sem_perm.key = key;
 
        sma->sem_perm.security = NULL;
        retval = security_sem_alloc(sma);
        if (retval) {
-               ipc_rcu_putref(sma, ipc_rcu_free);
+               kvfree(sma);
                return retval;
        }
 
@@ -500,10 +513,10 @@ static int newary(struct ipc_namespace *ns, struct ipc_params *params)
        sma->sem_nsems = nsems;
        sma->sem_ctime = get_seconds();
 
-       id = ipc_addid(&sem_ids(ns), &sma->sem_perm, ns->sc_semmni);
-       if (id < 0) {
-               ipc_rcu_putref(sma, sem_rcu_free);
-               return id;
+       retval = ipc_addid(&sem_ids(ns), &sma->sem_perm, ns->sc_semmni);
+       if (retval < 0) {
+               call_rcu(&sma->sem_perm.rcu, sem_rcu_free);
+               return retval;
        }
        ns->used_sems += nsems;
 
@@ -1122,7 +1135,7 @@ static void freeary(struct ipc_namespace *ns, struct kern_ipc_perm *ipcp)
 
        wake_up_q(&wake_q);
        ns->used_sems -= sma->sem_nsems;
-       ipc_rcu_putref(sma, sem_rcu_free);
+       ipc_rcu_putref(&sma->sem_perm, sem_rcu_free);
 }
 
 static unsigned long copy_semid_to_user(void __user *buf, struct semid64_ds *in, int version)
@@ -1362,15 +1375,16 @@ static int semctl_main(struct ipc_namespace *ns, int semid, int semnum,
                        goto out_unlock;
                }
                if (nsems > SEMMSL_FAST) {
-                       if (!ipc_rcu_getref(sma)) {
+                       if (!ipc_rcu_getref(&sma->sem_perm)) {
                                err = -EIDRM;
                                goto out_unlock;
                        }
                        sem_unlock(sma, -1);
                        rcu_read_unlock();
-                       sem_io = ipc_alloc(sizeof(ushort)*nsems);
+                       sem_io = kvmalloc_array(nsems, sizeof(ushort),
+                                               GFP_KERNEL);
                        if (sem_io == NULL) {
-                               ipc_rcu_putref(sma, sem_rcu_free);
+                               ipc_rcu_putref(&sma->sem_perm, sem_rcu_free);
                                return -ENOMEM;
                        }
 
@@ -1395,29 +1409,30 @@ static int semctl_main(struct ipc_namespace *ns, int semid, int semnum,
                int i;
                struct sem_undo *un;
 
-               if (!ipc_rcu_getref(sma)) {
+               if (!ipc_rcu_getref(&sma->sem_perm)) {
                        err = -EIDRM;
                        goto out_rcu_wakeup;
                }
                rcu_read_unlock();
 
                if (nsems > SEMMSL_FAST) {
-                       sem_io = ipc_alloc(sizeof(ushort)*nsems);
+                       sem_io = kvmalloc_array(nsems, sizeof(ushort),
+                                               GFP_KERNEL);
                        if (sem_io == NULL) {
-                               ipc_rcu_putref(sma, sem_rcu_free);
+                               ipc_rcu_putref(&sma->sem_perm, sem_rcu_free);
                                return -ENOMEM;
                        }
                }
 
                if (copy_from_user(sem_io, p, nsems*sizeof(ushort))) {
-                       ipc_rcu_putref(sma, sem_rcu_free);
+                       ipc_rcu_putref(&sma->sem_perm, sem_rcu_free);
                        err = -EFAULT;
                        goto out_free;
                }
 
                for (i = 0; i < nsems; i++) {
                        if (sem_io[i] > SEMVMX) {
-                               ipc_rcu_putref(sma, sem_rcu_free);
+                               ipc_rcu_putref(&sma->sem_perm, sem_rcu_free);
                                err = -ERANGE;
                                goto out_free;
                        }
@@ -1480,7 +1495,7 @@ out_rcu_wakeup:
        wake_up_q(&wake_q);
 out_free:
        if (sem_io != fast_sem_io)
-               ipc_free(sem_io);
+               kvfree(sem_io);
        return err;
 }
 
@@ -1699,7 +1714,7 @@ static struct sem_undo *find_alloc_undo(struct ipc_namespace *ns, int semid)
        }
 
        nsems = sma->sem_nsems;
-       if (!ipc_rcu_getref(sma)) {
+       if (!ipc_rcu_getref(&sma->sem_perm)) {
                rcu_read_unlock();
                un = ERR_PTR(-EIDRM);
                goto out;
@@ -1709,7 +1724,7 @@ static struct sem_undo *find_alloc_undo(struct ipc_namespace *ns, int semid)
        /* step 2: allocate new undo structure */
        new = kzalloc(sizeof(struct sem_undo) + sizeof(short)*nsems, GFP_KERNEL);
        if (!new) {
-               ipc_rcu_putref(sma, sem_rcu_free);
+               ipc_rcu_putref(&sma->sem_perm, sem_rcu_free);
                return ERR_PTR(-ENOMEM);
        }
 
@@ -2164,7 +2179,8 @@ void exit_sem(struct task_struct *tsk)
 static int sysvipc_sem_proc_show(struct seq_file *s, void *it)
 {
        struct user_namespace *user_ns = seq_user_ns(s);
-       struct sem_array *sma = it;
+       struct kern_ipc_perm *ipcp = it;
+       struct sem_array *sma = container_of(ipcp, struct sem_array, sem_perm);
        time_t sem_otime;
 
        /*