[PATCH v4 00/19] LSM: Module stacking for SARA and Landlock

Stephen Smalley sds at tycho.nsa.gov
Mon Sep 24 15:01:30 UTC 2018


On 09/23/2018 01:09 PM, Casey Schaufler wrote:
> On 9/23/2018 8:59 AM, Tetsuo Handa wrote:
>> On 2018/09/23 11:43, Kees Cook wrote:
>>>>> I'm excited about getting this landed!
>>>> Soon. Real soon. I hope. I would very much like for
>>>> someone from the SELinux camp to chime in, especially on
>>>> the selinux_is_enabled() removal.
>>> Agreed.
>>>
>> This patchset from Casey lands before the patchset from Kees, doesn't it?
> 
> That is up for negotiation. We may end up combining them.
> 
>> OK, a few comments (if I didn't overlook something).
>>
>>    lsm_early_cred()/lsm_early_task() are called from only __init functions.
> 
> True.
> 
>>    lsm_cred_alloc()/lsm_file_alloc() are called from only security/security.c .
> 
> Also true.
> 
>>    lsm_early_inode() should be avoided because it is not appropriate to
>>    call panic() when lsm_early_inode() is called after __init phase.
> 
> You're correct. In fact, lsm_early_inode() isn't needed at all
> until multiple inode using modules are supported.
> 
>>    Since all free hooks are called when one of init hooks failed, each
>>    free hook needs to check whether init hook was called. An example is
>>    inode_free_security() in security/selinux/hooks.c (but not addressed in
>>    this patch).
> 
> I *think* that selinux_inode_free_security() is safe in this
> case because the blob will be zeroed, hence isec->list will
> be NULL.

That's not safe - look more closely at what list_empty_careful() tests, 
and then think about what happens when list_del_init() gets called on 
that isec->list.  selinux_inode_free_security() presumes that 
selinux_inode_alloc_security() has been called already.  If you are 
breaking that assumption, you have to fix it.

Is there a reason you can't make inode_alloc_security() return void 
since you moved the allocation to the framework?  Unfortunate that 
inode_init_security name is already in use for another purpose since 
essentially you have reduced these hooks to initialization only.

> 
>>    This patchset might fatally prevent LKM-based LSM modules, for LKM-based
>>    LSMs cannot count on lsm_*_alloc() because size for lsm_*_alloc() cannot
>>    be updated upon loading LKM-based LSMs.
> 
> LKM based security modules will require dynamically sized blobs.
> These can be added to the scheme used here. Each blob would get a
> header identifying the modules for which it contains data. When an
> LKM is registered if has to declare it's blob space requirements
> and gets back the offsets. All alloc operations have to put their
> marks in the header. All LKM blob users have to check that the blob
> they are looking at has the required data.
> 
> module_cred(struct cred *cred) {
> 	return cred->security + module_blob_sizes.lbs_cred;
> }
> 
> becomes
> 
> module_cred(struct cred *cred) {
> 	if (blob_includes(module_id))
> 		return cred->security + module_blob_sizes.lbs_cred;
> 	return NULL;
> }
> 
> and the calling code needs to accept a NULL return.
> Blobs can never get smaller because readjusting the offsets
> isn't going to work, so unloading an LKM security module isn't
> going to be as complete as you might like. There may be a way
> around this if you unload all the LKM modules, but that's a
> special case and there may be dragon lurking in the mist.
> 
>>   If security_file_free() is called
>>    regardless of whether lsm_file_cache is defined, LKM-based LSMs can be
>>    loaded using current behavior (apart from the fact that legitimate
>>    interface for appending to security_hook_heads is currently missing).
>>    How do you plan to handle LKM-based LSMs?
> 
> My position all along has been that I don't plan to handle LKM
> based LSMs, but that I won't do anything to prevent someone else
> from adding them later. I believe that I've done that. Several
> designs, including a separate list for dynamically loaded modules
> have been proposed. I think some of those would work.
> 
>>   include/linux/lsm_hooks.h  |    6 ++----
>>   security/security.c        |   31 ++++++-------------------------
>>   security/smack/smack_lsm.c |    8 +++++++-
>>   3 files changed, 15 insertions(+), 30 deletions(-)
>>
>> diff --git a/include/linux/lsm_hooks.h b/include/linux/lsm_hooks.h
>> index 7e8b32f..8014614 100644
>> --- a/include/linux/lsm_hooks.h
>> +++ b/include/linux/lsm_hooks.h
>> @@ -2095,13 +2095,11 @@ static inline void __init yama_add_hooks(void) { }
>>   static inline void loadpin_add_hooks(void) { };
>>   #endif
>>   
>> -extern int lsm_cred_alloc(struct cred *cred, gfp_t gfp);
>>   extern int lsm_inode_alloc(struct inode *inode);
>>   
>>   #ifdef CONFIG_SECURITY
>> -void lsm_early_cred(struct cred *cred);
>> -void lsm_early_inode(struct inode *inode);
>> -void lsm_early_task(struct task_struct *task);
>> +void __init lsm_early_cred(struct cred *cred);
>> +void __init lsm_early_task(struct task_struct *task);
>>   #endif
>>   
>>   #endif /* ! __LINUX_LSM_HOOKS_H */
>> diff --git a/security/security.c b/security/security.c
>> index e7c85060..341e8df 100644
>> --- a/security/security.c
>> +++ b/security/security.c
>> @@ -267,7 +267,7 @@ int unregister_lsm_notifier(struct notifier_block *nb)
>>    *
>>    * Returns 0, or -ENOMEM if memory can't be allocated.
>>    */
>> -int lsm_cred_alloc(struct cred *cred, gfp_t gfp)
>> +static int lsm_cred_alloc(struct cred *cred, gfp_t gfp)
>>   {
>>   	if (blob_sizes.lbs_cred == 0) {
>>   		cred->security = NULL;
>> @@ -286,7 +286,7 @@ int lsm_cred_alloc(struct cred *cred, gfp_t gfp)
>>    *
>>    * Allocate the cred blob for all the modules if it's not already there
>>    */
>> -void lsm_early_cred(struct cred *cred)
>> +void __init lsm_early_cred(struct cred *cred)
>>   {
>>   	int rc;
>>   
>> @@ -344,7 +344,7 @@ void __init security_add_blobs(struct lsm_blob_sizes *needed)
>>    *
>>    * Returns 0, or -ENOMEM if memory can't be allocated.
>>    */
>> -int lsm_file_alloc(struct file *file)
>> +static int lsm_file_alloc(struct file *file)
>>   {
>>   	if (!lsm_file_cache) {
>>   		file->f_security = NULL;
>> @@ -379,25 +379,6 @@ int lsm_inode_alloc(struct inode *inode)
>>   }
>>   
>>   /**
>> - * lsm_early_inode - during initialization allocate a composite inode blob
>> - * @inode: the inode that needs a blob
>> - *
>> - * Allocate the inode blob for all the modules if it's not already there
>> - */
>> -void lsm_early_inode(struct inode *inode)
>> -{
>> -	int rc;
>> -
>> -	if (inode == NULL)
>> -		panic("%s: NULL inode.\n", __func__);
>> -	if (inode->i_security != NULL)
>> -		return;
>> -	rc = lsm_inode_alloc(inode);
>> -	if (rc)
>> -		panic("%s: Early inode alloc failed.\n", __func__);
>> -}
>> -
>> -/**
>>    * lsm_task_alloc - allocate a composite task blob
>>    * @task: the task that needs a blob
>>    *
>> @@ -466,7 +447,7 @@ int lsm_msg_msg_alloc(struct msg_msg *mp)
>>    *
>>    * Allocate the task blob for all the modules if it's not already there
>>    */
>> -void lsm_early_task(struct task_struct *task)
>> +void __init lsm_early_task(struct task_struct *task)
>>   {
>>   	int rc;
>>   
>> @@ -1202,11 +1183,11 @@ void security_file_free(struct file *file)
>>   {
>>   	void *blob;
>>   
>> +	call_void_hook(file_free_security, file);
>> +
>>   	if (!lsm_file_cache)
>>   		return;
>>   
>> -	call_void_hook(file_free_security, file);
>> -
> 
> Why does this make sense? If the lsm_file_cache isn't
> initialized you can't have allocated any file blobs,
> no module can have initialized a file blob, hence there
> can be nothing for the module to do.
> 
>>   	blob = file->f_security;
>>   	file->f_security = NULL;
>>   	kmem_cache_free(lsm_file_cache, blob);
>> diff --git a/security/smack/smack_lsm.c b/security/smack/smack_lsm.c
>> index 7843004..b0b4045 100644
>> --- a/security/smack/smack_lsm.c
>> +++ b/security/smack/smack_lsm.c
>> @@ -750,6 +750,13 @@ static int smack_set_mnt_opts(struct super_block *sb,
>>   	if (sp->smk_flags & SMK_SB_INITIALIZED)
>>   		return 0;
>>   
>> +	if (inode->i_security == NULL) {
>> +		int rc = lsm_inode_alloc(inode);
>> +
>> +		if (rc)
>> +			return rc;
>> +	}
>> +
>>   	if (!smack_privileged(CAP_MAC_ADMIN)) {
>>   		/*
>>   		 * Unprivileged mounts don't get to specify Smack values.
>> @@ -818,7 +825,6 @@ static int smack_set_mnt_opts(struct super_block *sb,
>>   	/*
>>   	 * Initialize the root inode.
>>   	 */
>> -	lsm_early_inode(inode);
>>   	init_inode_smack(inode, sp->smk_root);
>>   
>>   	if (transmute) {
> 



More information about the Linux-security-module-archive mailing list