From a33e6751003c5ade603737d828b1519d980ce392 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Wed, 10 Dec 2008 03:40:06 -0500 Subject: sanitize audit_ipc_obj() * get rid of allocations * make it return void * simplify callers Signed-off-by: Al Viro --- ipc/shm.c | 4 +--- ipc/util.c | 9 +++------ 2 files changed, 4 insertions(+), 9 deletions(-) (limited to 'ipc') diff --git a/ipc/shm.c b/ipc/shm.c index 38a0557..57dd500 100644 --- a/ipc/shm.c +++ b/ipc/shm.c @@ -747,9 +747,7 @@ asmlinkage long sys_shmctl(int shmid, int cmd, struct shmid_ds __user *buf) goto out; } - err = audit_ipc_obj(&(shp->shm_perm)); - if (err) - goto out_unlock; + audit_ipc_obj(&(shp->shm_perm)); if (!capable(CAP_IPC_LOCK)) { uid_t euid = current_euid(); diff --git a/ipc/util.c b/ipc/util.c index 5a1808c..579552ab 100644 --- a/ipc/util.c +++ b/ipc/util.c @@ -624,10 +624,9 @@ void ipc_rcu_putref(void *ptr) int ipcperms (struct kern_ipc_perm *ipcp, short flag) { /* flag will most probably be 0 or S_...UGO from */ uid_t euid = current_euid(); - int requested_mode, granted_mode, err; + int requested_mode, granted_mode; - if (unlikely((err = audit_ipc_obj(ipcp)))) - return err; + audit_ipc_obj(ipcp); requested_mode = (flag >> 6) | (flag >> 3) | flag; granted_mode = ipcp->mode; if (euid == ipcp->cuid || @@ -803,9 +802,7 @@ struct kern_ipc_perm *ipcctl_pre_down(struct ipc_ids *ids, int id, int cmd, goto out_up; } - err = audit_ipc_obj(ipcp); - if (err) - goto out_unlock; + audit_ipc_obj(ipcp); if (cmd == IPC_SET) { err = audit_ipc_set_perm(extra_perm, perm->uid, -- cgit v1.1 From e816f370cbadd2afea9f1a42f232d0636137d563 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Wed, 10 Dec 2008 03:47:15 -0500 Subject: sanitize audit_ipc_set_perm() * get rid of allocations * make it return void * simplify callers Signed-off-by: Al Viro --- ipc/util.c | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) (limited to 'ipc') diff --git a/ipc/util.c b/ipc/util.c index 579552ab..7585a72 100644 --- a/ipc/util.c +++ b/ipc/util.c @@ -803,13 +803,9 @@ struct kern_ipc_perm *ipcctl_pre_down(struct ipc_ids *ids, int id, int cmd, } audit_ipc_obj(ipcp); - - if (cmd == IPC_SET) { - err = audit_ipc_set_perm(extra_perm, perm->uid, + if (cmd == IPC_SET) + audit_ipc_set_perm(extra_perm, perm->uid, perm->gid, perm->mode); - if (err) - goto out_unlock; - } euid = current_euid(); if (euid == ipcp->cuid || @@ -817,7 +813,6 @@ struct kern_ipc_perm *ipcctl_pre_down(struct ipc_ids *ids, int id, int cmd, return ipcp; err = -EPERM; -out_unlock: ipc_unlock(ipcp); out_up: up_write(&ids->rw_mutex); -- cgit v1.1 From 7392906ea915b9a2c14dea32b3604b4e178f82f7 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Wed, 10 Dec 2008 06:58:59 -0500 Subject: sanitize audit_mq_getsetattr() * get rid of allocations * make it return void * don't duplicate parts of audit_dummy_context() Signed-off-by: Al Viro --- ipc/mqueue.c | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) (limited to 'ipc') diff --git a/ipc/mqueue.c b/ipc/mqueue.c index d9393f8..7563611 100644 --- a/ipc/mqueue.c +++ b/ipc/mqueue.c @@ -1150,11 +1150,7 @@ asmlinkage long sys_mq_getsetattr(mqd_t mqdes, omqstat = info->attr; omqstat.mq_flags = filp->f_flags & O_NONBLOCK; if (u_mqstat) { - ret = audit_mq_getsetattr(mqdes, &mqstat); - if (ret != 0) { - spin_unlock(&info->lock); - goto out_fput; - } + audit_mq_getsetattr(mqdes, &mqstat); if (mqstat.mq_flags & O_NONBLOCK) filp->f_flags |= O_NONBLOCK; else -- cgit v1.1 From 20114f71b27cafeb7c7e41d2b0f0b68c3fbb022b Mon Sep 17 00:00:00 2001 From: Al Viro Date: Wed, 10 Dec 2008 07:16:12 -0500 Subject: sanitize audit_mq_notify() * don't copy_from_user() twice * don't bother with allocations * don't duplicate parts of audit_dummy_context() * make it return void Signed-off-by: Al Viro --- ipc/mqueue.c | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) (limited to 'ipc') diff --git a/ipc/mqueue.c b/ipc/mqueue.c index 7563611..e7b2f68 100644 --- a/ipc/mqueue.c +++ b/ipc/mqueue.c @@ -1003,17 +1003,17 @@ asmlinkage long sys_mq_notify(mqd_t mqdes, struct mqueue_inode_info *info; struct sk_buff *nc; - ret = audit_mq_notify(mqdes, u_notification); - if (ret != 0) - return ret; - - nc = NULL; - sock = NULL; - if (u_notification != NULL) { + if (u_notification) { if (copy_from_user(¬ification, u_notification, sizeof(struct sigevent))) return -EFAULT; + } + + audit_mq_notify(mqdes, u_notification ? ¬ification : NULL); + nc = NULL; + sock = NULL; + if (u_notification != NULL) { if (unlikely(notification.sigev_notify != SIGEV_NONE && notification.sigev_notify != SIGEV_SIGNAL && notification.sigev_notify != SIGEV_THREAD)) -- cgit v1.1 From c32c8af43b9adde8d6f938d8e6328c13b8de79ac Mon Sep 17 00:00:00 2001 From: Al Viro Date: Sun, 14 Dec 2008 03:46:48 -0500 Subject: sanitize AUDIT_MQ_SENDRECV * logging the original value of *msg_prio in mq_timedreceive(2) is insane - the argument is write-only (i.e. syscall always ignores the original value and only overwrites it). * merge __audit_mq_timed{send,receive} * don't do copy_from_user() twice * don't mess with allocations in auditsc part * ... and don't bother checking !audit_enabled and !context in there - we'd already checked for audit_dummy_context(). Signed-off-by: Al Viro --- ipc/mqueue.c | 54 ++++++++++++++++++++++++++++++------------------------ 1 file changed, 30 insertions(+), 24 deletions(-) (limited to 'ipc') diff --git a/ipc/mqueue.c b/ipc/mqueue.c index e7b2f68..192da80 100644 --- a/ipc/mqueue.c +++ b/ipc/mqueue.c @@ -524,31 +524,27 @@ static void __do_notify(struct mqueue_inode_info *info) wake_up(&info->wait_q); } -static long prepare_timeout(const struct timespec __user *u_arg) +static long prepare_timeout(struct timespec *p) { - struct timespec ts, nowts; + struct timespec nowts; long timeout; - if (u_arg) { - if (unlikely(copy_from_user(&ts, u_arg, - sizeof(struct timespec)))) - return -EFAULT; - - if (unlikely(ts.tv_nsec < 0 || ts.tv_sec < 0 - || ts.tv_nsec >= NSEC_PER_SEC)) + if (p) { + if (unlikely(p->tv_nsec < 0 || p->tv_sec < 0 + || p->tv_nsec >= NSEC_PER_SEC)) return -EINVAL; nowts = CURRENT_TIME; /* first subtract as jiffies can't be too big */ - ts.tv_sec -= nowts.tv_sec; - if (ts.tv_nsec < nowts.tv_nsec) { - ts.tv_nsec += NSEC_PER_SEC; - ts.tv_sec--; + p->tv_sec -= nowts.tv_sec; + if (p->tv_nsec < nowts.tv_nsec) { + p->tv_nsec += NSEC_PER_SEC; + p->tv_sec--; } - ts.tv_nsec -= nowts.tv_nsec; - if (ts.tv_sec < 0) + p->tv_nsec -= nowts.tv_nsec; + if (p->tv_sec < 0) return 0; - timeout = timespec_to_jiffies(&ts) + 1; + timeout = timespec_to_jiffies(p) + 1; } else return MAX_SCHEDULE_TIMEOUT; @@ -829,17 +825,22 @@ asmlinkage long sys_mq_timedsend(mqd_t mqdes, const char __user *u_msg_ptr, struct ext_wait_queue *receiver; struct msg_msg *msg_ptr; struct mqueue_inode_info *info; + struct timespec ts, *p = NULL; long timeout; int ret; - ret = audit_mq_timedsend(mqdes, msg_len, msg_prio, u_abs_timeout); - if (ret != 0) - return ret; + if (u_abs_timeout) { + if (copy_from_user(&ts, u_abs_timeout, + sizeof(struct timespec))) + return -EFAULT; + p = &ts; + } if (unlikely(msg_prio >= (unsigned long) MQ_PRIO_MAX)) return -EINVAL; - timeout = prepare_timeout(u_abs_timeout); + audit_mq_sendrecv(mqdes, msg_len, msg_prio, p); + timeout = prepare_timeout(p); ret = -EBADF; filp = fget(mqdes); @@ -918,12 +919,17 @@ asmlinkage ssize_t sys_mq_timedreceive(mqd_t mqdes, char __user *u_msg_ptr, struct inode *inode; struct mqueue_inode_info *info; struct ext_wait_queue wait; + struct timespec ts, *p = NULL; - ret = audit_mq_timedreceive(mqdes, msg_len, u_msg_prio, u_abs_timeout); - if (ret != 0) - return ret; + if (u_abs_timeout) { + if (copy_from_user(&ts, u_abs_timeout, + sizeof(struct timespec))) + return -EFAULT; + p = &ts; + } - timeout = prepare_timeout(u_abs_timeout); + audit_mq_sendrecv(mqdes, msg_len, 0, p); + timeout = prepare_timeout(p); ret = -EBADF; filp = fget(mqdes); -- cgit v1.1 From 564f6993ffef656aebaf46cf2f1f6cb4f5c97207 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Sun, 14 Dec 2008 04:02:26 -0500 Subject: sanitize audit_mq_open() * don't bother with allocations * don't do double copy_from_user() * don't duplicate parts of check for audit_dummy_context() Signed-off-by: Al Viro --- ipc/mqueue.c | 23 +++++++++++------------ 1 file changed, 11 insertions(+), 12 deletions(-) (limited to 'ipc') diff --git a/ipc/mqueue.c b/ipc/mqueue.c index 192da80..d448b69 100644 --- a/ipc/mqueue.c +++ b/ipc/mqueue.c @@ -588,22 +588,18 @@ static int mq_attr_ok(struct mq_attr *attr) * Invoked when creating a new queue via sys_mq_open */ static struct file *do_create(struct dentry *dir, struct dentry *dentry, - int oflag, mode_t mode, struct mq_attr __user *u_attr) + int oflag, mode_t mode, struct mq_attr *attr) { const struct cred *cred = current_cred(); - struct mq_attr attr; struct file *result; int ret; - if (u_attr) { - ret = -EFAULT; - if (copy_from_user(&attr, u_attr, sizeof(attr))) - goto out; + if (attr) { ret = -EINVAL; - if (!mq_attr_ok(&attr)) + if (!mq_attr_ok(attr)) goto out; /* store for use during create */ - dentry->d_fsdata = &attr; + dentry->d_fsdata = attr; } mode &= ~current->fs->umask; @@ -660,11 +656,13 @@ asmlinkage long sys_mq_open(const char __user *u_name, int oflag, mode_t mode, struct dentry *dentry; struct file *filp; char *name; + struct mq_attr attr; int fd, error; - error = audit_mq_open(oflag, mode, u_attr); - if (error != 0) - return error; + if (u_attr && copy_from_user(&attr, u_attr, sizeof(struct mq_attr))) + return -EFAULT; + + audit_mq_open(oflag, mode, u_attr ? &attr : NULL); if (IS_ERR(name = getname(u_name))) return PTR_ERR(name); @@ -690,7 +688,8 @@ asmlinkage long sys_mq_open(const char __user *u_name, int oflag, mode_t mode, filp = do_open(dentry, oflag); } else { filp = do_create(mqueue_mnt->mnt_root, dentry, - oflag, mode, u_attr); + oflag, mode, + u_attr ? &attr : NULL); } } else { error = -ENOENT; -- cgit v1.1 From 56ff5efad96182f4d3cb3dc6b07396762c658f16 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Tue, 9 Dec 2008 09:34:39 -0500 Subject: zero i_uid/i_gid on inode allocation ... and don't bother in callers. Don't bother with zeroing i_blocks, while we are at it - it's already been zeroed. i_mode is not worth the effort; it has no common default value. Signed-off-by: Al Viro --- ipc/mqueue.c | 1 - 1 file changed, 1 deletion(-) (limited to 'ipc') diff --git a/ipc/mqueue.c b/ipc/mqueue.c index d9393f8..41b72f0 100644 --- a/ipc/mqueue.c +++ b/ipc/mqueue.c @@ -120,7 +120,6 @@ static struct inode *mqueue_get_inode(struct super_block *sb, int mode, inode->i_mode = mode; inode->i_uid = current_fsuid(); inode->i_gid = current_fsgid(); - inode->i_blocks = 0; inode->i_mtime = inode->i_ctime = inode->i_atime = CURRENT_TIME; -- cgit v1.1 From 046c68842bce6b77509cf56e94a561029124b0ce Mon Sep 17 00:00:00 2001 From: Alan Cox Date: Mon, 5 Jan 2009 14:06:29 +0000 Subject: mm: update my address Signed-off-by: Alan Cox Signed-off-by: Linus Torvalds --- ipc/sem.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'ipc') diff --git a/ipc/sem.c b/ipc/sem.c index 0821224..fea0ad3 100644 --- a/ipc/sem.c +++ b/ipc/sem.c @@ -58,7 +58,7 @@ * SMP-threaded, sysctl's added * (c) 1999 Manfred Spraul * Enforced range limit on SEM_UNDO - * (c) 2001 Red Hat Inc + * (c) 2001 Red Hat Inc * Lockless wakeup * (c) 2003 Manfred Spraul * -- cgit v1.1 From e8148f7588064e45080bf1120883380a2efe5c9b Mon Sep 17 00:00:00 2001 From: WANG Cong Date: Tue, 6 Jan 2009 14:42:49 -0800 Subject: ipc: clean up ipc/shm.c Use the macro shm_ids(). Remove useless check for a userspace pointer, because copy_to_user() will check it. Some style cleanups. Signed-off-by: WANG Cong Cc: Nadia Derbey Cc: Pierre Peiffer Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- ipc/shm.c | 15 +++++---------- 1 file changed, 5 insertions(+), 10 deletions(-) (limited to 'ipc') diff --git a/ipc/shm.c b/ipc/shm.c index 57dd500..b125b56 100644 --- a/ipc/shm.c +++ b/ipc/shm.c @@ -75,7 +75,7 @@ void shm_init_ns(struct ipc_namespace *ns) ns->shm_ctlall = SHMALL; ns->shm_ctlmni = SHMMNI; ns->shm_tot = 0; - ipc_init_ids(&ns->ids[IPC_SHM_IDS]); + ipc_init_ids(&shm_ids(ns)); } /* @@ -644,7 +644,7 @@ asmlinkage long sys_shmctl(int shmid, int cmd, struct shmid_ds __user *buf) if (err) return err; - memset(&shminfo,0,sizeof(shminfo)); + memset(&shminfo, 0, sizeof(shminfo)); shminfo.shmmni = shminfo.shmseg = ns->shm_ctlmni; shminfo.shmmax = ns->shm_ctlmax; shminfo.shmall = ns->shm_ctlall; @@ -669,7 +669,7 @@ asmlinkage long sys_shmctl(int shmid, int cmd, struct shmid_ds __user *buf) if (err) return err; - memset(&shm_info,0,sizeof(shm_info)); + memset(&shm_info, 0, sizeof(shm_info)); down_read(&shm_ids(ns).rw_mutex); shm_info.used_ids = shm_ids(ns).in_use; shm_get_stat (ns, &shm_info.shm_rss, &shm_info.shm_swp); @@ -678,7 +678,7 @@ asmlinkage long sys_shmctl(int shmid, int cmd, struct shmid_ds __user *buf) shm_info.swap_successes = 0; err = ipc_get_maxid(&shm_ids(ns)); up_read(&shm_ids(ns).rw_mutex); - if(copy_to_user (buf, &shm_info, sizeof(shm_info))) { + if (copy_to_user(buf, &shm_info, sizeof(shm_info))) { err = -EFAULT; goto out; } @@ -692,11 +692,6 @@ asmlinkage long sys_shmctl(int shmid, int cmd, struct shmid_ds __user *buf) struct shmid64_ds tbuf; int result; - if (!buf) { - err = -EFAULT; - goto out; - } - if (cmd == SHM_STAT) { shp = shm_lock(ns, shmid); if (IS_ERR(shp)) { @@ -712,7 +707,7 @@ asmlinkage long sys_shmctl(int shmid, int cmd, struct shmid_ds __user *buf) } result = 0; } - err=-EACCES; + err = -EACCES; if (ipcperms (&shp->shm_perm, S_IRUGO)) goto out_unlock; err = security_shm_shmctl(shp, cmd); -- cgit v1.1 From e953ac2195659940d0d042f7ac962700a6a0f0e3 Mon Sep 17 00:00:00 2001 From: "Denis V. Lunev" Date: Tue, 6 Jan 2009 14:42:50 -0800 Subject: ipc: do not goto to the next line Signed-off-by: Denis V. Lunev Reviewed-by: WANG Cong Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- ipc/sem.c | 1 - 1 file changed, 1 deletion(-) (limited to 'ipc') diff --git a/ipc/sem.c b/ipc/sem.c index fea0ad3..c68cd3f 100644 --- a/ipc/sem.c +++ b/ipc/sem.c @@ -1216,7 +1216,6 @@ asmlinkage long sys_semtimedop(int semid, struct sembuf __user *tsops, if (timeout && jiffies_left == 0) error = -EAGAIN; list_del(&queue.list); - goto out_unlock_free; out_unlock_free: sem_unlock(sma); -- cgit v1.1 From 4c2c3b4aaf3c10a636490438e9648a314ce414f9 Mon Sep 17 00:00:00 2001 From: "akpm@linux-foundation.org" Date: Tue, 6 Jan 2009 14:42:51 -0800 Subject: ipc/ipc_sysctl.c: move the definition of ipc_auto_callback() proc_ipcauto_dointvec_minmax() is the only user of ipc_auto_callback(), since the former function is protected by CONFIG_PROC_FS, so should be the latter one. Just move its definition down. Signed-off-by: WANG Cong Cc: Eric Biederman Cc: Nadia Derbey Cc: Alexey Dobriyan Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- ipc/ipc_sysctl.c | 46 +++++++++++++++++++++++----------------------- 1 file changed, 23 insertions(+), 23 deletions(-) (limited to 'ipc') diff --git a/ipc/ipc_sysctl.c b/ipc/ipc_sysctl.c index 0dfebc5..4a7a12c 100644 --- a/ipc/ipc_sysctl.c +++ b/ipc/ipc_sysctl.c @@ -26,29 +26,6 @@ static void *get_ipc(ctl_table *table) return which; } -/* - * Routine that is called when the file "auto_msgmni" has successfully been - * written. - * Two values are allowed: - * 0: unregister msgmni's callback routine from the ipc namespace notifier - * chain. This means that msgmni won't be recomputed anymore upon memory - * add/remove or ipc namespace creation/removal. - * 1: register back the callback routine. - */ -static void ipc_auto_callback(int val) -{ - if (!val) - unregister_ipcns_notifier(current->nsproxy->ipc_ns); - else { - /* - * Re-enable automatic recomputing only if not already - * enabled. - */ - recompute_msgmni(current->nsproxy->ipc_ns); - cond_register_ipcns_notifier(current->nsproxy->ipc_ns); - } -} - #ifdef CONFIG_PROC_FS static int proc_ipc_dointvec(ctl_table *table, int write, struct file *filp, void __user *buffer, size_t *lenp, loff_t *ppos) @@ -94,6 +71,29 @@ static int proc_ipc_doulongvec_minmax(ctl_table *table, int write, lenp, ppos); } +/* + * Routine that is called when the file "auto_msgmni" has successfully been + * written. + * Two values are allowed: + * 0: unregister msgmni's callback routine from the ipc namespace notifier + * chain. This means that msgmni won't be recomputed anymore upon memory + * add/remove or ipc namespace creation/removal. + * 1: register back the callback routine. + */ +static void ipc_auto_callback(int val) +{ + if (!val) + unregister_ipcns_notifier(current->nsproxy->ipc_ns); + else { + /* + * Re-enable automatic recomputing only if not already + * enabled. + */ + recompute_msgmni(current->nsproxy->ipc_ns); + cond_register_ipcns_notifier(current->nsproxy->ipc_ns); + } +} + static int proc_ipcauto_dointvec_minmax(ctl_table *table, int write, struct file *filp, void __user *buffer, size_t *lenp, loff_t *ppos) { -- cgit v1.1 From 8feae13110d60cc6287afabc2887366b0eb226c2 Mon Sep 17 00:00:00 2001 From: David Howells Date: Thu, 8 Jan 2009 12:04:47 +0000 Subject: NOMMU: Make VMAs per MM as for MMU-mode linux Make VMAs per mm_struct as for MMU-mode linux. This solves two problems: (1) In SYSV SHM where nattch for a segment does not reflect the number of shmat's (and forks) done. (2) In mmap() where the VMA's vm_mm is set to point to the parent mm by an exec'ing process when VM_EXECUTABLE is specified, regardless of the fact that a VMA might be shared and already have its vm_mm assigned to another process or a dead process. A new struct (vm_region) is introduced to track a mapped region and to remember the circumstances under which it may be shared and the vm_list_struct structure is discarded as it's no longer required. This patch makes the following additional changes: (1) Regions are now allocated with alloc_pages() rather than kmalloc() and with no recourse to __GFP_COMP, so the pages are not composite. Instead, each page has a reference on it held by the region. Anything else that is interested in such a page will have to get a reference on it to retain it. When the pages are released due to unmapping, each page is passed to put_page() and will be freed when the page usage count reaches zero. (2) Excess pages are trimmed after an allocation as the allocation must be made as a power-of-2 quantity of pages. (3) VMAs are added to the parent MM's R/B tree and mmap lists. As an MM may end up with overlapping VMAs within the tree, the VMA struct address is appended to the sort key. (4) Non-anonymous VMAs are now added to the backing inode's prio list. (5) Holes may be punched in anonymous VMAs with munmap(), releasing parts of the backing region. The VMA and region structs will be split if necessary. (6) sys_shmdt() only releases one attachment to a SYSV IPC shared memory segment instead of all the attachments at that addresss. Multiple shmat()'s return the same address under NOMMU-mode instead of different virtual addresses as under MMU-mode. (7) Core dumping for ELF-FDPIC requires fewer exceptions for NOMMU-mode. (8) /proc/maps is now the global list of mapped regions, and may list bits that aren't actually mapped anywhere. (9) /proc/meminfo gains a line (tagged "MmapCopy") that indicates the amount of RAM currently allocated by mmap to hold mappable regions that can't be mapped directly. These are copies of the backing device or file if not anonymous. These changes make NOMMU mode more similar to MMU mode. The downside is that NOMMU mode requires some extra memory to track things over NOMMU without this patch (VMAs are no longer shared, and there are now region structs). Signed-off-by: David Howells Tested-by: Mike Frysinger Acked-by: Paul Mundt --- ipc/shm.c | 12 ++++++++++++ 1 file changed, 12 insertions(+) (limited to 'ipc') diff --git a/ipc/shm.c b/ipc/shm.c index b125b56..d0ab552 100644 --- a/ipc/shm.c +++ b/ipc/shm.c @@ -990,6 +990,7 @@ asmlinkage long sys_shmdt(char __user *shmaddr) */ vma = find_vma(mm, addr); +#ifdef CONFIG_MMU while (vma) { next = vma->vm_next; @@ -1034,6 +1035,17 @@ asmlinkage long sys_shmdt(char __user *shmaddr) vma = next; } +#else /* CONFIG_MMU */ + /* under NOMMU conditions, the exact address to be destroyed must be + * given */ + retval = -EINVAL; + if (vma->vm_start == addr && vma->vm_ops == &shm_vm_ops) { + do_munmap(mm, vma->vm_start, vma->vm_end - vma->vm_start); + retval = 0; + } + +#endif + up_write(&mm->mmap_sem); return retval; } -- cgit v1.1 From a6684999f7c6bddd75cf9755ad7ff44435f72fff Mon Sep 17 00:00:00 2001 From: Sukadev Bhattiprolu Date: Wed, 7 Jan 2009 18:08:50 -0800 Subject: mqueue: fix si_pid value in mqueue do_notify() If a process registers for asynchronous notification on a POSIX message queue, it gets a signal and a siginfo_t structure when a message arrives on the message queue. The si_pid in the siginfo_t structure is set to the PID of the process that sent the message to the message queue. The principle is the following: . when mq_notify(SIGEV_SIGNAL) is called, the caller registers for notification when a msg arrives. The associated pid structure is stroed into inode_info->notify_owner. Let's call this process P1. . when mq_send() is called by say P2, P2 sends a signal to P1 to notify him about msg arrival. The way .si_pid is set today is not correct, since it doesn't take into account the fact that the process that is sending the message might not be in the same namespace as the notified one. This patch proposes to set si_pid to the sender's pid into the notify_owner namespace. Signed-off-by: Nadia Derbey Signed-off-by: Sukadev Bhattiprolu Acked-by: Oleg Nesterov Cc: Roland McGrath Cc: Bastian Blank Cc: Pavel Emelyanov Cc: Eric W. Biederman Acked-by: Serge Hallyn Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- ipc/mqueue.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'ipc') diff --git a/ipc/mqueue.c b/ipc/mqueue.c index eddb624..23fdb84 100644 --- a/ipc/mqueue.c +++ b/ipc/mqueue.c @@ -505,7 +505,8 @@ static void __do_notify(struct mqueue_inode_info *info) sig_i.si_errno = 0; sig_i.si_code = SI_MESGQ; sig_i.si_value = info->notify.sigev_value; - sig_i.si_pid = task_tgid_vnr(current); + sig_i.si_pid = task_tgid_nr_ns(current, + ns_of_pid(info->notify_owner)); sig_i.si_uid = current_uid(); kill_pid_info(info->notify.sigev_signo, -- cgit v1.1 From 2ed7c03ec17779afb4fcfa3b8c61df61bd4879ba Mon Sep 17 00:00:00 2001 From: Heiko Carstens Date: Wed, 14 Jan 2009 14:13:54 +0100 Subject: [CVE-2009-0029] Convert all system calls to return a long Convert all system calls to return a long. This should be a NOP since all converted types should have the same size anyway. With the exception of sys_exit_group which returned void. But that doesn't matter since the system call doesn't return. Signed-off-by: Heiko Carstens --- ipc/mqueue.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'ipc') diff --git a/ipc/mqueue.c b/ipc/mqueue.c index 23fdb84..6df028b 100644 --- a/ipc/mqueue.c +++ b/ipc/mqueue.c @@ -907,7 +907,7 @@ out: return ret; } -asmlinkage ssize_t sys_mq_timedreceive(mqd_t mqdes, char __user *u_msg_ptr, +asmlinkage long sys_mq_timedreceive(mqd_t mqdes, char __user *u_msg_ptr, size_t msg_len, unsigned int __user *u_msg_prio, const struct timespec __user *u_abs_timeout) { -- cgit v1.1 From 6673e0c3fbeaed2cd08e2fd4a4aa97382d6fedb0 Mon Sep 17 00:00:00 2001 From: Heiko Carstens Date: Wed, 14 Jan 2009 14:14:02 +0100 Subject: [CVE-2009-0029] System call wrapper special cases System calls with an unsigned long long argument can't be converted with the standard wrappers since that would include a cast to long, which in turn means that we would lose the upper 32 bit on 32 bit architectures. Also semctl can't use the standard wrapper since it has a 'union' parameter. So we handle them as special case and add some extra wrappers instead. Signed-off-by: Heiko Carstens --- ipc/sem.c | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) (limited to 'ipc') diff --git a/ipc/sem.c b/ipc/sem.c index c68cd3f..c385c40 100644 --- a/ipc/sem.c +++ b/ipc/sem.c @@ -887,7 +887,7 @@ out_up: return err; } -asmlinkage long sys_semctl (int semid, int semnum, int cmd, union semun arg) +SYSCALL_DEFINE(semctl)(int semid, int semnum, int cmd, union semun arg) { int err = -EINVAL; int version; @@ -923,6 +923,13 @@ asmlinkage long sys_semctl (int semid, int semnum, int cmd, union semun arg) return -EINVAL; } } +#ifdef CONFIG_HAVE_SYSCALL_WRAPPERS +asmlinkage long SyS_semctl(int semid, int semnum, int cmd, union semun arg) +{ + return SYSC_semctl((int) semid, (int) semnum, (int) cmd, arg); +} +SYSCALL_ALIAS(sys_semctl, SyS_semctl); +#endif /* If the task doesn't already have a undo_list, then allocate one * here. We guarantee there is only one thread using this undo list, -- cgit v1.1 From e48fbb699f82ef1e80bd7126046394d2dc9ca7e6 Mon Sep 17 00:00:00 2001 From: Heiko Carstens Date: Wed, 14 Jan 2009 14:14:26 +0100 Subject: [CVE-2009-0029] System call wrappers part 24 Signed-off-by: Heiko Carstens --- ipc/msg.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) (limited to 'ipc') diff --git a/ipc/msg.c b/ipc/msg.c index b4eee1c..2ceab7f 100644 --- a/ipc/msg.c +++ b/ipc/msg.c @@ -309,7 +309,7 @@ static inline int msg_security(struct kern_ipc_perm *ipcp, int msgflg) return security_msg_queue_associate(msq, msgflg); } -asmlinkage long sys_msgget(key_t key, int msgflg) +SYSCALL_DEFINE2(msgget, key_t, key, int, msgflg) { struct ipc_namespace *ns; struct ipc_ops msg_ops; @@ -466,7 +466,7 @@ out_up: return err; } -asmlinkage long sys_msgctl(int msqid, int cmd, struct msqid_ds __user *buf) +SYSCALL_DEFINE3(msgctl, int, msqid, int, cmd, struct msqid_ds __user *, buf) { struct msg_queue *msq; int err, version; @@ -723,8 +723,8 @@ out_free: return err; } -asmlinkage long -sys_msgsnd(int msqid, struct msgbuf __user *msgp, size_t msgsz, int msgflg) +SYSCALL_DEFINE4(msgsnd, int, msqid, struct msgbuf __user *, msgp, size_t, msgsz, + int, msgflg) { long mtype; @@ -904,8 +904,8 @@ out_unlock: return msgsz; } -asmlinkage long sys_msgrcv(int msqid, struct msgbuf __user *msgp, size_t msgsz, - long msgtyp, int msgflg) +SYSCALL_DEFINE5(msgrcv, int, msqid, struct msgbuf __user *, msgp, size_t, msgsz, + long, msgtyp, int, msgflg) { long err, mtype; -- cgit v1.1 From d5460c9974a321a194aded4a8c4daaac68ea8171 Mon Sep 17 00:00:00 2001 From: Heiko Carstens Date: Wed, 14 Jan 2009 14:14:27 +0100 Subject: [CVE-2009-0029] System call wrappers part 25 Signed-off-by: Heiko Carstens --- ipc/mqueue.c | 6 +++--- ipc/sem.c | 9 +++++---- ipc/shm.c | 8 ++++---- 3 files changed, 12 insertions(+), 11 deletions(-) (limited to 'ipc') diff --git a/ipc/mqueue.c b/ipc/mqueue.c index 6df028b..faac04c 100644 --- a/ipc/mqueue.c +++ b/ipc/mqueue.c @@ -650,8 +650,8 @@ static struct file *do_open(struct dentry *dentry, int oflag) return dentry_open(dentry, mqueue_mnt, oflag, cred); } -asmlinkage long sys_mq_open(const char __user *u_name, int oflag, mode_t mode, - struct mq_attr __user *u_attr) +SYSCALL_DEFINE4(mq_open, const char __user *, u_name, int, oflag, mode_t, mode, + struct mq_attr __user *, u_attr) { struct dentry *dentry; struct file *filp; @@ -721,7 +721,7 @@ out_putname: return fd; } -asmlinkage long sys_mq_unlink(const char __user *u_name) +SYSCALL_DEFINE1(mq_unlink, const char __user *, u_name) { int err; char *name; diff --git a/ipc/sem.c b/ipc/sem.c index c385c40..16a2189 100644 --- a/ipc/sem.c +++ b/ipc/sem.c @@ -308,7 +308,7 @@ static inline int sem_more_checks(struct kern_ipc_perm *ipcp, return 0; } -asmlinkage long sys_semget(key_t key, int nsems, int semflg) +SYSCALL_DEFINE3(semget, key_t, key, int, nsems, int, semflg) { struct ipc_namespace *ns; struct ipc_ops sem_ops; @@ -1055,8 +1055,8 @@ out: return un; } -asmlinkage long sys_semtimedop(int semid, struct sembuf __user *tsops, - unsigned nsops, const struct timespec __user *timeout) +SYSCALL_DEFINE4(semtimedop, int, semid, struct sembuf __user *, tsops, + unsigned, nsops, const struct timespec __user *, timeout) { int error = -EINVAL; struct sem_array *sma; @@ -1232,7 +1232,8 @@ out_free: return error; } -asmlinkage long sys_semop (int semid, struct sembuf __user *tsops, unsigned nsops) +SYSCALL_DEFINE3(semop, int, semid, struct sembuf __user *, tsops, + unsigned, nsops) { return sys_semtimedop(semid, tsops, nsops, NULL); } diff --git a/ipc/shm.c b/ipc/shm.c index d0ab552..a9e09ad 100644 --- a/ipc/shm.c +++ b/ipc/shm.c @@ -440,7 +440,7 @@ static inline int shm_more_checks(struct kern_ipc_perm *ipcp, return 0; } -asmlinkage long sys_shmget (key_t key, size_t size, int shmflg) +SYSCALL_DEFINE3(shmget, key_t, key, size_t, size, int, shmflg) { struct ipc_namespace *ns; struct ipc_ops shm_ops; @@ -621,7 +621,7 @@ out_up: return err; } -asmlinkage long sys_shmctl(int shmid, int cmd, struct shmid_ds __user *buf) +SYSCALL_DEFINE3(shmctl, int, shmid, int, cmd, struct shmid_ds __user *, buf) { struct shmid_kernel *shp; int err, version; @@ -939,7 +939,7 @@ out_put_dentry: goto out_nattch; } -asmlinkage long sys_shmat(int shmid, char __user *shmaddr, int shmflg) +SYSCALL_DEFINE3(shmat, int, shmid, char __user *, shmaddr, int, shmflg) { unsigned long ret; long err; @@ -955,7 +955,7 @@ asmlinkage long sys_shmat(int shmid, char __user *shmaddr, int shmflg) * detach and kill segment if marked destroyed. * The work is done in shm_close. */ -asmlinkage long sys_shmdt(char __user *shmaddr) +SYSCALL_DEFINE1(shmdt, char __user *, shmaddr) { struct mm_struct *mm = current->mm; struct vm_area_struct *vma, *next; -- cgit v1.1 From c4ea37c26a691ad0b7e86aa5884aab27830e95c9 Mon Sep 17 00:00:00 2001 From: Heiko Carstens Date: Wed, 14 Jan 2009 14:14:28 +0100 Subject: [CVE-2009-0029] System call wrappers part 26 Signed-off-by: Heiko Carstens --- ipc/mqueue.c | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) (limited to 'ipc') diff --git a/ipc/mqueue.c b/ipc/mqueue.c index faac04c..54b4077 100644 --- a/ipc/mqueue.c +++ b/ipc/mqueue.c @@ -814,9 +814,9 @@ static inline void pipelined_receive(struct mqueue_inode_info *info) sender->state = STATE_READY; } -asmlinkage long sys_mq_timedsend(mqd_t mqdes, const char __user *u_msg_ptr, - size_t msg_len, unsigned int msg_prio, - const struct timespec __user *u_abs_timeout) +SYSCALL_DEFINE5(mq_timedsend, mqd_t, mqdes, const char __user *, u_msg_ptr, + size_t, msg_len, unsigned int, msg_prio, + const struct timespec __user *, u_abs_timeout) { struct file *filp; struct inode *inode; @@ -907,9 +907,9 @@ out: return ret; } -asmlinkage long sys_mq_timedreceive(mqd_t mqdes, char __user *u_msg_ptr, - size_t msg_len, unsigned int __user *u_msg_prio, - const struct timespec __user *u_abs_timeout) +SYSCALL_DEFINE5(mq_timedreceive, mqd_t, mqdes, char __user *, u_msg_ptr, + size_t, msg_len, unsigned int __user *, u_msg_prio, + const struct timespec __user *, u_abs_timeout) { long timeout; ssize_t ret; @@ -997,8 +997,8 @@ out: * and he isn't currently owner of notification, will be silently discarded. * It isn't explicitly defined in the POSIX. */ -asmlinkage long sys_mq_notify(mqd_t mqdes, - const struct sigevent __user *u_notification) +SYSCALL_DEFINE2(mq_notify, mqd_t, mqdes, + const struct sigevent __user *, u_notification) { int ret; struct file *filp; @@ -1123,9 +1123,9 @@ out: return ret; } -asmlinkage long sys_mq_getsetattr(mqd_t mqdes, - const struct mq_attr __user *u_mqstat, - struct mq_attr __user *u_omqstat) +SYSCALL_DEFINE3(mq_getsetattr, mqd_t, mqdes, + const struct mq_attr __user *, u_mqstat, + struct mq_attr __user *, u_omqstat) { int ret; struct mq_attr mqstat, omqstat; -- cgit v1.1 From fc8744adc870a8d4366908221508bb113d8b72ee Mon Sep 17 00:00:00 2001 From: Linus Torvalds Date: Sat, 31 Jan 2009 15:08:56 -0800 Subject: Stop playing silly games with the VM_ACCOUNT flag The mmap_region() code would temporarily set the VM_ACCOUNT flag for anonymous shared mappings just to inform shmem_zero_setup() that it should enable accounting for the resulting shm object. It would then clear the flag after calling ->mmap (for the /dev/zero case) or doing shmem_zero_setup() (for the MAP_ANON case). This just resulted in vma merge issues, but also made for just unnecessary confusion. Use the already-existing VM_NORESERVE flag for this instead, and let shmem_{zero|file}_setup() just figure it out from that. This also happens to make it obvious that the new DRI2 GEM layer uses a non-reserving backing store for its object allocation - which is quite possibly not intentional. But since I didn't want to change semantics in this patch, I left it alone, and just updated the caller to use the new flag semantics. Signed-off-by: Linus Torvalds --- ipc/shm.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'ipc') diff --git a/ipc/shm.c b/ipc/shm.c index a9e09ad..c0a021f 100644 --- a/ipc/shm.c +++ b/ipc/shm.c @@ -368,14 +368,14 @@ static int newseg(struct ipc_namespace *ns, struct ipc_params *params) file = hugetlb_file_setup(name, size); shp->mlock_user = current_user(); } else { - int acctflag = VM_ACCOUNT; + int acctflag = 0; /* * Do not allow no accounting for OVERCOMMIT_NEVER, even * if it's asked for. */ if ((shmflg & SHM_NORESERVE) && sysctl_overcommit_memory != OVERCOMMIT_NEVER) - acctflag = 0; + acctflag = VM_NORESERVE; file = shmem_file_setup(name, size, acctflag); } error = PTR_ERR(file); -- cgit v1.1 From a68e61e8ff2d46327a37b69056998b47745db6fa Mon Sep 17 00:00:00 2001 From: Tony Battersby Date: Wed, 4 Feb 2009 15:12:04 -0800 Subject: shm: fix shmctl(SHM_INFO) lockup with !CONFIG_SHMEM shm_get_stat() assumes that the inode is a "struct shmem_inode_info", which is incorrect for !CONFIG_SHMEM (see fs/ramfs/inode.c: ramfs_get_inode() vs. mm/shmem.c: shmem_get_inode()). This bad assumption can cause shmctl(SHM_INFO) to lockup when shm_get_stat() tries to spin_lock(&info->lock). Users of !CONFIG_SHMEM may encounter this lockup simply by invoking the 'ipcs' command. Reported by Jiri Olsa back in February 2008: http://lkml.org/lkml/2008/2/29/74 Signed-off-by: Tony Battersby Cc: Jiri Kosina Reported-by: Jiri Olsa Cc: Hugh Dickins Cc: [2.6.everything] Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- ipc/shm.c | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'ipc') diff --git a/ipc/shm.c b/ipc/shm.c index c0a021f..f8f69fa 100644 --- a/ipc/shm.c +++ b/ipc/shm.c @@ -565,11 +565,15 @@ static void shm_get_stat(struct ipc_namespace *ns, unsigned long *rss, struct hstate *h = hstate_file(shp->shm_file); *rss += pages_per_huge_page(h) * mapping->nrpages; } else { +#ifdef CONFIG_SHMEM struct shmem_inode_info *info = SHMEM_I(inode); spin_lock(&info->lock); *rss += inode->i_mapping->nrpages; *swp += info->swapped; spin_unlock(&info->lock); +#else + *rss += inode->i_mapping->nrpages; +#endif } total++; -- cgit v1.1