2005-02-22 12:15:30

by Herbert Poetzl

[permalink] [raw]
Subject: [Patch 4/6] Bind Mount Extensions 0.06



;
; Bind Mount Extensions
;
; This part adds mnt_may_create() and mnt_may_unlink() checks
; and uses them in lookup_create(), sys_rmdir() and sys_unlink()
; it also adds a RDONLY check to generic_write_checks() and
; for pipe_writev()
;
; Copyright (C) 2003-2005 Herbert P?tzl <[email protected]>
;
; Changelog:
;
; 0.01 - broken out part from bme0.05
;
; this patch is free software; you can redistribute it and/or
; modify it under the terms of the GNU General Public License
; as published by the Free Software Foundation; either version 2
; of the License, or (at your option) any later version.
;
; this patch is distributed in the hope that it will be useful,
; but WITHOUT ANY WARRANTY; without even the implied warranty of
; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
; GNU General Public License for more details.
;

diff -NurpP --minimal linux-2.6.11-rc4-bme0.06-bm0.01-at0.01-cc0.01/fs/namei.c linux-2.6.11-rc4-bme0.06-bm0.01-at0.01-cc0.01-co0.01/fs/namei.c
--- linux-2.6.11-rc4-bme0.06-bm0.01-at0.01-cc0.01/fs/namei.c 2005-02-13 17:16:55 +0100
+++ linux-2.6.11-rc4-bme0.06-bm0.01-at0.01-cc0.01-co0.01/fs/namei.c 2005-02-19 06:31:50 +0100
@@ -1168,6 +1168,24 @@ static inline int may_create(struct inod
return permission(dir,MAY_WRITE | MAY_EXEC, nd);
}

+static inline int mnt_may_create(struct vfsmount *mnt, struct inode *dir, struct dentry *child) {
+ if (child->d_inode)
+ return -EEXIST;
+ if (IS_DEADDIR(dir))
+ return -ENOENT;
+ if (MNT_IS_RDONLY(mnt))
+ return -EROFS;
+ return 0;
+}
+
+static inline int mnt_may_unlink(struct vfsmount *mnt, struct inode *dir, struct dentry *child) {
+ if (!child->d_inode)
+ return -ENOENT;
+ if (MNT_IS_RDONLY(mnt))
+ return -EROFS;
+ return 0;
+}
+
/*
* Special case: O_CREAT|O_EXCL implies O_NOFOLLOW for security
* reasons.
@@ -1518,23 +1536,28 @@ do_link:
struct dentry *lookup_create(struct nameidata *nd, int is_dir)
{
struct dentry *dentry;
+ int error;

down(&nd->dentry->d_inode->i_sem);
- dentry = ERR_PTR(-EEXIST);
+ error = -EEXIST;
if (nd->last_type != LAST_NORM)
- goto fail;
+ goto out;
nd->flags &= ~LOOKUP_PARENT;
dentry = lookup_hash(&nd->last, nd->dentry);
if (IS_ERR(dentry))
+ goto ret;
+ error = mnt_may_create(nd->mnt, nd->dentry->d_inode, dentry);
+ if (error)
goto fail;
+ error = -ENOENT;
if (!is_dir && nd->last.name[nd->last.len] && !dentry->d_inode)
- goto enoent;
+ goto fail;
+ret:
return dentry;
-enoent:
- dput(dentry);
- dentry = ERR_PTR(-ENOENT);
fail:
- return dentry;
+ dput(dentry);
+out:
+ return ERR_PTR(error);
}

int vfs_mknod(struct inode *dir, struct dentry *dentry, int mode, dev_t dev)
@@ -1763,7 +1786,11 @@ asmlinkage long sys_rmdir(const char __u
dentry = lookup_hash(&nd.last, nd.dentry);
error = PTR_ERR(dentry);
if (!IS_ERR(dentry)) {
+ error = mnt_may_unlink(nd.mnt, nd.dentry->d_inode, dentry);
+ if (error)
+ goto exit2;
error = vfs_rmdir(nd.dentry->d_inode, dentry);
+ exit2:
dput(dentry);
}
up(&nd.dentry->d_inode->i_sem);
@@ -1835,6 +1862,9 @@ asmlinkage long sys_unlink(const char __
/* Why not before? Because we want correct error value */
if (nd.last.name[nd.last.len])
goto slashes;
+ error = mnt_may_unlink(nd.mnt, nd.dentry->d_inode, dentry);
+ if (error)
+ goto exit2;
inode = dentry->d_inode;
if (inode)
atomic_inc(&inode->i_count);
diff -NurpP --minimal linux-2.6.11-rc4-bme0.06-bm0.01-at0.01-cc0.01/fs/pipe.c linux-2.6.11-rc4-bme0.06-bm0.01-at0.01-cc0.01-co0.01/fs/pipe.c
--- linux-2.6.11-rc4-bme0.06-bm0.01-at0.01-cc0.01/fs/pipe.c 2005-02-13 17:16:58 +0100
+++ linux-2.6.11-rc4-bme0.06-bm0.01-at0.01-cc0.01-co0.01/fs/pipe.c 2005-02-19 06:31:50 +0100
@@ -334,7 +334,7 @@ out:
wake_up_interruptible(PIPE_WAIT(*inode));
kill_fasync(PIPE_FASYNC_READERS(*inode), SIGIO, POLL_IN);
}
- if (ret > 0)
+ if ((ret > 0) && !MNT_IS_RDONLY(filp->f_vfsmnt))
inode_update_time(inode, 1); /* mtime and ctime */
return ret;
}
diff -NurpP --minimal linux-2.6.11-rc4-bme0.06-bm0.01-at0.01-cc0.01/mm/filemap.c linux-2.6.11-rc4-bme0.06-bm0.01-at0.01-cc0.01-co0.01/mm/filemap.c
--- linux-2.6.11-rc4-bme0.06-bm0.01-at0.01-cc0.01/mm/filemap.c 2005-02-13 17:17:15 +0100
+++ linux-2.6.11-rc4-bme0.06-bm0.01-at0.01-cc0.01-co0.01/mm/filemap.c 2005-02-19 06:31:50 +0100
@@ -1810,6 +1810,8 @@ inline int generic_write_checks(struct f
}

if (!isblk) {
+ if (MNT_IS_RDONLY(file->f_vfsmnt))
+ return -EROFS;
/* FIXME: this is for backwards compatibility with 2.4 */
if (file->f_flags & O_APPEND)
*pos = i_size_read(inode);


2005-02-22 14:48:25

by Trond Myklebust

[permalink] [raw]
Subject: Re: [Patch 4/6] Bind Mount Extensions 0.06

ty den 22.02.2005 Klokka 13:12 (+0100) skreiv Herbert Poetzl:

> diff -NurpP --minimal linux-2.6.11-rc4-bme0.06-bm0.01-at0.01-cc0.01/fs/namei.c linux-2.6.11-rc4-bme0.06-bm0.01-at0.01-cc0.01-co0.01/fs/namei.c
> --- linux-2.6.11-rc4-bme0.06-bm0.01-at0.01-cc0.01/fs/namei.c 2005-02-13 17:16:55 +0100
> +++ linux-2.6.11-rc4-bme0.06-bm0.01-at0.01-cc0.01-co0.01/fs/namei.c 2005-02-19 06:31:50 +0100
> @@ -1168,6 +1168,24 @@ static inline int may_create(struct inod
> return permission(dir,MAY_WRITE | MAY_EXEC, nd);
> }
>
> +static inline int mnt_may_create(struct vfsmount *mnt, struct inode *dir, struct dentry *child) {
> + if (child->d_inode)
> + return -EEXIST;
> + if (IS_DEADDIR(dir))
> + return -ENOENT;
> + if (MNT_IS_RDONLY(mnt))
> + return -EROFS;
> + return 0;
> +}
> +
> +static inline int mnt_may_unlink(struct vfsmount *mnt, struct inode *dir, struct dentry *child) {
> + if (!child->d_inode)
> + return -ENOENT;
> + if (MNT_IS_RDONLY(mnt))
> + return -EROFS;
> + return 0;
> +}

Most of these checks are redundant, since they are already being done
elsewhere in the code.
child->d_inode is, for instance checked in may_delete() and in
may_create.
IS_DEADDIR is also checked in may_create.

> /*
> * Special case: O_CREAT|O_EXCL implies O_NOFOLLOW for security
> * reasons.
> @@ -1518,23 +1536,28 @@ do_link:
> struct dentry *lookup_create(struct nameidata *nd, int is_dir)
> {
> struct dentry *dentry;
> + int error;
>
> down(&nd->dentry->d_inode->i_sem);
> - dentry = ERR_PTR(-EEXIST);
> + error = -EEXIST;
> if (nd->last_type != LAST_NORM)
> - goto fail;
> + goto out;
> nd->flags &= ~LOOKUP_PARENT;
> dentry = lookup_hash(&nd->last, nd->dentry);
> if (IS_ERR(dentry))
> + goto ret;
> + error = mnt_may_create(nd->mnt, nd->dentry->d_inode, dentry);
> + if (error)
> goto fail;
> + error = -ENOENT;
> if (!is_dir && nd->last.name[nd->last.len] && !dentry->d_inode)
> - goto enoent;
> + goto fail;
> +ret:
> return dentry;
> -enoent:
> - dput(dentry);
> - dentry = ERR_PTR(-ENOENT);
> fail:
> - return dentry;
> + dput(dentry);
> +out:
> + return ERR_PTR(error);
> }

What is the value of adding "error"? The current code is more efficient,
and just as readable.

Cheers,
Trond

--
Trond Myklebust <[email protected]>

2005-02-23 00:29:39

by Ingo Oeser

[permalink] [raw]
Subject: Re: [Patch 4/6] Bind Mount Extensions 0.06

Hi,

Herbert Poetzl wrote:
> +static inline int mnt_may_unlink(struct vfsmount *mnt, struct inode *dir,
> struct dentry *child) { + if (!child->d_inode)
> + return -ENOENT;
> + if (MNT_IS_RDONLY(mnt))
> + return -EROFS;
> + return 0;
> +}

The argument "dir" is not used. Please remove it and fix the callers.


Regards

Ingo Oeser

2005-02-23 22:51:24

by Herbert Poetzl

[permalink] [raw]
Subject: Re: [Patch 4/6] Bind Mount Extensions 0.06

On Tue, Feb 22, 2005 at 09:45:37AM -0500, Trond Myklebust wrote:
> ty den 22.02.2005 Klokka 13:12 (+0100) skreiv Herbert Poetzl:
>
> > diff -NurpP --minimal linux-2.6.11-rc4-bme0.06-bm0.01-at0.01-cc0.01/fs/namei.c linux-2.6.11-rc4-bme0.06-bm0.01-at0.01-cc0.01-co0.01/fs/namei.c
> > --- linux-2.6.11-rc4-bme0.06-bm0.01-at0.01-cc0.01/fs/namei.c 2005-02-13 17:16:55 +0100
> > +++ linux-2.6.11-rc4-bme0.06-bm0.01-at0.01-cc0.01-co0.01/fs/namei.c 2005-02-19 06:31:50 +0100
> > @@ -1168,6 +1168,24 @@ static inline int may_create(struct inod
> > return permission(dir,MAY_WRITE | MAY_EXEC, nd);
> > }
> >
> > +static inline int mnt_may_create(struct vfsmount *mnt, struct inode *dir, struct dentry *child) {
> > + if (child->d_inode)
> > + return -EEXIST;
> > + if (IS_DEADDIR(dir))
> > + return -ENOENT;
> > + if (MNT_IS_RDONLY(mnt))
> > + return -EROFS;
> > + return 0;
> > +}
> > +
> > +static inline int mnt_may_unlink(struct vfsmount *mnt, struct inode *dir, struct dentry *child) {
> > + if (!child->d_inode)
> > + return -ENOENT;
> > + if (MNT_IS_RDONLY(mnt))
> > + return -EROFS;
> > + return 0;
> > +}
>
> Most of these checks are redundant, since they are already being done
> elsewhere in the code.
> child->d_inode is, for instance checked in may_delete() and in
> may_create.

well, but mnt_may_create() for example is called from
lookup_create() which in turn is (for example) called
from sys_mknod() which doesn't call may_delete() or
may_create() ... did I miss something?

> IS_DEADDIR is also checked in may_create.

ditto ...

> > /*
> > * Special case: O_CREAT|O_EXCL implies O_NOFOLLOW for security
> > * reasons.
> > @@ -1518,23 +1536,28 @@ do_link:
> > struct dentry *lookup_create(struct nameidata *nd, int is_dir)
> > {
> > struct dentry *dentry;
> > + int error;
> >
> > down(&nd->dentry->d_inode->i_sem);
> > - dentry = ERR_PTR(-EEXIST);
> > + error = -EEXIST;
> > if (nd->last_type != LAST_NORM)
> > - goto fail;
> > + goto out;
> > nd->flags &= ~LOOKUP_PARENT;
> > dentry = lookup_hash(&nd->last, nd->dentry);
> > if (IS_ERR(dentry))
> > + goto ret;
> > + error = mnt_may_create(nd->mnt, nd->dentry->d_inode, dentry);
> > + if (error)
> > goto fail;
> > + error = -ENOENT;
> > if (!is_dir && nd->last.name[nd->last.len] && !dentry->d_inode)
> > - goto enoent;
> > + goto fail;
> > +ret:
> > return dentry;
> > -enoent:
> > - dput(dentry);
> > - dentry = ERR_PTR(-ENOENT);
> > fail:
> > - return dentry;
> > + dput(dentry);
> > +out:
> > + return ERR_PTR(error);
> > }
>
> What is the value of adding "error"?
> The current code is more efficient, and just as readable.

hmm, a compile test resulted in almost
identical code, but maybe I did miss some
aspect of the efficiency ...

anyway, thanks for the feedback,
Herbert

> Cheers,
> Trond
>
> --
> Trond Myklebust <[email protected]>

2005-02-24 21:22:26

by Herbert Poetzl

[permalink] [raw]
Subject: Re: [Patch 4/6] Bind Mount Extensions 0.06

On Wed, Feb 23, 2005 at 01:29:30AM +0100, Ingo Oeser wrote:
> Hi,
>
> Herbert Poetzl wrote:
> > +static inline int mnt_may_unlink(struct vfsmount *mnt, struct inode *dir,
> > struct dentry *child) { + if (!child->d_inode)
> > + return -ENOENT;
> > + if (MNT_IS_RDONLY(mnt))
> > + return -EROFS;
> > + return 0;
> > +}
>
> The argument "dir" is not used. Please remove it and fix the callers.

hmm, yes, just saw that the mnt_may*() functions
are not according to the 'current' coding style for
that section/file, so I'll rework that anyway ...

thanks a lot for the input,
Herbert

> Regards
>
> Ingo Oeser
>
> -
> To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
> the body of a message to [email protected]
> More majordomo info at http://vger.kernel.org/majordomo-info.html
> Please read the FAQ at http://www.tux.org/lkml/

2005-02-26 18:38:27

by Herbert Poetzl

[permalink] [raw]
Subject: Re: [Patch 4/6] Bind Mount Extensions 0.06

On Tue, Feb 22, 2005 at 09:45:37AM -0500, Trond Myklebust wrote:
> ty den 22.02.2005 Klokka 13:12 (+0100) skreiv Herbert Poetzl:
>
> > * Special case: O_CREAT|O_EXCL implies O_NOFOLLOW for security
> > * reasons.
> > @@ -1518,23 +1536,28 @@ do_link:
> > struct dentry *lookup_create(struct nameidata *nd, int is_dir)
> > {
> > struct dentry *dentry;
> > + int error;
> >
> > down(&nd->dentry->d_inode->i_sem);
> > - dentry = ERR_PTR(-EEXIST);
> > + error = -EEXIST;
> > if (nd->last_type != LAST_NORM)
> > - goto fail;
> > + goto out;
> > nd->flags &= ~LOOKUP_PARENT;
> > dentry = lookup_hash(&nd->last, nd->dentry);
> > if (IS_ERR(dentry))
> > + goto ret;
> > + error = mnt_may_create(nd->mnt, nd->dentry->d_inode, dentry);
> > + if (error)
> > goto fail;
> > + error = -ENOENT;
> > if (!is_dir && nd->last.name[nd->last.len] && !dentry->d_inode)
> > - goto enoent;
> > + goto fail;
> > +ret:
> > return dentry;
> > -enoent:
> > - dput(dentry);
> > - dentry = ERR_PTR(-ENOENT);
> > fail:
> > - return dentry;
> > + dput(dentry);
> > +out:
> > + return ERR_PTR(error);
> > }
>
> What is the value of adding "error"? The current code is more efficient,
> and just as readable.

okay, had a deeper look at this and now I remember
why I added 'error' in the first place (quite some
time ago ;)

basically we need to check for RO in lookup_create()
now to give the same (error) results than a 'normal'
ro mounted filesystem, it is required to do the
dentry lookup and check the dentry->d_inode to return
EEXIST before returning EROFS ...

something like this would be the result:

if (dentry->d_inode) {
dput(dentry);
dentry = ERR_PTR(-EEXIST);
goto fail;
}
if (MNT_IS_RDONLY(nd->mnt)) {
dput(dentry);
dentry = ERR_PTR(-EROFS);
goto fail;
}

I'm currently looking into moving that check upwards
so that it will happen _after_ the EEXIST one ...

best,
Herbert

> Cheers,
> Trond
>
> --
> Trond Myklebust <[email protected]>