diff options
| author | Linus Torvalds <torvalds@linux-foundation.org> | 2010-03-04 08:15:33 -0800 | 
|---|---|---|
| committer | Linus Torvalds <torvalds@linux-foundation.org> | 2010-03-04 08:15:33 -0800 | 
| commit | 0f2cc4ecd81dc1917a041dc93db0ada28f8356fa (patch) | |
| tree | f128b50f48f50f0cda6d2b20b53e9ad6e2dfded3 /ipc | |
| parent | 1fae4cfb97302289bb5df6a8195eb28385d0b002 (diff) | |
| parent | 9643f5d94aadd47a5fa9754fb60f2c957de05903 (diff) | |
Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/viro/vfs-2.6
* 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/viro/vfs-2.6: (52 commits)
  init: Open /dev/console from rootfs
  mqueue: fix typo "failues" -> "failures"
  mqueue: only set error codes if they are really necessary
  mqueue: simplify do_open() error handling
  mqueue: apply mathematics distributivity on mq_bytes calculation
  mqueue: remove unneeded info->messages initialization
  mqueue: fix mq_open() file descriptor leak on user-space processes
  fix race in d_splice_alias()
  set S_DEAD on unlink() and non-directory rename() victims
  vfs: add NOFOLLOW flag to umount(2)
  get rid of ->mnt_parent in tomoyo/realpath
  hppfs can use existing proc_mnt, no need for do_kern_mount() in there
  Mirror MS_KERNMOUNT in ->mnt_flags
  get rid of useless vfsmount_lock use in put_mnt_ns()
  Take vfsmount_lock to fs/internal.h
  get rid of insanity with namespace roots in tomoyo
  take check for new events in namespace (guts of mounts_poll()) to namespace.c
  Don't mess with generic_permission() under ->d_lock in hpfs
  sanitize const/signedness for udf
  nilfs: sanitize const/signedness in dealing with ->d_name.name
  ...
Fix up fairly trivial (famous last words...) conflicts in
drivers/infiniband/core/uverbs_main.c and security/tomoyo/realpath.c
Diffstat (limited to 'ipc')
| -rw-r--r-- | ipc/mqueue.c | 120 | 
1 files changed, 72 insertions, 48 deletions
| diff --git a/ipc/mqueue.c b/ipc/mqueue.c index c79bd57353e7..b6cb06451f4b 100644 --- a/ipc/mqueue.c +++ b/ipc/mqueue.c @@ -134,7 +134,6 @@ static struct inode *mqueue_get_inode(struct super_block *sb,  			init_waitqueue_head(&info->wait_q);  			INIT_LIST_HEAD(&info->e_wait_q[0].list);  			INIT_LIST_HEAD(&info->e_wait_q[1].list); -			info->messages = NULL;  			info->notify_owner = NULL;  			info->qsize = 0;  			info->user = NULL;	/* set when all is ok */ @@ -146,6 +145,10 @@ static struct inode *mqueue_get_inode(struct super_block *sb,  				info->attr.mq_msgsize = attr->mq_msgsize;  			}  			mq_msg_tblsz = info->attr.mq_maxmsg * sizeof(struct msg_msg *); +			info->messages = kmalloc(mq_msg_tblsz, GFP_KERNEL); +			if (!info->messages) +				goto out_inode; +  			mq_bytes = (mq_msg_tblsz +  				(info->attr.mq_maxmsg * info->attr.mq_msgsize)); @@ -154,18 +157,12 @@ static struct inode *mqueue_get_inode(struct super_block *sb,  		 	    u->mq_bytes + mq_bytes >  			    p->signal->rlim[RLIMIT_MSGQUEUE].rlim_cur) {  				spin_unlock(&mq_lock); +				kfree(info->messages);  				goto out_inode;  			}  			u->mq_bytes += mq_bytes;  			spin_unlock(&mq_lock); -			info->messages = kmalloc(mq_msg_tblsz, GFP_KERNEL); -			if (!info->messages) { -				spin_lock(&mq_lock); -				u->mq_bytes -= mq_bytes; -				spin_unlock(&mq_lock); -				goto out_inode; -			}  			/* all is ok */  			info->user = get_uid(u);  		} else if (S_ISDIR(mode)) { @@ -187,7 +184,7 @@ static int mqueue_fill_super(struct super_block *sb, void *data, int silent)  {  	struct inode *inode;  	struct ipc_namespace *ns = data; -	int error = 0; +	int error;  	sb->s_blocksize = PAGE_CACHE_SIZE;  	sb->s_blocksize_bits = PAGE_CACHE_SHIFT; @@ -205,7 +202,9 @@ static int mqueue_fill_super(struct super_block *sb, void *data, int silent)  	if (!sb->s_root) {  		iput(inode);  		error = -ENOMEM; +		goto out;  	} +	error = 0;  out:  	return error; @@ -264,8 +263,9 @@ static void mqueue_delete_inode(struct inode *inode)  	clear_inode(inode); -	mq_bytes = (info->attr.mq_maxmsg * sizeof(struct msg_msg *) + -		   (info->attr.mq_maxmsg * info->attr.mq_msgsize)); +	/* Total amount of bytes accounted for the mqueue */ +	mq_bytes = info->attr.mq_maxmsg * (sizeof(struct msg_msg *) +	    + info->attr.mq_msgsize);  	user = info->user;  	if (user) {  		spin_lock(&mq_lock); @@ -604,8 +604,8 @@ static int mq_attr_ok(struct ipc_namespace *ipc_ns, struct mq_attr *attr)  	/* check for overflow */  	if (attr->mq_msgsize > ULONG_MAX/attr->mq_maxmsg)  		return 0; -	if ((unsigned long)(attr->mq_maxmsg * attr->mq_msgsize) + -	    (attr->mq_maxmsg * sizeof (struct msg_msg *)) < +	if ((unsigned long)(attr->mq_maxmsg * (attr->mq_msgsize +	    + sizeof (struct msg_msg *))) <  	    (unsigned long)(attr->mq_maxmsg * attr->mq_msgsize))  		return 0;  	return 1; @@ -623,9 +623,10 @@ static struct file *do_create(struct ipc_namespace *ipc_ns, struct dentry *dir,  	int ret;  	if (attr) { -		ret = -EINVAL; -		if (!mq_attr_ok(ipc_ns, attr)) +		if (!mq_attr_ok(ipc_ns, attr)) { +			ret = -EINVAL;  			goto out; +		}  		/* store for use during create */  		dentry->d_fsdata = attr;  	} @@ -659,24 +660,28 @@ out:  static struct file *do_open(struct ipc_namespace *ipc_ns,  				struct dentry *dentry, int oflag)  { +	int ret;  	const struct cred *cred = current_cred();  	static const int oflag2acc[O_ACCMODE] = { MAY_READ, MAY_WRITE,  						  MAY_READ | MAY_WRITE };  	if ((oflag & O_ACCMODE) == (O_RDWR | O_WRONLY)) { -		dput(dentry); -		mntput(ipc_ns->mq_mnt); -		return ERR_PTR(-EINVAL); +		ret = -EINVAL; +		goto err;  	}  	if (inode_permission(dentry->d_inode, oflag2acc[oflag & O_ACCMODE])) { -		dput(dentry); -		mntput(ipc_ns->mq_mnt); -		return ERR_PTR(-EACCES); +		ret = -EACCES; +		goto err;  	}  	return dentry_open(dentry, ipc_ns->mq_mnt, oflag, cred); + +err: +	dput(dentry); +	mntput(ipc_ns->mq_mnt); +	return ERR_PTR(ret);  }  SYSCALL_DEFINE4(mq_open, const char __user *, u_name, int, oflag, mode_t, mode, @@ -705,16 +710,17 @@ SYSCALL_DEFINE4(mq_open, const char __user *, u_name, int, oflag, mode_t, mode,  	dentry = lookup_one_len(name, ipc_ns->mq_mnt->mnt_root, strlen(name));  	if (IS_ERR(dentry)) {  		error = PTR_ERR(dentry); -		goto out_err; +		goto out_putfd;  	}  	mntget(ipc_ns->mq_mnt);  	if (oflag & O_CREAT) {  		if (dentry->d_inode) {	/* entry already exists */  			audit_inode(name, dentry); -			error = -EEXIST; -			if (oflag & O_EXCL) +			if (oflag & O_EXCL) { +				error = -EEXIST;  				goto out; +			}  			filp = do_open(ipc_ns, dentry, oflag);  		} else {  			filp = do_create(ipc_ns, ipc_ns->mq_mnt->mnt_root, @@ -722,9 +728,10 @@ SYSCALL_DEFINE4(mq_open, const char __user *, u_name, int, oflag, mode_t, mode,  						u_attr ? &attr : NULL);  		}  	} else { -		error = -ENOENT; -		if (!dentry->d_inode) +		if (!dentry->d_inode) { +			error = -ENOENT;  			goto out; +		}  		audit_inode(name, dentry);  		filp = do_open(ipc_ns, dentry, oflag);  	} @@ -742,7 +749,6 @@ out:  	mntput(ipc_ns->mq_mnt);  out_putfd:  	put_unused_fd(fd); -out_err:  	fd = error;  out_upsem:  	mutex_unlock(&ipc_ns->mq_mnt->mnt_root->d_inode->i_mutex); @@ -872,19 +878,24 @@ SYSCALL_DEFINE5(mq_timedsend, mqd_t, mqdes, const char __user *, u_msg_ptr,  	audit_mq_sendrecv(mqdes, msg_len, msg_prio, p);  	timeout = prepare_timeout(p); -	ret = -EBADF;  	filp = fget(mqdes); -	if (unlikely(!filp)) +	if (unlikely(!filp)) { +		ret = -EBADF;  		goto out; +	}  	inode = filp->f_path.dentry->d_inode; -	if (unlikely(filp->f_op != &mqueue_file_operations)) +	if (unlikely(filp->f_op != &mqueue_file_operations)) { +		ret = -EBADF;  		goto out_fput; +	}  	info = MQUEUE_I(inode);  	audit_inode(NULL, filp->f_path.dentry); -	if (unlikely(!(filp->f_mode & FMODE_WRITE))) +	if (unlikely(!(filp->f_mode & FMODE_WRITE))) { +		ret = -EBADF;  		goto out_fput; +	}  	if (unlikely(msg_len > info->attr.mq_msgsize)) {  		ret = -EMSGSIZE; @@ -961,19 +972,24 @@ SYSCALL_DEFINE5(mq_timedreceive, mqd_t, mqdes, char __user *, u_msg_ptr,  	audit_mq_sendrecv(mqdes, msg_len, 0, p);  	timeout = prepare_timeout(p); -	ret = -EBADF;  	filp = fget(mqdes); -	if (unlikely(!filp)) +	if (unlikely(!filp)) { +		ret = -EBADF;  		goto out; +	}  	inode = filp->f_path.dentry->d_inode; -	if (unlikely(filp->f_op != &mqueue_file_operations)) +	if (unlikely(filp->f_op != &mqueue_file_operations)) { +		ret = -EBADF;  		goto out_fput; +	}  	info = MQUEUE_I(inode);  	audit_inode(NULL, filp->f_path.dentry); -	if (unlikely(!(filp->f_mode & FMODE_READ))) +	if (unlikely(!(filp->f_mode & FMODE_READ))) { +		ret = -EBADF;  		goto out_fput; +	}  	/* checks if buffer is big enough */  	if (unlikely(msg_len < info->attr.mq_msgsize)) { @@ -1063,13 +1079,14 @@ SYSCALL_DEFINE2(mq_notify, mqd_t, mqdes,  			/* create the notify skb */  			nc = alloc_skb(NOTIFY_COOKIE_LEN, GFP_KERNEL); -			ret = -ENOMEM; -			if (!nc) +			if (!nc) { +				ret = -ENOMEM;  				goto out; -			ret = -EFAULT; +			}  			if (copy_from_user(nc->data,  					notification.sigev_value.sival_ptr,  					NOTIFY_COOKIE_LEN)) { +				ret = -EFAULT;  				goto out;  			} @@ -1078,9 +1095,10 @@ SYSCALL_DEFINE2(mq_notify, mqd_t, mqdes,  			/* and attach it to the socket */  retry:  			filp = fget(notification.sigev_signo); -			ret = -EBADF; -			if (!filp) +			if (!filp) { +				ret = -EBADF;  				goto out; +			}  			sock = netlink_getsockbyfilp(filp);  			fput(filp);  			if (IS_ERR(sock)) { @@ -1092,7 +1110,7 @@ retry:  			timeo = MAX_SCHEDULE_TIMEOUT;  			ret = netlink_attachskb(sock, nc, &timeo, NULL);  			if (ret == 1) -		       		goto retry; +				goto retry;  			if (ret) {  				sock = NULL;  				nc = NULL; @@ -1101,14 +1119,17 @@ retry:  		}  	} -	ret = -EBADF;  	filp = fget(mqdes); -	if (!filp) +	if (!filp) { +		ret = -EBADF;  		goto out; +	}  	inode = filp->f_path.dentry->d_inode; -	if (unlikely(filp->f_op != &mqueue_file_operations)) +	if (unlikely(filp->f_op != &mqueue_file_operations)) { +		ret = -EBADF;  		goto out_fput; +	}  	info = MQUEUE_I(inode);  	ret = 0; @@ -1171,14 +1192,17 @@ SYSCALL_DEFINE3(mq_getsetattr, mqd_t, mqdes,  			return -EINVAL;  	} -	ret = -EBADF;  	filp = fget(mqdes); -	if (!filp) +	if (!filp) { +		ret = -EBADF;  		goto out; +	}  	inode = filp->f_path.dentry->d_inode; -	if (unlikely(filp->f_op != &mqueue_file_operations)) +	if (unlikely(filp->f_op != &mqueue_file_operations)) { +		ret = -EBADF;  		goto out_fput; +	}  	info = MQUEUE_I(inode);  	spin_lock(&info->lock); @@ -1272,7 +1296,7 @@ static int __init init_mqueue_fs(void)  	if (mqueue_inode_cachep == NULL)  		return -ENOMEM; -	/* ignore failues - they are not fatal */ +	/* ignore failures - they are not fatal */  	mq_sysctl_table = mq_register_sysctl_table();  	error = register_filesystem(&mqueue_fs_type); | 
