diff options
Diffstat (limited to 'ipc')
-rw-r--r-- | ipc/compat.c | 92 | ||||
-rw-r--r-- | ipc/ipc_sysctl.c | 3 | ||||
-rw-r--r-- | ipc/namespace.c | 6 | ||||
-rw-r--r-- | ipc/shm.c | 82 | ||||
-rw-r--r-- | ipc/util.c | 20 |
5 files changed, 93 insertions, 110 deletions
diff --git a/ipc/compat.c b/ipc/compat.c index b5ef4f7946d..9b3c85f8a53 100644 --- a/ipc/compat.c +++ b/ipc/compat.c @@ -171,32 +171,32 @@ static inline int __put_compat_ipc64_perm(struct ipc64_perm *p64, } static inline int __put_compat_ipc_perm(struct ipc64_perm *p, - struct compat_ipc_perm __user *up) + struct compat_ipc_perm __user *uip) { int err; __compat_uid_t u; __compat_gid_t g; - err = __put_user(p->key, &up->key); + err = __put_user(p->key, &uip->key); SET_UID(u, p->uid); - err |= __put_user(u, &up->uid); + err |= __put_user(u, &uip->uid); SET_GID(g, p->gid); - err |= __put_user(g, &up->gid); + err |= __put_user(g, &uip->gid); SET_UID(u, p->cuid); - err |= __put_user(u, &up->cuid); + err |= __put_user(u, &uip->cuid); SET_GID(g, p->cgid); - err |= __put_user(g, &up->cgid); - err |= __put_user(p->mode, &up->mode); - err |= __put_user(p->seq, &up->seq); + err |= __put_user(g, &uip->cgid); + err |= __put_user(p->mode, &uip->mode); + err |= __put_user(p->seq, &uip->seq); return err; } -static inline int get_compat_semid64_ds(struct semid64_ds *s64, +static inline int get_compat_semid64_ds(struct semid64_ds *sem64, struct compat_semid64_ds __user *up64) { if (!access_ok(VERIFY_READ, up64, sizeof(*up64))) return -EFAULT; - return __get_compat_ipc64_perm(&s64->sem_perm, &up64->sem_perm); + return __get_compat_ipc64_perm(&sem64->sem_perm, &up64->sem_perm); } static inline int get_compat_semid_ds(struct semid64_ds *s, @@ -207,17 +207,17 @@ static inline int get_compat_semid_ds(struct semid64_ds *s, return __get_compat_ipc_perm(&s->sem_perm, &up->sem_perm); } -static inline int put_compat_semid64_ds(struct semid64_ds *s64, +static inline int put_compat_semid64_ds(struct semid64_ds *sem64, struct compat_semid64_ds __user *up64) { int err; if (!access_ok(VERIFY_WRITE, up64, sizeof(*up64))) return -EFAULT; - err = __put_compat_ipc64_perm(&s64->sem_perm, &up64->sem_perm); - err |= __put_user(s64->sem_otime, &up64->sem_otime); - err |= __put_user(s64->sem_ctime, &up64->sem_ctime); - err |= __put_user(s64->sem_nsems, &up64->sem_nsems); + err = __put_compat_ipc64_perm(&sem64->sem_perm, &up64->sem_perm); + err |= __put_user(sem64->sem_otime, &up64->sem_otime); + err |= __put_user(sem64->sem_ctime, &up64->sem_ctime); + err |= __put_user(sem64->sem_nsems, &up64->sem_nsems); return err; } @@ -239,11 +239,11 @@ static long do_compat_semctl(int first, int second, int third, u32 pad) { unsigned long fourth; int err, err2; - struct semid64_ds s64; + struct semid64_ds sem64; struct semid64_ds __user *up64; int version = compat_ipc_parse_version(&third); - memset(&s64, 0, sizeof(s64)); + memset(&sem64, 0, sizeof(sem64)); if ((third & (~IPC_64)) == SETVAL) #ifdef __BIG_ENDIAN @@ -269,29 +269,29 @@ static long do_compat_semctl(int first, int second, int third, u32 pad) case IPC_STAT: case SEM_STAT: - up64 = compat_alloc_user_space(sizeof(s64)); + up64 = compat_alloc_user_space(sizeof(sem64)); fourth = (unsigned long)up64; err = sys_semctl(first, second, third, fourth); if (err < 0) break; - if (copy_from_user(&s64, up64, sizeof(s64))) + if (copy_from_user(&sem64, up64, sizeof(sem64))) err2 = -EFAULT; else if (version == IPC_64) - err2 = put_compat_semid64_ds(&s64, compat_ptr(pad)); + err2 = put_compat_semid64_ds(&sem64, compat_ptr(pad)); else - err2 = put_compat_semid_ds(&s64, compat_ptr(pad)); + err2 = put_compat_semid_ds(&sem64, compat_ptr(pad)); if (err2) err = -EFAULT; break; case IPC_SET: if (version == IPC_64) - err = get_compat_semid64_ds(&s64, compat_ptr(pad)); + err = get_compat_semid64_ds(&sem64, compat_ptr(pad)); else - err = get_compat_semid_ds(&s64, compat_ptr(pad)); + err = get_compat_semid_ds(&sem64, compat_ptr(pad)); - up64 = compat_alloc_user_space(sizeof(s64)); - if (copy_to_user(up64, &s64, sizeof(s64))) + up64 = compat_alloc_user_space(sizeof(sem64)); + if (copy_to_user(up64, &sem64, sizeof(sem64))) err = -EFAULT; if (err) break; @@ -561,12 +561,12 @@ COMPAT_SYSCALL_DEFINE3(shmat, int, shmid, compat_uptr_t, shmaddr, int, shmflg) return (long)ret; } -static inline int get_compat_shmid64_ds(struct shmid64_ds *s64, +static inline int get_compat_shmid64_ds(struct shmid64_ds *sem64, struct compat_shmid64_ds __user *up64) { if (!access_ok(VERIFY_READ, up64, sizeof(*up64))) return -EFAULT; - return __get_compat_ipc64_perm(&s64->shm_perm, &up64->shm_perm); + return __get_compat_ipc64_perm(&sem64->shm_perm, &up64->shm_perm); } static inline int get_compat_shmid_ds(struct shmid64_ds *s, @@ -577,21 +577,21 @@ static inline int get_compat_shmid_ds(struct shmid64_ds *s, return __get_compat_ipc_perm(&s->shm_perm, &up->shm_perm); } -static inline int put_compat_shmid64_ds(struct shmid64_ds *s64, +static inline int put_compat_shmid64_ds(struct shmid64_ds *sem64, struct compat_shmid64_ds __user *up64) { int err; if (!access_ok(VERIFY_WRITE, up64, sizeof(*up64))) return -EFAULT; - err = __put_compat_ipc64_perm(&s64->shm_perm, &up64->shm_perm); - err |= __put_user(s64->shm_atime, &up64->shm_atime); - err |= __put_user(s64->shm_dtime, &up64->shm_dtime); - err |= __put_user(s64->shm_ctime, &up64->shm_ctime); - err |= __put_user(s64->shm_segsz, &up64->shm_segsz); - err |= __put_user(s64->shm_nattch, &up64->shm_nattch); - err |= __put_user(s64->shm_cpid, &up64->shm_cpid); - err |= __put_user(s64->shm_lpid, &up64->shm_lpid); + err = __put_compat_ipc64_perm(&sem64->shm_perm, &up64->shm_perm); + err |= __put_user(sem64->shm_atime, &up64->shm_atime); + err |= __put_user(sem64->shm_dtime, &up64->shm_dtime); + err |= __put_user(sem64->shm_ctime, &up64->shm_ctime); + err |= __put_user(sem64->shm_segsz, &up64->shm_segsz); + err |= __put_user(sem64->shm_nattch, &up64->shm_nattch); + err |= __put_user(sem64->shm_cpid, &up64->shm_cpid); + err |= __put_user(sem64->shm_lpid, &up64->shm_lpid); return err; } @@ -668,12 +668,12 @@ static inline int put_compat_shm_info(struct shm_info __user *ip, COMPAT_SYSCALL_DEFINE3(shmctl, int, first, int, second, void __user *, uptr) { void __user *p; - struct shmid64_ds s64; + struct shmid64_ds sem64; struct shminfo64 smi; int err, err2; int version = compat_ipc_parse_version(&second); - memset(&s64, 0, sizeof(s64)); + memset(&sem64, 0, sizeof(sem64)); switch (second & (~IPC_64)) { case IPC_RMID: @@ -700,14 +700,14 @@ COMPAT_SYSCALL_DEFINE3(shmctl, int, first, int, second, void __user *, uptr) case IPC_SET: if (version == IPC_64) - err = get_compat_shmid64_ds(&s64, uptr); + err = get_compat_shmid64_ds(&sem64, uptr); else - err = get_compat_shmid_ds(&s64, uptr); + err = get_compat_shmid_ds(&sem64, uptr); if (err) break; - p = compat_alloc_user_space(sizeof(s64)); - if (copy_to_user(p, &s64, sizeof(s64))) + p = compat_alloc_user_space(sizeof(sem64)); + if (copy_to_user(p, &sem64, sizeof(sem64))) err = -EFAULT; else err = sys_shmctl(first, second, p); @@ -715,16 +715,16 @@ COMPAT_SYSCALL_DEFINE3(shmctl, int, first, int, second, void __user *, uptr) case IPC_STAT: case SHM_STAT: - p = compat_alloc_user_space(sizeof(s64)); + p = compat_alloc_user_space(sizeof(sem64)); err = sys_shmctl(first, second, p); if (err < 0) break; - if (copy_from_user(&s64, p, sizeof(s64))) + if (copy_from_user(&sem64, p, sizeof(sem64))) err2 = -EFAULT; else if (version == IPC_64) - err2 = put_compat_shmid64_ds(&s64, uptr); + err2 = put_compat_shmid64_ds(&sem64, uptr); else - err2 = put_compat_shmid_ds(&s64, uptr); + err2 = put_compat_shmid_ds(&sem64, uptr); if (err2) err = -EFAULT; break; diff --git a/ipc/ipc_sysctl.c b/ipc/ipc_sysctl.c index c3f0326e98d..e8075b24749 100644 --- a/ipc/ipc_sysctl.c +++ b/ipc/ipc_sysctl.c @@ -123,7 +123,6 @@ static int proc_ipcauto_dointvec_minmax(struct ctl_table *table, int write, void __user *buffer, size_t *lenp, loff_t *ppos) { struct ctl_table ipc_table; - size_t lenp_bef = *lenp; int oldval; int rc; @@ -133,7 +132,7 @@ static int proc_ipcauto_dointvec_minmax(struct ctl_table *table, int write, rc = proc_dointvec_minmax(&ipc_table, write, buffer, lenp, ppos); - if (write && !rc && lenp_bef == *lenp) { + if (write && !rc) { int newval = *((int *)(ipc_table.data)); /* * The file "auto_msgmni" has correctly been set. diff --git a/ipc/namespace.c b/ipc/namespace.c index 59451c1e214..b54468e48e3 100644 --- a/ipc/namespace.c +++ b/ipc/namespace.c @@ -154,11 +154,11 @@ static void *ipcns_get(struct task_struct *task) struct ipc_namespace *ns = NULL; struct nsproxy *nsproxy; - rcu_read_lock(); - nsproxy = task_nsproxy(task); + task_lock(task); + nsproxy = task->nsproxy; if (nsproxy) ns = get_ipc_ns(nsproxy->ipc_ns); - rcu_read_unlock(); + task_unlock(task); return ns; } diff --git a/ipc/shm.c b/ipc/shm.c index 89fc354156c..01454796ba3 100644 --- a/ipc/shm.c +++ b/ipc/shm.c @@ -178,6 +178,7 @@ static void shm_rcu_free(struct rcu_head *head) static inline void shm_rmid(struct ipc_namespace *ns, struct shmid_kernel *s) { + list_del(&s->shm_clist); ipc_rmid(&shm_ids(ns), &s->shm_perm); } @@ -268,37 +269,6 @@ static void shm_close(struct vm_area_struct *vma) } /* Called with ns->shm_ids(ns).rwsem locked */ -static int shm_try_destroy_current(int id, void *p, void *data) -{ - struct ipc_namespace *ns = data; - struct kern_ipc_perm *ipcp = p; - struct shmid_kernel *shp = container_of(ipcp, struct shmid_kernel, shm_perm); - - if (shp->shm_creator != current) - return 0; - - /* - * Mark it as orphaned to destroy the segment when - * kernel.shm_rmid_forced is changed. - * It is noop if the following shm_may_destroy() returns true. - */ - shp->shm_creator = NULL; - - /* - * Don't even try to destroy it. If shm_rmid_forced=0 and IPC_RMID - * is not set, it shouldn't be deleted here. - */ - if (!ns->shm_rmid_forced) - return 0; - - if (shm_may_destroy(ns, shp)) { - shm_lock_by_ptr(shp); - shm_destroy(ns, shp); - } - return 0; -} - -/* Called with ns->shm_ids(ns).rwsem locked */ static int shm_try_destroy_orphaned(int id, void *p, void *data) { struct ipc_namespace *ns = data; @@ -329,18 +299,50 @@ void shm_destroy_orphaned(struct ipc_namespace *ns) up_write(&shm_ids(ns).rwsem); } - +/* Locking assumes this will only be called with task == current */ void exit_shm(struct task_struct *task) { struct ipc_namespace *ns = task->nsproxy->ipc_ns; + struct shmid_kernel *shp, *n; - if (shm_ids(ns).in_use == 0) + if (list_empty(&task->sysvshm.shm_clist)) return; - /* Destroy all already created segments, but not mapped yet */ + /* + * If kernel.shm_rmid_forced is not set then only keep track of + * which shmids are orphaned, so that a later set of the sysctl + * can clean them up. + */ + if (!ns->shm_rmid_forced) { + down_read(&shm_ids(ns).rwsem); + list_for_each_entry(shp, &task->sysvshm.shm_clist, shm_clist) + shp->shm_creator = NULL; + /* + * Only under read lock but we are only called on current + * so no entry on the list will be shared. + */ + list_del(&task->sysvshm.shm_clist); + up_read(&shm_ids(ns).rwsem); + return; + } + + /* + * Destroy all already created segments, that were not yet mapped, + * and mark any mapped as orphan to cover the sysctl toggling. + * Destroy is skipped if shm_may_destroy() returns false. + */ down_write(&shm_ids(ns).rwsem); - if (shm_ids(ns).in_use) - idr_for_each(&shm_ids(ns).ipcs_idr, &shm_try_destroy_current, ns); + list_for_each_entry_safe(shp, n, &task->sysvshm.shm_clist, shm_clist) { + shp->shm_creator = NULL; + + if (shm_may_destroy(ns, shp)) { + shm_lock_by_ptr(shp); + shm_destroy(ns, shp); + } + } + + /* Remove the list head from any segments still attached. */ + list_del(&task->sysvshm.shm_clist); up_write(&shm_ids(ns).rwsem); } @@ -561,6 +563,7 @@ static int newseg(struct ipc_namespace *ns, struct ipc_params *params) shp->shm_nattch = 0; shp->shm_file = file; shp->shm_creator = current; + list_add(&shp->shm_clist, ¤t->sysvshm.shm_clist); /* * shmid gets reported as "inode#" in /proc/pid/maps. @@ -1169,13 +1172,6 @@ long do_shmat(int shmid, char __user *shmaddr, int shmflg, ulong *raddr, if (find_vma_intersection(current->mm, addr, addr + size)) goto invalid; - /* - * If shm segment goes below stack, make sure there is some - * space left for the stack to grow (at least 4 pages). - */ - if (addr < current->mm->start_stack && - addr > current->mm->start_stack - size - PAGE_SIZE * 5) - goto invalid; } addr = do_mmap_pgoff(file, addr, size, prot, flags, 0, &populate); diff --git a/ipc/util.c b/ipc/util.c index d73b7af581e..88adc329888 100644 --- a/ipc/util.c +++ b/ipc/util.c @@ -892,28 +892,16 @@ static const struct seq_operations sysvipc_proc_seqops = { static int sysvipc_proc_open(struct inode *inode, struct file *file) { - int ret; - struct seq_file *seq; struct ipc_proc_iter *iter; - ret = -ENOMEM; - iter = kmalloc(sizeof(*iter), GFP_KERNEL); + iter = __seq_open_private(file, &sysvipc_proc_seqops, sizeof(*iter)); if (!iter) - goto out; - - ret = seq_open(file, &sysvipc_proc_seqops); - if (ret) { - kfree(iter); - goto out; - } - - seq = file->private_data; - seq->private = iter; + return -ENOMEM; iter->iface = PDE_DATA(inode); iter->ns = get_ipc_ns(current->nsproxy->ipc_ns); -out: - return ret; + + return 0; } static int sysvipc_proc_release(struct inode *inode, struct file *file) |