Groups | Search | Server Info | Keyboard shortcuts | Login | Register [http] [https] [nntp] [nntps]
Groups > linux.kernel > #1741502 > unrolled thread
| Started by | Mimi Zohar <zohar@linux.vnet.ibm.com> |
|---|---|
| First post | 2017-09-28 14:50 +0200 |
| Last post | 2017-09-28 18:00 +0200 |
| Articles | 20 on this page of 27 — 6 participants |
Back to article view | Back to linux.kernel
[RFC PATCH 0/3] define new read_iter file operation rwf flag Mimi Zohar <zohar@linux.vnet.ibm.com> - 2017-09-28 14:50 +0200
[RFC PATCH 3/3] fs: detect that the i_rwsem has already been taken exclusively Mimi Zohar <zohar@linux.vnet.ibm.com> - 2017-09-28 14:50 +0200
Re: [RFC PATCH 3/3] fs: detect that the i_rwsem has already been taken exclusively Dave Chinner <david@fromorbit.com> - 2017-09-29 00:10 +0200
Re: [RFC PATCH 3/3] fs: detect that the i_rwsem has already been taken exclusively Linus Torvalds <torvalds@linux-foundation.org> - 2017-09-29 01:40 +0200
Re: [RFC PATCH 3/3] fs: detect that the i_rwsem has already been taken exclusively Mimi Zohar <zohar@linux.vnet.ibm.com> - 2017-09-29 02:20 +0200
Re: [RFC PATCH 3/3] fs: detect that the i_rwsem has already been taken exclusively Linus Torvalds <torvalds@linux-foundation.org> - 2017-09-29 02:40 +0200
Re: [RFC PATCH 3/3] fs: detect that the i_rwsem has already been taken exclusively Mimi Zohar <zohar@linux.vnet.ibm.com> - 2017-09-29 04:00 +0200
Re: [RFC PATCH 3/3] fs: detect that the i_rwsem has already been taken exclusively Linus Torvalds <torvalds@linux-foundation.org> - 2017-09-29 05:30 +0200
Re: [RFC PATCH 3/3] fs: detect that the i_rwsem has already been taken exclusively ebiederm@xmission.com (Eric W. Biederman) - 2017-10-01 03:40 +0200
Re: [RFC PATCH 3/3] fs: detect that the i_rwsem has already been taken exclusively Mimi Zohar <zohar@linux.vnet.ibm.com> - 2017-10-01 14:10 +0200
Re: [RFC PATCH 3/3] fs: detect that the i_rwsem has already been taken exclusively Linus Torvalds <torvalds@linux-foundation.org> - 2017-10-01 20:50 +0200
Re: [RFC PATCH 3/3] fs: detect that the i_rwsem has already been taken exclusively Dave Chinner <david@fromorbit.com> - 2017-10-02 00:40 +0200
Re: [RFC PATCH 3/3] fs: detect that the i_rwsem has already been taken exclusively Linus Torvalds <torvalds@linux-foundation.org> - 2017-10-02 01:20 +0200
Re: [RFC PATCH 3/3] fs: detect that the i_rwsem has already been taken exclusively Dave Chinner <david@fromorbit.com> - 2017-10-02 06:00 +0200
Re: [RFC PATCH 3/3] fs: detect that the i_rwsem has already been taken exclusively Mimi Zohar <zohar@linux.vnet.ibm.com> - 2017-10-02 01:50 +0200
Re: [RFC PATCH 3/3] fs: detect that the i_rwsem has already been taken exclusively ebiederm@xmission.com (Eric W. Biederman) - 2017-10-02 05:30 +0200
Re: [RFC PATCH 3/3] fs: detect that the i_rwsem has already been taken exclusively Mimi Zohar <zohar@linux.vnet.ibm.com> - 2017-10-02 14:30 +0200
Re: [RFC PATCH 3/3] fs: detect that the i_rwsem has already been taken exclusively Dave Chinner <david@fromorbit.com> - 2017-10-02 06:40 +0200
Re: [RFC PATCH 3/3] fs: detect that the i_rwsem has already been taken exclusively Mimi Zohar <zohar@linux.vnet.ibm.com> - 2017-10-02 14:20 +0200
Re: [RFC PATCH 3/3] fs: detect that the i_rwsem has already been taken exclusively Jeff Layton <jlayton@redhat.com> - 2017-10-02 14:50 +0200
Re: [RFC PATCH 3/3] fs: detect that the i_rwsem has already been taken exclusively ebiederm@xmission.com (Eric W. Biederman) - 2017-10-02 00:10 +0200
Re: [RFC PATCH 3/3] fs: detect that the i_rwsem has already been taken exclusively Linus Torvalds <torvalds@linux-foundation.org> - 2017-10-02 00:30 +0200
Re: [RFC PATCH 3/3] fs: detect that the i_rwsem has already been taken exclusively Mimi Zohar <zohar@linux.vnet.ibm.com> - 2017-10-02 02:00 +0200
[RFC PATCH 1/3] fs: define new read_iter rwf flag Mimi Zohar <zohar@linux.vnet.ibm.com> - 2017-09-28 14:50 +0200
Re: [RFC PATCH 1/3] fs: define new read_iter rwf flag Matthew Wilcox <willy@infradead.org> - 2017-09-28 16:00 +0200
Re: [RFC PATCH 1/3] fs: define new read_iter rwf flag Mimi Zohar <zohar@linux.vnet.ibm.com> - 2017-09-28 16:40 +0200
Re: [RFC PATCH 1/3] fs: define new read_iter rwf flag Linus Torvalds <torvalds@linux-foundation.org> - 2017-09-28 18:00 +0200
Page 1 of 2 [1] 2 Next page →
| From | Mimi Zohar <zohar@linux.vnet.ibm.com> |
|---|---|
| Date | 2017-09-28 14:50 +0200 |
| Subject | [RFC PATCH 0/3] define new read_iter file operation rwf flag |
| Message-ID | <uuGql-C7-5@gated-at.bofh.it> |
This patch set replaces the "integrity_read" file operation method, as defined in the "ima: use fs method to read integrity data" patch, with a new read_iter file operation "rwf" flag. (The other patches are the same.*) The main difference between these approaches is whether IMA must be explicitly enabled (opt-in), by defining the "integrity_read" file operation method for each file system, or enabled by default, with modifications as needed to the read_iter. *The entire patch sets can be found in git://git.kernel.org/pub/scm/linux/kernel/git/zohar/linux-integrity.git next-integrity-read and next-read-iter. Mimi Mimi Zohar (3): fs: define new read_iter rwf flag integrity: use call_read_iter to calculate the file hash fs: detect that the i_rwsem has already been taken exclusively arch/s390/hypfs/inode.c | 3 ++- drivers/block/loop.c | 2 +- drivers/char/mem.c | 6 ++++-- drivers/gpu/drm/drm_dp_aux_dev.c | 3 ++- drivers/net/tap.c | 3 ++- drivers/net/tun.c | 3 ++- drivers/staging/android/ashmem.c | 3 ++- drivers/staging/lustre/lustre/llite/file.c | 3 ++- drivers/staging/lustre/lustre/llite/vvp_io.c | 2 +- drivers/usb/gadget/function/f_fs.c | 3 ++- drivers/usb/gadget/legacy/inode.c | 2 +- drivers/vhost/net.c | 3 ++- fs/9p/vfs_file.c | 8 +++++--- fs/aio.c | 2 +- fs/block_dev.c | 4 ++-- fs/ceph/file.c | 5 +++-- fs/cifs/cifsfs.c | 6 +++--- fs/cifs/cifsfs.h | 4 ++-- fs/cifs/file.c | 10 +++++----- fs/coda/file.c | 2 +- fs/ecryptfs/file.c | 4 ++-- fs/efivarfs/file.c | 2 +- fs/ext2/file.c | 16 +++++++++------ fs/ext4/file.c | 20 +++++++++++-------- fs/fuse/cuse.c | 3 ++- fs/fuse/dev.c | 3 ++- fs/fuse/file.c | 8 +++++--- fs/hugetlbfs/inode.c | 3 ++- fs/ncpfs/file.c | 2 +- fs/nfs/file.c | 4 ++-- fs/nfs/internal.h | 2 +- fs/ocfs2/file.c | 5 +++-- fs/orangefs/file.c | 3 ++- fs/pipe.c | 2 +- fs/read_write.c | 4 ++-- fs/splice.c | 2 +- fs/xfs/xfs_file.c | 30 +++++++++++++++++----------- include/linux/fs.h | 10 +++++----- mm/filemap.c | 3 ++- mm/shmem.c | 3 ++- net/socket.c | 4 ++-- security/integrity/iint.c | 21 +++++++++++++------ sound/core/pcm_native.c | 2 +- 43 files changed, 139 insertions(+), 94 deletions(-) -- 2.7.4
[toc] | [next] | [standalone]
| From | Mimi Zohar <zohar@linux.vnet.ibm.com> |
|---|---|
| Date | 2017-09-28 14:50 +0200 |
| Subject | [RFC PATCH 3/3] fs: detect that the i_rwsem has already been taken exclusively |
| Message-ID | <uuGqm-C7-31@gated-at.bofh.it> |
| In reply to | #1741502 |
Don't attempt to take the i_rwsem, if it has already been taken
exclusively.
Signed-off-by: Mimi Zohar <zohar@linux.vnet.ibm.com>
---
fs/ext2/file.c | 6 ++++--
fs/ext4/file.c | 8 +++++---
fs/xfs/xfs_file.c | 10 ++++++----
3 files changed, 15 insertions(+), 9 deletions(-)
diff --git a/fs/ext2/file.c b/fs/ext2/file.c
index 839095f66d8d..d174b2880929 100644
--- a/fs/ext2/file.c
+++ b/fs/ext2/file.c
@@ -38,9 +38,11 @@ static ssize_t ext2_dax_read_iter(struct kiocb *iocb, struct iov_iter *to,
if (!iov_iter_count(to))
return 0; /* skip atime */
- inode_lock_shared(inode);
+ if (!rwf)
+ inode_lock_shared(inode);
ret = dax_iomap_rw(iocb, to, &ext2_iomap_ops);
- inode_unlock_shared(inode);
+ if (!rwf)
+ inode_unlock_shared(inode);
file_accessed(iocb->ki_filp);
return ret;
diff --git a/fs/ext4/file.c b/fs/ext4/file.c
index 10789666725e..7d7c0e380add 100644
--- a/fs/ext4/file.c
+++ b/fs/ext4/file.c
@@ -38,7 +38,7 @@ static ssize_t ext4_dax_read_iter(struct kiocb *iocb, struct iov_iter *to,
struct inode *inode = file_inode(iocb->ki_filp);
ssize_t ret;
- if (!inode_trylock_shared(inode)) {
+ if (!rwf && !inode_trylock_shared(inode)) {
if (iocb->ki_flags & IOCB_NOWAIT)
return -EAGAIN;
inode_lock_shared(inode);
@@ -48,12 +48,14 @@ static ssize_t ext4_dax_read_iter(struct kiocb *iocb, struct iov_iter *to,
* change anymore
*/
if (!IS_DAX(inode)) {
- inode_unlock_shared(inode);
+ if (!rwf)
+ inode_unlock_shared(inode);
/* Fallback to buffered IO in case we cannot support DAX */
return generic_file_read_iter(iocb, to, rwf);
}
ret = dax_iomap_rw(iocb, to, &ext4_iomap_ops);
- inode_unlock_shared(inode);
+ if (!rwf)
+ inode_unlock_shared(inode);
file_accessed(iocb->ki_filp);
return ret;
diff --git a/fs/xfs/xfs_file.c b/fs/xfs/xfs_file.c
index cf1ce8961601..0cffca97ed68 100644
--- a/fs/xfs/xfs_file.c
+++ b/fs/xfs/xfs_file.c
@@ -239,7 +239,7 @@ xfs_file_dax_read(
if (!count)
return 0; /* skip atime */
- if (!xfs_ilock_nowait(ip, XFS_IOLOCK_SHARED)) {
+ if (!rwf && !xfs_ilock_nowait(ip, XFS_IOLOCK_SHARED)) {
if (iocb->ki_flags & IOCB_NOWAIT)
return -EAGAIN;
xfs_ilock(ip, XFS_IOLOCK_SHARED);
@@ -247,7 +247,8 @@ xfs_file_dax_read(
ret = dax_iomap_rw(iocb, to, &xfs_iomap_ops);
xfs_iunlock(ip, XFS_IOLOCK_SHARED);
- file_accessed(iocb->ki_filp);
+ if (!rwf)
+ file_accessed(iocb->ki_filp);
return ret;
}
@@ -262,13 +263,14 @@ xfs_file_buffered_aio_read(
trace_xfs_file_buffered_read(ip, iov_iter_count(to), iocb->ki_pos);
- if (!xfs_ilock_nowait(ip, XFS_IOLOCK_SHARED)) {
+ if (!rwf && !xfs_ilock_nowait(ip, XFS_IOLOCK_SHARED)) {
if (iocb->ki_flags & IOCB_NOWAIT)
return -EAGAIN;
xfs_ilock(ip, XFS_IOLOCK_SHARED);
}
ret = generic_file_read_iter(iocb, to, rwf);
- xfs_iunlock(ip, XFS_IOLOCK_SHARED);
+ if (!rwf)
+ xfs_iunlock(ip, XFS_IOLOCK_SHARED);
return ret;
}
--
2.7.4
[toc] | [prev] | [next] | [standalone]
| From | Dave Chinner <david@fromorbit.com> |
|---|---|
| Date | 2017-09-29 00:10 +0200 |
| Subject | Re: [RFC PATCH 3/3] fs: detect that the i_rwsem has already been taken exclusively |
| Message-ID | <uuPah-6b6-1@gated-at.bofh.it> |
| In reply to | #1741504 |
On Thu, Sep 28, 2017 at 08:39:33AM -0400, Mimi Zohar wrote: > Don't attempt to take the i_rwsem, if it has already been taken > exclusively. > > Signed-off-by: Mimi Zohar <zohar@linux.vnet.ibm.com> That's bloody awful. The locking in filesystem IO paths is already complex enough without adding a new IO path semantic that says "caller has already locked the i_rwsem in some order and some dependencies that we have no idea about". Instead of having well defined locking in a small amount of self contained code, we've now got to search through completely unfamiliar code to analyse any sort of filesystem lockdep report or deadlock to determine if that somethign else has screwed up the filesystem IO path locking. It also seems to have an undocumented semantic of not updating access times on the inode, which effectively makes this invisible IO and means we're assuming that timestamp updates will be done by correctly callers outside the filesystem IO path. That's almost certainly going to be a source of bugs in the future. This seems like a recipe for future disasters to me.... Cheers, Dave. -- Dave Chinner david@fromorbit.com
[toc] | [prev] | [next] | [standalone]
| From | Linus Torvalds <torvalds@linux-foundation.org> |
|---|---|
| Date | 2017-09-29 01:40 +0200 |
| Subject | Re: [RFC PATCH 3/3] fs: detect that the i_rwsem has already been taken exclusively |
| Message-ID | <uuQzo-6Ul-15@gated-at.bofh.it> |
| In reply to | #1741827 |
On Thu, Sep 28, 2017 at 3:02 PM, Dave Chinner <david@fromorbit.com> wrote:
> On Thu, Sep 28, 2017 at 08:39:33AM -0400, Mimi Zohar wrote:
>> Don't attempt to take the i_rwsem, if it has already been taken
>> exclusively.
>>
>> Signed-off-by: Mimi Zohar <zohar@linux.vnet.ibm.com>
>
> That's bloody awful.
>
> The locking in filesystem IO paths is already complex enough without
> adding a new IO path semantic that says "caller has already locked
> the i_rwsem in some order and some dependencies that we have no idea
> about".
I do have to admit that I never got a satisfactory answer on why IMA
doesn't just use its own private per-inode lock for this all.
It isn't using the i_rwsem for file consistency reasons anyway, so it
seems to be purely about serializing the actual signature generation
with the xattr writing, but since IMA does those both, why isn't IMA
just using its own lock (not the filesystem lock) to do that?
Linus
[toc] | [prev] | [next] | [standalone]
| From | Mimi Zohar <zohar@linux.vnet.ibm.com> |
|---|---|
| Date | 2017-09-29 02:20 +0200 |
| Subject | Re: [RFC PATCH 3/3] fs: detect that the i_rwsem has already been taken exclusively |
| Message-ID | <uuRc5-7nV-1@gated-at.bofh.it> |
| In reply to | #1741863 |
On Thu, 2017-09-28 at 16:39 -0700, Linus Torvalds wrote: > On Thu, Sep 28, 2017 at 3:02 PM, Dave Chinner <david@fromorbit.com> wrote: > > On Thu, Sep 28, 2017 at 08:39:33AM -0400, Mimi Zohar wrote: > >> Don't attempt to take the i_rwsem, if it has already been taken > >> exclusively. > >> > >> Signed-off-by: Mimi Zohar <zohar@linux.vnet.ibm.com> > > > > That's bloody awful. > > > > The locking in filesystem IO paths is already complex enough without > > adding a new IO path semantic that says "caller has already locked > > the i_rwsem in some order and some dependencies that we have no idea > > about". > > I do have to admit that I never got a satisfactory answer on why IMA > doesn't just use its own private per-inode lock for this all. > > It isn't using the i_rwsem for file consistency reasons anyway, so it > seems to be purely about serializing the actual signature generation > with the xattr writing, but since IMA does those both, why isn't IMA > just using its own lock (not the filesystem lock) to do that? Originally IMA did define it's own lock, prior to IMA-appraisal. IMA- appraisal introduced writing the file hash as an xattr, which required taking the i_mutex. process_measurement() and ima_file_free() took the iint->mutex first and then the i_mutex, while setxattr, chmod and chown took the locks in reverse order. To resolve the potential deadlock, the iint->mutex was eliminated. Mimi
[toc] | [prev] | [next] | [standalone]
| From | Linus Torvalds <torvalds@linux-foundation.org> |
|---|---|
| Date | 2017-09-29 02:40 +0200 |
| Subject | Re: [RFC PATCH 3/3] fs: detect that the i_rwsem has already been taken exclusively |
| Message-ID | <uuRvr-7tU-5@gated-at.bofh.it> |
| In reply to | #1741872 |
On Thu, Sep 28, 2017 at 5:12 PM, Mimi Zohar <zohar@linux.vnet.ibm.com> wrote:
>
> Originally IMA did define it's own lock, prior to IMA-appraisal. IMA-
> appraisal introduced writing the file hash as an xattr, which required
> taking the i_mutex. process_measurement() and ima_file_free() took
> the iint->mutex first and then the i_mutex, while setxattr, chmod and
> chown took the locks in reverse order. To resolve the potential
> deadlock, the iint->mutex was eliminated.
Umm. You already have an explicit invalidation model, where you
invalidate after a write has occurred.
But the locking of the generation count (or "invalidation status" or
whatever) can - and should be - entirely independent of the locking of
the actual appraisal.
So make the appraisal itself use a semaphore ("only one appraisal at a time").
But use a separate lock for the generation count.
So then appraisal is:
- get appraisal semaphore
- get generation count lock
read generation count
- drop generation count lock
- do the actual appraisal
- drop appraisal semaphore
Note that you now have a tuple of "generation count, appraisal" that
you have *not* saved off yet, but it's your stable thing.
Now you can write the xattr:
- get exclusive inode lock (for xattr)
- get generation count lock
- if the appraisal generation does not match, do NOT write
the appraisal you just calculated, since it's pointless: it's already
stale.
- otherwise write the appraisal and generation count to the xattr
- drop generation count lock
- release exclusive inode lock
and then for anything that does setxattr or chmod or whatever, just
use that generation count lock to invalidate the appraisal. You don't
need to actual appraisal lock for that.
So now the appraisal lock is always the outermost one, and the
generation count lock is always the innermost.
Anyway, I haven't looked at the details of what IMA does, but
something like the above really sounds like it should work and seems
pretty straightforward.
No?
Linus
[toc] | [prev] | [next] | [standalone]
| From | Mimi Zohar <zohar@linux.vnet.ibm.com> |
|---|---|
| Date | 2017-09-29 04:00 +0200 |
| Subject | Re: [RFC PATCH 3/3] fs: detect that the i_rwsem has already been taken exclusively |
| Message-ID | <uuSKR-8ao-1@gated-at.bofh.it> |
| In reply to | #1741875 |
On Thu, 2017-09-28 at 17:33 -0700, Linus Torvalds wrote:
> On Thu, Sep 28, 2017 at 5:12 PM, Mimi Zohar <zohar@linux.vnet.ibm.com> wrote:
> >
> > Originally IMA did define it's own lock, prior to IMA-appraisal. IMA-
> > appraisal introduced writing the file hash as an xattr, which required
> > taking the i_mutex. process_measurement() and ima_file_free() took
> > the iint->mutex first and then the i_mutex, while setxattr, chmod and
> > chown took the locks in reverse order. To resolve the potential
> > deadlock, the iint->mutex was eliminated.
>
> Umm. You already have an explicit invalidation model, where you
> invalidate after a write has occurred.
Invalidating after each write would be horrible performance. Only
after all the changes are made, after the file close, is the file
integrity status invalidated and the file hash re-calculated and
written out.
At some point, we might want to go back and look at having finer grain
file integrity invalidation.
> But the locking of the generation count (or "invalidation status" or
> whatever) can - and should be - entirely independent of the locking of
> the actual appraisal.
The locking issue isn't with validating the file hash, but with the
setxattr, chmod, chown syscalls. Each of these syscalls takes the
i_rwsem exclusively before IMA (or EVM) is called.
In ima_file_free(), the locking would be:
lock: iint->mutex
lock: i_rwsem
write hash as xattr
unlock: i_rwsem
unlock iint->mutex
In setxattr, chmod, chown syscalls, IMA (and EVM) are called after the
i_rwsem is already taken. So the locking would be:
lock: i_rwsem
lock: iint->mutex
unlock: iint->mutex
unlock: i_rwsem
Perhaps now the problem is clearer?
Mimi
> So make the appraisal itself use a semaphore ("only one appraisal at a time").
>
> But use a separate lock for the generation count.
> So then appraisal is:
>
> - get appraisal semaphore
> - get generation count lock
> read generation count
> - drop generation count lock
> - do the actual appraisal
> - drop appraisal semaphore
>
> Note that you now have a tuple of "generation count, appraisal" that
> you have *not* saved off yet, but it's your stable thing.
>
> Now you can write the xattr:
>
> - get exclusive inode lock (for xattr)
> - get generation count lock
> - if the appraisal generation does not match, do NOT write
> the appraisal you just calculated, since it's pointless: it's already
> stale.
> - otherwise write the appraisal and generation count to the xattr
> - drop generation count lock
> - release exclusive inode lock
>
> and then for anything that does setxattr or chmod or whatever, just
> use that generation count lock to invalidate the appraisal. You don't
> need to actual appraisal lock for that.
>
> So now the appraisal lock is always the outermost one, and the
> generation count lock is always the innermost.
>
> Anyway, I haven't looked at the details of what IMA does, but
> something like the above really sounds like it should work and seems
> pretty straightforward.
>
> No?
>
> Linus
>
[toc] | [prev] | [next] | [standalone]
| From | Linus Torvalds <torvalds@linux-foundation.org> |
|---|---|
| Date | 2017-09-29 05:30 +0200 |
| Subject | Re: [RFC PATCH 3/3] fs: detect that the i_rwsem has already been taken exclusively |
| Message-ID | <uuU9Y-NR-15@gated-at.bofh.it> |
| In reply to | #1741894 |
On Thu, Sep 28, 2017 at 6:53 PM, Mimi Zohar <zohar@linux.vnet.ibm.com> wrote:
>
> The locking issue isn't with validating the file hash, but with the
> setxattr, chmod, chown syscalls. Each of these syscalls takes the
> i_rwsem exclusively before IMA (or EVM) is called.
Read my email again.
> In setxattr, chmod, chown syscalls, IMA (and EVM) are called after the
> i_rwsem is already taken. So the locking would be:
>
> lock: i_rwsem
> lock: iint->mutex
No.
Two locks. One inner, one outer. Only the actual ones that calculates
the hash would take the outer one. Read my email.
Linus
[toc] | [prev] | [next] | [standalone]
| From | ebiederm@xmission.com (Eric W. Biederman) |
|---|---|
| Date | 2017-10-01 03:40 +0200 |
| Subject | Re: [RFC PATCH 3/3] fs: detect that the i_rwsem has already been taken exclusively |
| Message-ID | <uvBoB-3Mo-1@gated-at.bofh.it> |
| In reply to | #1741912 |
Linus Torvalds <torvalds@linux-foundation.org> writes: > On Thu, Sep 28, 2017 at 6:53 PM, Mimi Zohar <zohar@linux.vnet.ibm.com> wrote: >> >> The locking issue isn't with validating the file hash, but with the >> setxattr, chmod, chown syscalls. Each of these syscalls takes the >> i_rwsem exclusively before IMA (or EVM) is called. > > Read my email again. > >> In setxattr, chmod, chown syscalls, IMA (and EVM) are called after the >> i_rwsem is already taken. So the locking would be: >> >> lock: i_rwsem >> lock: iint->mutex > > No. > > Two locks. One inner, one outer. Only the actual ones that calculates > the hash would take the outer one. Read my email. That would require a task_work or another kind of work callback so that the writes of the xattr are not synchronous with the vfs callback correct? Eric
[toc] | [prev] | [next] | [standalone]
| From | Mimi Zohar <zohar@linux.vnet.ibm.com> |
|---|---|
| Date | 2017-10-01 14:10 +0200 |
| Subject | Re: [RFC PATCH 3/3] fs: detect that the i_rwsem has already been taken exclusively |
| Message-ID | <uvLei-1Zz-15@gated-at.bofh.it> |
| In reply to | #1742724 |
On Sat, 2017-09-30 at 18:56 -0700, Linus Torvalds wrote: > On Sep 30, 2017 18:33, "Eric W. Biederman" <ebiederm@xmission.com> wrote:. > > > That would require a task_work or another kind of work callback so that > the writes of the xattr are not synchronous with the vfs callback > correct? > > > No, why? > > You should just invalidate the IMA on xattr write or other operations that > make the measurement invalid. You only need the inner lock. Right, re-introducing the iint->mutex and a new i_generation field in the iint struct with a separate set of locks should work. It will be reset if the file metadata changes (eg. setxattr, chown, chmod). (We need i_generation for namespacing IMA as well.) thanks, Mimi
[toc] | [prev] | [next] | [standalone]
| From | Linus Torvalds <torvalds@linux-foundation.org> |
|---|---|
| Date | 2017-10-01 20:50 +0200 |
| Subject | Re: [RFC PATCH 3/3] fs: detect that the i_rwsem has already been taken exclusively |
| Message-ID | <uvRtn-5BE-1@gated-at.bofh.it> |
| In reply to | #1742785 |
On Sun, Oct 1, 2017 at 5:08 AM, Mimi Zohar <zohar@linux.vnet.ibm.com> wrote:
>
> Right, re-introducing the iint->mutex and a new i_generation field in
> the iint struct with a separate set of locks should work. It will be
> reset if the file metadata changes (eg. setxattr, chown, chmod).
Note that the "inner lock" could possibly be omitted if the
invalidation can be just a single atomic instruction.
So particularly if invalidation could be just an atomic_inc() on the
generation count, there might not need to be any inner lock at all.
You'd have to serialize the actual measurement with the "read
generation count", but that should be as simple as just doing a
smp_rmb() between the "read generation count" and "do measurement on
file contents".
Of course, if you do something more complex in invalidation, you may
end up needing a real lock.
Linus
[toc] | [prev] | [next] | [standalone]
| From | Dave Chinner <david@fromorbit.com> |
|---|---|
| Date | 2017-10-02 00:40 +0200 |
| Subject | Re: [RFC PATCH 3/3] fs: detect that the i_rwsem has already been taken exclusively |
| Message-ID | <uvV3Y-7M7-11@gated-at.bofh.it> |
| In reply to | #1742858 |
On Sun, Oct 01, 2017 at 11:41:48AM -0700, Linus Torvalds wrote: > On Sun, Oct 1, 2017 at 5:08 AM, Mimi Zohar <zohar@linux.vnet.ibm.com> wrote: > > > > Right, re-introducing the iint->mutex and a new i_generation field in > > the iint struct with a separate set of locks should work. It will be > > reset if the file metadata changes (eg. setxattr, chown, chmod). > > Note that the "inner lock" could possibly be omitted if the > invalidation can be just a single atomic instruction. > > So particularly if invalidation could be just an atomic_inc() on the > generation count, there might not need to be any inner lock at all. > > You'd have to serialize the actual measurement with the "read > generation count", but that should be as simple as just doing a > smp_rmb() between the "read generation count" and "do measurement on > file contents". We already have a change counter on the inode, which is modified on any data or metadata write (i_version) under filesystem locks. The i_version counter has well defined semantics - it's required by NFSv4 to increment on any metadata or data change - so we should be able to rely on it's behaviour to implement IMA as well. Filesystems that support i_version are marked with [SB|MS]_I_VERSION in the superblock (IS_I_VERSION(inode)) so it should be easy to tell if IMA can be supported on a specific filesystem (btrfs, ext4, fuse and xfs ATM). The IMA code should be able to sample that at measurement time and either fail or be retried if i_version changes during measurement. We can then simply make the IMA xattr write conditional on the i_version value being unchanged from the sample the IMA code passes into the filesystem once the filesystem holds all the locks it needs to write the xattr... I note that IMA already grabs the i_version in ima_collect_measurement(), so this shouldn't be too hard to do. Perhaps we don't need any new locks or counters at all, maybe just the ability to feed a version cookie to the set_xattr method? Cheers, Dave. -- Dave Chinner david@fromorbit.com
[toc] | [prev] | [next] | [standalone]
| From | Linus Torvalds <torvalds@linux-foundation.org> |
|---|---|
| Date | 2017-10-02 01:20 +0200 |
| Subject | Re: [RFC PATCH 3/3] fs: detect that the i_rwsem has already been taken exclusively |
| Message-ID | <uvVGG-8gb-3@gated-at.bofh.it> |
| In reply to | #1742902 |
On Sun, Oct 1, 2017 at 3:34 PM, Dave Chinner <david@fromorbit.com> wrote:
>
> We already have a change counter on the inode, which is modified on
> any data or metadata write (i_version) under filesystem locks. The
> i_version counter has well defined semantics - it's required by
> NFSv4 to increment on any metadata or data change - so we should be
> able to rely on it's behaviour to implement IMA as well.
I actually think i_version has exactly the wrong semantics.
Afaik, it doesn't actually version the file _data_ at all, it only
versions "inode itself changed".
But I might have missed something obvious. The updates are hidden in
some odd places sometimes.
Linus
[toc] | [prev] | [next] | [standalone]
| From | Dave Chinner <david@fromorbit.com> |
|---|---|
| Date | 2017-10-02 06:00 +0200 |
| Subject | Re: [RFC PATCH 3/3] fs: detect that the i_rwsem has already been taken exclusively |
| Message-ID | <uw03E-2kf-3@gated-at.bofh.it> |
| In reply to | #1742909 |
On Sun, Oct 01, 2017 at 04:15:07PM -0700, Linus Torvalds wrote: > On Sun, Oct 1, 2017 at 3:34 PM, Dave Chinner <david@fromorbit.com> wrote: > > > > We already have a change counter on the inode, which is modified on > > any data or metadata write (i_version) under filesystem locks. The > > i_version counter has well defined semantics - it's required by > > NFSv4 to increment on any metadata or data change - so we should be > > able to rely on it's behaviour to implement IMA as well. > > I actually think i_version has exactly the wrong semantics. > > Afaik, it doesn't actually version the file _data_ at all, it only > versions "inode itself changed". No, the NFSv4 change attribute must change if either data or metadata on the inode is changed, and be consistent and persistent across server crashes. For data updates, they piggy back on mtime updates .... > But I might have missed something obvious. The updates are hidden in > some odd places sometimes. ... which are in file_update_time(). Hence every data write or write page fault will call file_update_time() and trigger an i_version increment, even if the mtime doesn't change. Cheers, Dave. -- Dave Chinner david@fromorbit.com
[toc] | [prev] | [next] | [standalone]
| From | Mimi Zohar <zohar@linux.vnet.ibm.com> |
|---|---|
| Date | 2017-10-02 01:50 +0200 |
| Subject | Re: [RFC PATCH 3/3] fs: detect that the i_rwsem has already been taken exclusively |
| Message-ID | <uvW9H-8px-5@gated-at.bofh.it> |
| In reply to | #1742902 |
On Mon, 2017-10-02 at 09:34 +1100, Dave Chinner wrote: > On Sun, Oct 01, 2017 at 11:41:48AM -0700, Linus Torvalds wrote: > > On Sun, Oct 1, 2017 at 5:08 AM, Mimi Zohar <zohar@linux.vnet.ibm.com> wrote: > > > > > > Right, re-introducing the iint->mutex and a new i_generation field in > > > the iint struct with a separate set of locks should work. It will be > > > reset if the file metadata changes (eg. setxattr, chown, chmod). > > > > Note that the "inner lock" could possibly be omitted if the > > invalidation can be just a single atomic instruction. > > > > So particularly if invalidation could be just an atomic_inc() on the > > generation count, there might not need to be any inner lock at all. > > > > You'd have to serialize the actual measurement with the "read > > generation count", but that should be as simple as just doing a > > smp_rmb() between the "read generation count" and "do measurement on > > file contents". > > We already have a change counter on the inode, which is modified on > any data or metadata write (i_version) under filesystem locks. The > i_version counter has well defined semantics - it's required by > NFSv4 to increment on any metadata or data change - so we should be > able to rely on it's behaviour to implement IMA as well. Filesystems > that support i_version are marked with [SB|MS]_I_VERSION in the > superblock (IS_I_VERSION(inode)) so it should be easy to tell if IMA > can be supported on a specific filesystem (btrfs, ext4, fuse and xfs > ATM). Recently I received a patch to replace i_version with mtime/atime. Now, even more recently, I received a patch that claims that i_version is just a performance improvement. For file systems that don't support i_version, assume that the file has changed. For file systems that don't support i_version, instead of assuming that the file has changed, we can at least use i_generation. With Linus' suggested changes, I think this will work nicely. > The IMA code should be able to sample that at measurement time and > either fail or be retried if i_version changes during measurement. > We can then simply make the IMA xattr write conditional on the > i_version value being unchanged from the sample the IMA code passes > into the filesystem once the filesystem holds all the locks it needs > to write the xattr... > I note that IMA already grabs the i_version in > ima_collect_measurement(), so this shouldn't be too hard to do. > Perhaps we don't need any new locks or counterst all, maybe just > the ability to feed a version cookie to the set_xattr method? The security.ima xattr is normally written out in ima_check_last_writer(), not in ima_collect_measurement(). ima_collect_measurement() calculates the file hash for storing in the measurement list (IMA-measurement), verifying the hash/signature (IMA- appraisal) already stored in the xattr, and auditing (IMA-audit). The only time that ima_collect_measurement() writes the file xattr is in "fix" mode. Writing the xattr will need to be deferred until after the iint->mutex is released. There should be no open writers in ima_check_last_writer(), so the file shouldn't be changing. Mimi
[toc] | [prev] | [next] | [standalone]
| From | ebiederm@xmission.com (Eric W. Biederman) |
|---|---|
| Date | 2017-10-02 05:30 +0200 |
| Subject | Re: [RFC PATCH 3/3] fs: detect that the i_rwsem has already been taken exclusively |
| Message-ID | <uvZAC-2b9-1@gated-at.bofh.it> |
| In reply to | #1742911 |
Mimi Zohar <zohar@linux.vnet.ibm.com> writes: > On Mon, 2017-10-02 at 09:34 +1100, Dave Chinner wrote: >> On Sun, Oct 01, 2017 at 11:41:48AM -0700, Linus Torvalds wrote: >> > On Sun, Oct 1, 2017 at 5:08 AM, Mimi Zohar <zohar@linux.vnet.ibm.com> wrote: >> > > >> > > Right, re-introducing the iint->mutex and a new i_generation field in >> > > the iint struct with a separate set of locks should work. It will be >> > > reset if the file metadata changes (eg. setxattr, chown, chmod). >> > >> > Note that the "inner lock" could possibly be omitted if the >> > invalidation can be just a single atomic instruction. >> > >> > So particularly if invalidation could be just an atomic_inc() on the >> > generation count, there might not need to be any inner lock at all. >> > >> > You'd have to serialize the actual measurement with the "read >> > generation count", but that should be as simple as just doing a >> > smp_rmb() between the "read generation count" and "do measurement on >> > file contents". >> >> We already have a change counter on the inode, which is modified on >> any data or metadata write (i_version) under filesystem locks. The >> i_version counter has well defined semantics - it's required by >> NFSv4 to increment on any metadata or data change - so we should be >> able to rely on it's behaviour to implement IMA as well. Filesystems >> that support i_version are marked with [SB|MS]_I_VERSION in the >> superblock (IS_I_VERSION(inode)) so it should be easy to tell if IMA >> can be supported on a specific filesystem (btrfs, ext4, fuse and xfs >> ATM). > > Recently I received a patch to replace i_version with mtime/atime. > Now, even more recently, I received a patch that claims that > i_version is just a performance improvement. For file systems that > don't support i_version, assume that the file has changed. > > For file systems that don't support i_version, instead of assuming > that the file has changed, we can at least use i_generation. > > With Linus' suggested changes, I think this will work nicely. > >> The IMA code should be able to sample that at measurement time and >> either fail or be retried if i_version changes during measurement. >> We can then simply make the IMA xattr write conditional on the >> i_version value being unchanged from the sample the IMA code passes >> into the filesystem once the filesystem holds all the locks it needs >> to write the xattr... > >> I note that IMA already grabs the i_version in >> ima_collect_measurement(), so this shouldn't be too hard to do. >> Perhaps we don't need any new locks or counterst all, maybe just >> the ability to feed a version cookie to the set_xattr method? > > The security.ima xattr is normally written out in > ima_check_last_writer(), not in ima_collect_measurement(). > ima_collect_measurement() calculates the file hash for storing in the > measurement list (IMA-measurement), verifying the hash/signature (IMA- > appraisal) already stored in the xattr, and auditing (IMA-audit). > > The only time that ima_collect_measurement() writes the file xattr is > in "fix" mode. Writing the xattr will need to be deferred until after > the iint->mutex is released. > > There should be no open writers in ima_check_last_writer(), so the > file shouldn't be changing. This is slightly tangential but I think important to consider. What do you do about distributed filesystems fuse, nfs, etc that can change the data behind the kernels back. Do you not support such systems or do you have a sufficient way to detect changes? Eric
[toc] | [prev] | [next] | [standalone]
| From | Mimi Zohar <zohar@linux.vnet.ibm.com> |
|---|---|
| Date | 2017-10-02 14:30 +0200 |
| Subject | Re: [RFC PATCH 3/3] fs: detect that the i_rwsem has already been taken exclusively |
| Message-ID | <uw81b-7ep-5@gated-at.bofh.it> |
| In reply to | #1742956 |
On Sun, 2017-10-01 at 22:25 -0500, Eric W. Biederman wrote: > Mimi Zohar <zohar@linux.vnet.ibm.com> writes: > > There should be no open writers in ima_check_last_writer(), so the > > file shouldn't be changing. > > This is slightly tangential but I think important to consider. > What do you do about distributed filesystems fuse, nfs, etc that > can change the data behind the kernels back. Exactly! > Do you not support such systems or do you have a sufficient way to > detect changes? Currently, only the initial file access in policy is measured, verified, audited. Even if there was a way of detecting the change, since we can't trust these file systems, the performance would be awful, but we should probably not be caching the measurement/verification results. Mimi
[toc] | [prev] | [next] | [standalone]
| From | Dave Chinner <david@fromorbit.com> |
|---|---|
| Date | 2017-10-02 06:40 +0200 |
| Subject | Re: [RFC PATCH 3/3] fs: detect that the i_rwsem has already been taken exclusively |
| Message-ID | <uw0Gl-2Oa-5@gated-at.bofh.it> |
| In reply to | #1742911 |
On Sun, Oct 01, 2017 at 07:42:42PM -0400, Mimi Zohar wrote:
> On Mon, 2017-10-02 at 09:34 +1100, Dave Chinner wrote:
> > On Sun, Oct 01, 2017 at 11:41:48AM -0700, Linus Torvalds wrote:
> > > On Sun, Oct 1, 2017 at 5:08 AM, Mimi Zohar <zohar@linux.vnet.ibm.com> wrote:
> > > >
> > > > Right, re-introducing the iint->mutex and a new i_generation field in
> > > > the iint struct with a separate set of locks should work. It will be
> > > > reset if the file metadata changes (eg. setxattr, chown, chmod).
> > >
> > > Note that the "inner lock" could possibly be omitted if the
> > > invalidation can be just a single atomic instruction.
> > >
> > > So particularly if invalidation could be just an atomic_inc() on the
> > > generation count, there might not need to be any inner lock at all.
> > >
> > > You'd have to serialize the actual measurement with the "read
> > > generation count", but that should be as simple as just doing a
> > > smp_rmb() between the "read generation count" and "do measurement on
> > > file contents".
> >
> > We already have a change counter on the inode, which is modified on
> > any data or metadata write (i_version) under filesystem locks. The
> > i_version counter has well defined semantics - it's required by
> > NFSv4 to increment on any metadata or data change - so we should be
> > able to rely on it's behaviour to implement IMA as well. Filesystems
> > that support i_version are marked with [SB|MS]_I_VERSION in the
> > superblock (IS_I_VERSION(inode)) so it should be easy to tell if IMA
> > can be supported on a specific filesystem (btrfs, ext4, fuse and xfs
> > ATM).
>
> Recently I received a patch to replace i_version with mtime/atime.
mtime is not guaranteed to change on data writes - the resolution of
the filesystem timestamps may mean mtime only changes once a second
regardless of the number of writes performed to that file. That's
why NFS can't use it as a change attribute, and hence we have
i_version....
> Now, even more recently, I received a patch that claims that
> i_version is just a performance improvement.
Did you ask them to explain/quantify the performance improvement?
e.g. Using i_version on XFS slows down performance on small
writes by 2-3% because i_version because all data writes log a
version change rather than only logging a change when mtime updates.
We take that penalty because NFS requires specific change attribute
behaviour, otherwise we wouldn't have implemented it at all in
XFS...
> For file systems that
> don't support i_version, assume that the file has changed.
>
> For file systems that don't support i_version, instead of assuming
> that the file has changed, we can at least use i_generation.
I'm not sure what you mean here - the struct inode already has a
i_generation variable. It's a lifecycle indicator used to
discriminate between alloc/free cycles on the same inode number.
i.e. It only changes at inode allocation time, not whenever the data
in the inode changes...
> With Linus' suggested changes, I think this will work nicely.
>
> > The IMA code should be able to sample that at measurement time and
> > either fail or be retried if i_version changes during measurement.
> > We can then simply make the IMA xattr write conditional on the
> > i_version value being unchanged from the sample the IMA code passes
> > into the filesystem once the filesystem holds all the locks it needs
> > to write the xattr...
>
> > I note that IMA already grabs the i_version in
> > ima_collect_measurement(), so this shouldn't be too hard to do.
> > Perhaps we don't need any new locks or counterst all, maybe just
> > the ability to feed a version cookie to the set_xattr method?
>
> The security.ima xattr is normally written out in
> ima_check_last_writer(), not in ima_collect_measurement().
Which, if IIUC, does this to measure and update the xattr:
ima_check_last_writer
-> ima_update_xattr
-> ima_collect_measurement
-> ima_fix_xattr
> ima_collect_measurement() calculates the file hash for storing in the
> measurement list (IMA-measurement), verifying the hash/signature (IMA-
> appraisal) already stored in the xattr, and auditing (IMA-audit).
Yup, and it samples the i_version before it calculates the hash and
stores it in the iint, which then gets passed to ima_fix_xattr().
Looks like all that is needed is to pass the i_version back to the
filesystem through the xattr call....
IOWs, sample the i_version early while we hold the inode lock and
check the writer count, then if it is the last writer drop the inode
lock and call ima_update_xattr(). The sampled i_version then tells
us if the file has changed before we write the updated xattr...
> The only time that ima_collect_measurement() writes the file xattr is
> in "fix" mode. Writing the xattr will need to be deferred until after
> the iint->mutex is released.
ima_collect_measurement() doesn't write an xattr at all - it just
reads the file data and calculates the hash.
> There should be no open writers in ima_check_last_writer(), so the
> file shouldn't be changing.
If that code is not holding the inode i_rwsem across
ima_update_xattr(), then the writer check is racy as hell. We're
trying to get rid of the need for this code to hold the inode lock
to stabilise the writer count for the entire operation, and it looks
to me like everything is there to use the i_version to ensure the
the IMA code doesn't need to hold the inode lock across
ima_collect_measurement() and ima_fix_xattr()...
Cheers,
Dave.
--
Dave Chinner
david@fromorbit.com
[toc] | [prev] | [next] | [standalone]
| From | Mimi Zohar <zohar@linux.vnet.ibm.com> |
|---|---|
| Date | 2017-10-02 14:20 +0200 |
| Subject | Re: [RFC PATCH 3/3] fs: detect that the i_rwsem has already been taken exclusively |
| Message-ID | <uw7Rw-7b4-15@gated-at.bofh.it> |
| In reply to | #1742963 |
On Mon, 2017-10-02 at 15:35 +1100, Dave Chinner wrote: > On Sun, Oct 01, 2017 at 07:42:42PM -0400, Mimi Zohar wrote: > > On Mon, 2017-10-02 at 09:34 +1100, Dave Chinner wrote: > > > On Sun, Oct 01, 2017 at 11:41:48AM -0700, Linus Torvalds wrote: > > > > On Sun, Oct 1, 2017 at 5:08 AM, Mimi Zohar <zohar@linux.vnet.ibm.com> wrote: > > > > > > > > > > Right, re-introducing the iint->mutex and a new i_generation field in > > > > > the iint struct with a separate set of locks should work. It will be > > > > > reset if the file metadata changes (eg. setxattr, chown, chmod). > > > > > > > > Note that the "inner lock" could possibly be omitted if the > > > > invalidation can be just a single atomic instruction. > > > > > > > > So particularly if invalidation could be just an atomic_inc() on the > > > > generation count, there might not need to be any inner lock at all. > > > > > > > > You'd have to serialize the actual measurement with the "read > > > > generation count", but that should be as simple as just doing a > > > > smp_rmb() between the "read generation count" and "do measurement on > > > > file contents". > > > > > > We already have a change counter on the inode, which is modified on > > > any data or metadata write (i_version) under filesystem locks. The > > > i_version counter has well defined semantics - it's required by > > > NFSv4 to increment on any metadata or data change - so we should be > > > able to rely on it's behaviour to implement IMA as well. Filesystems > > > that support i_version are marked with [SB|MS]_I_VERSION in the > > > superblock (IS_I_VERSION(inode)) so it should be easy to tell if IMA > > > can be supported on a specific filesystem (btrfs, ext4, fuse and xfs > > > ATM). > > > > Recently I received a patch to replace i_version with mtime/atime. > > mtime is not guaranteed to change on data writes - the resolution of > the filesystem timestamps may mean mtime only changes once a second > regardless of the number of writes performed to that file. That's > why NFS can't use it as a change attribute, and hence we have > i_version.... > > > Now, even more recently, I received a patch that claims that > > i_version is just a performance improvement. > > Did you ask them to explain/quantify the performance improvement? Using i_version is a performance improvement as opposed to always calculating the file hash and writing the xattr. The patch is intended for filesystems that don't support i_version (eg. ubifs). > e.g. Using i_version on XFS slows down performance on small > writes by 2-3% because i_version because all data writes log a > version change rather than only logging a change when mtime updates. > We take that penalty because NFS requires specific change attribute > behaviour, otherwise we wouldn't have implemented it at all in > XFS... > > > For file systems that > > don't support i_version, assume that the file has changed. > > > > For file systems that don't support i_version, instead of assuming > > that the file has changed, we can at least use i_generation. > > I'm not sure what you mean here - the struct inode already has a > i_generation variable. It's a lifecycle indicator used to > discriminate between alloc/free cycles on the same inode number. > i.e. It only changes at inode allocation time, not whenever the data > in the inode changes... Sigh, my error. > > > With Linus' suggested changes, I think this will work nicely. > > > > > The IMA code should be able to sample that at measurement time and > > > either fail or be retried if i_version changes during measurement. > > > We can then simply make the IMA xattr write conditional on the > > > i_version value being unchanged from the sample the IMA code passes > > > into the filesystem once the filesystem holds all the locks it needs > > > to write the xattr... > > > > > I note that IMA already grabs the i_version in > > > ima_collect_measurement(), so this shouldn't be too hard to do. > > > Perhaps we don't need any new locks or counterst all, maybe just > > > the ability to feed a version cookie to the set_xattr method? > > > > The security.ima xattr is normally written out in > > ima_check_last_writer(), not in ima_collect_measurement(). > > Which, if IIUC, does this to measure and update the xattr: > > ima_check_last_writer > -> ima_update_xattr > -> ima_collect_measurement > -> ima_fix_xattr > > > ima_collect_measurement() calculates the file hash for storing in the > > measurement list (IMA-measurement), verifying the hash/signature (IMA- > > appraisal) already stored in the xattr, and auditing (IMA-audit). > > Yup, and it samples the i_version before it calculates the hash and > stores it in the iint, which then gets passed to ima_fix_xattr(). > Looks like all that is needed is to pass the i_version back to the > filesystem through the xattr call.... > > IOWs, sample the i_version early while we hold the inode lock and > check the writer count, then if it is the last writer drop the inode > lock and call ima_update_xattr(). The sampled i_version then tells > us if the file has changed before we write the updated xattr... > > > The only time that ima_collect_measurement() writes the file xattr is > > in "fix" mode. Writing the xattr will need to be deferred until after > > the iint->mutex is released. > > ima_collect_measurement() doesn't write an xattr at all - it just > reads the file data and calculates the hash. There's another call to ima_fix_xattr() from ima_appraise_measurement(). > > There should be no open writers in ima_check_last_writer(), so the > > file shouldn't be changing. > > If that code is not holding the inode i_rwsem across > ima_update_xattr(), then the writer check is racy as hell. We're > trying to get rid of the need for this code to hold the inode lock > to stabilise the writer count for the entire operation, and it looks > to me like everything is there to use the i_version to ensure the > the IMA code doesn't need to hold the inode lock across > ima_collect_measurement() and ima_fix_xattr()... Ok Mimi
[toc] | [prev] | [next] | [standalone]
| From | Jeff Layton <jlayton@redhat.com> |
|---|---|
| Date | 2017-10-02 14:50 +0200 |
| Subject | Re: [RFC PATCH 3/3] fs: detect that the i_rwsem has already been taken exclusively |
| Message-ID | <uw8kz-7kS-31@gated-at.bofh.it> |
| In reply to | #1743162 |
On Mon, 2017-10-02 at 08:09 -0400, Mimi Zohar wrote: > On Mon, 2017-10-02 at 15:35 +1100, Dave Chinner wrote: > > On Sun, Oct 01, 2017 at 07:42:42PM -0400, Mimi Zohar wrote: > > > On Mon, 2017-10-02 at 09:34 +1100, Dave Chinner wrote: > > > > On Sun, Oct 01, 2017 at 11:41:48AM -0700, Linus Torvalds wrote: > > > > > On Sun, Oct 1, 2017 at 5:08 AM, Mimi Zohar <zohar@linux.vnet. > > > > > ibm.com> wrote: > > > > > > > > > > > > Right, re-introducing the iint->mutex and a new > > > > > > i_generation field in > > > > > > the iint struct with a separate set of locks should > > > > > > work. It will be > > > > > > reset if the file metadata changes (eg. setxattr, chown, > > > > > > chmod). > > > > > > > > > > Note that the "inner lock" could possibly be omitted if the > > > > > invalidation can be just a single atomic instruction. > > > > > > > > > > So particularly if invalidation could be just an atomic_inc() > > > > > on the > > > > > generation count, there might not need to be any inner lock > > > > > at all. > > > > > > > > > > You'd have to serialize the actual measurement with the "read > > > > > generation count", but that should be as simple as just doing > > > > > a > > > > > smp_rmb() between the "read generation count" and "do > > > > > measurement on > > > > > file contents". > > > > > > > > We already have a change counter on the inode, which is > > > > modified on > > > > any data or metadata write (i_version) under filesystem > > > > locks. The > > > > i_version counter has well defined semantics - it's required by > > > > NFSv4 to increment on any metadata or data change - so we > > > > should be > > > > able to rely on it's behaviour to implement IMA as well. > > > > Filesystems > > > > that support i_version are marked with [SB|MS]_I_VERSION in the > > > > superblock (IS_I_VERSION(inode)) so it should be easy to tell > > > > if IMA > > > > can be supported on a specific filesystem (btrfs, ext4, fuse > > > > and xfs > > > > ATM). > > > > > > Recently I received a patch to replace i_version with > > > mtime/atime. > > I assume you're talking here about the patch I sent a few months ago. I specifically do _not_ want to replace i_version with the mtime/atime. The point there was to stop trying to use i_version on filesystems that don't properly implement it (which is most of them). The next best approximation on those filesystems is the mtime. It's not perfect, but it's better than nothing (which is what you have now on filesystems that never increment i_version on writes). IOW, it just added a fallback for when you can't count on the i_version changing. (BTW: atime is worthless here -- who cares if the thing was accessed? IIUC, we only care if something changed.) Ideally, all filesystems would implement i_version properly. In practice, that's a tall order as that may require on-disk changes for some of them. That's not always possible where cross-OS compatibility is necessary (e.g. FAT or NTFS). > > mtime is not guaranteed to change on data writes - the resolution > > of > > the filesystem timestamps may mean mtime only changes once a second > > regardless of the number of writes performed to that file. That's > > why NFS can't use it as a change attribute, and hence we have > > i_version.... > > > > > Now, even more recently, I received a patch that claims that > > > i_version is just a performance improvement. > > > > Did you ask them to explain/quantify the performance improvement? > > Using i_version is a performance improvement as opposed to always > calculating the file hash and writing the xattr. The patch is > intended for filesystems that don't support i_version (eg. ubifs). > > > e.g. Using i_version on XFS slows down performance on small > > writes by 2-3% because i_version because all data writes log a > > version change rather than only logging a change when mtime > > updates. > > We take that penalty because NFS requires specific change attribute > > behaviour, otherwise we wouldn't have implemented it at all in > > XFS... > > > > > For file systems that > > > don't support i_version, assume that the file has changed. > > > > > > For file systems that don't support i_version, instead of > > > assuming > > > that the file has changed, we can at least use i_generation. > > > > I'm not sure what you mean here - the struct inode already has a > > i_generation variable. It's a lifecycle indicator used to > > discriminate between alloc/free cycles on the same inode number. > > i.e. It only changes at inode allocation time, not whenever the > > data > > in the inode changes... > > Sigh, my error. > > > > > > With Linus' suggested changes, I think this will work nicely. > > > > > > > The IMA code should be able to sample that at measurement time > > > > and > > > > either fail or be retried if i_version changes during > > > > measurement. > > > > We can then simply make the IMA xattr write conditional on the > > > > i_version value being unchanged from the sample the IMA code > > > > passes > > > > into the filesystem once the filesystem holds all the locks it > > > > needs > > > > to write the xattr... > > > > I note that IMA already grabs the i_version in > > > > ima_collect_measurement(), so this shouldn't be too hard to do. > > > > Perhaps we don't need any new locks or counterst all, maybe > > > > just > > > > the ability to feed a version cookie to the set_xattr method? > > > > > > The security.ima xattr is normally written out in > > > ima_check_last_writer(), not in ima_collect_measurement(). > > > > Which, if IIUC, does this to measure and update the xattr: > > > > ima_check_last_writer > > -> ima_update_xattr > > -> ima_collect_measurement > > -> ima_fix_xattr > > > > > ima_collect_measurement() calculates the file hash for storing > > > in the > > > measurement list (IMA-measurement), verifying the hash/signature > > > (IMA- > > > appraisal) already stored in the xattr, and auditing (IMA-audit). > > > > Yup, and it samples the i_version before it calculates the hash and > > stores it in the iint, which then gets passed to ima_fix_xattr(). > > Looks like all that is needed is to pass the i_version back to the > > filesystem through the xattr call.... > > > > IOWs, sample the i_version early while we hold the inode lock and > > check the writer count, then if it is the last writer drop the > > inode > > lock and call ima_update_xattr(). The sampled i_version then tells > > us if the file has changed before we write the updated xattr... > > > > > The only time that ima_collect_measurement() writes the file > > > xattr is > > > in "fix" mode. Writing the xattr will need to be deferred until > > > after > > > the iint->mutex is released. > > > > ima_collect_measurement() doesn't write an xattr at all - it just > > reads the file data and calculates the hash. > > There's another call to ima_fix_xattr() from > ima_appraise_measurement(). > > > > There should be no open writers in ima_check_last_writer(), so > > > the > > > file shouldn't be changing. > > > > If that code is not holding the inode i_rwsem across > > ima_update_xattr(), then the writer check is racy as hell. We're > > trying to get rid of the need for this code to hold the inode lock > > to stabilise the writer count for the entire operation, and it > > looks > > to me like everything is there to use the i_version to ensure the > > the IMA code doesn't need to hold the inode lock across > > ima_collect_measurement() and ima_fix_xattr()... > > Ok > > Mimi > -- Jeff Layton <jlayton@redhat.com>
[toc] | [prev] | [next] | [standalone]
Page 1 of 2 [1] 2 Next page →
Back to top | Article view | linux.kernel
csiph-web