Merge git://git.kernel.org/pub/scm/linux/kernel/git/bpf/bpf
[linux-2.6-microblaze.git] / ipc / shm.c
index bd65275..4643865 100644 (file)
--- a/ipc/shm.c
+++ b/ipc/shm.c
@@ -601,6 +601,7 @@ static int newseg(struct ipc_namespace *ns, struct ipc_params *params)
        shp->shm_file = file;
        shp->shm_creator = current;
 
+       /* ipc_addid() locks shp upon success. */
        error = ipc_addid(&shm_ids(ns), &shp->shm_perm, ns->shm_ctlmni);
        if (error < 0)
                goto no_id;
@@ -908,9 +909,11 @@ static int shmctl_stat(struct ipc_namespace *ns, int shmid,
                        int cmd, struct shmid64_ds *tbuf)
 {
        struct shmid_kernel *shp;
-       int result;
+       int id = 0;
        int err;
 
+       memset(tbuf, 0, sizeof(*tbuf));
+
        rcu_read_lock();
        if (cmd == SHM_STAT) {
                shp = shm_obtain_object(ns, shmid);
@@ -918,14 +921,13 @@ static int shmctl_stat(struct ipc_namespace *ns, int shmid,
                        err = PTR_ERR(shp);
                        goto out_unlock;
                }
-               result = shp->shm_perm.id;
+               id = shp->shm_perm.id;
        } else {
                shp = shm_obtain_object_check(ns, shmid);
                if (IS_ERR(shp)) {
                        err = PTR_ERR(shp);
                        goto out_unlock;
                }
-               result = 0;
        }
 
        err = -EACCES;
@@ -936,7 +938,14 @@ static int shmctl_stat(struct ipc_namespace *ns, int shmid,
        if (err)
                goto out_unlock;
 
-       memset(tbuf, 0, sizeof(*tbuf));
+       ipc_lock_object(&shp->shm_perm);
+
+       if (!ipc_valid_object(&shp->shm_perm)) {
+               ipc_unlock_object(&shp->shm_perm);
+               err = -EIDRM;
+               goto out_unlock;
+       }
+
        kernel_to_ipc64_perm(&shp->shm_perm, &tbuf->shm_perm);
        tbuf->shm_segsz = shp->shm_segsz;
        tbuf->shm_atime = shp->shm_atim;
@@ -945,8 +954,10 @@ static int shmctl_stat(struct ipc_namespace *ns, int shmid,
        tbuf->shm_cpid  = shp->shm_cprid;
        tbuf->shm_lpid  = shp->shm_lprid;
        tbuf->shm_nattch = shp->shm_nattch;
+
+       ipc_unlock_object(&shp->shm_perm);
        rcu_read_unlock();
-       return result;
+       return id;
 
 out_unlock:
        rcu_read_unlock();
@@ -1194,10 +1205,10 @@ static int copy_compat_shmid_from_user(struct shmid64_ds *out, void __user *buf,
 {
        memset(out, 0, sizeof(*out));
        if (version == IPC_64) {
-               struct compat_shmid64_ds *p = buf;
+               struct compat_shmid64_ds __user *p = buf;
                return get_compat_ipc64_perm(&out->shm_perm, &p->shm_perm);
        } else {
-               struct compat_shmid_ds *p = buf;
+               struct compat_shmid_ds __user *p = buf;
                return get_compat_ipc_perm(&out->shm_perm, &p->shm_perm);
        }
 }