diff options
Diffstat (limited to 'fs/namei.c')
-rw-r--r-- | fs/namei.c | 48 |
1 files changed, 37 insertions, 11 deletions
diff --git a/fs/namei.c b/fs/namei.c index 89ef3178eaaa..3fbcf2021a2e 100644 --- a/fs/namei.c +++ b/fs/namei.c | |||
@@ -1984,6 +1984,23 @@ int vfs_mknod(struct inode *dir, struct dentry *dentry, int mode, dev_t dev) | |||
1984 | return error; | 1984 | return error; |
1985 | } | 1985 | } |
1986 | 1986 | ||
1987 | static int may_mknod(mode_t mode) | ||
1988 | { | ||
1989 | switch (mode & S_IFMT) { | ||
1990 | case S_IFREG: | ||
1991 | case S_IFCHR: | ||
1992 | case S_IFBLK: | ||
1993 | case S_IFIFO: | ||
1994 | case S_IFSOCK: | ||
1995 | case 0: /* zero mode translates to S_IFREG */ | ||
1996 | return 0; | ||
1997 | case S_IFDIR: | ||
1998 | return -EPERM; | ||
1999 | default: | ||
2000 | return -EINVAL; | ||
2001 | } | ||
2002 | } | ||
2003 | |||
1987 | asmlinkage long sys_mknodat(int dfd, const char __user *filename, int mode, | 2004 | asmlinkage long sys_mknodat(int dfd, const char __user *filename, int mode, |
1988 | unsigned dev) | 2005 | unsigned dev) |
1989 | { | 2006 | { |
@@ -2002,12 +2019,19 @@ asmlinkage long sys_mknodat(int dfd, const char __user *filename, int mode, | |||
2002 | if (error) | 2019 | if (error) |
2003 | goto out; | 2020 | goto out; |
2004 | dentry = lookup_create(&nd, 0); | 2021 | dentry = lookup_create(&nd, 0); |
2005 | error = PTR_ERR(dentry); | 2022 | if (IS_ERR(dentry)) { |
2006 | 2023 | error = PTR_ERR(dentry); | |
2024 | goto out_unlock; | ||
2025 | } | ||
2007 | if (!IS_POSIXACL(nd.path.dentry->d_inode)) | 2026 | if (!IS_POSIXACL(nd.path.dentry->d_inode)) |
2008 | mode &= ~current->fs->umask; | 2027 | mode &= ~current->fs->umask; |
2009 | if (!IS_ERR(dentry)) { | 2028 | error = may_mknod(mode); |
2010 | switch (mode & S_IFMT) { | 2029 | if (error) |
2030 | goto out_dput; | ||
2031 | error = mnt_want_write(nd.path.mnt); | ||
2032 | if (error) | ||
2033 | goto out_dput; | ||
2034 | switch (mode & S_IFMT) { | ||
2011 | case 0: case S_IFREG: | 2035 | case 0: case S_IFREG: |
2012 | error = vfs_create(nd.path.dentry->d_inode,dentry,mode,&nd); | 2036 | error = vfs_create(nd.path.dentry->d_inode,dentry,mode,&nd); |
2013 | break; | 2037 | break; |
@@ -2018,14 +2042,11 @@ asmlinkage long sys_mknodat(int dfd, const char __user *filename, int mode, | |||
2018 | case S_IFIFO: case S_IFSOCK: | 2042 | case S_IFIFO: case S_IFSOCK: |
2019 | error = vfs_mknod(nd.path.dentry->d_inode,dentry,mode,0); | 2043 | error = vfs_mknod(nd.path.dentry->d_inode,dentry,mode,0); |
2020 | break; | 2044 | break; |
2021 | case S_IFDIR: | ||
2022 | error = -EPERM; | ||
2023 | break; | ||
2024 | default: | ||
2025 | error = -EINVAL; | ||
2026 | } | ||
2027 | dput(dentry); | ||
2028 | } | 2045 | } |
2046 | mnt_drop_write(nd.path.mnt); | ||
2047 | out_dput: | ||
2048 | dput(dentry); | ||
2049 | out_unlock: | ||
2029 | mutex_unlock(&nd.path.dentry->d_inode->i_mutex); | 2050 | mutex_unlock(&nd.path.dentry->d_inode->i_mutex); |
2030 | path_put(&nd.path); | 2051 | path_put(&nd.path); |
2031 | out: | 2052 | out: |
@@ -2083,7 +2104,12 @@ asmlinkage long sys_mkdirat(int dfd, const char __user *pathname, int mode) | |||
2083 | 2104 | ||
2084 | if (!IS_POSIXACL(nd.path.dentry->d_inode)) | 2105 | if (!IS_POSIXACL(nd.path.dentry->d_inode)) |
2085 | mode &= ~current->fs->umask; | 2106 | mode &= ~current->fs->umask; |
2107 | error = mnt_want_write(nd.path.mnt); | ||
2108 | if (error) | ||
2109 | goto out_dput; | ||
2086 | error = vfs_mkdir(nd.path.dentry->d_inode, dentry, mode); | 2110 | error = vfs_mkdir(nd.path.dentry->d_inode, dentry, mode); |
2111 | mnt_drop_write(nd.path.mnt); | ||
2112 | out_dput: | ||
2087 | dput(dentry); | 2113 | dput(dentry); |
2088 | out_unlock: | 2114 | out_unlock: |
2089 | mutex_unlock(&nd.path.dentry->d_inode->i_mutex); | 2115 | mutex_unlock(&nd.path.dentry->d_inode->i_mutex); |