[RFC v2 19/19] ima: Setup securityfs for IMA namespace

Stefan Berger stefanb at linux.ibm.com
Fri Dec 3 18:06:13 UTC 2021


On 12/3/21 12:03, James Bottomley wrote:
> On Thu, 2021-12-02 at 21:31 -0500, Stefan Berger wrote:
> [...]
>>   static int securityfs_init_fs_context(struct fs_context *fc)
>>   {
>> +	int rc;
>> +
>> +	if (fc->user_ns->ima_ns->late_fs_init) {
>> +		rc = fc->user_ns->ima_ns->late_fs_init(fc->user_ns);
>> +		if (rc)
>> +			return rc;
>> +	}
>>   	fc->ops = &securityfs_context_ops;
>>   	return 0;
>>   }
> I know I suggested this, but to get this to work in general, it's going
> to have to not be specific to IMA, so it's going to have to become
> something generic like a notifier chain.  The other problem is it's
> only working still by accident:

I had thought about this also but the rationale was:

securityfs is compiled due to CONFIG_IMA_NS and the user namespace 
exists there and that has a pointer now to ima_namespace, which can have 
that callback. I assumed that other namespaced subsystems could also be 
reached then via such a callback, but I don't know.

I suppose any late filesystem init callchain would have to be connected 
to the user_namespace somehow?


>
>> +int ima_fs_ns_init(struct ima_namespace *ns)
>> +{
>> +	ns->mount = securityfs_ns_create_mount(ns->user_ns);
> This actually triggers on the call to securityfs_init_fs_context, but
> nothing happens because the callback is null.  Every subsequent use of
> fscontext will trigger this.  The point of a keyed supeblock is that
> fill_super is only called once per key, that's the place we should be
> doing this.   It should also probably be a blocking notifier so any
> consumer of securityfs can be namespaced by registering for this
> notifier.


What I don't like about the fill_super is that it gets called too early:

[   67.058611] securityfs_ns_create_mount @ 102 target user_ns: 
ffff95c010698c80; nr_extents: 0
[   67.059836] securityfs_fill_super @ 47  user_ns: ffff95c010698c80; 
nr_extents: 0

We are switching to the target user namespace in 
securityfs_ns_create_mount. The expected nr_extents at this point is 0, 
since user_ns hasn't been configured, yet. But then security_fill_super 
is also called with nr_extents 0. We cannot use that, it's too early!


>
>> +	if (IS_ERR(ns->mount)) {
>> +		ns->mount = NULL;
>> +		return -1;
>> +	}
>> +	ns->mount_count = 1;
> This is a bit nasty, too: we're spilling the guts of mount count
> tracking into IMA instead of encapsulating it inside securityfs.


Ok, I can make this disappear.


>
>> +
>> +	/* Adjust the trigger for user namespace's early teardown of
>> dependent
>> +	 * namespaces. Due to the filesystem there's an additional
>> reference
>> +	 * to the user namespace.
>> +	 */
>> +	ns->user_ns->refcount_teardown += 1;
>> +
>> +	ns->late_fs_init = ima_fs_ns_late_init;
>> +
>> +	return 0;
>> +}
> I think what should be happening is that we shouldn't so the
> simple_pin_fs, which creates the inodes, ahead of time; we should do it
> inside fill_super using a notifier, meaning it gets called once per

fill_super would only work for the init_user_ns from what I can see.


> key, creates the root dentry then triggers the notifier which
> instantiates all the namespaced entries.  We can still use
> simple_pin_fs for this because there's no locking across fill_super.
> This would mean fill_super would be called the first time the
> securityfs is mounted inside the namespace.


I guess I would need to know how fill_super would work or how it could 
be called late/delayed as well.


>
> If we do it this way, we can now make securityfs have its own mount and
> mount_count inside the user namespace, which it uses internally to the
> securityfs code, thus avoiding exposing them to ima or any other
> namespaced consumer.
>
> I also think we now don't need the securityfs_ns_ duplicated functions
> because the callback via the notifier chain now ensures we can use the
> namespace they were created in to distinguish between non namespaced
> and namespaced entries.

Is there then no need to pass a separate vfsmount * in anymore? Where 
would the vfsmount pointer reside? For now it's in ima_namespace, but it 
sounds like it should be in a more centralized place? Should it also be 
connected to the user_namespace so we can pick it up using get_user_ns()?


>
> So non-namespaced consumers of securityfs would do what they do now
> (calling the securityfs_create on initialization) and namespaced
> consumers would register a callback on the notifier which would get
> called once for every namespace the securityfs gets mounted in.
>
> I also theorize if we do it with notifiers, we could have a notifier on
> kill_sb to tear down all the entires.  If we do this, I think we don't
> have to pin any more.
>
> James
>
>

diff --git a/security/inode.c b/security/inode.c
index ed5f1c533776..49c9839642ed 100644
--- a/security/inode.c
+++ b/security/inode.c
@@ -44,6 +44,8 @@ static int securityfs_fill_super(struct super_block 
*sb, struct fs_context *fc)
         static const struct tree_descr files[] = {{""}};
         int error;

+       printk(KERN_INFO "%s @ %u  user_ns: %px; nr_extents: %d\n", 
__func__, __LINE__, fc->user_ns, fc->user_ns->uid_map.nr_extents);
+
         error = simple_fill_super(sb, SECURITYFS_MAGIC, files);
         if (error)
                 return error;
@@ -97,6 +99,8 @@ struct vfsmount *securityfs_ns_create_mount(struct 
user_namespace *user_ns)
         put_user_ns(fc->user_ns);
         fc->user_ns = get_user_ns(user_ns);

+       printk(KERN_INFO "%s @ %u target user_ns: %px; nr_extents: 
%d\n", __func__, __LINE__, fc->user_ns, fc->user_ns->uid_map.nr_extents);
+
         mnt = fc_mount(fc);
         put_fs_context(fc);
         return mnt;



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