From 0d094efeb1e98010c6b99923f1eb7e17bf1e3a74 Mon Sep 17 00:00:00 2001 From: Roland McGrath Date: Fri, 25 Jul 2008 19:45:49 -0700 Subject: tracehook: tracehook_tracer_task This adds the tracehook_tracer_task() hook to consolidate all forms of "Who is using ptrace on me?" logic. This is used for "TracerPid:" in /proc and for permission checks. We also clean up the selinux code the called an identical accessor. Signed-off-by: Roland McGrath Cc: Oleg Nesterov Reviewed-by: Ingo Molnar Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- security/selinux/hooks.c | 22 +++------------------- 1 file changed, 3 insertions(+), 19 deletions(-) (limited to 'security/selinux/hooks.c') diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c index 63f131fc42e..3481cde5bf1 100644 --- a/security/selinux/hooks.c +++ b/security/selinux/hooks.c @@ -25,7 +25,7 @@ #include #include -#include +#include #include #include #include @@ -1971,22 +1971,6 @@ static int selinux_vm_enough_memory(struct mm_struct *mm, long pages) return __vm_enough_memory(mm, pages, cap_sys_admin); } -/** - * task_tracer_task - return the task that is tracing the given task - * @task: task to consider - * - * Returns NULL if noone is tracing @task, or the &struct task_struct - * pointer to its tracer. - * - * Must be called under rcu_read_lock(). - */ -static struct task_struct *task_tracer_task(struct task_struct *task) -{ - if (task->ptrace & PT_PTRACED) - return rcu_dereference(task->parent); - return NULL; -} - /* binprm security operations */ static int selinux_bprm_alloc_security(struct linux_binprm *bprm) @@ -2238,7 +2222,7 @@ static void selinux_bprm_apply_creds(struct linux_binprm *bprm, int unsafe) u32 ptsid = 0; rcu_read_lock(); - tracer = task_tracer_task(current); + tracer = tracehook_tracer_task(current); if (likely(tracer != NULL)) { sec = tracer->security; ptsid = sec->sid; @@ -5247,7 +5231,7 @@ static int selinux_setprocattr(struct task_struct *p, Otherwise, leave SID unchanged and fail. */ task_lock(p); rcu_read_lock(); - tracer = task_tracer_task(p); + tracer = tracehook_tracer_task(p); if (tracer != NULL) { struct task_security_struct *ptsec = tracer->security; u32 ptsid = ptsec->sid; -- cgit v1.2.3-70-g09d2 From 6c5a9d2e1599a099b0e47235a1c1502162b14310 Mon Sep 17 00:00:00 2001 From: Alexey Dobriyan Date: Sat, 26 Jul 2008 17:48:15 -0700 Subject: selinux: use nf_register_hooks() Signed-off-by: Alexey Dobriyan Acked-by: James Morris Signed-off-by: Patrick McHardy Signed-off-by: David S. Miller --- security/selinux/hooks.c | 27 ++++++++------------------- 1 file changed, 8 insertions(+), 19 deletions(-) (limited to 'security/selinux/hooks.c') diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c index 63f131fc42e..df0515dd4d1 100644 --- a/security/selinux/hooks.c +++ b/security/selinux/hooks.c @@ -5670,27 +5670,20 @@ static struct nf_hook_ops selinux_ipv6_ops[] = { static int __init selinux_nf_ip_init(void) { int err = 0; - u32 iter; if (!selinux_enabled) goto out; printk(KERN_DEBUG "SELinux: Registering netfilter hooks\n"); - for (iter = 0; iter < ARRAY_SIZE(selinux_ipv4_ops); iter++) { - err = nf_register_hook(&selinux_ipv4_ops[iter]); - if (err) - panic("SELinux: nf_register_hook for IPv4: error %d\n", - err); - } + err = nf_register_hooks(selinux_ipv4_ops, ARRAY_SIZE(selinux_ipv4_ops)); + if (err) + panic("SELinux: nf_register_hooks for IPv4: error %d\n", err); #if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) - for (iter = 0; iter < ARRAY_SIZE(selinux_ipv6_ops); iter++) { - err = nf_register_hook(&selinux_ipv6_ops[iter]); - if (err) - panic("SELinux: nf_register_hook for IPv6: error %d\n", - err); - } + err = nf_register_hooks(selinux_ipv6_ops, ARRAY_SIZE(selinux_ipv6_ops)); + if (err) + panic("SELinux: nf_register_hooks for IPv6: error %d\n", err); #endif /* IPV6 */ out: @@ -5702,15 +5695,11 @@ __initcall(selinux_nf_ip_init); #ifdef CONFIG_SECURITY_SELINUX_DISABLE static void selinux_nf_ip_exit(void) { - u32 iter; - printk(KERN_DEBUG "SELinux: Unregistering netfilter hooks\n"); - for (iter = 0; iter < ARRAY_SIZE(selinux_ipv4_ops); iter++) - nf_unregister_hook(&selinux_ipv4_ops[iter]); + nf_unregister_hooks(selinux_ipv4_ops, ARRAY_SIZE(selinux_ipv4_ops)); #if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) - for (iter = 0; iter < ARRAY_SIZE(selinux_ipv6_ops); iter++) - nf_unregister_hook(&selinux_ipv6_ops[iter]); + nf_unregister_hooks(selinux_ipv6_ops, ARRAY_SIZE(selinux_ipv6_ops)); #endif /* IPV6 */ } #endif -- cgit v1.2.3-70-g09d2 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 'security/selinux/hooks.c') diff --git a/fs/exec.c b/fs/exec.c index b8792a13153..0ba5d355c5a 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 33dcaf025c4..6b0e8e5e079 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 f0e9adb22ac..fd96e7f8a6f 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 5b01c0b0242..63d10da515a 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 59f23b5918b..78ed3ffde24 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 3481cde5bf1..5ba13908b5b 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 ee5a51cbc5e..1b40e558f98 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-70-g09d2 From 383795c206946777d87ed5f6d61d6659110f9344 Mon Sep 17 00:00:00 2001 From: Eric Paris Date: Tue, 29 Jul 2008 17:07:26 -0400 Subject: SELinux: /proc/mounts should show what it can Given a hosed SELinux config in which a system never loads policy or disables SELinux we currently just return -EINVAL for anyone trying to read /proc/mounts. This is a configuration problem but we can certainly be more graceful. This patch just ignores -EINVAL when displaying LSM options and causes /proc/mounts display everything else it can. If policy isn't loaded the obviously there are no options, so we aren't really loosing any information here. This is safe as the only other return of EINVAL comes from security_sid_to_context_core() in the case of an invalid sid. Even if a FS was mounted with a now invalidated context that sid should have been remapped to unlabeled and so we won't hit the EINVAL and will work like we should. (yes, I tested to make sure it worked like I thought) Signed-off-by: Eric Paris Tested-by: Marc Dionne Signed-off-by: James Morris --- security/selinux/hooks.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) (limited to 'security/selinux/hooks.c') diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c index 40d06c533f8..3ae9bec5a50 100644 --- a/security/selinux/hooks.c +++ b/security/selinux/hooks.c @@ -998,8 +998,12 @@ static int selinux_sb_show_options(struct seq_file *m, struct super_block *sb) int rc; rc = selinux_get_mnt_opts(sb, &opts); - if (rc) + if (rc) { + /* before policy load we may get EINVAL, don't show anything */ + if (rc == -EINVAL) + rc = 0; return rc; + } selinux_write_opts(m, &opts); -- cgit v1.2.3-70-g09d2