|
@@ -1984,6 +1984,23 @@ int vfs_mknod(struct inode *dir, struct dentry *dentry, int mode, dev_t dev)
|
|
|
return error;
|
|
|
}
|
|
|
|
|
|
+static int may_mknod(mode_t mode)
|
|
|
+{
|
|
|
+ switch (mode & S_IFMT) {
|
|
|
+ case S_IFREG:
|
|
|
+ case S_IFCHR:
|
|
|
+ case S_IFBLK:
|
|
|
+ case S_IFIFO:
|
|
|
+ case S_IFSOCK:
|
|
|
+ case 0: /* zero mode translates to S_IFREG */
|
|
|
+ return 0;
|
|
|
+ case S_IFDIR:
|
|
|
+ return -EPERM;
|
|
|
+ default:
|
|
|
+ return -EINVAL;
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
asmlinkage long sys_mknodat(int dfd, const char __user *filename, int mode,
|
|
|
unsigned dev)
|
|
|
{
|
|
@@ -2002,12 +2019,19 @@ asmlinkage long sys_mknodat(int dfd, const char __user *filename, int mode,
|
|
|
if (error)
|
|
|
goto out;
|
|
|
dentry = lookup_create(&nd, 0);
|
|
|
- error = PTR_ERR(dentry);
|
|
|
-
|
|
|
+ if (IS_ERR(dentry)) {
|
|
|
+ error = PTR_ERR(dentry);
|
|
|
+ goto out_unlock;
|
|
|
+ }
|
|
|
if (!IS_POSIXACL(nd.path.dentry->d_inode))
|
|
|
mode &= ~current->fs->umask;
|
|
|
- if (!IS_ERR(dentry)) {
|
|
|
- switch (mode & S_IFMT) {
|
|
|
+ error = may_mknod(mode);
|
|
|
+ if (error)
|
|
|
+ goto out_dput;
|
|
|
+ error = mnt_want_write(nd.path.mnt);
|
|
|
+ if (error)
|
|
|
+ goto out_dput;
|
|
|
+ switch (mode & S_IFMT) {
|
|
|
case 0: case S_IFREG:
|
|
|
error = vfs_create(nd.path.dentry->d_inode,dentry,mode,&nd);
|
|
|
break;
|
|
@@ -2018,14 +2042,11 @@ asmlinkage long sys_mknodat(int dfd, const char __user *filename, int mode,
|
|
|
case S_IFIFO: case S_IFSOCK:
|
|
|
error = vfs_mknod(nd.path.dentry->d_inode,dentry,mode,0);
|
|
|
break;
|
|
|
- case S_IFDIR:
|
|
|
- error = -EPERM;
|
|
|
- break;
|
|
|
- default:
|
|
|
- error = -EINVAL;
|
|
|
- }
|
|
|
- dput(dentry);
|
|
|
}
|
|
|
+ mnt_drop_write(nd.path.mnt);
|
|
|
+out_dput:
|
|
|
+ dput(dentry);
|
|
|
+out_unlock:
|
|
|
mutex_unlock(&nd.path.dentry->d_inode->i_mutex);
|
|
|
path_put(&nd.path);
|
|
|
out:
|
|
@@ -2083,7 +2104,12 @@ asmlinkage long sys_mkdirat(int dfd, const char __user *pathname, int mode)
|
|
|
|
|
|
if (!IS_POSIXACL(nd.path.dentry->d_inode))
|
|
|
mode &= ~current->fs->umask;
|
|
|
+ error = mnt_want_write(nd.path.mnt);
|
|
|
+ if (error)
|
|
|
+ goto out_dput;
|
|
|
error = vfs_mkdir(nd.path.dentry->d_inode, dentry, mode);
|
|
|
+ mnt_drop_write(nd.path.mnt);
|
|
|
+out_dput:
|
|
|
dput(dentry);
|
|
|
out_unlock:
|
|
|
mutex_unlock(&nd.path.dentry->d_inode->i_mutex);
|