An overlayfs mount using an upper or lower directory from a
nosuid filesystem bypasses this restriction. Change this so
that if any lower or upper directory is nosuid at mount time the
overlayfs superblock is marked nosuid. This requires some
additions at the vfs level since nosuid currently only applies to
mounts, so a SB_I_NOSUID flag is added along with a helper
function to check a path for nosuid in both the mount and the
superblock.
BugLink: http://bugs.launchpad.net/bugs/1534961
BugLink: http://bugs.launchpad.net/bugs/1535150
Signed-off-by: Seth Forshee <seth.forshee@canonical.com>
Signed-off-by: Leann Ogasawara <leann.ogasawara@canonical.com>
(path->mnt->mnt_sb->s_iflags & SB_I_NOEXEC);
}
(path->mnt->mnt_sb->s_iflags & SB_I_NOEXEC);
}
+bool path_nosuid(const struct path *path)
+{
+ return !mnt_may_suid(path->mnt) ||
+ (path->mnt->mnt_sb->s_iflags & SB_I_NOSUID);
+}
+EXPORT_SYMBOL(path_nosuid);
+
#ifdef CONFIG_USELIB
/*
* Note that a shared library must be both readable and executable due to
#ifdef CONFIG_USELIB
/*
* Note that a shared library must be both readable and executable due to
bprm->cred->euid = current_euid();
bprm->cred->egid = current_egid();
bprm->cred->euid = current_euid();
bprm->cred->egid = current_egid();
- if (!mnt_may_suid(bprm->file->f_path.mnt))
+ if (path_nosuid(&bprm->file->f_path))
return;
if (task_no_new_privs(current))
return;
if (task_no_new_privs(current))
mnt->mnt_flags |= MNT_READONLY | MNT_NOATIME;
ofs->lower_layers[ofs->numlower].trap = trap;
mnt->mnt_flags |= MNT_READONLY | MNT_NOATIME;
ofs->lower_layers[ofs->numlower].trap = trap;
+
+ /*
+ * If any lower mount is nosuid, force the ovl sb to also
+ * be nosuid.
+ */
+ if (mnt->mnt_flags & MNT_NOSUID)
+ sb->s_iflags |= SB_I_NOSUID;
+
ofs->lower_layers[ofs->numlower].mnt = mnt;
ofs->lower_layers[ofs->numlower].idx = i + 1;
ofs->lower_layers[ofs->numlower].fsid = fsid;
ofs->lower_layers[ofs->numlower].mnt = mnt;
ofs->lower_layers[ofs->numlower].idx = i + 1;
ofs->lower_layers[ofs->numlower].fsid = fsid;
if (!ofs->workdir)
sb->s_flags |= SB_RDONLY;
if (!ofs->workdir)
sb->s_flags |= SB_RDONLY;
+ /*
+ * If the upper mount is nosuid, force the ovl sb to also
+ * be nosuid.
+ */
+ if (ofs->upper_mnt->mnt_flags & MNT_NOSUID)
+ sb->s_iflags |= SB_I_NOSUID;
+
sb->s_stack_depth = ofs->upper_mnt->mnt_sb->s_stack_depth;
sb->s_time_gran = ofs->upper_mnt->mnt_sb->s_time_gran;
sb->s_stack_depth = ofs->upper_mnt->mnt_sb->s_stack_depth;
sb->s_time_gran = ofs->upper_mnt->mnt_sb->s_time_gran;
#define SB_I_NOEXEC 0x00000002 /* Ignore executables on this fs */
#define SB_I_NODEV 0x00000004 /* Ignore devices on this fs */
#define SB_I_MULTIROOT 0x00000008 /* Multiple roots to the dentry tree */
#define SB_I_NOEXEC 0x00000002 /* Ignore executables on this fs */
#define SB_I_NODEV 0x00000004 /* Ignore devices on this fs */
#define SB_I_MULTIROOT 0x00000008 /* Multiple roots to the dentry tree */
+#define SB_I_NOSUID 0x00000010 /* Ignore suid on this fs */
/* sb->s_iflags to limit user namespace mounts */
#define SB_I_USERNS_VISIBLE 0x00000010 /* fstype already mounted */
/* sb->s_iflags to limit user namespace mounts */
#define SB_I_USERNS_VISIBLE 0x00000010 /* fstype already mounted */
}
extern bool path_noexec(const struct path *path);
}
extern bool path_noexec(const struct path *path);
+extern bool path_nosuid(const struct path *path);
extern void inode_nohighmem(struct inode *inode);
/* mm/fadvise.c */
extern void inode_nohighmem(struct inode *inode);
/* mm/fadvise.c */
if (!file_caps_enabled)
return 0;
if (!file_caps_enabled)
return 0;
- if (!mnt_may_suid(bprm->file->f_path.mnt))
+ if (path_nosuid(&bprm->file->f_path))
const struct task_security_struct *new_tsec)
{
int nnp = (bprm->unsafe & LSM_UNSAFE_NO_NEW_PRIVS);
const struct task_security_struct *new_tsec)
{
int nnp = (bprm->unsafe & LSM_UNSAFE_NO_NEW_PRIVS);
- int nosuid = !mnt_may_suid(bprm->file->f_path.mnt);
+ int nosuid = path_nosuid(&bprm->file->f_path);