[RFC][PATCH] security: Make the selinux setxattr and removexattr hooks behave

Eric W. Biederman ebiederm at xmission.com
Sat Sep 30 20:40:43 UTC 2017


Casey Schaufler <casey at schaufler-ca.com> writes:

> On 9/30/2017 9:22 AM, Eric W. Biederman wrote:
>> Casey Schaufler <casey at schaufler-ca.com> writes:
>>
>>> On 9/29/2017 7:18 AM, Stephen Smalley wrote:
>>>> On Thu, 2017-09-28 at 18:16 -0700, Casey Schaufler wrote:
>>>>> On 9/28/2017 3:34 PM, Eric W. Biederman wrote:
>>>>>> It looks like once upon a time a long time ago selinux copied code
>>>>>> from cap_inode_removexattr and cap_inode_setxattr into
>>>>>> selinux_inode_setotherxattr.  However the code has now diverged and
>>>>>> selinux is implementing a policy that is quite different than
>>>>>> cap_inode_setxattr and cap_inode_removexattr especially when it
>>>>>> comes
>>>>>> to the security.capable xattr.
>>>>> What leads you to believe that this isn't intentional?
>>>>> It's most likely the case that this change occurred as
>>>>> part of the first round module stacking change. What behavior
>>>>> do you see that you're unhappy with?
>>>>>
>>>>>> To keep things working
>>>>> Which "things"? How are they not "working"?
>>>>>
>>>>>>  and to make the comments in security/security.c
>>>>>> correct when the xattr is securit.capable, call cap_inode_setxattr
>>>>>> or cap_inode_removexattr as appropriate.
>>>>>>
>>>>>> I suspect there is a larger conversation to be had here but this
>>>>>> is enough to keep selinux from implementing a non-sense hard coded
>>>>>> policy that breaks other parts of the kernel.
>>>>> Specifics, please. Since I can't guess what problem you've
>>>>> encountered I can't tell if it's here, in the infrastructure,
>>>>> or in your perception of what constitutes "broken".
>>>>>
>>>>>> Signed-off-by: "Eric W. Biederman" <ebiederm at xmission.com>
>>>>>> ---
>>>>>>  security/selinux/hooks.c | 6 ++++++
>>>>>>  1 file changed, 6 insertions(+)
>>>>>>
>>>>>> diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c
>>>>>> index f5d304736852..edf4bd292dc7 100644
>>>>>> --- a/security/selinux/hooks.c
>>>>>> +++ b/security/selinux/hooks.c
>>>>>> @@ -3167,6 +3167,9 @@ static int selinux_inode_setxattr(struct
>>>>>> dentry *dentry, const char *name,
>>>>>>  	u32 newsid, sid = current_sid();
>>>>>>  	int rc = 0;
>>>>>>  
>>>>>> +	if (strcmp(name, XATTR_NAME_CAPS) == 0)
>>>>>> +		return cap_inode_setxattr(dentry, name, value,
>>>>>> size, flags);
>>>>>> +
>>>>> No. Don't even think of contemplating considering embedding the cap
>>>>> attribute check in the SELinux code. cap_inode_setxattr() is called
>>>>> in
>>>>> the infrastructure.
>>>> Except that it isn't, not if any other security module is enabled and
>>>> implements those hooks, to prevent imposing CAP_SYS_ADMIN checks when
>>>> setting security.selinux or security.SMACK*.
>>> OK. Yes, this bit of the infrastructure is some of the
>>> worst I've done in a long time. This is a case where we
>>> already need special case stacking infrastructure. It looks
>>> like we'll have to separate setting the cap attribute from
>>> checking the cap state in order to make this work. In any
>>> case, the security_inode_setxattr() code is where the change
>>> belongs. There will likely be fallout changes in the modules,
>>> including the cap module.
>>>  
>>>
>>>> An alternative approach to fixing this would be to change the cap
>>>> functions to only apply their checks if setting the capability
>>>> attribute and defer any checks on other security.* attributes to either
>>>> the security framework or the other security modules.  Then the
>>>> framework could always call all the modules on the inode_setxattr and
>>>> inode_removexattr hooks as with other hooks.  The security framework
>>>> would then need to ensure that a check is still applied when setting
>>>> security.* attributes if it isn't already handled by one of the enabled
>>>> security modules, as you don't want unprivileged userspace to be able
>>>> to set arbitrary security.foo attributes or to set up security.selinux
>>>> or security.SMACK* attributes if those modules happen to be disabled.
>>> Agreed. This isn't a two line change. Grumble.
>>>
>>> I can guess at what the problem might be, but I hate making
>>> assumptions when I go to fix a problem. I will start looking
>>> at a patch, but it would really help if I could say for sure
>>> what I'm out to accomplish. It may be obvious to the casual
>>> observer, but that description has not been applied to me very
>>> often.
>> Apologies for the delayed reply.
>>
>> I am looking at security_inode_setxattr.
>>
>> For setting attributes in the security.* the generic code in fs/xattr.c
>> applies no permission checks.
>>
>> Each security module that implements an xattr in security.* then imposes
>> it's own policy on it's own attribute.
>>
>> For smack the basic rule is smack_privileged(CAP_MAC_ADMIN).
>> For selinux the basic rule is inode_or_owner_capable(inode).
>> For commoncap the basic rule is capable_wrt_inode_uidgid(inode, CAP_SETFCAP).
>>
>> commoncap also applies a default policity to setting security.* xattrs.
>> ns_capable(dentry->d_sb->s_userns, CAP_SYS_ADMIN).
>>
>> smack reuses that default policy by calling cap_inode_setxattr if it
>> isn't a smack security.* xattr.
>>
>> selinux has what looks like an old copy of the commoncap checks for
>> the security.* in selinux_inode_setotherxattr.  Testing for
>> capable(CAP_SETFCAP) for security.capable and capable(CAP_SYS_ADMIN)
>> for the others.
>>
>> With the added complication that selinux calls
>> selinux_inode_setotherxattr also for the remove_xattr case.  So fixing
>> this in selinux_inode_setotherxattr is not appropriate.
>>
>> I believe selinux also has general policy hooks it applies to all
>> invocations of setxattr.
>>
>> So I think to really fix this we need to separate the cases of is this
>> your security modules attribute from general policy checks added by the
>> security modules.  Perhaps something like this for
>> security_inode_setxattr:
>>
>> Hmm.  Looking at least ima also has the distinction between protecting
>> it's own xattr writes and running generaly security module policy on
>> xattr writes.
>>
>> int security_inode_setxattr(struct dentry *dentry, const char *name,
>> 			    const void *value, size_t size, int flags)
>> {
>> 	int ret = 0;
>>
>> 	if (unlikely(IS_PRIVATE(d_backing_inode(dentry))))
>> 		return 0;
>>
>> 	if (strncmp(name, XATTR_SECURITY_PREFIX,
>> 			sizeof(XATTR_SECURITY_PREFIX) - 1) == 0) {
>> 		/* Call the security modules and see if they all return
>>                  * -EOPNOTSUPP if so apply the default permission
>>                  * check of ns_capable(dentry->d_sb->s_user_ns, CAP_SYS_ADMIN)
>>                  * otherwise if one of the security modules supports
>> 		 * this attribute (signaled by returning something other
>> 		 * -EOPNOTSUPP) then set ret to that result.
>>                  *
>>                  * The security modules include at least smack, selinux,
>> 		 * commoncap, ima, and evm.
>>                  */
>>                  ret = magic_inode_protect_setxattr(dentry, name, value, size);
>>         }
>> 	if (ret)
>> 		return ret;
>>
>>         /* Run all of the security module policy against this setxattr call */
>>         return magic_inode_policy_setxattr(dentry, name, value, size);
>> }
>>
>> Eric
>
> Yup, that's pretty much what I'm thinking. It's unfortunate
> that the magic_ API isn't fully implemented. There's going to
> be a good deal of code surgery instead. Is there an observed
> problem today? This is going to have to get addressed for stacking,
> so if there isn't a behavioral issue that impacts something real
> I would like to defer spending significant time on it. Do you have
> a case where this is not working correctly?

Merged as of 4.14-rc1 is the support for user namespace root to set
sercurity.capable.  This fails when selinux is loaded.

removexattr has the same problem and the code is a little less
convoluted in that case.

Not being able to set the capability when you should be able to is
very noticable.  Like running into a brick wall noticable.

Which is where the minimal patch for selinux comes in.  I think it
solves the exact case in question, even if it isn't the perfect long
term solution.

Eric



More information about the Containers mailing list