aboutsummaryrefslogtreecommitdiffstats
path: root/ipc/mqueue.c
diff options
context:
space:
mode:
Diffstat (limited to 'ipc/mqueue.c')
-rw-r--r--ipc/mqueue.c119
1 files changed, 48 insertions, 71 deletions
diff --git a/ipc/mqueue.c b/ipc/mqueue.c
index 8ce57691e7b6..f8e54f5b9080 100644
--- a/ipc/mqueue.c
+++ b/ipc/mqueue.c
@@ -413,7 +413,7 @@ static void mqueue_evict_inode(struct inode *inode)
413} 413}
414 414
415static int mqueue_create(struct inode *dir, struct dentry *dentry, 415static int mqueue_create(struct inode *dir, struct dentry *dentry,
416 umode_t mode, struct nameidata *nd) 416 umode_t mode, bool excl)
417{ 417{
418 struct inode *inode; 418 struct inode *inode;
419 struct mq_attr *attr = dentry->d_fsdata; 419 struct mq_attr *attr = dentry->d_fsdata;
@@ -721,8 +721,8 @@ static int mq_attr_ok(struct ipc_namespace *ipc_ns, struct mq_attr *attr)
721/* 721/*
722 * Invoked when creating a new queue via sys_mq_open 722 * Invoked when creating a new queue via sys_mq_open
723 */ 723 */
724static struct file *do_create(struct ipc_namespace *ipc_ns, struct dentry *dir, 724static struct file *do_create(struct ipc_namespace *ipc_ns, struct inode *dir,
725 struct dentry *dentry, int oflag, umode_t mode, 725 struct path *path, int oflag, umode_t mode,
726 struct mq_attr *attr) 726 struct mq_attr *attr)
727{ 727{
728 const struct cred *cred = current_cred(); 728 const struct cred *cred = current_cred();
@@ -732,9 +732,9 @@ static struct file *do_create(struct ipc_namespace *ipc_ns, struct dentry *dir,
732 if (attr) { 732 if (attr) {
733 ret = mq_attr_ok(ipc_ns, attr); 733 ret = mq_attr_ok(ipc_ns, attr);
734 if (ret) 734 if (ret)
735 goto out; 735 return ERR_PTR(ret);
736 /* store for use during create */ 736 /* store for use during create */
737 dentry->d_fsdata = attr; 737 path->dentry->d_fsdata = attr;
738 } else { 738 } else {
739 struct mq_attr def_attr; 739 struct mq_attr def_attr;
740 740
@@ -744,71 +744,51 @@ static struct file *do_create(struct ipc_namespace *ipc_ns, struct dentry *dir,
744 ipc_ns->mq_msgsize_default); 744 ipc_ns->mq_msgsize_default);
745 ret = mq_attr_ok(ipc_ns, &def_attr); 745 ret = mq_attr_ok(ipc_ns, &def_attr);
746 if (ret) 746 if (ret)
747 goto out; 747 return ERR_PTR(ret);
748 } 748 }
749 749
750 mode &= ~current_umask(); 750 mode &= ~current_umask();
751 ret = mnt_want_write(ipc_ns->mq_mnt); 751 ret = mnt_want_write(path->mnt);
752 if (ret) 752 if (ret)
753 goto out; 753 return ERR_PTR(ret);
754 ret = vfs_create(dir->d_inode, dentry, mode, NULL); 754 ret = vfs_create(dir, path->dentry, mode, true);
755 dentry->d_fsdata = NULL; 755 path->dentry->d_fsdata = NULL;
756 if (ret) 756 if (!ret)
757 goto out_drop_write; 757 result = dentry_open(path, oflag, cred);
758 758 else
759 result = dentry_open(dentry, ipc_ns->mq_mnt, oflag, cred); 759 result = ERR_PTR(ret);
760 /* 760 /*
761 * dentry_open() took a persistent mnt_want_write(), 761 * dentry_open() took a persistent mnt_want_write(),
762 * so we can now drop this one. 762 * so we can now drop this one.
763 */ 763 */
764 mnt_drop_write(ipc_ns->mq_mnt); 764 mnt_drop_write(path->mnt);
765 return result; 765 return result;
766
767out_drop_write:
768 mnt_drop_write(ipc_ns->mq_mnt);
769out:
770 dput(dentry);
771 mntput(ipc_ns->mq_mnt);
772 return ERR_PTR(ret);
773} 766}
774 767
775/* Opens existing queue */ 768/* Opens existing queue */
776static struct file *do_open(struct ipc_namespace *ipc_ns, 769static struct file *do_open(struct path *path, int oflag)
777 struct dentry *dentry, int oflag)
778{ 770{
779 int ret;
780 const struct cred *cred = current_cred();
781
782 static const int oflag2acc[O_ACCMODE] = { MAY_READ, MAY_WRITE, 771 static const int oflag2acc[O_ACCMODE] = { MAY_READ, MAY_WRITE,
783 MAY_READ | MAY_WRITE }; 772 MAY_READ | MAY_WRITE };
784 773 int acc;
785 if ((oflag & O_ACCMODE) == (O_RDWR | O_WRONLY)) { 774 if ((oflag & O_ACCMODE) == (O_RDWR | O_WRONLY))
786 ret = -EINVAL; 775 return ERR_PTR(-EINVAL);
787 goto err; 776 acc = oflag2acc[oflag & O_ACCMODE];
788 } 777 if (inode_permission(path->dentry->d_inode, acc))
789 778 return ERR_PTR(-EACCES);
790 if (inode_permission(dentry->d_inode, oflag2acc[oflag & O_ACCMODE])) { 779 return dentry_open(path, oflag, current_cred());
791 ret = -EACCES;
792 goto err;
793 }
794
795 return dentry_open(dentry, ipc_ns->mq_mnt, oflag, cred);
796
797err:
798 dput(dentry);
799 mntput(ipc_ns->mq_mnt);
800 return ERR_PTR(ret);
801} 780}
802 781
803SYSCALL_DEFINE4(mq_open, const char __user *, u_name, int, oflag, umode_t, mode, 782SYSCALL_DEFINE4(mq_open, const char __user *, u_name, int, oflag, umode_t, mode,
804 struct mq_attr __user *, u_attr) 783 struct mq_attr __user *, u_attr)
805{ 784{
806 struct dentry *dentry; 785 struct path path;
807 struct file *filp; 786 struct file *filp;
808 char *name; 787 char *name;
809 struct mq_attr attr; 788 struct mq_attr attr;
810 int fd, error; 789 int fd, error;
811 struct ipc_namespace *ipc_ns = current->nsproxy->ipc_ns; 790 struct ipc_namespace *ipc_ns = current->nsproxy->ipc_ns;
791 struct dentry *root = ipc_ns->mq_mnt->mnt_root;
812 792
813 if (u_attr && copy_from_user(&attr, u_attr, sizeof(struct mq_attr))) 793 if (u_attr && copy_from_user(&attr, u_attr, sizeof(struct mq_attr)))
814 return -EFAULT; 794 return -EFAULT;
@@ -822,52 +802,49 @@ SYSCALL_DEFINE4(mq_open, const char __user *, u_name, int, oflag, umode_t, mode,
822 if (fd < 0) 802 if (fd < 0)
823 goto out_putname; 803 goto out_putname;
824 804
825 mutex_lock(&ipc_ns->mq_mnt->mnt_root->d_inode->i_mutex); 805 error = 0;
826 dentry = lookup_one_len(name, ipc_ns->mq_mnt->mnt_root, strlen(name)); 806 mutex_lock(&root->d_inode->i_mutex);
827 if (IS_ERR(dentry)) { 807 path.dentry = lookup_one_len(name, root, strlen(name));
828 error = PTR_ERR(dentry); 808 if (IS_ERR(path.dentry)) {
809 error = PTR_ERR(path.dentry);
829 goto out_putfd; 810 goto out_putfd;
830 } 811 }
831 mntget(ipc_ns->mq_mnt); 812 path.mnt = mntget(ipc_ns->mq_mnt);
832 813
833 if (oflag & O_CREAT) { 814 if (oflag & O_CREAT) {
834 if (dentry->d_inode) { /* entry already exists */ 815 if (path.dentry->d_inode) { /* entry already exists */
835 audit_inode(name, dentry); 816 audit_inode(name, path.dentry);
836 if (oflag & O_EXCL) { 817 if (oflag & O_EXCL) {
837 error = -EEXIST; 818 error = -EEXIST;
838 goto out; 819 goto out;
839 } 820 }
840 filp = do_open(ipc_ns, dentry, oflag); 821 filp = do_open(&path, oflag);
841 } else { 822 } else {
842 filp = do_create(ipc_ns, ipc_ns->mq_mnt->mnt_root, 823 filp = do_create(ipc_ns, root->d_inode,
843 dentry, oflag, mode, 824 &path, oflag, mode,
844 u_attr ? &attr : NULL); 825 u_attr ? &attr : NULL);
845 } 826 }
846 } else { 827 } else {
847 if (!dentry->d_inode) { 828 if (!path.dentry->d_inode) {
848 error = -ENOENT; 829 error = -ENOENT;
849 goto out; 830 goto out;
850 } 831 }
851 audit_inode(name, dentry); 832 audit_inode(name, path.dentry);
852 filp = do_open(ipc_ns, dentry, oflag); 833 filp = do_open(&path, oflag);
853 } 834 }
854 835
855 if (IS_ERR(filp)) { 836 if (!IS_ERR(filp))
837 fd_install(fd, filp);
838 else
856 error = PTR_ERR(filp); 839 error = PTR_ERR(filp);
857 goto out_putfd;
858 }
859
860 fd_install(fd, filp);
861 goto out_upsem;
862
863out: 840out:
864 dput(dentry); 841 path_put(&path);
865 mntput(ipc_ns->mq_mnt);
866out_putfd: 842out_putfd:
867 put_unused_fd(fd); 843 if (error) {
868 fd = error; 844 put_unused_fd(fd);
869out_upsem: 845 fd = error;
870 mutex_unlock(&ipc_ns->mq_mnt->mnt_root->d_inode->i_mutex); 846 }
847 mutex_unlock(&root->d_inode->i_mutex);
871out_putname: 848out_putname:
872 putname(name); 849 putname(name);
873 return fd; 850 return fd;