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