Re: [PATCH v2 1/1] ovl: setxattr: avoid deadlock when setting IMA xattr.

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



On Mon, May 16, 2016 at 6:13 PM, Krisztian Litkey <kli@xxxxxx> wrote:
> On Mon, May 16, 2016 at 5:20 PM, Mimi Zohar <zohar@xxxxxxxxxx> wrote:
>> Krisztian Litkey wrote on 05/15/2016 04:07:35 PM:
>>
>>> If we're writing the extended attribute used by IMA, don't
>>> try to lock sb_writers (mnt_want_write) or i_mutex. We're
>>> being called from ima_file_free and the necessary locks
>>> are already being held. Trying to lock them again will
>>> deadlock.
>>
>> Thinking about this some more, security.ima can be written here in
>> ima_file_free, but it also can be written by userspace.  The former updates
>> the file hash, while the latter is used to write the file signature.
>>
>>> In practice we test if the real inode has the S_IMA flag
>>> set and if the xattr being set is the IMA attribute. If
>>> both are true, we call __vfs_setxattr_noperm instead of
>>> the usual vfs_setxattr we call for all other cases.
>>>
>>> Signed-off-by: Krisztian Litkey <kli@xxxxxx>
>>
>> Writing the file signature from userspace should call the normal
>> vfs_setxattr().
>
> Yes. If there was a reliable way to detect that we're being called
> as an end result of ima_fix_attr we should check for that and branch
> accordingly. Based on your original suggestion I was under the
> impression that testing S_IMA would have been the right check.
> Now based on your recent comment, and checking the code, I see
> that it will be set for all inodes that are associated with an iint cache
> entry...
>
> Unless we add a dedicated *vfs_setxattr* flag just for this and pass it
> from ima_fix_xattr (so that it'd propagate back to ovl_setxattr where
> we test and branch accordingly), I see no easy way to check for the
> necessary precondition. And adding a dedicated flag would probably
> be considered a horrible kludge... so I think I need to dig deeper and
> see if I can come up with another way of fixing this.
>
> I have taken a small peek at other architecturally not quite unlike FS
> implementations. Encryptfs seems to be one of the closest ones. I
> will test if their approach works together with IMA and if it does I'll try
> to roll a similar implementation for overlayfs. Does that sound
> reasonable to you ?

Hmm... after having taken a closer look at ecryptfs, I think its setxattr
is not comparable to overlayfs. The former is much simpler because
it simply passes the call on to the underlying filesystem implementation
calling vfs_setxattr, much like overlayfs was trying to do. But ecryptfs
does not need to do anything else besides setting the attribute so it can
call vfs_setxattr without taking any locks or mutexes itself.

However, there is a crucial difference in overlayfs: it might need to
copy the dentry (and all directories leading up to it) on demand in
setxattr. This happens if setxattr is being called for a file system entry
which has never been modified in/through the overlay. I think this copy
operation is what really should be protected by mnt_{want,drop}_write.

So the right thing to do would be to protect the copy and do the rest by
unconditionally calling __vfs_setxattr_noperm. But wouldn't that just bring
us back to the original problem: if i_mutex is already held, can't really
mnt_want_write without triggering the lockdep problem, right ?

>
>>
>> Mimi
>>

  Cheers,
    Krisztian

>
>   Cheers,
>     Krisztian
>
>>
>>
>>> ---
>>>  fs/overlayfs/inode.c | 24 ++++++++++++++++++------
>>>  1 file changed, 18 insertions(+), 6 deletions(-)
>>>
>>> diff --git a/fs/overlayfs/inode.c b/fs/overlayfs/inode.c
>>> index b29036a..15f4af3 100644
>>> --- a/fs/overlayfs/inode.c
>>> +++ b/fs/overlayfs/inode.c
>>> @@ -222,12 +222,18 @@ static bool ovl_is_private_xattr(const char *name)
>>>  int ovl_setxattr(struct dentry *dentry, const char *name,
>>>         const void *value, size_t size, int flags)
>>>  {
>>> -   int err;
>>> +   int err, ima;
>>>     struct dentry *upperdentry;
>>> +   struct inode *inode;
>>>
>>> -   err = ovl_want_write(dentry);
>>> -   if (err)
>>> -      goto out;
>>> +   inode = ovl_dentry_real(dentry)->d_inode;
>>> +   ima = IS_IMA(inode) && !strcmp(name, XATTR_NAME_IMA);
>>> +
>>> +   if (!ima) {
>>> +      err = ovl_want_write(dentry);
>>> +      if (err)
>>> +         goto out;
>>> +   }
>>>
>>>     err = -EPERM;
>>>     if (ovl_is_private_xattr(name))
>>> @@ -238,10 +244,16 @@ int ovl_setxattr(struct dentry *dentry, const
>>> char *name,
>>>        goto out_drop_write;
>>>
>>>     upperdentry = ovl_dentry_upper(dentry);
>>> -   err = vfs_setxattr(upperdentry, name, value, size, flags);
>>> +
>>> +   if (!ima)
>>> +      err = vfs_setxattr(upperdentry, name, value, size, flags);
>>> +   else
>>> +      err = __vfs_setxattr_noperm(upperdentry, name, value, size,
>>> +                   flags);
>>>
>>>  out_drop_write:
>>> -   ovl_drop_write(dentry);
>>> +   if (!ima)
>>> +      ovl_drop_write(dentry);
>>>  out:
>>>     return err;
>>>  }
>>> --
>>> 2.5.5
>>>
>>
--
To unsubscribe from this list: send the line "unsubscribe linux-unionfs" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html



[Index of Archives]     [Linux Filesystems Devel]     [Linux NFS]     [Linux NILFS]     [Linux USB Devel]     [Linux Audio Users]     [Yosemite News]     [Linux Kernel]     [Linux SCSI]

  Powered by Linux