Skip to content

Commit

Permalink
Merge tag 'selinux-pr-20190917' of git://git.kernel.org/pub/scm/linux…
Browse files Browse the repository at this point in the history
…/kernel/git/pcmoore/selinux

Pull selinux updates from Paul Moore:

 - Add LSM hooks, and SELinux access control hooks, for dnotify,
   fanotify, and inotify watches. This has been discussed with both the
   LSM and fs/notify folks and everybody is good with these new hooks.

 - The LSM stacking changes missed a few calls to current_security() in
   the SELinux code; we fix those and remove current_security() for
   good.

 - Improve our network object labeling cache so that we always return
   the object's label, even when under memory pressure. Previously we
   would return an error if we couldn't allocate a new cache entry, now
   we always return the label even if we can't create a new cache entry
   for it.

 - Convert the sidtab atomic_t counter to a normal u32 with
   READ/WRITE_ONCE() and memory barrier protection.

 - A few patches to policydb.c to clean things up (remove forward
   declarations, long lines, bad variable names, etc)

* tag 'selinux-pr-20190917' of git://git.kernel.org/pub/scm/linux/kernel/git/pcmoore/selinux:
  lsm: remove current_security()
  selinux: fix residual uses of current_security() for the SELinux blob
  selinux: avoid atomic_t usage in sidtab
  fanotify, inotify, dnotify, security: add security hook for fs notifications
  selinux: always return a secid from the network caches if we find one
  selinux: policydb - rename type_val_to_struct_array
  selinux: policydb - fix some checkpatch.pl warnings
  selinux: shuffle around policydb.c to get rid of forward declarations
  • Loading branch information
torvalds committed Sep 23, 2019
2 parents 3c6a691 + 15322a0 commit 5825a95
Show file tree
Hide file tree
Showing 18 changed files with 403 additions and 307 deletions.
15 changes: 12 additions & 3 deletions fs/notify/dnotify/dnotify.c
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
#include <linux/sched/signal.h>
#include <linux/dnotify.h>
#include <linux/init.h>
#include <linux/security.h>
#include <linux/spinlock.h>
#include <linux/slab.h>
#include <linux/fdtable.h>
Expand Down Expand Up @@ -279,6 +280,17 @@ int fcntl_dirnotify(int fd, struct file *filp, unsigned long arg)
goto out_err;
}

/*
* convert the userspace DN_* "arg" to the internal FS_*
* defined in fsnotify
*/
mask = convert_arg(arg);

error = security_path_notify(&filp->f_path, mask,
FSNOTIFY_OBJ_TYPE_INODE);
if (error)
goto out_err;

/* expect most fcntl to add new rather than augment old */
dn = kmem_cache_alloc(dnotify_struct_cache, GFP_KERNEL);
if (!dn) {
Expand All @@ -293,9 +305,6 @@ int fcntl_dirnotify(int fd, struct file *filp, unsigned long arg)
goto out_err;
}

/* convert the userspace DN_* "arg" to the internal FS_* defines in fsnotify */
mask = convert_arg(arg);

/* set up the new_fsn_mark and new_dn_mark */
new_fsn_mark = &new_dn_mark->fsn_mark;
fsnotify_init_mark(new_fsn_mark, dnotify_group);
Expand Down
19 changes: 17 additions & 2 deletions fs/notify/fanotify/fanotify_user.c
Original file line number Diff line number Diff line change
Expand Up @@ -528,7 +528,8 @@ static const struct file_operations fanotify_fops = {
};

static int fanotify_find_path(int dfd, const char __user *filename,
struct path *path, unsigned int flags)
struct path *path, unsigned int flags, __u64 mask,
unsigned int obj_type)
{
int ret;

Expand Down Expand Up @@ -567,8 +568,15 @@ static int fanotify_find_path(int dfd, const char __user *filename,

/* you can only watch an inode if you have read permissions on it */
ret = inode_permission(path->dentry->d_inode, MAY_READ);
if (ret) {
path_put(path);
goto out;
}

ret = security_path_notify(path, mask, obj_type);
if (ret)
path_put(path);

out:
return ret;
}
Expand Down Expand Up @@ -947,6 +955,7 @@ static int do_fanotify_mark(int fanotify_fd, unsigned int flags, __u64 mask,
__kernel_fsid_t __fsid, *fsid = NULL;
u32 valid_mask = FANOTIFY_EVENTS | FANOTIFY_EVENT_FLAGS;
unsigned int mark_type = flags & FANOTIFY_MARK_TYPE_BITS;
unsigned int obj_type;
int ret;

pr_debug("%s: fanotify_fd=%d flags=%x dfd=%d pathname=%p mask=%llx\n",
Expand All @@ -961,8 +970,13 @@ static int do_fanotify_mark(int fanotify_fd, unsigned int flags, __u64 mask,

switch (mark_type) {
case FAN_MARK_INODE:
obj_type = FSNOTIFY_OBJ_TYPE_INODE;
break;
case FAN_MARK_MOUNT:
obj_type = FSNOTIFY_OBJ_TYPE_VFSMOUNT;
break;
case FAN_MARK_FILESYSTEM:
obj_type = FSNOTIFY_OBJ_TYPE_SB;
break;
default:
return -EINVAL;
Expand Down Expand Up @@ -1030,7 +1044,8 @@ static int do_fanotify_mark(int fanotify_fd, unsigned int flags, __u64 mask,
goto fput_and_out;
}

ret = fanotify_find_path(dfd, pathname, &path, flags);
ret = fanotify_find_path(dfd, pathname, &path, flags,
(mask & ALL_FSNOTIFY_EVENTS), obj_type);
if (ret)
goto fput_and_out;

Expand Down
14 changes: 12 additions & 2 deletions fs/notify/inotify/inotify_user.c
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@
#include <linux/poll.h>
#include <linux/wait.h>
#include <linux/memcontrol.h>
#include <linux/security.h>

#include "inotify.h"
#include "../fdinfo.h"
Expand Down Expand Up @@ -331,7 +332,8 @@ static const struct file_operations inotify_fops = {
/*
* find_inode - resolve a user-given path to a specific inode
*/
static int inotify_find_inode(const char __user *dirname, struct path *path, unsigned flags)
static int inotify_find_inode(const char __user *dirname, struct path *path,
unsigned int flags, __u64 mask)
{
int error;

Expand All @@ -340,8 +342,15 @@ static int inotify_find_inode(const char __user *dirname, struct path *path, uns
return error;
/* you can only watch an inode if you have read permissions on it */
error = inode_permission(path->dentry->d_inode, MAY_READ);
if (error) {
path_put(path);
return error;
}
error = security_path_notify(path, mask,
FSNOTIFY_OBJ_TYPE_INODE);
if (error)
path_put(path);

return error;
}

Expand Down Expand Up @@ -733,7 +742,8 @@ SYSCALL_DEFINE3(inotify_add_watch, int, fd, const char __user *, pathname,
if (mask & IN_ONLYDIR)
flags |= LOOKUP_DIRECTORY;

ret = inotify_find_inode(pathname, &path, flags);
ret = inotify_find_inode(pathname, &path, flags,
(mask & IN_ALL_EVENTS));
if (ret)
goto fput_and_out;

Expand Down
1 change: 0 additions & 1 deletion include/linux/cred.h
Original file line number Diff line number Diff line change
Expand Up @@ -386,7 +386,6 @@ static inline void put_cred(const struct cred *_cred)
#define current_fsgid() (current_cred_xxx(fsgid))
#define current_cap() (current_cred_xxx(cap_effective))
#define current_user() (current_cred_xxx(user))
#define current_security() (current_cred_xxx(security))

extern struct user_namespace init_user_ns;
#ifdef CONFIG_USER_NS
Expand Down
9 changes: 8 additions & 1 deletion include/linux/lsm_hooks.h
Original file line number Diff line number Diff line change
Expand Up @@ -339,6 +339,9 @@
* Check for permission to change root directory.
* @path contains the path structure.
* Return 0 if permission is granted.
* @path_notify:
* Check permissions before setting a watch on events as defined by @mask,
* on an object at @path, whose type is defined by @obj_type.
* @inode_readlink:
* Check the permission to read the symbolic link.
* @dentry contains the dentry structure for the file link.
Expand Down Expand Up @@ -1535,7 +1538,9 @@ union security_list_options {
int (*path_chown)(const struct path *path, kuid_t uid, kgid_t gid);
int (*path_chroot)(const struct path *path);
#endif

/* Needed for inode based security check */
int (*path_notify)(const struct path *path, u64 mask,
unsigned int obj_type);
int (*inode_alloc_security)(struct inode *inode);
void (*inode_free_security)(struct inode *inode);
int (*inode_init_security)(struct inode *inode, struct inode *dir,
Expand Down Expand Up @@ -1860,6 +1865,8 @@ struct security_hook_heads {
struct hlist_head path_chown;
struct hlist_head path_chroot;
#endif
/* Needed for inode based modules as well */
struct hlist_head path_notify;
struct hlist_head inode_alloc_security;
struct hlist_head inode_free_security;
struct hlist_head inode_init_security;
Expand Down
10 changes: 8 additions & 2 deletions include/linux/security.h
Original file line number Diff line number Diff line change
Expand Up @@ -259,7 +259,8 @@ int security_dentry_create_files_as(struct dentry *dentry, int mode,
struct qstr *name,
const struct cred *old,
struct cred *new);

int security_path_notify(const struct path *path, u64 mask,
unsigned int obj_type);
int security_inode_alloc(struct inode *inode);
void security_inode_free(struct inode *inode);
int security_inode_init_security(struct inode *inode, struct inode *dir,
Expand Down Expand Up @@ -387,7 +388,6 @@ int security_ismaclabel(const char *name);
int security_secid_to_secctx(u32 secid, char **secdata, u32 *seclen);
int security_secctx_to_secid(const char *secdata, u32 seclen, u32 *secid);
void security_release_secctx(char *secdata, u32 seclen);

void security_inode_invalidate_secctx(struct inode *inode);
int security_inode_notifysecctx(struct inode *inode, void *ctx, u32 ctxlen);
int security_inode_setsecctx(struct dentry *dentry, void *ctx, u32 ctxlen);
Expand Down Expand Up @@ -621,6 +621,12 @@ static inline int security_move_mount(const struct path *from_path,
return 0;
}

static inline int security_path_notify(const struct path *path, u64 mask,
unsigned int obj_type)
{
return 0;
}

static inline int security_inode_alloc(struct inode *inode)
{
return 0;
Expand Down
6 changes: 6 additions & 0 deletions security/security.c
Original file line number Diff line number Diff line change
Expand Up @@ -870,6 +870,12 @@ int security_move_mount(const struct path *from_path, const struct path *to_path
return call_int_hook(move_mount, 0, from_path, to_path);
}

int security_path_notify(const struct path *path, u64 mask,
unsigned int obj_type)
{
return call_int_hook(path_notify, 0, path, mask, obj_type);
}

int security_inode_alloc(struct inode *inode)
{
int rc = lsm_inode_alloc(inode);
Expand Down
49 changes: 48 additions & 1 deletion security/selinux/hooks.c
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,8 @@
#include <linux/kernfs.h>
#include <linux/stringhash.h> /* for hashlen_string() */
#include <uapi/linux/mount.h>
#include <linux/fsnotify.h>
#include <linux/fanotify.h>

#include "avc.h"
#include "objsec.h"
Expand Down Expand Up @@ -3275,6 +3277,50 @@ static int selinux_inode_removexattr(struct dentry *dentry, const char *name)
return -EACCES;
}

static int selinux_path_notify(const struct path *path, u64 mask,
unsigned int obj_type)
{
int ret;
u32 perm;

struct common_audit_data ad;

ad.type = LSM_AUDIT_DATA_PATH;
ad.u.path = *path;

/*
* Set permission needed based on the type of mark being set.
* Performs an additional check for sb watches.
*/
switch (obj_type) {
case FSNOTIFY_OBJ_TYPE_VFSMOUNT:
perm = FILE__WATCH_MOUNT;
break;
case FSNOTIFY_OBJ_TYPE_SB:
perm = FILE__WATCH_SB;
ret = superblock_has_perm(current_cred(), path->dentry->d_sb,
FILESYSTEM__WATCH, &ad);
if (ret)
return ret;
break;
case FSNOTIFY_OBJ_TYPE_INODE:
perm = FILE__WATCH;
break;
default:
return -EINVAL;
}

/* blocking watches require the file:watch_with_perm permission */
if (mask & (ALL_FSNOTIFY_PERM_EVENTS))
perm |= FILE__WATCH_WITH_PERM;

/* watches on read-like events need the file:watch_reads permission */
if (mask & (FS_ACCESS | FS_ACCESS_PERM | FS_CLOSE_NOWRITE))
perm |= FILE__WATCH_READS;

return path_has_perm(current_cred(), path, perm);
}

/*
* Copy the inode security context value to the user.
*
Expand Down Expand Up @@ -3403,7 +3449,7 @@ static int selinux_inode_copy_up_xattr(const char *name)
static int selinux_kernfs_init_security(struct kernfs_node *kn_dir,
struct kernfs_node *kn)
{
const struct task_security_struct *tsec = current_security();
const struct task_security_struct *tsec = selinux_cred(current_cred());
u32 parent_sid, newsid, clen;
int rc;
char *context;
Expand Down Expand Up @@ -6818,6 +6864,7 @@ static struct security_hook_list selinux_hooks[] __lsm_ro_after_init = {
LSM_HOOK_INIT(inode_getsecid, selinux_inode_getsecid),
LSM_HOOK_INIT(inode_copy_up, selinux_inode_copy_up),
LSM_HOOK_INIT(inode_copy_up_xattr, selinux_inode_copy_up_xattr),
LSM_HOOK_INIT(path_notify, selinux_path_notify),

LSM_HOOK_INIT(kernfs_init_security, selinux_kernfs_init_security),

Expand Down
5 changes: 3 additions & 2 deletions security/selinux/include/classmap.h
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,8 @@

#define COMMON_FILE_PERMS COMMON_FILE_SOCK_PERMS, "unlink", "link", \
"rename", "execute", "quotaon", "mounton", "audit_access", \
"open", "execmod"
"open", "execmod", "watch", "watch_mount", "watch_sb", \
"watch_with_perm", "watch_reads"

#define COMMON_SOCK_PERMS COMMON_FILE_SOCK_PERMS, "bind", "connect", \
"listen", "accept", "getopt", "setopt", "shutdown", "recvfrom", \
Expand Down Expand Up @@ -60,7 +61,7 @@ struct security_class_mapping secclass_map[] = {
{ "filesystem",
{ "mount", "remount", "unmount", "getattr",
"relabelfrom", "relabelto", "associate", "quotamod",
"quotaget", NULL } },
"quotaget", "watch", NULL } },
{ "file",
{ COMMON_FILE_PERMS,
"execute_no_trans", "entrypoint", NULL } },
Expand Down
20 changes: 10 additions & 10 deletions security/selinux/include/objsec.h
Original file line number Diff line number Diff line change
Expand Up @@ -37,16 +37,6 @@ struct task_security_struct {
u32 sockcreate_sid; /* fscreate SID */
};

/*
* get the subjective security ID of the current task
*/
static inline u32 current_sid(void)
{
const struct task_security_struct *tsec = current_security();

return tsec->sid;
}

enum label_initialized {
LABEL_INVALID, /* invalid or not initialized */
LABEL_INITIALIZED, /* initialized */
Expand Down Expand Up @@ -185,4 +175,14 @@ static inline struct ipc_security_struct *selinux_ipc(
return ipc->security + selinux_blob_sizes.lbs_ipc;
}

/*
* get the subjective security ID of the current task
*/
static inline u32 current_sid(void)
{
const struct task_security_struct *tsec = selinux_cred(current_cred());

return tsec->sid;
}

#endif /* _SELINUX_OBJSEC_H_ */
Loading

0 comments on commit 5825a95

Please sign in to comment.