From 8fd00b4d7014b00448eb33cf0590815304769798 Mon Sep 17 00:00:00 2001 From: Jiri Slaby Date: Wed, 26 Aug 2009 18:41:16 +0200 Subject: rlimits: security, add task_struct to setrlimit Add task_struct to task_setrlimit of security_operations to be able to set rlimit of task other than current. Signed-off-by: Jiri Slaby Acked-by: Eric Paris Acked-by: James Morris --- include/linux/security.h | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) (limited to 'include/linux/security.h') diff --git a/include/linux/security.h b/include/linux/security.h index 0c8819170463..1a3eb5ff4357 100644 --- a/include/linux/security.h +++ b/include/linux/security.h @@ -1501,7 +1501,8 @@ struct security_operations { int (*task_setnice) (struct task_struct *p, int nice); int (*task_setioprio) (struct task_struct *p, int ioprio); int (*task_getioprio) (struct task_struct *p); - int (*task_setrlimit) (unsigned int resource, struct rlimit *new_rlim); + int (*task_setrlimit) (struct task_struct *p, unsigned int resource, + struct rlimit *new_rlim); int (*task_setscheduler) (struct task_struct *p, int policy, struct sched_param *lp); int (*task_getscheduler) (struct task_struct *p); @@ -1751,7 +1752,8 @@ void security_task_getsecid(struct task_struct *p, u32 *secid); int security_task_setnice(struct task_struct *p, int nice); int security_task_setioprio(struct task_struct *p, int ioprio); int security_task_getioprio(struct task_struct *p); -int security_task_setrlimit(unsigned int resource, struct rlimit *new_rlim); +int security_task_setrlimit(struct task_struct *p, unsigned int resource, + struct rlimit *new_rlim); int security_task_setscheduler(struct task_struct *p, int policy, struct sched_param *lp); int security_task_getscheduler(struct task_struct *p); @@ -2313,7 +2315,8 @@ static inline int security_task_getioprio(struct task_struct *p) return 0; } -static inline int security_task_setrlimit(unsigned int resource, +static inline int security_task_setrlimit(struct task_struct *p, + unsigned int resource, struct rlimit *new_rlim) { return 0; -- cgit v1.2.3 From c4ec54b40d33f8016fea970a383cc584dd0e6019 Mon Sep 17 00:00:00 2001 From: Eric Paris Date: Thu, 17 Dec 2009 21:24:34 -0500 Subject: fsnotify: new fsnotify hooks and events types for access decisions introduce a new fsnotify hook, fsnotify_perm(), which is called from the security code. This hook is used to allow fsnotify groups to make access control decisions about events on the system. We also must change the generic fsnotify function to return an error code if we intend these hooks to be in any way useful. Signed-off-by: Eric Paris --- fs/notify/fsnotify.c | 47 ++++++++++++++++++++-------------------- include/linux/fsnotify.h | 19 ++++++++++++++++ include/linux/fsnotify_backend.h | 15 ++++++++----- include/linux/security.h | 1 + security/security.c | 16 ++++++++++++-- 5 files changed, 68 insertions(+), 30 deletions(-) (limited to 'include/linux/security.h') diff --git a/fs/notify/fsnotify.c b/fs/notify/fsnotify.c index c5adf833bf6a..668268627894 100644 --- a/fs/notify/fsnotify.c +++ b/fs/notify/fsnotify.c @@ -169,27 +169,22 @@ void __fsnotify_flush_ignored_mask(struct inode *inode, void *data, int data_is) } } -static void send_to_group(struct fsnotify_group *group, struct inode *to_tell, - struct vfsmount *mnt, __u32 mask, void *data, - int data_is, u32 cookie, const unsigned char *file_name, - struct fsnotify_event **event) +static int send_to_group(struct fsnotify_group *group, struct inode *to_tell, + struct vfsmount *mnt, __u32 mask, void *data, + int data_is, u32 cookie, const unsigned char *file_name, + struct fsnotify_event **event) { if (!group->ops->should_send_event(group, to_tell, mnt, mask, data, data_is)) - return; + return 0; if (!*event) { *event = fsnotify_create_event(to_tell, mask, data, data_is, file_name, cookie, GFP_KERNEL); - /* - * shit, we OOM'd and now we can't tell, maybe - * someday someone else will want to do something - * here - */ if (!*event) - return; + return -ENOMEM; } - group->ops->handle_event(group, *event); + return group->ops->handle_event(group, *event); } static bool needed_by_vfsmount(__u32 test_mask, struct vfsmount *mnt) @@ -206,20 +201,20 @@ static bool needed_by_vfsmount(__u32 test_mask, struct vfsmount *mnt) * out to all of the registered fsnotify_group. Those groups can then use the * notification event in whatever means they feel necessary. */ -void fsnotify(struct inode *to_tell, __u32 mask, void *data, int data_is, - const unsigned char *file_name, u32 cookie) +int fsnotify(struct inode *to_tell, __u32 mask, void *data, int data_is, + const unsigned char *file_name, u32 cookie) { struct fsnotify_group *group; struct fsnotify_event *event = NULL; struct vfsmount *mnt = NULL; - int idx; + int idx, ret = 0; /* global tests shouldn't care about events on child only the specific event */ __u32 test_mask = (mask & ~FS_EVENT_ON_CHILD); /* if no fsnotify listeners, nothing to do */ if (list_empty(&fsnotify_inode_groups) && list_empty(&fsnotify_vfsmount_groups)) - return; + return 0; if (mask & FS_MODIFY) __fsnotify_flush_ignored_mask(to_tell, data, data_is); @@ -227,7 +222,7 @@ void fsnotify(struct inode *to_tell, __u32 mask, void *data, int data_is, /* if none of the directed listeners or vfsmount listeners care */ if (!(test_mask & fsnotify_inode_mask) && !(test_mask & fsnotify_vfsmount_mask)) - return; + return 0; if (data_is == FSNOTIFY_EVENT_PATH) mnt = ((struct path *)data)->mnt; @@ -236,7 +231,7 @@ void fsnotify(struct inode *to_tell, __u32 mask, void *data, int data_is, * listeners list cares, nothing to do */ if (!(test_mask & to_tell->i_fsnotify_mask) && !needed_by_vfsmount(test_mask, mnt)) - return; + return 0; /* * SRCU!! the groups list is very very much read only and the path is @@ -248,20 +243,24 @@ void fsnotify(struct inode *to_tell, __u32 mask, void *data, int data_is, if (test_mask & to_tell->i_fsnotify_mask) { list_for_each_entry_rcu(group, &fsnotify_inode_groups, inode_group_list) { if (test_mask & group->mask) { - send_to_group(group, to_tell, NULL, mask, data, data_is, - cookie, file_name, &event); + ret = send_to_group(group, to_tell, NULL, mask, data, data_is, + cookie, file_name, &event); + if (ret) + goto out; } } } if (needed_by_vfsmount(test_mask, mnt)) { list_for_each_entry_rcu(group, &fsnotify_vfsmount_groups, vfsmount_group_list) { if (test_mask & group->mask) { - send_to_group(group, to_tell, mnt, mask, data, data_is, - cookie, file_name, &event); + ret = send_to_group(group, to_tell, mnt, mask, data, data_is, + cookie, file_name, &event); + if (ret) + goto out; } } } - +out: srcu_read_unlock(&fsnotify_grp_srcu, idx); /* * fsnotify_create_event() took a reference so the event can't be cleaned @@ -269,6 +268,8 @@ void fsnotify(struct inode *to_tell, __u32 mask, void *data, int data_is, */ if (event) fsnotify_put_event(event); + + return 0; } EXPORT_SYMBOL_GPL(fsnotify); diff --git a/include/linux/fsnotify.h b/include/linux/fsnotify.h index b8cf161f5a6d..64efda9aae62 100644 --- a/include/linux/fsnotify.h +++ b/include/linux/fsnotify.h @@ -34,6 +34,25 @@ static inline void fsnotify_parent(struct path *path, struct dentry *dentry, __u __fsnotify_parent(path, dentry, mask); } +/* simple call site for access decisions */ +static inline int fsnotify_perm(struct file *file, int mask) +{ + struct path *path = &file->f_path; + struct inode *inode = path->dentry->d_inode; + __u32 fsnotify_mask; + + if (file->f_mode & FMODE_NONOTIFY) + return 0; + if (!(mask & (MAY_READ | MAY_OPEN))) + return 0; + if (mask & MAY_READ) + fsnotify_mask = FS_ACCESS_PERM; + if (mask & MAY_OPEN) + fsnotify_mask = FS_OPEN_PERM; + + return fsnotify(inode, fsnotify_mask, path, FSNOTIFY_EVENT_PATH, NULL, 0); +} + /* * fsnotify_d_move - dentry has been moved * Called with dcache_lock and dentry->d_lock held. diff --git a/include/linux/fsnotify_backend.h b/include/linux/fsnotify_backend.h index efe9ba321cf2..c34728e7d8cb 100644 --- a/include/linux/fsnotify_backend.h +++ b/include/linux/fsnotify_backend.h @@ -41,6 +41,9 @@ #define FS_Q_OVERFLOW 0x00004000 /* Event queued overflowed */ #define FS_IN_IGNORED 0x00008000 /* last inotify event here */ +#define FS_OPEN_PERM 0x00010000 /* open event in an permission hook */ +#define FS_ACCESS_PERM 0x00020000 /* access event in a permissions hook */ + #define FS_IN_ISDIR 0x40000000 /* event occurred against dir */ #define FS_IN_ONESHOT 0x80000000 /* only send event once */ @@ -282,8 +285,8 @@ struct fsnotify_mark { /* called from the vfs helpers */ /* main fsnotify call to send events */ -extern void fsnotify(struct inode *to_tell, __u32 mask, void *data, int data_is, - const unsigned char *name, u32 cookie); +extern int fsnotify(struct inode *to_tell, __u32 mask, void *data, int data_is, + const unsigned char *name, u32 cookie); extern void __fsnotify_parent(struct path *path, struct dentry *dentry, __u32 mask); extern void __fsnotify_inode_delete(struct inode *inode); extern void __fsnotify_vfsmount_delete(struct vfsmount *mnt); @@ -413,9 +416,11 @@ extern int fsnotify_replace_event(struct fsnotify_event_holder *old_holder, #else -static inline void fsnotify(struct inode *to_tell, __u32 mask, void *data, int data_is, - const unsigned char *name, u32 cookie) -{} +static inline int fsnotify(struct inode *to_tell, __u32 mask, void *data, int data_is, + const unsigned char *name, u32 cookie) +{ + return 0; +} static inline void __fsnotify_parent(struct path *path, struct dentry *dentry, __u32 mask) {} diff --git a/include/linux/security.h b/include/linux/security.h index 0c8819170463..24fc29540aa3 100644 --- a/include/linux/security.h +++ b/include/linux/security.h @@ -23,6 +23,7 @@ #define __LINUX_SECURITY_H #include +#include #include #include #include diff --git a/security/security.c b/security/security.c index 351942a4ca0e..f6ac27cd3452 100644 --- a/security/security.c +++ b/security/security.c @@ -620,7 +620,13 @@ void security_inode_getsecid(const struct inode *inode, u32 *secid) int security_file_permission(struct file *file, int mask) { - return security_ops->file_permission(file, mask); + int ret; + + ret = security_ops->file_permission(file, mask); + if (ret) + return ret; + + return fsnotify_perm(file, mask); } int security_file_alloc(struct file *file) @@ -684,7 +690,13 @@ int security_file_receive(struct file *file) int security_dentry_open(struct file *file, const struct cred *cred) { - return security_ops->dentry_open(file, cred); + int ret; + + ret = security_ops->dentry_open(file, cred); + if (ret) + return ret; + + return fsnotify_perm(file, MAY_OPEN); } int security_task_create(unsigned long clone_flags) -- cgit v1.2.3 From ea0d3ab239fba48d6e998b19c28d78f765963007 Mon Sep 17 00:00:00 2001 From: Tetsuo Handa Date: Wed, 2 Jun 2010 13:24:43 +0900 Subject: LSM: Remove unused arguments from security_path_truncate(). When commit be6d3e56a6b9b3a4ee44a0685e39e595073c6f0d "introduce new LSM hooks where vfsmount is available." was proposed, regarding security_path_truncate(), only "struct file *" argument (which AppArmor wanted to use) was removed. But length and time_attrs arguments are not used by TOMOYO nor AppArmor. Thus, let's remove these arguments. Signed-off-by: Tetsuo Handa Acked-by: Nick Piggin Signed-off-by: James Morris --- fs/namei.c | 3 +-- fs/open.c | 5 ++--- include/linux/security.h | 11 +++-------- security/capability.c | 3 +-- security/security.c | 5 ++--- security/tomoyo/tomoyo.c | 3 +-- 6 files changed, 10 insertions(+), 20 deletions(-) (limited to 'include/linux/security.h') diff --git a/fs/namei.c b/fs/namei.c index 868d0cb9d473..fe34c2b879f4 100644 --- a/fs/namei.c +++ b/fs/namei.c @@ -1484,8 +1484,7 @@ static int handle_truncate(struct path *path) */ error = locks_verify_locked(inode); if (!error) - error = security_path_truncate(path, 0, - ATTR_MTIME|ATTR_CTIME|ATTR_OPEN); + error = security_path_truncate(path); if (!error) { error = do_truncate(path->dentry, 0, ATTR_MTIME|ATTR_CTIME|ATTR_OPEN, diff --git a/fs/open.c b/fs/open.c index 5463266db9e6..a54ed85209c1 100644 --- a/fs/open.c +++ b/fs/open.c @@ -110,7 +110,7 @@ static long do_sys_truncate(const char __user *pathname, loff_t length) error = locks_verify_truncate(inode, NULL, length); if (!error) - error = security_path_truncate(&path, length, 0); + error = security_path_truncate(&path); if (!error) error = do_truncate(path.dentry, length, 0, NULL); @@ -165,8 +165,7 @@ static long do_sys_ftruncate(unsigned int fd, loff_t length, int small) error = locks_verify_truncate(inode, file, length); if (!error) - error = security_path_truncate(&file->f_path, length, - ATTR_MTIME|ATTR_CTIME); + error = security_path_truncate(&file->f_path); if (!error) error = do_truncate(dentry, length, ATTR_MTIME|ATTR_CTIME, file); out_putf: diff --git a/include/linux/security.h b/include/linux/security.h index 0c8819170463..723a93df756a 100644 --- a/include/linux/security.h +++ b/include/linux/security.h @@ -470,8 +470,6 @@ static inline void security_free_mnt_opts(struct security_mnt_opts *opts) * @path_truncate: * Check permission before truncating a file. * @path contains the path structure for the file. - * @length is the new length of the file. - * @time_attrs is the flags passed to do_truncate(). * Return 0 if permission is granted. * @inode_getattr: * Check permission before obtaining file attributes. @@ -1412,8 +1410,7 @@ struct security_operations { int (*path_rmdir) (struct path *dir, struct dentry *dentry); int (*path_mknod) (struct path *dir, struct dentry *dentry, int mode, unsigned int dev); - int (*path_truncate) (struct path *path, loff_t length, - unsigned int time_attrs); + int (*path_truncate) (struct path *path); int (*path_symlink) (struct path *dir, struct dentry *dentry, const char *old_name); int (*path_link) (struct dentry *old_dentry, struct path *new_dir, @@ -2806,8 +2803,7 @@ int security_path_mkdir(struct path *dir, struct dentry *dentry, int mode); int security_path_rmdir(struct path *dir, struct dentry *dentry); int security_path_mknod(struct path *dir, struct dentry *dentry, int mode, unsigned int dev); -int security_path_truncate(struct path *path, loff_t length, - unsigned int time_attrs); +int security_path_truncate(struct path *path); int security_path_symlink(struct path *dir, struct dentry *dentry, const char *old_name); int security_path_link(struct dentry *old_dentry, struct path *new_dir, @@ -2841,8 +2837,7 @@ static inline int security_path_mknod(struct path *dir, struct dentry *dentry, return 0; } -static inline int security_path_truncate(struct path *path, loff_t length, - unsigned int time_attrs) +static inline int security_path_truncate(struct path *path) { return 0; } diff --git a/security/capability.c b/security/capability.c index 8168e3ecd5bf..4aeb699da1b3 100644 --- a/security/capability.c +++ b/security/capability.c @@ -268,8 +268,7 @@ static int cap_path_rename(struct path *old_path, struct dentry *old_dentry, return 0; } -static int cap_path_truncate(struct path *path, loff_t length, - unsigned int time_attrs) +static int cap_path_truncate(struct path *path) { return 0; } diff --git a/security/security.c b/security/security.c index 351942a4ca0e..e8c87b8601b4 100644 --- a/security/security.c +++ b/security/security.c @@ -417,12 +417,11 @@ int security_path_rename(struct path *old_dir, struct dentry *old_dentry, new_dentry); } -int security_path_truncate(struct path *path, loff_t length, - unsigned int time_attrs) +int security_path_truncate(struct path *path) { if (unlikely(IS_PRIVATE(path->dentry->d_inode))) return 0; - return security_ops->path_truncate(path, length, time_attrs); + return security_ops->path_truncate(path); } int security_path_chmod(struct dentry *dentry, struct vfsmount *mnt, diff --git a/security/tomoyo/tomoyo.c b/security/tomoyo/tomoyo.c index 57d442e7339b..7be732cadd47 100644 --- a/security/tomoyo/tomoyo.c +++ b/security/tomoyo/tomoyo.c @@ -93,8 +93,7 @@ static int tomoyo_bprm_check_security(struct linux_binprm *bprm) return tomoyo_check_open_permission(domain, &bprm->file->f_path, O_RDONLY); } -static int tomoyo_path_truncate(struct path *path, loff_t length, - unsigned int time_attrs) +static int tomoyo_path_truncate(struct path *path) { return tomoyo_path_perm(TOMOYO_TYPE_TRUNCATE, path); } -- cgit v1.2.3 From b0ae19811375031ae3b3fecc65b702a9c6e5cc28 Mon Sep 17 00:00:00 2001 From: KOSAKI Motohiro Date: Fri, 15 Oct 2010 04:21:18 +0900 Subject: security: remove unused parameter from security_task_setscheduler() All security modules shouldn't change sched_param parameter of security_task_setscheduler(). This is not only meaningless, but also make a harmful result if caller pass a static variable. This patch remove policy and sched_param parameter from security_task_setscheduler() becuase none of security module is using it. Cc: James Morris Signed-off-by: KOSAKI Motohiro Signed-off-by: James Morris --- arch/mips/kernel/mips-mt-fpaff.c | 2 +- include/linux/security.h | 14 +++++--------- kernel/cpuset.c | 4 ++-- kernel/sched.c | 4 ++-- security/commoncap.c | 5 +---- security/security.c | 5 ++--- security/selinux/hooks.c | 4 ++-- security/smack/smack_lsm.c | 5 ++--- 8 files changed, 17 insertions(+), 26 deletions(-) (limited to 'include/linux/security.h') diff --git a/arch/mips/kernel/mips-mt-fpaff.c b/arch/mips/kernel/mips-mt-fpaff.c index 2340f11dc29c..9a526ba6f257 100644 --- a/arch/mips/kernel/mips-mt-fpaff.c +++ b/arch/mips/kernel/mips-mt-fpaff.c @@ -103,7 +103,7 @@ asmlinkage long mipsmt_sys_sched_setaffinity(pid_t pid, unsigned int len, if (!check_same_owner(p) && !capable(CAP_SYS_NICE)) goto out_unlock; - retval = security_task_setscheduler(p, 0, NULL); + retval = security_task_setscheduler(p) if (retval) goto out_unlock; diff --git a/include/linux/security.h b/include/linux/security.h index a22219afff09..294a0b228123 100644 --- a/include/linux/security.h +++ b/include/linux/security.h @@ -74,7 +74,7 @@ extern int cap_file_mmap(struct file *file, unsigned long reqprot, extern int cap_task_fix_setuid(struct cred *new, const struct cred *old, int flags); extern int cap_task_prctl(int option, unsigned long arg2, unsigned long arg3, unsigned long arg4, unsigned long arg5); -extern int cap_task_setscheduler(struct task_struct *p, int policy, struct sched_param *lp); +extern int cap_task_setscheduler(struct task_struct *p); extern int cap_task_setioprio(struct task_struct *p, int ioprio); extern int cap_task_setnice(struct task_struct *p, int nice); extern int cap_syslog(int type, bool from_file); @@ -1501,8 +1501,7 @@ struct security_operations { int (*task_getioprio) (struct task_struct *p); int (*task_setrlimit) (struct task_struct *p, unsigned int resource, struct rlimit *new_rlim); - int (*task_setscheduler) (struct task_struct *p, int policy, - struct sched_param *lp); + int (*task_setscheduler) (struct task_struct *p); int (*task_getscheduler) (struct task_struct *p); int (*task_movememory) (struct task_struct *p); int (*task_kill) (struct task_struct *p, @@ -1752,8 +1751,7 @@ int security_task_setioprio(struct task_struct *p, int ioprio); int security_task_getioprio(struct task_struct *p); int security_task_setrlimit(struct task_struct *p, unsigned int resource, struct rlimit *new_rlim); -int security_task_setscheduler(struct task_struct *p, - int policy, struct sched_param *lp); +int security_task_setscheduler(struct task_struct *p); int security_task_getscheduler(struct task_struct *p); int security_task_movememory(struct task_struct *p); int security_task_kill(struct task_struct *p, struct siginfo *info, @@ -2320,11 +2318,9 @@ static inline int security_task_setrlimit(struct task_struct *p, return 0; } -static inline int security_task_setscheduler(struct task_struct *p, - int policy, - struct sched_param *lp) +static inline int security_task_setscheduler(struct task_struct *p) { - return cap_task_setscheduler(p, policy, lp); + return cap_task_setscheduler(p); } static inline int security_task_getscheduler(struct task_struct *p) diff --git a/kernel/cpuset.c b/kernel/cpuset.c index b23c0979bbe7..51b143e2a07a 100644 --- a/kernel/cpuset.c +++ b/kernel/cpuset.c @@ -1397,7 +1397,7 @@ static int cpuset_can_attach(struct cgroup_subsys *ss, struct cgroup *cont, if (tsk->flags & PF_THREAD_BOUND) return -EINVAL; - ret = security_task_setscheduler(tsk, 0, NULL); + ret = security_task_setscheduler(tsk); if (ret) return ret; if (threadgroup) { @@ -1405,7 +1405,7 @@ static int cpuset_can_attach(struct cgroup_subsys *ss, struct cgroup *cont, rcu_read_lock(); list_for_each_entry_rcu(c, &tsk->thread_group, thread_group) { - ret = security_task_setscheduler(c, 0, NULL); + ret = security_task_setscheduler(c); if (ret) { rcu_read_unlock(); return ret; diff --git a/kernel/sched.c b/kernel/sched.c index dc85ceb90832..df6579d9b4df 100644 --- a/kernel/sched.c +++ b/kernel/sched.c @@ -4645,7 +4645,7 @@ recheck: } if (user) { - retval = security_task_setscheduler(p, policy, param); + retval = security_task_setscheduler(p); if (retval) return retval; } @@ -4887,7 +4887,7 @@ long sched_setaffinity(pid_t pid, const struct cpumask *in_mask) if (!check_same_owner(p) && !capable(CAP_SYS_NICE)) goto out_unlock; - retval = security_task_setscheduler(p, 0, NULL); + retval = security_task_setscheduler(p); if (retval) goto out_unlock; diff --git a/security/commoncap.c b/security/commoncap.c index 9d172e6e330c..5e632b4857e4 100644 --- a/security/commoncap.c +++ b/security/commoncap.c @@ -719,14 +719,11 @@ static int cap_safe_nice(struct task_struct *p) /** * cap_task_setscheduler - Detemine if scheduler policy change is permitted * @p: The task to affect - * @policy: The policy to effect - * @lp: The parameters to the scheduling policy * * Detemine if the requested scheduler policy change is permitted for the * specified task, returning 0 if permission is granted, -ve if denied. */ -int cap_task_setscheduler(struct task_struct *p, int policy, - struct sched_param *lp) +int cap_task_setscheduler(struct task_struct *p) { return cap_safe_nice(p); } diff --git a/security/security.c b/security/security.c index 43b6463ebbfb..1cbcdfa4b015 100644 --- a/security/security.c +++ b/security/security.c @@ -778,10 +778,9 @@ int security_task_setrlimit(struct task_struct *p, unsigned int resource, return security_ops->task_setrlimit(p, resource, new_rlim); } -int security_task_setscheduler(struct task_struct *p, - int policy, struct sched_param *lp) +int security_task_setscheduler(struct task_struct *p) { - return security_ops->task_setscheduler(p, policy, lp); + return security_ops->task_setscheduler(p); } int security_task_getscheduler(struct task_struct *p) diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c index 4796ddd4e721..db2b331de89a 100644 --- a/security/selinux/hooks.c +++ b/security/selinux/hooks.c @@ -3354,11 +3354,11 @@ static int selinux_task_setrlimit(struct task_struct *p, unsigned int resource, return 0; } -static int selinux_task_setscheduler(struct task_struct *p, int policy, struct sched_param *lp) +static int selinux_task_setscheduler(struct task_struct *p) { int rc; - rc = cap_task_setscheduler(p, policy, lp); + rc = cap_task_setscheduler(p); if (rc) return rc; diff --git a/security/smack/smack_lsm.c b/security/smack/smack_lsm.c index c448d57ae2b7..174aec44bfac 100644 --- a/security/smack/smack_lsm.c +++ b/security/smack/smack_lsm.c @@ -1281,12 +1281,11 @@ static int smack_task_getioprio(struct task_struct *p) * * Return 0 if read access is permitted */ -static int smack_task_setscheduler(struct task_struct *p, int policy, - struct sched_param *lp) +static int smack_task_setscheduler(struct task_struct *p) { int rc; - rc = cap_task_setscheduler(p, policy, lp); + rc = cap_task_setscheduler(p); if (rc == 0) rc = smk_curacc_on_task(p, MAY_WRITE); return rc; -- cgit v1.2.3 From 2606fd1fa5710205b23ee859563502aa18362447 Mon Sep 17 00:00:00 2001 From: Eric Paris Date: Wed, 13 Oct 2010 16:24:41 -0400 Subject: secmark: make secmark object handling generic Right now secmark has lots of direct selinux calls. Use all LSM calls and remove all SELinux specific knowledge. The only SELinux specific knowledge we leave is the mode. The only point is to make sure that other LSMs at least test this generic code before they assume it works. (They may also have to make changes if they do not represent labels as strings) Signed-off-by: Eric Paris Acked-by: Paul Moore Acked-by: Patrick McHardy Signed-off-by: James Morris --- include/linux/netfilter/xt_SECMARK.h | 12 ++----- include/linux/security.h | 25 ++++++++++++++ include/linux/selinux.h | 63 ------------------------------------ net/netfilter/xt_CT.c | 1 - net/netfilter/xt_SECMARK.c | 35 ++++++++++---------- security/capability.c | 17 +++++++++- security/security.c | 18 +++++++++++ security/selinux/exports.c | 49 ---------------------------- security/selinux/hooks.c | 24 ++++++++++++++ security/selinux/include/security.h | 1 + 10 files changed, 104 insertions(+), 141 deletions(-) (limited to 'include/linux/security.h') diff --git a/include/linux/netfilter/xt_SECMARK.h b/include/linux/netfilter/xt_SECMARK.h index 6fcd3448b186..989092bd6274 100644 --- a/include/linux/netfilter/xt_SECMARK.h +++ b/include/linux/netfilter/xt_SECMARK.h @@ -11,18 +11,12 @@ * packets are being marked for. */ #define SECMARK_MODE_SEL 0x01 /* SELinux */ -#define SECMARK_SELCTX_MAX 256 - -struct xt_secmark_target_selinux_info { - __u32 selsid; - char selctx[SECMARK_SELCTX_MAX]; -}; +#define SECMARK_SECCTX_MAX 256 struct xt_secmark_target_info { __u8 mode; - union { - struct xt_secmark_target_selinux_info sel; - } u; + __u32 secid; + char secctx[SECMARK_SECCTX_MAX]; }; #endif /*_XT_SECMARK_H_target */ diff --git a/include/linux/security.h b/include/linux/security.h index 294a0b228123..d70adc394f62 100644 --- a/include/linux/security.h +++ b/include/linux/security.h @@ -959,6 +959,12 @@ static inline void security_free_mnt_opts(struct security_mnt_opts *opts) * Sets the new child socket's sid to the openreq sid. * @inet_conn_established: * Sets the connection's peersid to the secmark on skb. + * @secmark_relabel_packet: + * check if the process should be allowed to relabel packets to the given secid + * @security_secmark_refcount_inc + * tells the LSM to increment the number of secmark labeling rules loaded + * @security_secmark_refcount_dec + * tells the LSM to decrement the number of secmark labeling rules loaded * @req_classify_flow: * Sets the flow's sid to the openreq sid. * @tun_dev_create: @@ -1593,6 +1599,9 @@ struct security_operations { struct request_sock *req); void (*inet_csk_clone) (struct sock *newsk, const struct request_sock *req); void (*inet_conn_established) (struct sock *sk, struct sk_buff *skb); + int (*secmark_relabel_packet) (u32 secid); + void (*secmark_refcount_inc) (void); + void (*secmark_refcount_dec) (void); void (*req_classify_flow) (const struct request_sock *req, struct flowi *fl); int (*tun_dev_create)(void); void (*tun_dev_post_create)(struct sock *sk); @@ -2547,6 +2556,9 @@ void security_inet_csk_clone(struct sock *newsk, const struct request_sock *req); void security_inet_conn_established(struct sock *sk, struct sk_buff *skb); +int security_secmark_relabel_packet(u32 secid); +void security_secmark_refcount_inc(void); +void security_secmark_refcount_dec(void); int security_tun_dev_create(void); void security_tun_dev_post_create(struct sock *sk); int security_tun_dev_attach(struct sock *sk); @@ -2701,6 +2713,19 @@ static inline void security_inet_conn_established(struct sock *sk, { } +static inline int security_secmark_relabel_packet(u32 secid) +{ + return 0; +} + +static inline void security_secmark_refcount_inc(void) +{ +} + +static inline void security_secmark_refcount_dec(void) +{ +} + static inline int security_tun_dev_create(void) { return 0; diff --git a/include/linux/selinux.h b/include/linux/selinux.h index 82e0f26a1299..44f459612690 100644 --- a/include/linux/selinux.h +++ b/include/linux/selinux.h @@ -20,75 +20,12 @@ struct kern_ipc_perm; #ifdef CONFIG_SECURITY_SELINUX -/** - * selinux_string_to_sid - map a security context string to a security ID - * @str: the security context string to be mapped - * @sid: ID value returned via this. - * - * Returns 0 if successful, with the SID stored in sid. A value - * of zero for sid indicates no SID could be determined (but no error - * occurred). - */ -int selinux_string_to_sid(char *str, u32 *sid); - -/** - * selinux_secmark_relabel_packet_permission - secmark permission check - * @sid: SECMARK ID value to be applied to network packet - * - * Returns 0 if the current task is allowed to set the SECMARK label of - * packets with the supplied security ID. Note that it is implicit that - * the packet is always being relabeled from the default unlabeled value, - * and that the access control decision is made in the AVC. - */ -int selinux_secmark_relabel_packet_permission(u32 sid); - -/** - * selinux_secmark_refcount_inc - increments the secmark use counter - * - * SELinux keeps track of the current SECMARK targets in use so it knows - * when to apply SECMARK label access checks to network packets. This - * function incements this reference count to indicate that a new SECMARK - * target has been configured. - */ -void selinux_secmark_refcount_inc(void); - -/** - * selinux_secmark_refcount_dec - decrements the secmark use counter - * - * SELinux keeps track of the current SECMARK targets in use so it knows - * when to apply SECMARK label access checks to network packets. This - * function decements this reference count to indicate that one of the - * existing SECMARK targets has been removed/flushed. - */ -void selinux_secmark_refcount_dec(void); - /** * selinux_is_enabled - is SELinux enabled? */ bool selinux_is_enabled(void); #else -static inline int selinux_string_to_sid(const char *str, u32 *sid) -{ - *sid = 0; - return 0; -} - -static inline int selinux_secmark_relabel_packet_permission(u32 sid) -{ - return 0; -} - -static inline void selinux_secmark_refcount_inc(void) -{ - return; -} - -static inline void selinux_secmark_refcount_dec(void) -{ - return; -} - static inline bool selinux_is_enabled(void) { return false; diff --git a/net/netfilter/xt_CT.c b/net/netfilter/xt_CT.c index 0cb6053f02fd..782e51986a6f 100644 --- a/net/netfilter/xt_CT.c +++ b/net/netfilter/xt_CT.c @@ -9,7 +9,6 @@ #include #include #include -#include #include #include #include diff --git a/net/netfilter/xt_SECMARK.c b/net/netfilter/xt_SECMARK.c index 364ad1600129..9faf5e050b79 100644 --- a/net/netfilter/xt_SECMARK.c +++ b/net/netfilter/xt_SECMARK.c @@ -14,8 +14,8 @@ */ #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt #include +#include #include -#include #include #include @@ -39,9 +39,8 @@ secmark_tg(struct sk_buff *skb, const struct xt_action_param *par) switch (mode) { case SECMARK_MODE_SEL: - secmark = info->u.sel.selsid; + secmark = info->secid; break; - default: BUG(); } @@ -50,33 +49,33 @@ secmark_tg(struct sk_buff *skb, const struct xt_action_param *par) return XT_CONTINUE; } -static int checkentry_selinux(struct xt_secmark_target_info *info) +static int checkentry_lsm(struct xt_secmark_target_info *info) { int err; - struct xt_secmark_target_selinux_info *sel = &info->u.sel; - sel->selctx[SECMARK_SELCTX_MAX - 1] = '\0'; + info->secctx[SECMARK_SECCTX_MAX - 1] = '\0'; + info->secid = 0; - err = selinux_string_to_sid(sel->selctx, &sel->selsid); + err = security_secctx_to_secid(info->secctx, strlen(info->secctx), + &info->secid); if (err) { if (err == -EINVAL) - pr_info("invalid SELinux context \'%s\'\n", - sel->selctx); + pr_info("invalid security context \'%s\'\n", info->secctx); return err; } - if (!sel->selsid) { - pr_info("unable to map SELinux context \'%s\'\n", sel->selctx); + if (!info->secid) { + pr_info("unable to map security context \'%s\'\n", info->secctx); return -ENOENT; } - err = selinux_secmark_relabel_packet_permission(sel->selsid); + err = security_secmark_relabel_packet(info->secid); if (err) { pr_info("unable to obtain relabeling permission\n"); return err; } - selinux_secmark_refcount_inc(); + security_secmark_refcount_inc(); return 0; } @@ -100,16 +99,16 @@ static int secmark_tg_check(const struct xt_tgchk_param *par) switch (info->mode) { case SECMARK_MODE_SEL: - err = checkentry_selinux(info); - if (err) - return err; break; - default: pr_info("invalid mode: %hu\n", info->mode); return -EINVAL; } + err = checkentry_lsm(info); + if (err) + return err; + if (!mode) mode = info->mode; return 0; @@ -119,7 +118,7 @@ static void secmark_tg_destroy(const struct xt_tgdtor_param *par) { switch (mode) { case SECMARK_MODE_SEL: - selinux_secmark_refcount_dec(); + security_secmark_refcount_dec(); } } diff --git a/security/capability.c b/security/capability.c index 95a6599a37bb..30ae00fbecd5 100644 --- a/security/capability.c +++ b/security/capability.c @@ -677,7 +677,18 @@ static void cap_inet_conn_established(struct sock *sk, struct sk_buff *skb) { } +static int cap_secmark_relabel_packet(u32 secid) +{ + return 0; +} +static void cap_secmark_refcount_inc(void) +{ +} + +static void cap_secmark_refcount_dec(void) +{ +} static void cap_req_classify_flow(const struct request_sock *req, struct flowi *fl) @@ -777,7 +788,8 @@ static int cap_secid_to_secctx(u32 secid, char **secdata, u32 *seclen) static int cap_secctx_to_secid(const char *secdata, u32 seclen, u32 *secid) { - return -EOPNOTSUPP; + *secid = 0; + return 0; } static void cap_release_secctx(char *secdata, u32 seclen) @@ -1018,6 +1030,9 @@ void __init security_fixup_ops(struct security_operations *ops) set_to_cap_if_null(ops, inet_conn_request); set_to_cap_if_null(ops, inet_csk_clone); set_to_cap_if_null(ops, inet_conn_established); + set_to_cap_if_null(ops, secmark_relabel_packet); + set_to_cap_if_null(ops, secmark_refcount_inc); + set_to_cap_if_null(ops, secmark_refcount_dec); set_to_cap_if_null(ops, req_classify_flow); set_to_cap_if_null(ops, tun_dev_create); set_to_cap_if_null(ops, tun_dev_post_create); diff --git a/security/security.c b/security/security.c index 1cbcdfa4b015..b50f472061a4 100644 --- a/security/security.c +++ b/security/security.c @@ -1136,6 +1136,24 @@ void security_inet_conn_established(struct sock *sk, security_ops->inet_conn_established(sk, skb); } +int security_secmark_relabel_packet(u32 secid) +{ + return security_ops->secmark_relabel_packet(secid); +} +EXPORT_SYMBOL(security_secmark_relabel_packet); + +void security_secmark_refcount_inc(void) +{ + security_ops->secmark_refcount_inc(); +} +EXPORT_SYMBOL(security_secmark_refcount_inc); + +void security_secmark_refcount_dec(void) +{ + security_ops->secmark_refcount_dec(); +} +EXPORT_SYMBOL(security_secmark_refcount_dec); + int security_tun_dev_create(void) { return security_ops->tun_dev_create(); diff --git a/security/selinux/exports.c b/security/selinux/exports.c index c0a454aee1e0..90664385dead 100644 --- a/security/selinux/exports.c +++ b/security/selinux/exports.c @@ -11,58 +11,9 @@ * it under the terms of the GNU General Public License version 2, * as published by the Free Software Foundation. */ -#include -#include #include -#include -#include -#include -#include #include "security.h" -#include "objsec.h" - -/* SECMARK reference count */ -extern atomic_t selinux_secmark_refcount; - -int selinux_string_to_sid(char *str, u32 *sid) -{ - if (selinux_enabled) - return security_context_to_sid(str, strlen(str), sid); - else { - *sid = 0; - return 0; - } -} -EXPORT_SYMBOL_GPL(selinux_string_to_sid); - -int selinux_secmark_relabel_packet_permission(u32 sid) -{ - if (selinux_enabled) { - const struct task_security_struct *__tsec; - u32 tsid; - - __tsec = current_security(); - tsid = __tsec->sid; - - return avc_has_perm(tsid, sid, SECCLASS_PACKET, - PACKET__RELABELTO, NULL); - } - return 0; -} -EXPORT_SYMBOL_GPL(selinux_secmark_relabel_packet_permission); - -void selinux_secmark_refcount_inc(void) -{ - atomic_inc(&selinux_secmark_refcount); -} -EXPORT_SYMBOL_GPL(selinux_secmark_refcount_inc); - -void selinux_secmark_refcount_dec(void) -{ - atomic_dec(&selinux_secmark_refcount); -} -EXPORT_SYMBOL_GPL(selinux_secmark_refcount_dec); bool selinux_is_enabled(void) { diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c index db2b331de89a..d9154cf90ae1 100644 --- a/security/selinux/hooks.c +++ b/security/selinux/hooks.c @@ -4279,6 +4279,27 @@ static void selinux_inet_conn_established(struct sock *sk, struct sk_buff *skb) selinux_skb_peerlbl_sid(skb, family, &sksec->peer_sid); } +static int selinux_secmark_relabel_packet(u32 sid) +{ + const struct task_security_struct *__tsec; + u32 tsid; + + __tsec = current_security(); + tsid = __tsec->sid; + + return avc_has_perm(tsid, sid, SECCLASS_PACKET, PACKET__RELABELTO, NULL); +} + +static void selinux_secmark_refcount_inc(void) +{ + atomic_inc(&selinux_secmark_refcount); +} + +static void selinux_secmark_refcount_dec(void) +{ + atomic_dec(&selinux_secmark_refcount); +} + static void selinux_req_classify_flow(const struct request_sock *req, struct flowi *fl) { @@ -5533,6 +5554,9 @@ static struct security_operations selinux_ops = { .inet_conn_request = selinux_inet_conn_request, .inet_csk_clone = selinux_inet_csk_clone, .inet_conn_established = selinux_inet_conn_established, + .secmark_relabel_packet = selinux_secmark_relabel_packet, + .secmark_refcount_inc = selinux_secmark_refcount_inc, + .secmark_refcount_dec = selinux_secmark_refcount_dec, .req_classify_flow = selinux_req_classify_flow, .tun_dev_create = selinux_tun_dev_create, .tun_dev_post_create = selinux_tun_dev_post_create, diff --git a/security/selinux/include/security.h b/security/selinux/include/security.h index 4b66f19bb1f3..611a526afae7 100644 --- a/security/selinux/include/security.h +++ b/security/selinux/include/security.h @@ -9,6 +9,7 @@ #define _SELINUX_SECURITY_H_ #include +#include #include "flask.h" #define SECSID_NULL 0x00000000 /* unspecified SID */ -- cgit v1.2.3 From d5630b9d276bd389299ffea620b7c340ab19bcf5 Mon Sep 17 00:00:00 2001 From: Eric Paris Date: Wed, 13 Oct 2010 16:24:48 -0400 Subject: security: secid_to_secctx returns len when data is NULL With the (long ago) interface change to have the secid_to_secctx functions do the string allocation instead of having the caller do the allocation we lost the ability to query the security server for the length of the upcoming string. The SECMARK code would like to allocate a netlink skb with enough length to hold the string but it is just too unclean to do the string allocation twice or to do the allocation the first time and hold onto the string and slen. This patch adds the ability to call security_secid_to_secctx() with a NULL data pointer and it will just set the slen pointer. Signed-off-by: Eric Paris Reviewed-by: Paul Moore Signed-off-by: James Morris --- include/linux/security.h | 6 +++++- security/selinux/ss/services.c | 11 +++++++++-- security/smack/smack_lsm.c | 3 ++- 3 files changed, 16 insertions(+), 4 deletions(-) (limited to 'include/linux/security.h') diff --git a/include/linux/security.h b/include/linux/security.h index d70adc394f62..b8246a8df7d2 100644 --- a/include/linux/security.h +++ b/include/linux/security.h @@ -1285,9 +1285,13 @@ static inline void security_free_mnt_opts(struct security_mnt_opts *opts) * Return 0 if permission is granted. * * @secid_to_secctx: - * Convert secid to security context. + * Convert secid to security context. If secdata is NULL the length of + * the result will be returned in seclen, but no secdata will be returned. + * This does mean that the length could change between calls to check the + * length and the next call which actually allocates and returns the secdata. * @secid contains the security ID. * @secdata contains the pointer that stores the converted security context. + * @seclen pointer which contains the length of the data * @secctx_to_secid: * Convert security context to secid. * @secid contains the pointer to the generated security ID. diff --git a/security/selinux/ss/services.c b/security/selinux/ss/services.c index 494ff527c174..60964d79e5eb 100644 --- a/security/selinux/ss/services.c +++ b/security/selinux/ss/services.c @@ -991,7 +991,8 @@ static int context_struct_to_string(struct context *context, char **scontext, u3 { char *scontextp; - *scontext = NULL; + if (scontext) + *scontext = NULL; *scontext_len = 0; if (context->len) { @@ -1008,6 +1009,9 @@ static int context_struct_to_string(struct context *context, char **scontext, u3 *scontext_len += strlen(policydb.p_type_val_to_name[context->type - 1]) + 1; *scontext_len += mls_compute_context_len(context); + if (!scontext) + return 0; + /* Allocate space for the context; caller must free this space. */ scontextp = kmalloc(*scontext_len, GFP_ATOMIC); if (!scontextp) @@ -1047,7 +1051,8 @@ static int security_sid_to_context_core(u32 sid, char **scontext, struct context *context; int rc = 0; - *scontext = NULL; + if (scontext) + *scontext = NULL; *scontext_len = 0; if (!ss_initialized) { @@ -1055,6 +1060,8 @@ static int security_sid_to_context_core(u32 sid, char **scontext, char *scontextp; *scontext_len = strlen(initial_sid_to_string[sid]) + 1; + if (!scontext) + goto out; scontextp = kmalloc(*scontext_len, GFP_ATOMIC); if (!scontextp) { rc = -ENOMEM; diff --git a/security/smack/smack_lsm.c b/security/smack/smack_lsm.c index 174aec44bfac..bc39f4067af6 100644 --- a/security/smack/smack_lsm.c +++ b/security/smack/smack_lsm.c @@ -3004,7 +3004,8 @@ static int smack_secid_to_secctx(u32 secid, char **secdata, u32 *seclen) { char *sp = smack_from_secid(secid); - *secdata = sp; + if (secdata) + *secdata = sp; *seclen = strlen(sp); return 0; } -- cgit v1.2.3