Commit 46a2da0c authored by Alexander Viro's avatar Alexander Viro Committed by Linus Torvalds

[PATCH] open_namei cleanup, nfsctl permission check fix

	a) part of open_namei() done after we'd found vfsmount/dentry of
the object we want to open had been split into a helper - may_open().

	b) do_open() in fs/nfsctl.c didn't do any permission checks on
the nfsd file it was opening - sudden idiocy attack on my part (I missed
the fact that dentry_open() doesn't do permission checks - open_namei()
does).  Fixed by adding obvious may_open() calls.
parent 4f9af681
......@@ -988,6 +988,80 @@ int vfs_create(struct inode *dir, struct dentry *dentry, int mode)
return error;
}
int may_open(struct nameidata *nd, int acc_mode, int flag)
{
struct dentry *dentry = nd->dentry;
struct inode *inode = dentry->d_inode;
int error;
if (!inode)
return -ENOENT;
if (S_ISLNK(inode->i_mode))
return -ELOOP;
if (S_ISDIR(inode->i_mode) && (flag & FMODE_WRITE))
return -EISDIR;
error = permission(inode, acc_mode);
if (error)
return error;
/*
* FIFO's, sockets and device files are special: they don't
* actually live on the filesystem itself, and as such you
* can write to them even if the filesystem is read-only.
*/
if (S_ISFIFO(inode->i_mode) || S_ISSOCK(inode->i_mode)) {
flag &= ~O_TRUNC;
} else if (S_ISBLK(inode->i_mode) || S_ISCHR(inode->i_mode)) {
if (nd->mnt->mnt_flags & MNT_NODEV)
return -EACCES;
flag &= ~O_TRUNC;
} else if (IS_RDONLY(inode) && (flag & FMODE_WRITE))
return -EROFS;
/*
* An append-only file must be opened in append mode for writing.
*/
if (IS_APPEND(inode)) {
if ((flag & FMODE_WRITE) && !(flag & O_APPEND))
return -EPERM;
if (flag & O_TRUNC)
return -EPERM;
}
/*
* Ensure there are no outstanding leases on the file.
*/
error = get_lease(inode, flag);
if (error)
return error;
if (flag & O_TRUNC) {
error = get_write_access(inode);
if (error)
return error;
/*
* Refuse to truncate files with mandatory locks held on them.
*/
error = locks_verify_locked(inode);
if (!error) {
DQUOT_INIT(inode);
error = do_truncate(dentry, 0);
}
put_write_access(inode);
if (error)
return error;
} else
if (flag & FMODE_WRITE)
DQUOT_INIT(inode);
return 0;
}
/*
* open_namei()
*
......@@ -1005,7 +1079,6 @@ int vfs_create(struct inode *dir, struct dentry *dentry, int mode)
int open_namei(const char * pathname, int flag, int mode, struct nameidata *nd)
{
int acc_mode, error = 0;
struct inode *inode;
struct dentry *dentry;
struct dentry *dir;
int count = 0;
......@@ -1092,80 +1165,9 @@ int open_namei(const char * pathname, int flag, int mode, struct nameidata *nd)
if (dentry->d_inode && S_ISDIR(dentry->d_inode->i_mode))
goto exit;
ok:
error = -ENOENT;
inode = dentry->d_inode;
if (!inode)
goto exit;
error = -ELOOP;
if (S_ISLNK(inode->i_mode))
goto exit;
error = -EISDIR;
if (S_ISDIR(inode->i_mode) && (flag & FMODE_WRITE))
goto exit;
error = permission(inode,acc_mode);
error = may_open(nd, acc_mode, flag);
if (error)
goto exit;
/*
* FIFO's, sockets and device files are special: they don't
* actually live on the filesystem itself, and as such you
* can write to them even if the filesystem is read-only.
*/
if (S_ISFIFO(inode->i_mode) || S_ISSOCK(inode->i_mode)) {
flag &= ~O_TRUNC;
} else if (S_ISBLK(inode->i_mode) || S_ISCHR(inode->i_mode)) {
error = -EACCES;
if (nd->mnt->mnt_flags & MNT_NODEV)
goto exit;
flag &= ~O_TRUNC;
} else {
error = -EROFS;
if (IS_RDONLY(inode) && (flag & 2))
goto exit;
}
/*
* An append-only file must be opened in append mode for writing.
*/
error = -EPERM;
if (IS_APPEND(inode)) {
if ((flag & FMODE_WRITE) && !(flag & O_APPEND))
goto exit;
if (flag & O_TRUNC)
goto exit;
}
/*
* Ensure there are no outstanding leases on the file.
*/
error = get_lease(inode, flag);
if (error)
goto exit;
if (flag & O_TRUNC) {
error = get_write_access(inode);
if (error)
goto exit;
/*
* Refuse to truncate files with mandatory locks held on them.
*/
error = locks_verify_locked(inode);
if (!error) {
DQUOT_INIT(inode);
error = do_truncate(dentry, 0);
}
put_write_access(inode);
if (error)
goto exit;
} else
if (flag & FMODE_WRITE)
DQUOT_INIT(inode);
return 0;
exit_dput:
......
......@@ -37,7 +37,16 @@ static struct file *do_open(char *name, int flags)
if (error)
return ERR_PTR(error);
return dentry_open(nd.dentry, nd.mnt, flags);
if (flags == O_RDWR)
error = may_open(&nd,MAY_READ|MAY_WRITE,FMODE_READ|FMODE_WRITE);
else
error = may_open(&nd, MAY_WRITE, FMODE_WRITE);
if (!error)
return dentry_open(nd.dentry, nd.mnt, flags);
path_release(&nd);
return ERR_PTR(error);
}
static struct {
......
......@@ -1233,6 +1233,7 @@ static inline void allow_write_access(struct file *file)
extern int do_pipe(int *);
extern int open_namei(const char *, int, int, struct nameidata *);
extern int may_open(struct nameidata *, int, int);
extern int kernel_read(struct file *, unsigned long, char *, unsigned long);
extern struct file * open_exec(const char *);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment