Message ID | 1394041592-3772-3-git-send-email-apw@canonical.com |
---|---|
State | New |
Headers | show |
Quoting Andy Whitcroft (apw@canonical.com): > We need to be priviledged to perform operations such as copy up and > xattr manipulations on "trusted.". Use prepare_kernel_cred to obtain > the necessary priviledges; from its documentation: > > "Prepare a set of credentials for a kernel service. This can then be > used to override a task's own credentials so that work can be done > on behalf of that task that requires a different subjective context." > > Signed-off-by: Andy Whitcroft <apw@canonical.com> Thanks, Andy. Both of these worked, and both look sane. I prefer this patch, personally, but my test+ack applies to either. Tested-by: Serge E. Hallyn <serge.hallyn@ubuntu.com> Acked-by: Serge E. Hallyn <serge.hallyn@ubuntu.com> > --- > fs/overlayfs/copy_up.c | 14 +------------- > fs/overlayfs/dir.c | 35 +++++++++++------------------------ > fs/overlayfs/readdir.c | 18 ++---------------- > fs/overlayfs/super.c | 4 +--- > 4 files changed, 15 insertions(+), 56 deletions(-) > > diff --git a/fs/overlayfs/copy_up.c b/fs/overlayfs/copy_up.c > index 351c162..c7894de 100644 > --- a/fs/overlayfs/copy_up.c > +++ b/fs/overlayfs/copy_up.c > @@ -276,24 +276,12 @@ static int ovl_copy_up_one(struct dentry *parent, struct dentry *dentry, > } > > err = -ENOMEM; > - override_cred = prepare_creds(); > + override_cred = prepare_kernel_cred(NULL); > if (!override_cred) > goto out_free_link; > > override_cred->fsuid = stat->uid; > override_cred->fsgid = stat->gid; > - /* > - * CAP_SYS_ADMIN for copying up extended attributes > - * CAP_DAC_OVERRIDE for create > - * CAP_FOWNER for chmod, timestamp update > - * CAP_FSETID for chmod > - * CAP_MKNOD for mknod > - */ > - cap_raise(override_cred->cap_effective, CAP_SYS_ADMIN); > - cap_raise(override_cred->cap_effective, CAP_DAC_OVERRIDE); > - cap_raise(override_cred->cap_effective, CAP_FOWNER); > - cap_raise(override_cred->cap_effective, CAP_FSETID); > - cap_raise(override_cred->cap_effective, CAP_MKNOD); > old_cred = override_creds(override_cred); > > mutex_lock_nested(&upperdir->d_inode->i_mutex, I_MUTEX_PARENT); > diff --git a/fs/overlayfs/dir.c b/fs/overlayfs/dir.c > index a209409..0a7eb4a 100644 > --- a/fs/overlayfs/dir.c > +++ b/fs/overlayfs/dir.c > @@ -11,6 +11,7 @@ > #include <linux/namei.h> > #include <linux/xattr.h> > #include <linux/security.h> > +#include <linux/sched.h> > #include <linux/cred.h> > #include "overlayfs.h" > > @@ -26,20 +27,16 @@ static int ovl_whiteout(struct dentry *upperdir, struct dentry *dentry) > /* FIXME: recheck lower dentry to see if whiteout is really needed */ > > err = -ENOMEM; > - override_cred = prepare_creds(); > + override_cred = prepare_kernel_cred(NULL); > if (!override_cred) > goto out; > > - /* > - * CAP_SYS_ADMIN for setxattr > - * CAP_DAC_OVERRIDE for symlink creation > - * CAP_FOWNER for unlink in sticky directory > - */ > - cap_raise(override_cred->cap_effective, CAP_SYS_ADMIN); > - cap_raise(override_cred->cap_effective, CAP_DAC_OVERRIDE); > - cap_raise(override_cred->cap_effective, CAP_FOWNER); > - override_cred->fsuid = GLOBAL_ROOT_UID; > - override_cred->fsgid = GLOBAL_ROOT_GID; > + override_cred->fsuid = make_kuid(current_user_ns(), 0); > + if (!uid_valid(override_cred->fsuid)) > + override_cred->fsuid = GLOBAL_ROOT_UID; > + override_cred->fsgid = make_kgid(current_user_ns(), 0); > + if (!gid_valid(override_cred->fsgid)) > + override_cred->fsgid = GLOBAL_ROOT_GID; > old_cred = override_creds(override_cred); > > newdentry = lookup_one_len(dentry->d_name.name, upperdir, > @@ -103,16 +100,10 @@ static struct dentry *ovl_lookup_create(struct dentry *upperdir, > goto out_dput; > > err = -ENOMEM; > - override_cred = prepare_creds(); > + override_cred = prepare_kernel_cred(NULL); > if (!override_cred) > goto out_dput; > > - /* > - * CAP_SYS_ADMIN for getxattr > - * CAP_FOWNER for unlink in sticky directory > - */ > - cap_raise(override_cred->cap_effective, CAP_SYS_ADMIN); > - cap_raise(override_cred->cap_effective, CAP_FOWNER); > old_cred = override_creds(override_cred); > > err = -EEXIST; > @@ -205,12 +196,10 @@ static int ovl_set_opaque(struct dentry *upperdentry) > const struct cred *old_cred; > struct cred *override_cred; > > - override_cred = prepare_creds(); > + override_cred = prepare_kernel_cred(NULL); > if (!override_cred) > return -ENOMEM; > > - /* CAP_SYS_ADMIN for setxattr of "trusted" namespace */ > - cap_raise(override_cred->cap_effective, CAP_SYS_ADMIN); > old_cred = override_creds(override_cred); > err = vfs_setxattr(upperdentry, ovl_opaque_xattr, "y", 1, 0); > revert_creds(old_cred); > @@ -225,12 +214,10 @@ static int ovl_remove_opaque(struct dentry *upperdentry) > const struct cred *old_cred; > struct cred *override_cred; > > - override_cred = prepare_creds(); > + override_cred = prepare_kernel_cred(NULL); > if (!override_cred) > return -ENOMEM; > > - /* CAP_SYS_ADMIN for removexattr of "trusted" namespace */ > - cap_raise(override_cred->cap_effective, CAP_SYS_ADMIN); > old_cred = override_creds(override_cred); > err = vfs_removexattr(upperdentry, ovl_opaque_xattr); > revert_creds(old_cred); > diff --git a/fs/overlayfs/readdir.c b/fs/overlayfs/readdir.c > index 9c6f08f..1cc4cbd 100644 > --- a/fs/overlayfs/readdir.c > +++ b/fs/overlayfs/readdir.c > @@ -218,18 +218,12 @@ static int ovl_dir_mark_whiteouts(struct ovl_readdir_data *rdd) > const struct cred *old_cred; > struct cred *override_cred; > > - override_cred = prepare_creds(); > + override_cred = prepare_kernel_cred(NULL); > if (!override_cred) { > ovl_cache_free(rdd->list); > return -ENOMEM; > } > > - /* > - * CAP_SYS_ADMIN for getxattr > - * CAP_DAC_OVERRIDE for lookup > - */ > - cap_raise(override_cred->cap_effective, CAP_SYS_ADMIN); > - cap_raise(override_cred->cap_effective, CAP_DAC_OVERRIDE); > old_cred = override_creds(override_cred); > > mutex_lock(&rdd->dir->d_inode->i_mutex); > @@ -503,18 +497,10 @@ static int ovl_remove_whiteouts(struct dentry *dir, struct list_head *list) > ovl_path_upper(dir, &upperpath); > upperdir = upperpath.dentry; > > - override_cred = prepare_creds(); > + override_cred = prepare_kernel_cred(NULL); > if (!override_cred) > return -ENOMEM; > > - /* > - * CAP_DAC_OVERRIDE for lookup and unlink > - * CAP_SYS_ADMIN for setxattr of "trusted" namespace > - * CAP_FOWNER for unlink in sticky directory > - */ > - cap_raise(override_cred->cap_effective, CAP_DAC_OVERRIDE); > - cap_raise(override_cred->cap_effective, CAP_SYS_ADMIN); > - cap_raise(override_cred->cap_effective, CAP_FOWNER); > old_cred = override_creds(override_cred); > > err = vfs_setxattr(upperdir, ovl_opaque_xattr, "y", 1, 0); > diff --git a/fs/overlayfs/super.c b/fs/overlayfs/super.c > index 50890c2..79288a8 100644 > --- a/fs/overlayfs/super.c > +++ b/fs/overlayfs/super.c > @@ -304,12 +304,10 @@ static int ovl_do_lookup(struct dentry *dentry) > struct cred *override_cred; > > err = -ENOMEM; > - override_cred = prepare_creds(); > + override_cred = prepare_kernel_cred(NULL); > if (!override_cred) > goto out_dput_upper; > > - /* CAP_SYS_ADMIN needed for getxattr */ > - cap_raise(override_cred->cap_effective, CAP_SYS_ADMIN); > old_cred = override_creds(override_cred); > > if (ovl_is_opaquedir(upperdentry)) { > -- > 1.9.0
diff --git a/fs/overlayfs/copy_up.c b/fs/overlayfs/copy_up.c index 351c162..c7894de 100644 --- a/fs/overlayfs/copy_up.c +++ b/fs/overlayfs/copy_up.c @@ -276,24 +276,12 @@ static int ovl_copy_up_one(struct dentry *parent, struct dentry *dentry, } err = -ENOMEM; - override_cred = prepare_creds(); + override_cred = prepare_kernel_cred(NULL); if (!override_cred) goto out_free_link; override_cred->fsuid = stat->uid; override_cred->fsgid = stat->gid; - /* - * CAP_SYS_ADMIN for copying up extended attributes - * CAP_DAC_OVERRIDE for create - * CAP_FOWNER for chmod, timestamp update - * CAP_FSETID for chmod - * CAP_MKNOD for mknod - */ - cap_raise(override_cred->cap_effective, CAP_SYS_ADMIN); - cap_raise(override_cred->cap_effective, CAP_DAC_OVERRIDE); - cap_raise(override_cred->cap_effective, CAP_FOWNER); - cap_raise(override_cred->cap_effective, CAP_FSETID); - cap_raise(override_cred->cap_effective, CAP_MKNOD); old_cred = override_creds(override_cred); mutex_lock_nested(&upperdir->d_inode->i_mutex, I_MUTEX_PARENT); diff --git a/fs/overlayfs/dir.c b/fs/overlayfs/dir.c index a209409..0a7eb4a 100644 --- a/fs/overlayfs/dir.c +++ b/fs/overlayfs/dir.c @@ -11,6 +11,7 @@ #include <linux/namei.h> #include <linux/xattr.h> #include <linux/security.h> +#include <linux/sched.h> #include <linux/cred.h> #include "overlayfs.h" @@ -26,20 +27,16 @@ static int ovl_whiteout(struct dentry *upperdir, struct dentry *dentry) /* FIXME: recheck lower dentry to see if whiteout is really needed */ err = -ENOMEM; - override_cred = prepare_creds(); + override_cred = prepare_kernel_cred(NULL); if (!override_cred) goto out; - /* - * CAP_SYS_ADMIN for setxattr - * CAP_DAC_OVERRIDE for symlink creation - * CAP_FOWNER for unlink in sticky directory - */ - cap_raise(override_cred->cap_effective, CAP_SYS_ADMIN); - cap_raise(override_cred->cap_effective, CAP_DAC_OVERRIDE); - cap_raise(override_cred->cap_effective, CAP_FOWNER); - override_cred->fsuid = GLOBAL_ROOT_UID; - override_cred->fsgid = GLOBAL_ROOT_GID; + override_cred->fsuid = make_kuid(current_user_ns(), 0); + if (!uid_valid(override_cred->fsuid)) + override_cred->fsuid = GLOBAL_ROOT_UID; + override_cred->fsgid = make_kgid(current_user_ns(), 0); + if (!gid_valid(override_cred->fsgid)) + override_cred->fsgid = GLOBAL_ROOT_GID; old_cred = override_creds(override_cred); newdentry = lookup_one_len(dentry->d_name.name, upperdir, @@ -103,16 +100,10 @@ static struct dentry *ovl_lookup_create(struct dentry *upperdir, goto out_dput; err = -ENOMEM; - override_cred = prepare_creds(); + override_cred = prepare_kernel_cred(NULL); if (!override_cred) goto out_dput; - /* - * CAP_SYS_ADMIN for getxattr - * CAP_FOWNER for unlink in sticky directory - */ - cap_raise(override_cred->cap_effective, CAP_SYS_ADMIN); - cap_raise(override_cred->cap_effective, CAP_FOWNER); old_cred = override_creds(override_cred); err = -EEXIST; @@ -205,12 +196,10 @@ static int ovl_set_opaque(struct dentry *upperdentry) const struct cred *old_cred; struct cred *override_cred; - override_cred = prepare_creds(); + override_cred = prepare_kernel_cred(NULL); if (!override_cred) return -ENOMEM; - /* CAP_SYS_ADMIN for setxattr of "trusted" namespace */ - cap_raise(override_cred->cap_effective, CAP_SYS_ADMIN); old_cred = override_creds(override_cred); err = vfs_setxattr(upperdentry, ovl_opaque_xattr, "y", 1, 0); revert_creds(old_cred); @@ -225,12 +214,10 @@ static int ovl_remove_opaque(struct dentry *upperdentry) const struct cred *old_cred; struct cred *override_cred; - override_cred = prepare_creds(); + override_cred = prepare_kernel_cred(NULL); if (!override_cred) return -ENOMEM; - /* CAP_SYS_ADMIN for removexattr of "trusted" namespace */ - cap_raise(override_cred->cap_effective, CAP_SYS_ADMIN); old_cred = override_creds(override_cred); err = vfs_removexattr(upperdentry, ovl_opaque_xattr); revert_creds(old_cred); diff --git a/fs/overlayfs/readdir.c b/fs/overlayfs/readdir.c index 9c6f08f..1cc4cbd 100644 --- a/fs/overlayfs/readdir.c +++ b/fs/overlayfs/readdir.c @@ -218,18 +218,12 @@ static int ovl_dir_mark_whiteouts(struct ovl_readdir_data *rdd) const struct cred *old_cred; struct cred *override_cred; - override_cred = prepare_creds(); + override_cred = prepare_kernel_cred(NULL); if (!override_cred) { ovl_cache_free(rdd->list); return -ENOMEM; } - /* - * CAP_SYS_ADMIN for getxattr - * CAP_DAC_OVERRIDE for lookup - */ - cap_raise(override_cred->cap_effective, CAP_SYS_ADMIN); - cap_raise(override_cred->cap_effective, CAP_DAC_OVERRIDE); old_cred = override_creds(override_cred); mutex_lock(&rdd->dir->d_inode->i_mutex); @@ -503,18 +497,10 @@ static int ovl_remove_whiteouts(struct dentry *dir, struct list_head *list) ovl_path_upper(dir, &upperpath); upperdir = upperpath.dentry; - override_cred = prepare_creds(); + override_cred = prepare_kernel_cred(NULL); if (!override_cred) return -ENOMEM; - /* - * CAP_DAC_OVERRIDE for lookup and unlink - * CAP_SYS_ADMIN for setxattr of "trusted" namespace - * CAP_FOWNER for unlink in sticky directory - */ - cap_raise(override_cred->cap_effective, CAP_DAC_OVERRIDE); - cap_raise(override_cred->cap_effective, CAP_SYS_ADMIN); - cap_raise(override_cred->cap_effective, CAP_FOWNER); old_cred = override_creds(override_cred); err = vfs_setxattr(upperdir, ovl_opaque_xattr, "y", 1, 0); diff --git a/fs/overlayfs/super.c b/fs/overlayfs/super.c index 50890c2..79288a8 100644 --- a/fs/overlayfs/super.c +++ b/fs/overlayfs/super.c @@ -304,12 +304,10 @@ static int ovl_do_lookup(struct dentry *dentry) struct cred *override_cred; err = -ENOMEM; - override_cred = prepare_creds(); + override_cred = prepare_kernel_cred(NULL); if (!override_cred) goto out_dput_upper; - /* CAP_SYS_ADMIN needed for getxattr */ - cap_raise(override_cred->cap_effective, CAP_SYS_ADMIN); old_cred = override_creds(override_cred); if (ovl_is_opaquedir(upperdentry)) {
We need to be priviledged to perform operations such as copy up and xattr manipulations on "trusted.". Use prepare_kernel_cred to obtain the necessary priviledges; from its documentation: "Prepare a set of credentials for a kernel service. This can then be used to override a task's own credentials so that work can be done on behalf of that task that requires a different subjective context." Signed-off-by: Andy Whitcroft <apw@canonical.com> --- fs/overlayfs/copy_up.c | 14 +------------- fs/overlayfs/dir.c | 35 +++++++++++------------------------ fs/overlayfs/readdir.c | 18 ++---------------- fs/overlayfs/super.c | 4 +--- 4 files changed, 15 insertions(+), 56 deletions(-)