]> www.infradead.org Git - users/jedix/linux-maple.git/commitdiff
vfs: Commit to never having exectuables on proc and sysfs.
authorEric W. Biederman <ebiederm@xmission.com>
Mon, 29 Jun 2015 19:42:03 +0000 (14:42 -0500)
committerTim Tianyang Chen <tianyang.chen@oracle.com>
Thu, 24 Aug 2017 21:08:20 +0000 (14:08 -0700)
Today proc and sysfs do not contain any executable files.  Several
applications today mount proc or sysfs without noexec and nosuid and
then depend on there being no exectuables files on proc or sysfs.
Having any executable files show on proc or sysfs would cause
a user space visible regression, and most likely security problems.

Therefore commit to never allowing executables on proc and sysfs by
adding a new flag to mark them as filesystems without executables and
enforce that flag.

Test the flag where MNT_NOEXEC is tested today, so that the only user
visible effect will be that exectuables will be treated as if the
execute bit is cleared.

The filesystems proc and sysfs do not currently incoporate any
executable files so this does not result in any user visible effects.

This makes it unnecessary to vet changes to proc and sysfs tightly for
adding exectuable files or changes to chattr that would modify
existing files, as no matter what the individual file say they will
not be treated as exectuable files by the vfs.

Not having to vet changes to closely is important as without this we
are only one proc_create call (or another goof up in the
implementation of notify_change) from having problematic executables
on proc.  Those mistakes are all too easy to make and would create
a situation where there are security issues or the assumptions of
some program having to be broken (and cause userspace regressions).

Signed-off-by: "Eric W. Biederman" <ebiederm@xmission.com>
(cherry picked from commit 90f8572b0f021fdd1baa68e00a8c30482ee9e5f4)

Orabug: 26540416
CVE: CVE-2016-10044

Signed-off-by: Tim Tianyang Chen <tianyang.chen@oracle.com>
Reviewed-by: Jack Vogel <jack.vogel@oracle.com>
 Conflicts:
include/linux/fs.h

fs/exec.c
fs/open.c
fs/proc/root.c
fs/sysfs/mount.c
include/linux/fs.h
kernel/sys.c
mm/mmap.c
mm/nommu.c
security/security.c

index 133202e0fa2f5467f07556ef8db8c3382d8d8d10..9139f5a3c545c1697e8e8f4afa39689f5c15bedd 100644 (file)
--- a/fs/exec.c
+++ b/fs/exec.c
@@ -100,6 +100,12 @@ static inline void put_binfmt(struct linux_binfmt * fmt)
        module_put(fmt->module);
 }
 
+bool path_noexec(const struct path *path)
+{
+       return (path->mnt->mnt_flags & MNT_NOEXEC) ||
+              (path->mnt->mnt_sb->s_iflags & SB_I_NOEXEC);
+}
+
 #ifdef CONFIG_USELIB
 /*
  * Note that a shared library must be both readable and executable due to
@@ -134,7 +140,7 @@ SYSCALL_DEFINE1(uselib, const char __user *, library)
                goto exit;
 
        error = -EACCES;
-       if (file->f_path.mnt->mnt_flags & MNT_NOEXEC)
+       if (path_noexec(&file->f_path))
                goto exit;
 
        fsnotify_open(file);
@@ -799,7 +805,7 @@ static struct file *do_open_execat(int fd, struct filename *name, int flags)
        if (!S_ISREG(file_inode(file)->i_mode))
                goto exit;
 
-       if (file->f_path.mnt->mnt_flags & MNT_NOEXEC)
+       if (path_noexec(&file->f_path))
                goto exit;
 
        err = deny_write_access(file);
index 7bab5a4bb7b01dc395c7fe8d2f675469f648a317..72435c2b460feedd8b5a88e712ff6879e8adb728 100644 (file)
--- a/fs/open.c
+++ b/fs/open.c
@@ -377,7 +377,7 @@ retry:
                 * with the "noexec" flag.
                 */
                res = -EACCES;
-               if (path.mnt->mnt_flags & MNT_NOEXEC)
+               if (path_noexec(&path))
                        goto out_path_release;
        }
 
index c3e1bc595e6db67e68399459eeb0376fc9e3b169..ec649c92d2708831b5e2b19615ee276113a1dabe 100644 (file)
@@ -141,6 +141,8 @@ static struct dentry *proc_mount(struct file_system_type *fs_type,
                }
 
                sb->s_flags |= MS_ACTIVE;
+               /* User space would break if executables appear on proc */
+               sb->s_iflags |= SB_I_NOEXEC;
        }
 
        return dget(sb->s_root);
index 1c6ac6fcee9fb15c869ef80fc5947ba9117d77ea..f3db82071cfbd5997bdb1393097e755ae730ea96 100644 (file)
@@ -40,6 +40,10 @@ static struct dentry *sysfs_mount(struct file_system_type *fs_type,
                                SYSFS_MAGIC, &new_sb, ns);
        if (IS_ERR(root) || !new_sb)
                kobj_ns_drop(KOBJ_NS_TYPE_NET, ns);
+       else if (new_sb)
+               /* Userspace would break if executables appear on sysfs */
+               root->d_sb->s_iflags |= SB_I_NOEXEC;
+
        return root;
 }
 
index 1c57d74c1372da82dec7a0673c40791a8b72d60b..f8fd2cdbd6fd0ceedac8259cb9998bb05fe95731 100644 (file)
@@ -1253,6 +1253,8 @@ struct mm_struct;
 #define UMOUNT_NOFOLLOW        0x00000008      /* Don't follow symlink on umount */
 #define UMOUNT_UNUSED  0x80000000      /* Flag guaranteed to be unused */
 
+/* sb->s_iflags */
+#define SB_I_NOEXEC    0x00000002      /* Ignore executables on this fs */
 
 /* Possible states of 'frozen' field */
 enum {
@@ -3005,4 +3007,5 @@ static inline bool dir_relax(struct inode *inode)
        return !IS_DEADDIR(inode);
 }
 
+extern bool path_noexec(const struct path *path);
 #endif /* _LINUX_FS_H */
index 25ae8d2e65e2d2db755a2c255440e958069c318f..62f596a0d83d137068e2a1fd5f4323ce11e48a6a 100644 (file)
@@ -1668,8 +1668,7 @@ static int prctl_set_mm_exe_file(struct mm_struct *mm, unsigned int fd)
         * overall picture.
         */
        err = -EACCES;
-       if (!S_ISREG(inode->i_mode)     ||
-           exe.file->f_path.mnt->mnt_flags & MNT_NOEXEC)
+       if (!S_ISREG(inode->i_mode) || path_noexec(&exe.file->f_path))
                goto exit;
 
        err = inode_permission(inode, MAY_EXEC);
index 33d2142b9bf70c963130bf694e07efd389cd019f..4c07adafa01b101127f3d1c07206419eec90e6b6 100644 (file)
--- a/mm/mmap.c
+++ b/mm/mmap.c
@@ -1326,7 +1326,7 @@ unsigned long do_mmap_pgoff(struct file *file, unsigned long addr,
         *  mounted, in which case we dont add PROT_EXEC.)
         */
        if ((prot & PROT_READ) && (current->personality & READ_IMPLIES_EXEC))
-               if (!(file && (file->f_path.mnt->mnt_flags & MNT_NOEXEC)))
+               if (!(file && path_noexec(&file->f_path)))
                        prot |= PROT_EXEC;
 
        if (!len)
@@ -1398,7 +1398,7 @@ unsigned long do_mmap_pgoff(struct file *file, unsigned long addr,
                case MAP_PRIVATE:
                        if (!(file->f_mode & FMODE_READ))
                                return -EACCES;
-                       if (file->f_path.mnt->mnt_flags & MNT_NOEXEC) {
+                       if (path_noexec(&file->f_path)) {
                                if (vm_flags & VM_EXEC)
                                        return -EPERM;
                                vm_flags &= ~VM_MAYEXEC;
index cc5fe1804a9955c7f8f9dc90bb3523445ace6b67..19a7bdedd230baa6abc4979bc5023248909c8e1d 100644 (file)
@@ -1074,7 +1074,7 @@ static int validate_mmap_request(struct file *file,
 
                /* handle executable mappings and implied executable
                 * mappings */
-               if (file->f_path.mnt->mnt_flags & MNT_NOEXEC) {
+               if (path_noexec(&file->f_path)) {
                        if (prot & PROT_EXEC)
                                return -EPERM;
                } else if ((prot & PROT_READ) && !(prot & PROT_EXEC)) {
index 8e9b1f4b9b45dfac98287fe969b869a3a29fb2bc..391496b0c87741483ca3bb5114ffb50d6e8b09dd 100644 (file)
@@ -751,7 +751,7 @@ static inline unsigned long mmap_prot(struct file *file, unsigned long prot)
         * ditto if it's not on noexec mount, except that on !MMU we need
         * NOMMU_MAP_EXEC (== VM_MAYEXEC) in this case
         */
-       if (!(file->f_path.mnt->mnt_flags & MNT_NOEXEC)) {
+       if (!path_noexec(&file->f_path)) {
 #ifndef CONFIG_MMU
                if (file->f_op->mmap_capabilities) {
                        unsigned caps = file->f_op->mmap_capabilities(file);