Skip to content

Commit

Permalink
Merge tag 'selinux-pr-20190507' 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:
 "We've got a few SELinux patches for the v5.2 merge window, the
  highlights are below:

   - Add LSM hooks, and the SELinux implementation, for proper labeling
     of kernfs. While we are only including the SELinux implementation
     here, the rest of the LSM folks have given the hooks a thumbs-up.

   - Update the SELinux mdp (Make Dummy Policy) script to actually work
     on a modern system.

   - Disallow userspace to change the LSM credentials via
     /proc/self/attr when the task's credentials are already overridden.

     The change was made in procfs because all the LSM folks agreed this
     was the Right Thing To Do and duplicating it across each LSM was
     going to be annoying"

* tag 'selinux-pr-20190507' of git://git.kernel.org/pub/scm/linux/kernel/git/pcmoore/selinux:
  proc: prevent changes to overridden credentials
  selinux: Check address length before reading address family
  kernfs: fix xattr name handling in LSM helpers
  MAINTAINERS: update SELinux file patterns
  selinux: avoid uninitialized variable warning
  selinux: remove useless assignments
  LSM: lsm_hooks.h - fix missing colon in docstring
  selinux: Make selinux_kernfs_init_security static
  kernfs: initialize security of newly created nodes
  selinux: implement the kernfs_init_security hook
  LSM: add new hook for kernfs node initialization
  kernfs: use simple_xattrs for security attributes
  selinux: try security xattr after genfs for kernfs filesystems
  kernfs: do not alloc iattrs in kernfs_xattr_get
  kernfs: clean up struct kernfs_iattrs
  scripts/selinux: fix build
  selinux: use kernel linux/socket.h for genheaders and mdp
  scripts/selinux: modernize mdp
  • Loading branch information
torvalds committed May 8, 2019
2 parents 498e863 + 35a196b commit f72dae2
Show file tree
Hide file tree
Showing 17 changed files with 487 additions and 269 deletions.
2 changes: 1 addition & 1 deletion MAINTAINERS
Original file line number Diff line number Diff line change
Expand Up @@ -13994,7 +13994,7 @@ W: https://selinuxproject.org
W: https://github.com/SELinuxProject
T: git git://git.kernel.org/pub/scm/linux/kernel/git/pcmoore/selinux.git
S: Supported
F: include/linux/selinux*
F: include/uapi/linux/selinux_netlink.h
F: security/selinux/
F: scripts/selinux/
F: Documentation/admin-guide/LSM/SELinux.rst
Expand Down
24 changes: 13 additions & 11 deletions fs/kernfs/dir.c
Original file line number Diff line number Diff line change
Expand Up @@ -532,9 +532,6 @@ void kernfs_put(struct kernfs_node *kn)
kfree_const(kn->name);

if (kn->iattr) {
if (kn->iattr->ia_secdata)
security_release_secctx(kn->iattr->ia_secdata,
kn->iattr->ia_secdata_len);
simple_xattrs_free(&kn->iattr->xattrs);
kmem_cache_free(kernfs_iattrs_cache, kn->iattr);
}
Expand Down Expand Up @@ -618,6 +615,7 @@ struct kernfs_node *kernfs_node_from_dentry(struct dentry *dentry)
}

static struct kernfs_node *__kernfs_new_node(struct kernfs_root *root,
struct kernfs_node *parent,
const char *name, umode_t mode,
kuid_t uid, kgid_t gid,
unsigned flags)
Expand Down Expand Up @@ -673,6 +671,12 @@ static struct kernfs_node *__kernfs_new_node(struct kernfs_root *root,
goto err_out3;
}

if (parent) {
ret = security_kernfs_init_security(parent, kn);
if (ret)
goto err_out3;
}

return kn;

err_out3:
Expand All @@ -691,7 +695,7 @@ struct kernfs_node *kernfs_new_node(struct kernfs_node *parent,
{
struct kernfs_node *kn;

kn = __kernfs_new_node(kernfs_root(parent),
kn = __kernfs_new_node(kernfs_root(parent), parent,
name, mode, uid, gid, flags);
if (kn) {
kernfs_get(parent);
Expand Down Expand Up @@ -794,9 +798,8 @@ int kernfs_add_one(struct kernfs_node *kn)
/* Update timestamps on the parent */
ps_iattr = parent->iattr;
if (ps_iattr) {
struct iattr *ps_iattrs = &ps_iattr->ia_iattr;
ktime_get_real_ts64(&ps_iattrs->ia_ctime);
ps_iattrs->ia_mtime = ps_iattrs->ia_ctime;
ktime_get_real_ts64(&ps_iattr->ia_ctime);
ps_iattr->ia_mtime = ps_iattr->ia_ctime;
}

mutex_unlock(&kernfs_mutex);
Expand Down Expand Up @@ -961,7 +964,7 @@ struct kernfs_root *kernfs_create_root(struct kernfs_syscall_ops *scops,
INIT_LIST_HEAD(&root->supers);
root->next_generation = 1;

kn = __kernfs_new_node(root, "", S_IFDIR | S_IRUGO | S_IXUGO,
kn = __kernfs_new_node(root, NULL, "", S_IFDIR | S_IRUGO | S_IXUGO,
GLOBAL_ROOT_UID, GLOBAL_ROOT_GID,
KERNFS_DIR);
if (!kn) {
Expand Down Expand Up @@ -1328,9 +1331,8 @@ static void __kernfs_remove(struct kernfs_node *kn)

/* update timestamps on the parent */
if (ps_iattr) {
ktime_get_real_ts64(&ps_iattr->ia_iattr.ia_ctime);
ps_iattr->ia_iattr.ia_mtime =
ps_iattr->ia_iattr.ia_ctime;
ktime_get_real_ts64(&ps_iattr->ia_ctime);
ps_iattr->ia_mtime = ps_iattr->ia_ctime;
}

kernfs_put(pos);
Expand Down
162 changes: 62 additions & 100 deletions fs/kernfs/inode.c
Original file line number Diff line number Diff line change
Expand Up @@ -31,30 +31,27 @@ static const struct inode_operations kernfs_iops = {
.listxattr = kernfs_iop_listxattr,
};

static struct kernfs_iattrs *kernfs_iattrs(struct kernfs_node *kn)
static struct kernfs_iattrs *__kernfs_iattrs(struct kernfs_node *kn, int alloc)
{
static DEFINE_MUTEX(iattr_mutex);
struct kernfs_iattrs *ret;
struct iattr *iattrs;

mutex_lock(&iattr_mutex);

if (kn->iattr)
if (kn->iattr || !alloc)
goto out_unlock;

kn->iattr = kmem_cache_zalloc(kernfs_iattrs_cache, GFP_KERNEL);
if (!kn->iattr)
goto out_unlock;
iattrs = &kn->iattr->ia_iattr;

/* assign default attributes */
iattrs->ia_mode = kn->mode;
iattrs->ia_uid = GLOBAL_ROOT_UID;
iattrs->ia_gid = GLOBAL_ROOT_GID;
kn->iattr->ia_uid = GLOBAL_ROOT_UID;
kn->iattr->ia_gid = GLOBAL_ROOT_GID;

ktime_get_real_ts64(&iattrs->ia_atime);
iattrs->ia_mtime = iattrs->ia_atime;
iattrs->ia_ctime = iattrs->ia_atime;
ktime_get_real_ts64(&kn->iattr->ia_atime);
kn->iattr->ia_mtime = kn->iattr->ia_atime;
kn->iattr->ia_ctime = kn->iattr->ia_atime;

simple_xattrs_init(&kn->iattr->xattrs);
out_unlock:
Expand All @@ -63,32 +60,37 @@ static struct kernfs_iattrs *kernfs_iattrs(struct kernfs_node *kn)
return ret;
}

static struct kernfs_iattrs *kernfs_iattrs(struct kernfs_node *kn)
{
return __kernfs_iattrs(kn, 1);
}

static struct kernfs_iattrs *kernfs_iattrs_noalloc(struct kernfs_node *kn)
{
return __kernfs_iattrs(kn, 0);
}

int __kernfs_setattr(struct kernfs_node *kn, const struct iattr *iattr)
{
struct kernfs_iattrs *attrs;
struct iattr *iattrs;
unsigned int ia_valid = iattr->ia_valid;

attrs = kernfs_iattrs(kn);
if (!attrs)
return -ENOMEM;

iattrs = &attrs->ia_iattr;

if (ia_valid & ATTR_UID)
iattrs->ia_uid = iattr->ia_uid;
attrs->ia_uid = iattr->ia_uid;
if (ia_valid & ATTR_GID)
iattrs->ia_gid = iattr->ia_gid;
attrs->ia_gid = iattr->ia_gid;
if (ia_valid & ATTR_ATIME)
iattrs->ia_atime = iattr->ia_atime;
attrs->ia_atime = iattr->ia_atime;
if (ia_valid & ATTR_MTIME)
iattrs->ia_mtime = iattr->ia_mtime;
attrs->ia_mtime = iattr->ia_mtime;
if (ia_valid & ATTR_CTIME)
iattrs->ia_ctime = iattr->ia_ctime;
if (ia_valid & ATTR_MODE) {
umode_t mode = iattr->ia_mode;
iattrs->ia_mode = kn->mode = mode;
}
attrs->ia_ctime = iattr->ia_ctime;
if (ia_valid & ATTR_MODE)
kn->mode = iattr->ia_mode;
return 0;
}

Expand Down Expand Up @@ -135,23 +137,6 @@ int kernfs_iop_setattr(struct dentry *dentry, struct iattr *iattr)
return error;
}

static int kernfs_node_setsecdata(struct kernfs_iattrs *attrs, void **secdata,
u32 *secdata_len)
{
void *old_secdata;
size_t old_secdata_len;

old_secdata = attrs->ia_secdata;
old_secdata_len = attrs->ia_secdata_len;

attrs->ia_secdata = *secdata;
attrs->ia_secdata_len = *secdata_len;

*secdata = old_secdata;
*secdata_len = old_secdata_len;
return 0;
}

ssize_t kernfs_iop_listxattr(struct dentry *dentry, char *buf, size_t size)
{
struct kernfs_node *kn = kernfs_dentry_node(dentry);
Expand All @@ -171,30 +156,28 @@ static inline void set_default_inode_attr(struct inode *inode, umode_t mode)
inode->i_ctime = current_time(inode);
}

static inline void set_inode_attr(struct inode *inode, struct iattr *iattr)
static inline void set_inode_attr(struct inode *inode,
struct kernfs_iattrs *attrs)
{
struct super_block *sb = inode->i_sb;
inode->i_uid = iattr->ia_uid;
inode->i_gid = iattr->ia_gid;
inode->i_atime = timespec64_trunc(iattr->ia_atime, sb->s_time_gran);
inode->i_mtime = timespec64_trunc(iattr->ia_mtime, sb->s_time_gran);
inode->i_ctime = timespec64_trunc(iattr->ia_ctime, sb->s_time_gran);
inode->i_uid = attrs->ia_uid;
inode->i_gid = attrs->ia_gid;
inode->i_atime = timespec64_trunc(attrs->ia_atime, sb->s_time_gran);
inode->i_mtime = timespec64_trunc(attrs->ia_mtime, sb->s_time_gran);
inode->i_ctime = timespec64_trunc(attrs->ia_ctime, sb->s_time_gran);
}

static void kernfs_refresh_inode(struct kernfs_node *kn, struct inode *inode)
{
struct kernfs_iattrs *attrs = kn->iattr;

inode->i_mode = kn->mode;
if (attrs) {
if (attrs)
/*
* kernfs_node has non-default attributes get them from
* persistent copy in kernfs_node.
*/
set_inode_attr(inode, &attrs->ia_iattr);
security_inode_notifysecctx(inode, attrs->ia_secdata,
attrs->ia_secdata_len);
}
set_inode_attr(inode, attrs);

if (kernfs_type(kn) == KERNFS_DIR)
set_nlink(inode, kn->dir.subdirs + 2);
Expand Down Expand Up @@ -305,78 +288,57 @@ int kernfs_iop_permission(struct inode *inode, int mask)
return generic_permission(inode, mask);
}

static int kernfs_xattr_get(const struct xattr_handler *handler,
struct dentry *unused, struct inode *inode,
const char *suffix, void *value, size_t size)
int kernfs_xattr_get(struct kernfs_node *kn, const char *name,
void *value, size_t size)
{
const char *name = xattr_full_name(handler, suffix);
struct kernfs_node *kn = inode->i_private;
struct kernfs_iattrs *attrs;

attrs = kernfs_iattrs(kn);
struct kernfs_iattrs *attrs = kernfs_iattrs_noalloc(kn);
if (!attrs)
return -ENOMEM;
return -ENODATA;

return simple_xattr_get(&attrs->xattrs, name, value, size);
}

static int kernfs_xattr_set(const struct xattr_handler *handler,
struct dentry *unused, struct inode *inode,
const char *suffix, const void *value,
size_t size, int flags)
int kernfs_xattr_set(struct kernfs_node *kn, const char *name,
const void *value, size_t size, int flags)
{
const char *name = xattr_full_name(handler, suffix);
struct kernfs_node *kn = inode->i_private;
struct kernfs_iattrs *attrs;

attrs = kernfs_iattrs(kn);
struct kernfs_iattrs *attrs = kernfs_iattrs(kn);
if (!attrs)
return -ENOMEM;

return simple_xattr_set(&attrs->xattrs, name, value, size, flags);
}

static const struct xattr_handler kernfs_trusted_xattr_handler = {
.prefix = XATTR_TRUSTED_PREFIX,
.get = kernfs_xattr_get,
.set = kernfs_xattr_set,
};

static int kernfs_security_xattr_set(const struct xattr_handler *handler,
struct dentry *unused, struct inode *inode,
const char *suffix, const void *value,
size_t size, int flags)
static int kernfs_vfs_xattr_get(const struct xattr_handler *handler,
struct dentry *unused, struct inode *inode,
const char *suffix, void *value, size_t size)
{
const char *name = xattr_full_name(handler, suffix);
struct kernfs_node *kn = inode->i_private;
struct kernfs_iattrs *attrs;
void *secdata;
u32 secdata_len = 0;
int error;

attrs = kernfs_iattrs(kn);
if (!attrs)
return -ENOMEM;

error = security_inode_setsecurity(inode, suffix, value, size, flags);
if (error)
return error;
error = security_inode_getsecctx(inode, &secdata, &secdata_len);
if (error)
return error;
return kernfs_xattr_get(kn, name, value, size);
}

mutex_lock(&kernfs_mutex);
error = kernfs_node_setsecdata(attrs, &secdata, &secdata_len);
mutex_unlock(&kernfs_mutex);
static int kernfs_vfs_xattr_set(const struct xattr_handler *handler,
struct dentry *unused, struct inode *inode,
const char *suffix, const void *value,
size_t size, int flags)
{
const char *name = xattr_full_name(handler, suffix);
struct kernfs_node *kn = inode->i_private;

if (secdata)
security_release_secctx(secdata, secdata_len);
return error;
return kernfs_xattr_set(kn, name, value, size, flags);
}

static const struct xattr_handler kernfs_trusted_xattr_handler = {
.prefix = XATTR_TRUSTED_PREFIX,
.get = kernfs_vfs_xattr_get,
.set = kernfs_vfs_xattr_set,
};

static const struct xattr_handler kernfs_security_xattr_handler = {
.prefix = XATTR_SECURITY_PREFIX,
.get = kernfs_xattr_get,
.set = kernfs_security_xattr_set,
.get = kernfs_vfs_xattr_get,
.set = kernfs_vfs_xattr_set,
};

const struct xattr_handler *kernfs_xattr_handlers[] = {
Expand Down
8 changes: 5 additions & 3 deletions fs/kernfs/kernfs-internal.h
Original file line number Diff line number Diff line change
Expand Up @@ -20,9 +20,11 @@
#include <linux/fs_context.h>

struct kernfs_iattrs {
struct iattr ia_iattr;
void *ia_secdata;
u32 ia_secdata_len;
kuid_t ia_uid;
kgid_t ia_gid;
struct timespec64 ia_atime;
struct timespec64 ia_mtime;
struct timespec64 ia_ctime;

struct simple_xattrs xattrs;
};
Expand Down
4 changes: 2 additions & 2 deletions fs/kernfs/symlink.c
Original file line number Diff line number Diff line change
Expand Up @@ -33,8 +33,8 @@ struct kernfs_node *kernfs_create_link(struct kernfs_node *parent,
kgid_t gid = GLOBAL_ROOT_GID;

if (target->iattr) {
uid = target->iattr->ia_iattr.ia_uid;
gid = target->iattr->ia_iattr.ia_gid;
uid = target->iattr->ia_uid;
gid = target->iattr->ia_gid;
}

kn = kernfs_new_node(parent, name, S_IFLNK|S_IRWXUGO, uid, gid,
Expand Down
5 changes: 5 additions & 0 deletions fs/proc/base.c
Original file line number Diff line number Diff line change
Expand Up @@ -2535,6 +2535,11 @@ static ssize_t proc_pid_attr_write(struct file * file, const char __user * buf,
rcu_read_unlock();
return -EACCES;
}
/* Prevent changes to overridden credentials. */
if (current_cred() != current_real_cred()) {
rcu_read_unlock();
return -EBUSY;
}
rcu_read_unlock();

if (count > PAGE_SIZE)
Expand Down
Loading

0 comments on commit f72dae2

Please sign in to comment.