From 6341c393fcc37d58727865f1ee2f65e632e9d4f0 Mon Sep 17 00:00:00 2001 From: Roland McGrath Date: Fri, 25 Jul 2008 19:45:44 -0700 Subject: tracehook: exec This moves all the ptrace hooks related to exec into tracehook.h inlines. This also lifts the calls for tracing out of the binfmt load_binary hooks into search_binary_handler() after it calls into the binfmt module. This change has no effect, since all the binfmt modules' load_binary functions did the call at the end on success, and now search_binary_handler() does it immediately after return if successful. We consolidate the repeated code, and binfmt modules no longer need to import ptrace_notify(). Signed-off-by: Roland McGrath Cc: Oleg Nesterov Reviewed-by: Ingo Molnar Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- fs/exec.c | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) (limited to 'fs/exec.c') diff --git a/fs/exec.c b/fs/exec.c index 5e559013e303..b8792a131533 100644 --- a/fs/exec.c +++ b/fs/exec.c @@ -42,13 +42,13 @@ #include #include #include -#include #include #include #include #include #include #include +#include #include #include @@ -1071,13 +1071,8 @@ EXPORT_SYMBOL(prepare_binprm); static int unsafe_exec(struct task_struct *p) { - int unsafe = 0; - if (p->ptrace & PT_PTRACED) { - if (p->ptrace & PT_PTRACE_CAP) - unsafe |= LSM_UNSAFE_PTRACE_CAP; - else - unsafe |= LSM_UNSAFE_PTRACE; - } + int unsafe = tracehook_unsafe_exec(p); + if (atomic_read(&p->fs->count) > 1 || atomic_read(&p->files->count) > 1 || atomic_read(&p->sighand->count) > 1) @@ -1214,6 +1209,7 @@ int search_binary_handler(struct linux_binprm *bprm,struct pt_regs *regs) read_unlock(&binfmt_lock); retval = fn(bprm, regs); if (retval >= 0) { + tracehook_report_exec(fmt, bprm, regs); put_binfmt(fmt); allow_write_access(bprm->file); if (bprm->file) -- cgit v1.2.3 From b77b0646ef4efe31a7449bb3d9360fd00f95433d Mon Sep 17 00:00:00 2001 From: Al Viro Date: Thu, 17 Jul 2008 09:37:02 -0400 Subject: [PATCH] pass MAY_OPEN to vfs_permission() explicitly ... and get rid of the last "let's deduce mask from nameidata->flags" bit. Signed-off-by: Al Viro --- fs/exec.c | 4 ++-- fs/namei.c | 13 ++++--------- include/linux/security.h | 7 +++---- security/capability.c | 3 +-- security/security.c | 4 ++-- security/selinux/hooks.c | 5 ++--- security/smack/smack_lsm.c | 3 +-- 7 files changed, 15 insertions(+), 24 deletions(-) (limited to 'fs/exec.c') diff --git a/fs/exec.c b/fs/exec.c index b8792a131533..0ba5d355c5a1 100644 --- a/fs/exec.c +++ b/fs/exec.c @@ -118,7 +118,7 @@ asmlinkage long sys_uselib(const char __user * library) if (!S_ISREG(nd.path.dentry->d_inode->i_mode)) goto exit; - error = vfs_permission(&nd, MAY_READ | MAY_EXEC); + error = vfs_permission(&nd, MAY_READ | MAY_EXEC | MAY_OPEN); if (error) goto exit; @@ -666,7 +666,7 @@ struct file *open_exec(const char *name) struct inode *inode = nd.path.dentry->d_inode; file = ERR_PTR(-EACCES); if (S_ISREG(inode->i_mode)) { - int err = vfs_permission(&nd, MAY_EXEC); + int err = vfs_permission(&nd, MAY_EXEC | MAY_OPEN); file = ERR_PTR(err); if (!err) { file = nameidata_to_filp(&nd, diff --git a/fs/namei.c b/fs/namei.c index 33dcaf025c49..6b0e8e5e079e 100644 --- a/fs/namei.c +++ b/fs/namei.c @@ -263,12 +263,7 @@ int permission(struct inode *inode, int mask, struct nameidata *nd) /* Ordinary permission routines do not understand MAY_APPEND. */ if (inode->i_op && inode->i_op->permission) { - int extra = 0; - if (nd) { - if (nd->flags & LOOKUP_OPEN) - extra |= MAY_OPEN; - } - retval = inode->i_op->permission(inode, mask | extra); + retval = inode->i_op->permission(inode, mask); if (!retval) { /* * Exec permission on a regular file is denied if none @@ -292,7 +287,7 @@ int permission(struct inode *inode, int mask, struct nameidata *nd) return retval; return security_inode_permission(inode, - mask & (MAY_READ|MAY_WRITE|MAY_EXEC), nd); + mask & (MAY_READ|MAY_WRITE|MAY_EXEC)); } /** @@ -492,7 +487,7 @@ static int exec_permission_lite(struct inode *inode, return -EACCES; ok: - return security_inode_permission(inode, MAY_EXEC, nd); + return security_inode_permission(inode, MAY_EXEC); } /* @@ -1692,7 +1687,7 @@ struct file *do_filp_open(int dfd, const char *pathname, int will_write; int flag = open_to_namei_flags(open_flag); - acc_mode = ACC_MODE(flag); + acc_mode = MAY_OPEN | ACC_MODE(flag); /* O_TRUNC implies we need access checks for write permissions */ if (flag & O_TRUNC) diff --git a/include/linux/security.h b/include/linux/security.h index f0e9adb22ac2..fd96e7f8a6f9 100644 --- a/include/linux/security.h +++ b/include/linux/security.h @@ -1362,7 +1362,7 @@ struct security_operations { struct inode *new_dir, struct dentry *new_dentry); int (*inode_readlink) (struct dentry *dentry); int (*inode_follow_link) (struct dentry *dentry, struct nameidata *nd); - int (*inode_permission) (struct inode *inode, int mask, struct nameidata *nd); + int (*inode_permission) (struct inode *inode, int mask); int (*inode_setattr) (struct dentry *dentry, struct iattr *attr); int (*inode_getattr) (struct vfsmount *mnt, struct dentry *dentry); void (*inode_delete) (struct inode *inode); @@ -1628,7 +1628,7 @@ int security_inode_rename(struct inode *old_dir, struct dentry *old_dentry, struct inode *new_dir, struct dentry *new_dentry); int security_inode_readlink(struct dentry *dentry); int security_inode_follow_link(struct dentry *dentry, struct nameidata *nd); -int security_inode_permission(struct inode *inode, int mask, struct nameidata *nd); +int security_inode_permission(struct inode *inode, int mask); int security_inode_setattr(struct dentry *dentry, struct iattr *attr); int security_inode_getattr(struct vfsmount *mnt, struct dentry *dentry); void security_inode_delete(struct inode *inode); @@ -2021,8 +2021,7 @@ static inline int security_inode_follow_link(struct dentry *dentry, return 0; } -static inline int security_inode_permission(struct inode *inode, int mask, - struct nameidata *nd) +static inline int security_inode_permission(struct inode *inode, int mask) { return 0; } diff --git a/security/capability.c b/security/capability.c index 5b01c0b02422..63d10da515a5 100644 --- a/security/capability.c +++ b/security/capability.c @@ -211,8 +211,7 @@ static int cap_inode_follow_link(struct dentry *dentry, return 0; } -static int cap_inode_permission(struct inode *inode, int mask, - struct nameidata *nd) +static int cap_inode_permission(struct inode *inode, int mask) { return 0; } diff --git a/security/security.c b/security/security.c index 59f23b5918b3..78ed3ffde242 100644 --- a/security/security.c +++ b/security/security.c @@ -429,11 +429,11 @@ int security_inode_follow_link(struct dentry *dentry, struct nameidata *nd) return security_ops->inode_follow_link(dentry, nd); } -int security_inode_permission(struct inode *inode, int mask, struct nameidata *nd) +int security_inode_permission(struct inode *inode, int mask) { if (unlikely(IS_PRIVATE(inode))) return 0; - return security_ops->inode_permission(inode, mask, nd); + return security_ops->inode_permission(inode, mask); } int security_inode_setattr(struct dentry *dentry, struct iattr *attr) diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c index 3481cde5bf15..5ba13908b5b4 100644 --- a/security/selinux/hooks.c +++ b/security/selinux/hooks.c @@ -2624,12 +2624,11 @@ static int selinux_inode_follow_link(struct dentry *dentry, struct nameidata *na return dentry_has_perm(current, NULL, dentry, FILE__READ); } -static int selinux_inode_permission(struct inode *inode, int mask, - struct nameidata *nd) +static int selinux_inode_permission(struct inode *inode, int mask) { int rc; - rc = secondary_ops->inode_permission(inode, mask, nd); + rc = secondary_ops->inode_permission(inode, mask); if (rc) return rc; diff --git a/security/smack/smack_lsm.c b/security/smack/smack_lsm.c index ee5a51cbc5eb..1b40e558f983 100644 --- a/security/smack/smack_lsm.c +++ b/security/smack/smack_lsm.c @@ -522,8 +522,7 @@ static int smack_inode_rename(struct inode *old_inode, * * Returns 0 if access is permitted, -EACCES otherwise */ -static int smack_inode_permission(struct inode *inode, int mask, - struct nameidata *nd) +static int smack_inode_permission(struct inode *inode, int mask) { /* * No permission to check. Existence test. Yup, it's there. -- cgit v1.2.3 From e56b6a5dda1a36ffaa532df6f975ea324298fa4d Mon Sep 17 00:00:00 2001 From: Christoph Hellwig Date: Mon, 19 May 2008 07:53:34 +0200 Subject: Re: [PATCH 3/6] vfs: open_exec cleanup On Mon, May 19, 2008 at 12:01:49AM +0200, Marcin Slusarz wrote: > open_exec is needlessly indented, calls ERR_PTR with 0 argument > (which is not valid errno) and jumps into middle of function > just to return value. > So clean it up a bit. Still looks rather messy. See below for a better version. Signed-off-by: Christoph Hellwig Signed-off-by: Al Viro --- fs/exec.c | 58 ++++++++++++++++++++++++++++++---------------------------- 1 file changed, 30 insertions(+), 28 deletions(-) (limited to 'fs/exec.c') diff --git a/fs/exec.c b/fs/exec.c index 0ba5d355c5a1..346e3f69c6e0 100644 --- a/fs/exec.c +++ b/fs/exec.c @@ -656,38 +656,40 @@ EXPORT_SYMBOL(setup_arg_pages); struct file *open_exec(const char *name) { struct nameidata nd; - int err; struct file *file; + int err; - err = path_lookup_open(AT_FDCWD, name, LOOKUP_FOLLOW, &nd, FMODE_READ|FMODE_EXEC); - file = ERR_PTR(err); - - if (!err) { - struct inode *inode = nd.path.dentry->d_inode; - file = ERR_PTR(-EACCES); - if (S_ISREG(inode->i_mode)) { - int err = vfs_permission(&nd, MAY_EXEC | MAY_OPEN); - file = ERR_PTR(err); - if (!err) { - file = nameidata_to_filp(&nd, - O_RDONLY|O_LARGEFILE); - if (!IS_ERR(file)) { - err = deny_write_access(file); - if (err) { - fput(file); - file = ERR_PTR(err); - } - } -out: - return file; - } - } - release_open_intent(&nd); - path_put(&nd.path); + err = path_lookup_open(AT_FDCWD, name, LOOKUP_FOLLOW, &nd, + FMODE_READ|FMODE_EXEC); + if (err) + goto out; + + err = -EACCES; + if (!S_ISREG(nd.path.dentry->d_inode->i_mode)) + goto out_path_put; + + err = vfs_permission(&nd, MAY_EXEC | MAY_OPEN); + if (err) + goto out_path_put; + + file = nameidata_to_filp(&nd, O_RDONLY|O_LARGEFILE); + if (IS_ERR(file)) + return file; + + err = deny_write_access(file); + if (err) { + fput(file); + goto out; } - goto out; -} + return file; + + out_path_put: + release_open_intent(&nd); + path_put(&nd.path); + out: + return ERR_PTR(err); +} EXPORT_SYMBOL(open_exec); int kernel_read(struct file *file, unsigned long offset, -- cgit v1.2.3 From 30524472c2f728c20d6bf35191042a5d455c0a64 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Tue, 22 Jul 2008 00:02:33 -0400 Subject: [PATCH] take noexec checks to very few callers that care Signed-off-by: Al Viro --- fs/exec.c | 7 +++++++ fs/namei.c | 9 --------- fs/open.c | 10 ++++++++++ 3 files changed, 17 insertions(+), 9 deletions(-) (limited to 'fs/exec.c') diff --git a/fs/exec.c b/fs/exec.c index 346e3f69c6e0..eca58c29eded 100644 --- a/fs/exec.c +++ b/fs/exec.c @@ -118,6 +118,10 @@ asmlinkage long sys_uselib(const char __user * library) if (!S_ISREG(nd.path.dentry->d_inode->i_mode)) goto exit; + error = -EACCES; + if (nd.path.mnt->mnt_flags & MNT_NOEXEC) + goto exit; + error = vfs_permission(&nd, MAY_READ | MAY_EXEC | MAY_OPEN); if (error) goto exit; @@ -668,6 +672,9 @@ struct file *open_exec(const char *name) if (!S_ISREG(nd.path.dentry->d_inode->i_mode)) goto out_path_put; + if (nd.path.mnt->mnt_flags & MNT_NOEXEC) + goto out_path_put; + err = vfs_permission(&nd, MAY_EXEC | MAY_OPEN); if (err) goto out_path_put; diff --git a/fs/namei.c b/fs/namei.c index 6d75430358ac..396cb3e5c364 100644 --- a/fs/namei.c +++ b/fs/namei.c @@ -252,15 +252,6 @@ int permission(struct inode *inode, int mask, struct nameidata *nd) return -EACCES; } - if ((mask & MAY_EXEC) && S_ISREG(inode->i_mode)) { - /* - * MAY_EXEC on regular files is denied if the fs is mounted - * with the "noexec" flag. - */ - if (mnt && (mnt->mnt_flags & MNT_NOEXEC)) - return -EACCES; - } - /* Ordinary permission routines do not understand MAY_APPEND. */ if (inode->i_op && inode->i_op->permission) { retval = inode->i_op->permission(inode, mask); diff --git a/fs/open.c b/fs/open.c index 3b3c43674be3..d5e421ad0cf6 100644 --- a/fs/open.c +++ b/fs/open.c @@ -461,6 +461,16 @@ asmlinkage long sys_faccessat(int dfd, const char __user *filename, int mode) if (res) goto out; + if ((mode & MAY_EXEC) && S_ISREG(nd.path.dentry->d_inode->i_mode)) { + /* + * MAY_EXEC on regular files is denied if the fs is mounted + * with the "noexec" flag. + */ + res = -EACCES; + if (nd.path.mnt->mnt_flags & MNT_NOEXEC) + goto out_path_release; + } + res = vfs_permission(&nd, mode | MAY_ACCESS); /* SuS v2 requires we report a read only fs too */ if(res || !(mode & S_IWOTH) || -- cgit v1.2.3 From 964bd183624c03680796b63b4ab97ee3905a806a Mon Sep 17 00:00:00 2001 From: Al Viro Date: Sat, 26 Jul 2008 03:33:14 -0400 Subject: [PATCH] get rid of __user_path_lookup_open Signed-off-by: Al Viro --- fs/exec.c | 14 ++++++++++---- fs/namei.c | 13 ------------- include/linux/namei.h | 1 - 3 files changed, 10 insertions(+), 18 deletions(-) (limited to 'fs/exec.c') diff --git a/fs/exec.c b/fs/exec.c index eca58c29eded..9696bbf0f0b1 100644 --- a/fs/exec.c +++ b/fs/exec.c @@ -106,11 +106,17 @@ static inline void put_binfmt(struct linux_binfmt * fmt) */ asmlinkage long sys_uselib(const char __user * library) { - struct file * file; + struct file *file; struct nameidata nd; - int error; - - error = __user_path_lookup_open(library, LOOKUP_FOLLOW, &nd, FMODE_READ|FMODE_EXEC); + char *tmp = getname(library); + int error = PTR_ERR(tmp); + + if (!IS_ERR(tmp)) { + error = path_lookup_open(AT_FDCWD, tmp, + LOOKUP_FOLLOW, &nd, + FMODE_READ|FMODE_EXEC); + putname(tmp); + } if (error) goto out; diff --git a/fs/namei.c b/fs/namei.c index 38ceb6e06eba..a7b0a0b80128 100644 --- a/fs/namei.c +++ b/fs/namei.c @@ -1193,19 +1193,6 @@ static int path_lookup_create(int dfd, const char *name, nd, open_flags, create_mode); } -int __user_path_lookup_open(const char __user *name, unsigned int lookup_flags, - struct nameidata *nd, int open_flags) -{ - char *tmp = getname(name); - int err = PTR_ERR(tmp); - - if (!IS_ERR(tmp)) { - err = __path_lookup_intent_open(AT_FDCWD, tmp, lookup_flags, nd, open_flags, 0); - putname(tmp); - } - return err; -} - static struct dentry *__lookup_hash(struct qstr *name, struct dentry *base, struct nameidata *nd) { diff --git a/include/linux/namei.h b/include/linux/namei.h index 00888ff69504..68f8c3203c89 100644 --- a/include/linux/namei.h +++ b/include/linux/namei.h @@ -65,7 +65,6 @@ extern int path_lookup(const char *, unsigned, struct nameidata *); extern int vfs_path_lookup(struct dentry *, struct vfsmount *, const char *, unsigned int, struct nameidata *); -extern int __user_path_lookup_open(const char __user *, unsigned lookup_flags, struct nameidata *nd, int open_flags); extern int path_lookup_open(int dfd, const char *name, unsigned lookup_flags, struct nameidata *, int open_flags); extern struct file *lookup_instantiate_filp(struct nameidata *nd, struct dentry *dentry, int (*open)(struct inode *, struct file *)); -- cgit v1.2.3 From ca5b172bd2b2fe489e7ba11cedd46ddf772d132f Mon Sep 17 00:00:00 2001 From: Hugh Dickins Date: Mon, 28 Jul 2008 15:46:18 -0700 Subject: exec: include pagemap.h again to fix build Fix compilation errors on avr32 and without CONFIG_SWAP, introduced by ba92a43dbaee339cf5915ef766d3d3ffbaaf103c ("exec: remove some includes") In file included from include/asm/tlb.h:24, from fs/exec.c:55: include/asm-generic/tlb.h: In function 'tlb_flush_mmu': include/asm-generic/tlb.h:76: error: implicit declaration of function 'release_pages' include/asm-generic/tlb.h: In function 'tlb_remove_page': include/asm-generic/tlb.h:105: error: implicit declaration of function 'page_cache_release' make[1]: *** [fs/exec.o] Error 1 This straightforward part-revert is nobody's favourite patch to address the underlying tlb.h needs swap.h needs pagemap.h (but sparc won't like that) mess; but appropriate to fix the build now before any overhaul. Reported-by: Yoichi Yuasa Reported-by: Haavard Skinnemoen Signed-off-by: Hugh Dickins Tested-by: Adrian Bunk Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- fs/exec.c | 1 + 1 file changed, 1 insertion(+) (limited to 'fs/exec.c') diff --git a/fs/exec.c b/fs/exec.c index 9696bbf0f0b1..32993beecbe9 100644 --- a/fs/exec.c +++ b/fs/exec.c @@ -32,6 +32,7 @@ #include #include #include +#include #include #include #include -- cgit v1.2.3