On Mon, 2020-06-01 at 14:48 +0100, Filipe Manana wrote:
> On Mon, May 11, 2020 at 12:52 PM Filipe Manana <fdmanana@xxxxxxxxx>
> wrote:
> >
> > On Fri, May 8, 2020 at 9:14 PM Marcos Paulo de Souza
> > <marcos@xxxxxxxxxxxxx> wrote:
> > >
> > > From: Marcos Paulo de Souza <mpdesouza@xxxxxxxx>
> > >
> > > There is a situation where the incremental send can drop the
> capability
> > > from the receiving side. If you have a file that changed the
> group, but
> > > the capability was the same of before the group changed, the
> current
> > > kernel code will only emit a chown, since the capability is the
> same.
> > >
> > > The steps bellow can reproduce the problem.
> > >
> > > $ mount /dev/sda fs1
> > > $ mount /dev/sdb fs2
> > >
> > > $ touch fs1/foo.bar
> > > $ setcap cap_sys_nice+ep fs1/foo.bar
> > > $ btrfs subvol snap -r fs1 fs1/snap_init
> > > $ btrfs send fs1/snap_init | btrfs receive fs2
> > >
> > > $ chgrp adm fs1/foo.bar
> > > $ setcap cap_sys_nice+ep fs1/foo.bar
> > >
> > > $ btrfs subvol snap -r fs1 fs1/snap_complete
> > > $ btrfs subvol snap -r fs1 fs1/snap_incremental
> > >
> > > $ btrfs send fs1/snap_complete | btrfs receive fs2
> > > $ btrfs send -p fs1/snap_init fs1/snap_incremental | btrfs
> receive fs2
> >
> > It's redundant to put here the steps to trigger the problem, that's
> > what the test does.
> >
> > You just want to say this test exercises full send and incremental
> > send operations for cases where files have capabilities, to verify
> the
> > capabilities aren't lost.
> >
> > >
> > > At this point, a chown was emitted by "btrfs send" since only the
> group
> > > was changed. This makes the cap_sys_nice capability to be dropped
> from
> > > fs2/snap_incremental/foo.bar
> >
> > Explaining in a changelog for a test case why exactly the bug
> happens
> > is out of scope.
> > We just want to know what bug are we testing for.
> >
> > The gory details about why the bug happens usually go the in the
> > changelog of the patch that fixes btrfs.
> >
> > >
> > > This test fails on current kernel, the fix was submitted to the
> btrfs
> > > mailing list titled:
> > >
> > > "btrfs: send: Emit file capabilities after chown"
> > >
> > > Signed-off-by: Marcos Paulo de Souza <mpdesouza@xxxxxxxx>
> > > ---
> > > tests/btrfs/211 | 153
> ++++++++++++++++++++++++++++++++++++++++++++
> > > tests/btrfs/211.out | 6 ++
> > > tests/btrfs/group | 1 +
> > > 3 files changed, 160 insertions(+)
> > > create mode 100755 tests/btrfs/211
> > > create mode 100644 tests/btrfs/211.out
> > >
> > > diff --git a/tests/btrfs/211 b/tests/btrfs/211
> > > new file mode 100755
> > > index 00000000..e9aeaef3
> > > --- /dev/null
> > > +++ b/tests/btrfs/211
> > > @@ -0,0 +1,153 @@
> > > +#! /bin/bash
> > > +# SPDX-License-Identifier: GPL-2.0
> > > +# Copyright (C) 2020 SUSE Linux Products GmbH. All Rights
> Reserved.
> > > +#
> > > +# FS QA Test 211
> > > +#
> > > +# Test if the file capabilities aren't lost after full and
> incremental send
> > > +#
> > > +seq=`basename $0`
> > > +seqres=$RESULT_DIR/$seq
> > > +echo "QA output created by $seq"
> > > +
> > > +here=`pwd`
> > > +tmp=/tmp/$$
> > > +status=1 # failure is the default!
> > > +trap "_cleanup; exit \$status" 0 1 2 3 15
> > > +
> > > +# get standard environment, filters and checks
> > > +. ./common/rc
> > > +. ./common/filter
> > > +
> > > +# remove previous $seqres.full before test
> > > +rm -f $seqres.full
> > > +
> > > +_supported_fs btrfs
> > > +_supported_os Linux
> > > +_require_scratch
> > > +_require_command "$SETCAP_PROG" setcap
> > > +_require_command "$GETCAP_PROG" getcap
> > > +
> > > +_cleanup()
> > > +{
> > > + cd /
> > > + rm -f $tmp.*
> > > +}
> > > +
> > > +_check_xattr()
> >
> > Function names starting with '_' are usually reserved for functions
> > provided by fstests, global functions (like the ones in common/*).
> > Same comment applies to all the other function names.
> >
> > Also, a better name would be "check_capabilities" - that they are
> > stored in a xattr it's irrelevant as we are using the getcap and
> > setcap utilities to read and set them, and not accessing xattrs
> > directly.
> >
> > > +{
> > > + local RET
> > > + local FILE
> > > + local CAP
> > > + FILE="$1"
> > > + CAP="$2"
> >
> > Variables in uppercase are meant to be used for global variables.
> Same
> > comment applies to all the other functions.
> >
> > > + RET=$($GETCAP_PROG "$FILE")
> > > + if [ -z "$RET" ]; then
> > > + echo "$RET"
> > > + _fail "missing capability in file $FILE"
> >
> > This is a practice generally discouraged, we should avoid "_fail"
> > unless absolutely necessary.
> > The right approach here is just to "echo" the message. That's
> enough
> > to make the test fail as that message is not part of the golden
> > output.
> > Furthermore, not using _fail allows the test to proceed and
> > potentially find other problems.
> >
> > > + fi
> > > + if [[ "$RET" != *$CAP* ]]; then
> > > + echo "$RET"
> > > + echo "$CAP"
> > > + _fail "Capability do not match. Output: $RET"
> >
> > Capability -> Capabilities
> >
> > > + fi
> > > +}
> > > +
> > > +_setup()
> > > +{
> > > + _scratch_mkfs >/dev/null
> > > + _scratch_mount
> > > +
> > > + FS1="$SCRATCH_MNT/fs1"
> > > + FS2="$SCRATCH_MNT/fs2"
> >
> > To make it easier to follow, perhaps declare this outside this
> > function, as they are used by the other functions.
> >
> > > +
> > > + $BTRFS_UTIL_PROG subvolume create "$FS1" > /dev/null
> > > + $BTRFS_UTIL_PROG subvolume create "$FS2" > /dev/null
> > > +}
> > > +
> > > +_full_nocap_inc_withcap_send()
> > > +{
> > > + _setup
> > > +
> > > + # Test full send containing a file with no capability
> > > + touch "$FS1/foo.bar"
> > > + $BTRFS_UTIL_PROG subvolume snapshot -r "$FS1"
> "$FS1/snap_init" >/dev/null
> > > + $BTRFS_UTIL_PROG send "$FS1/snap_init" -q |
> $BTRFS_UTIL_PROG receive "$FS2" -q
> > > + # ensure that we don't have caps set
> > > + RET=$($GETCAP_PROG "$FS2/snap_init/foo.bar")
> >
> > Should be declared local (and lower case name).
> >
> > > + if [ -n "$RET" ]; then
> > > + _fail "File contain capabilities when it
> shouldn't"
> >
> > echo and contain -> contains
> >
> > > + fi
> > > +
> > > + # Test if incremental send bring the newly added
> capability
> > > + $SETCAP_PROG "cap_sys_ptrace+ep cap_sys_nice+ep"
> "$FS1/foo.bar"
> > > + $BTRFS_UTIL_PROG subvolume snapshot -r "$FS1"
> "$FS1/snap_inc" >/dev/null
> > > + $BTRFS_UTIL_PROG send -p "$FS1/snap_init" "$FS1/snap_inc"
> -q | \
> > > + $BTRFS_UTIL_PROG receive
> "$FS2" -q
> > > + _check_xattr "$FS2/snap_inc/foo.bar"
> "cap_sys_ptrace,cap_sys_nice+ep"
> > > +
> > > + _scratch_unmount
> > > +}
> > > +
> > > +_roundtrip_send()
> > > +{
> > > + local FILES
> > > + local FS1
> > > + local FS2
> >
> > So FS1 and FS2 are declared local but never set. And they were
> > previously set as global by "_setup".
> > So those two declarations should be removed here.
> >
> > > +
> > > + # FILES should include foo.bar
> > > + FILES="$1"
> > > +
> > > + _setup
> > > +
> > > + # create files on fs1, must contain foo.bar
> > > + for f in $FILES; do
> > > + touch "$FS1/$f"
> > > + done
> > > +
> > > + # Test full send, checking if the receiving side keeps
> the capability
> >
> > capability -> capabilities (as the test sets 2)
> >
> > > + $SETCAP_PROG "cap_sys_ptrace+ep cap_sys_nice+ep"
> "$FS1/foo.bar"
> > > + $BTRFS_UTIL_PROG subvolume snapshot -r "$FS1"
> "$FS1/snap_init" >/dev/null
> > > + $BTRFS_UTIL_PROG send "$FS1/snap_init" -q |
> $BTRFS_UTIL_PROG receive "$FS2" -q
> > > + _check_xattr "$FS2/snap_init/foo.bar"
> "cap_sys_ptrace,cap_sys_nice+ep"
> > > +
> > > + # Test incremental send with different owner/group but
> same capability
> >
> > capability -> capabilities (as the test sets 2)
> >
> > > + chgrp 100 "$FS1/foo.bar"
> > > + $SETCAP_PROG "cap_sys_ptrace+ep cap_sys_nice+ep"
> "$FS1/foo.bar"
> > > + $BTRFS_UTIL_PROG subvolume snapshot -r "$FS1"
> "$FS1/snap_inc" >/dev/null
> > > + _check_xattr "$FS1/snap_inc/foo.bar"
> "cap_sys_ptrace,cap_sys_nice+ep"
> > > + $BTRFS_UTIL_PROG send -p "$FS1/snap_init" "$FS1/snap_inc"
> -q | \
> > > + $BTRFS_UTIL_PROG receive "$FS2"
> -q
> > > + _check_xattr "$FS2/snap_inc/foo.bar"
> "cap_sys_ptrace,cap_sys_nice+ep"
> > > +
> > > + # Test capability after incremental send with different
> capability and group
> >
> > capability -> capabilities (as the test sets 2)
> >
> > > + chgrp 0 "$FS1/foo.bar"
> > > + $SETCAP_PROG "cap_sys_time+ep cap_syslog+ep"
> "$FS1/foo.bar"
> > > + $BTRFS_UTIL_PROG subvolume snapshot -r "$FS1"
> "$FS1/snap_inc2" >/dev/null
> > > + _check_xattr "$FS1/snap_inc2/foo.bar"
> "cap_sys_time,cap_syslog+ep"
> > > + $BTRFS_UTIL_PROG send -p "$FS1/snap_inc" "$FS1/snap_inc2"
> -q | \
> > > + $BTRFS_UTIL_PROG receive
> "$FS2" -q
> > > + _check_xattr "$FS2/snap_inc2/foo.bar"
> "cap_sys_time,cap_syslog+ep"
> > > +
> > > + _scratch_unmount
> > > +}
> > > +
> > > +# real QA test starts here
> > > +
> > > +echo "Test full send + file without caps, then inc send bringing
> a new cap"
> >
> > inc -> incremental
> >
> > Also, the abbreviation "caps" is used but in other messages (below)
> > the non-abbreviated name "capabilities" is used.
> > We should be consistent and use only one form.
> >
> > > +_full_nocap_inc_withcap_send
> > > +
> > > +echo "Testing if foo.bar alone can keep it's capability"
> >
> > it's -> its
> > capability -> capabilities (as the test sets 2)
> >
> > > +_roundtrip_send "foo.bar"
> > > +
> > > +echo "Test foo.bar being the first item among other files"
> > > +_roundtrip_send "foo.bar foo.bax foo.baz"
> > > +
> > > +echo "Test foo.bar with objectid between two other files"
> > > +_roundtrip_send "foo1 foo.bar foo3"
> > > +
> > > +echo "Test foo.bar being the last item among other files"
> > > +_roundtrip_send "foo1 foo2 foo.bar"
> > > +
> > > +status=0
> > > +exit
> > > diff --git a/tests/btrfs/211.out b/tests/btrfs/211.out
> > > new file mode 100644
> > > index 00000000..fc50c923
> > > --- /dev/null
> > > +++ b/tests/btrfs/211.out
> > > @@ -0,0 +1,6 @@
> > > +QA output created by 211
> > > +Test full send + file without caps, then inc send bringing a new
> cap
> > > +Testing if foo.bar alone can keep it's capability
> > > +Test foo.bar being the first item among other files
> > > +Test foo.bar with objectid between two other files
> > > +Test foo.bar being the last item among other files
> > > diff --git a/tests/btrfs/group b/tests/btrfs/group
> > > index 9426fb17..437d4431 100644
> > > --- a/tests/btrfs/group
> > > +++ b/tests/btrfs/group
> > > @@ -213,3 +213,4 @@
> > > 208 auto quick subvol
> > > 209 auto quick log
> > > 210 auto quick qgroup snapshot
> > > +211 auto quick snapshot
> >
> > Missing the 'send' group.
> >
> > Other that is looks good and it works as expected (with patched and
> > unpatched btrfs)
> > Thanks.
>
> Marcos, ping. Anything I can help with?
Sorry, the test was in my radar but somehow I forgot about it. I hope
to send a new version later today, addressing all your comments.
> We should really have this test case in fstests.
Sure, I agree.
>
>
> Thanks.
>
> >
> > > --
> > > 2.25.1
> > >
> >
> >
> > --
> > Filipe David Manana,
> >
> > “Whether you think you can, or you think you can't — you're right.”
>
>
>