VFS: Remove security module inode blob allocation overhead
Subsystems (6)
Casey Schaufler
maintainerRFC PATCH 1/1 VFS: Remove security module inode blob allocation overhead
Subject: [RFC PATCH] VFS: Remove security module inode blob allocation overhead
The LSM infrastructure requires that the security modules allocate and free inode data as they require it. SELinux and Smack, the two security modules that use inode data, require that all inodes allocate security data. Allocating and freeing this data independently from the inode adds unnecessary overhead. The indirection from the inode to the security blob also adds overhead.
I fully expect objections to this approach. This approach would have been unreasonable when the LSM was introduced, as the majority of systems did not use a security module. That is no longer the case. Most systems (RedHat, Fedora, Ubuntu, Tizen, Android) use security modules today.
Putting the security blob directly into the inode increases the size of the inode. The relative sizes are:
Security disabled: 552
Security enabled, no module: 552
Security enabled with Smack: 624
Security enabled with SELinux: 632
Security enabled with both: 632
The first two numbers are the same because the module data is only included if the module is included. There is no i_security taking up space when it isn't needed. The last two numbers are the same because i_selinux and i_smack are unioned, which is sane since you can't use them both at the same time. Systems using only AppArmor get smaller inodes when properly configured. Systems with security modules compiled out are unaffected. Systems using either SELinux or Smack get full advantage.
It should be clear that for a properly configured kernel it will always be advantageous to include the security blob in the inode. By "properly configured" I mean simply that the only security facilities built in are the ones that are intended to be used, or that the value of generality is sufficient to incur some overhead. A downside of this approach is that the security blob structures are exposed. I expect that there is some compiler trick I could use to get the size of the blobs without doing so, but I am disinclined to pursue that. Exposing the blob structure has typing advantages.
Earlier discussions about changing the inode structure to better accommodate the use of security data include:
https://lkml.org/lkml/2013/6/3/516
--- fs/nfs/inode.c | 5 +- include/linux/fs.h | 11 +++- include/linux/selinux_blob.h | 41 ++++++++++++ include/linux/smack_blob.h | 32 +++++++++ security/security.c | 2 +- security/selinux/hooks.c | 132 +++++++++++++++++--------------------- security/selinux/include/objsec.h | 14 +--- security/selinux/selinuxfs.c | 8 +-- security/smack/smack.h | 16 +---- security/smack/smack_lsm.c | 54 ++++++---------- 10 files changed, 174 insertions(+), 141 deletions(-)
fs/nfs/inode.c +4 -1
@@ -292,11 +292,14 @@ void nfs_setsecurity(struct inode *inode, struct nfs_fattr *fattr, struct nfs4_label *label) {int error; +u32 secid =0 ;if (label ==NULL )return ; -if ((fattr->valid &NFS_ATTR_FATTR_V4_SECURITY_LABEL ) && inode->i_security) { +security_inode_getsecid (inode, &secid); + +if ((fattr->valid &NFS_ATTR_FATTR_V4_SECURITY_LABEL ) && secid !=0 ) { error =security_inode_notifysecctx (inode, label->label, label->len);if (error)
include/linux/fs.h +10 -1
@@ -31,6 +31,8 @@#include <linux/blk_types.h> #include <linux/workqueue.h> #include <linux/percpu-rwsem.h> +#include <linux/selinux_blob.h> +#include <linux/smack_blob.h> #include <asm/byteorder.h> #include <uapi/linux/fs.h>
@@ -598,8 +600,15 @@ struct inode {struct address_space *i_mapping;#ifdef CONFIG_SECURITY -void *i_security; +union { +#ifdef CONFIG_SECURITY_SELINUX +struct inode_selinux i_selinux; +#endif +#ifdef CONFIG_SECURITY_SMACK +struct inode_smack i_smack;#endif + }; +#endif /* CONFIG_SECURITY */ /* Stat data, not accessed from path walking */ unsigned long i_ino;
include/linux/selinux_blob.h new file +41 -0
41 lines not on this page · raw message
include/linux/smack_blob.h new file +32 -0
@@ -0,0 +1,32 @@ +/* +* Copyright (C) 2015 Intel Corporation +* Copyright (C) 2015 Casey Schaufler <[email protected]> +* +* This program is free software; you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation, version 2. +* +* Author: +* Casey Schaufler <[email protected]> +* +*/ + +#ifndef _LINUX_SMACK_BLOB_H +#define _LINUX_SMACK_BLOB_H + +#include <linux/spinlock.h> + +struct smack_known ; + +/* +* Inode smack data +*/ +struct inode_smack { +struct smack_known *smk_inode;/* label of the fso */ +struct smack_known *smk_task;/* label of the task */ +struct smack_known *smk_mmap;/* label of the mmap domain */ +struct mutex smk_lock;/* initialization lock */ +int smk_flags;/* smack inode flags */ +}; + +#endif /* _LINUX_SMACK_BLOB_H */
security/security.c +1 -1
@@ -344,7 +344,6 @@ EXPORT_SYMBOL(security_sb_parse_opts_str);int security_inode_alloc (struct inode *inode) { - inode->i_security =NULL ;return call_int_hook (inode_alloc_security,0 , inode); }
@@ -725,6 +724,7 @@ void security_inode_getsecid(const struct inode *inode, u32 *secid) {call_void_hook (inode_getsecid, inode, secid); } +EXPORT_SYMBOL (security_inode_getsecid);int security_file_permission (struct file *file,int mask) {
security/selinux/hooks.c +59 -73
425 lines not on this page · raw message
security/selinux/include/objsec.h +1 -13
@@ -24,6 +24,7 @@#include <linux/binfmts.h> #include <linux/in.h> #include <linux/spinlock.h> +#include <linux/selinux_blob.h> #include <net/net_namespace.h> #include "flask.h" #include "avc.h"
@@ -37,19 +38,6 @@ struct task_security_struct {u32 sockcreate_sid;/* fscreate SID */ }; -struct inode_security_struct { -struct inode *inode;/* back pointer to inode object */ -union { -struct list_head list;/* list of inode_security_struct */ -struct rcu_head rcu;/* for freeing the inode_security_struct */ - }; -u32 task_sid;/* SID of creating task */ -u32 sid;/* SID of this object */ -u16 sclass;/* security class of this object */ -unsigned char initialized;/* initialization flag */ -struct mutex lock; -}; -struct file_security_struct {u32 sid;/* SID of open file description */ u32 fown_sid;/* SID of file owner (for SIGIO) */
security/selinux/selinuxfs.c +4 -4
@@ -1200,7 +1200,7 @@ static int sel_make_bools(void)struct dentry *dentry =NULL ;struct dentry *dir = bool_dir;struct inode *inode =NULL ; -struct inode_security_struct *isec; +struct inode_selinux *isec;char **names =NULL , *page;int num;int *values =NULL ;
@@ -1242,7 +1242,7 @@ static int sel_make_bools(void)if (len >=PAGE_SIZE ) goto out; - isec = (struct inode_security_struct *)inode->i_security; + isec = &inode->i_selinux; ret =security_genfs_sid ("selinuxfs" , page,SECCLASS_FILE , &sid);if (ret) goto out;
@@ -1739,7 +1739,7 @@ static int sel_fill_super(struct super_block *sb, void *data, int silent)int ret;struct dentry *dentry;struct inode *inode; -struct inode_security_struct *isec; +struct inode_selinux *isec;static struct tree_descr selinux_files[] = { [SEL_LOAD ] = {"load" , &sel_load_ops,S_IRUSR |S_IWUSR },
@@ -1783,7 +1783,7 @@ static int sel_fill_super(struct super_block *sb, void *data, int silent) goto err; inode->i_ino = ++sel_last_ino; - isec = (struct inode_security_struct *)inode->i_security; + isec = &inode->i_selinux; isec->sid =SECINITSID_DEVNULL ; isec->sclass =SECCLASS_CHR_FILE ; isec->initialized =1 ;
security/smack/smack.h +3 -13
@@ -24,6 +24,7 @@#include <linux/list.h> #include <linux/rculist.h> #include <linux/lsm_audit.h> +#include <linux/smack_blob.h> /* * Use IPv6 port labeling if IPv6 is enabled and secmarks
@@ -99,17 +100,6 @@ struct socket_smack {struct smack_known *smk_packet;/* TCP peer label */ }; -/* -* Inode smack data -*/ -struct inode_smack { -struct smack_known *smk_inode;/* label of the fso */ -struct smack_known *smk_task;/* label of the task */ -struct smack_known *smk_mmap;/* label of the mmap domain */ -struct mutex smk_lock;/* initialization lock */ -int smk_flags;/* smack inode flags */ -}; -struct task_smack {struct smack_known *smk_task;/* label for access control */ struct smack_known *smk_forked;/* label when forked */
@@ -342,7 +332,7 @@ extern struct hlist_head smack_known_hash[SMACK_HASH_SLOTS];*/ static inline int smk_inode_transmutable (const struct inode *isp) { -struct inode_smack *sip = isp->i_security; +const struct inode_smack *sip = &isp->i_smack;return (sip->smk_flags &SMK_INODE_TRANSMUTE ) !=0 ; }
@@ -351,7 +341,7 @@ static inline int smk_inode_transmutable(const struct inode *isp)*/ static inline struct smack_known *smk_of_inode (const struct inode *isp) { -struct inode_smack *sip = isp->i_security; +const struct inode_smack *sip = &isp->i_smack;return sip->smk_inode; }
security/smack/smack_lsm.c +19 -35
160 lines not on this page · raw message