diff options
Diffstat (limited to 'ipc/mqueue.c')
-rw-r--r-- | ipc/mqueue.c | 119 |
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 | ||
415 | static int mqueue_create(struct inode *dir, struct dentry *dentry, | 415 | static 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 | */ |
724 | static struct file *do_create(struct ipc_namespace *ipc_ns, struct dentry *dir, | 724 | static 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 | |||
767 | out_drop_write: | ||
768 | mnt_drop_write(ipc_ns->mq_mnt); | ||
769 | out: | ||
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 */ |
776 | static struct file *do_open(struct ipc_namespace *ipc_ns, | 769 | static 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 | |||
797 | err: | ||
798 | dput(dentry); | ||
799 | mntput(ipc_ns->mq_mnt); | ||
800 | return ERR_PTR(ret); | ||
801 | } | 780 | } |
802 | 781 | ||
803 | SYSCALL_DEFINE4(mq_open, const char __user *, u_name, int, oflag, umode_t, mode, | 782 | SYSCALL_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 | |||
863 | out: | 840 | out: |
864 | dput(dentry); | 841 | path_put(&path); |
865 | mntput(ipc_ns->mq_mnt); | ||
866 | out_putfd: | 842 | out_putfd: |
867 | put_unused_fd(fd); | 843 | if (error) { |
868 | fd = error; | 844 | put_unused_fd(fd); |
869 | out_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); | ||
871 | out_putname: | 848 | out_putname: |
872 | putname(name); | 849 | putname(name); |
873 | return fd; | 850 | return fd; |