Skip to content

Commit

Permalink
First commit of test to verify *xattr() syscall interception.
Browse files Browse the repository at this point in the history
These tests verify that sysbox performs syscall interception
of the *xattr() syscalls correctly, particularly to enable
sys container processes to set the 'trusted.overlay.opaque'
extended attribute.

See Sysbox issue #254 for more info on why this is necessary.

Signed-off-by: Cesar Talledo <ctalledo@nestybox.com>
  • Loading branch information
ctalledo committed Sep 7, 2021
1 parent f550e79 commit c030ae4
Show file tree
Hide file tree
Showing 6 changed files with 447 additions and 0 deletions.
9 changes: 9 additions & 0 deletions tests/syscall/xattr/Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
# Makefile to build xattr.go

all: xattr-test

xattr-test: xattr.go
GOOS=linux go build -ldflags "-extldflags -static" -o xattr-test && chown "rootless:rootless" xattr-test

clean:
rm xattr-test
5 changes: 5 additions & 0 deletions tests/syscall/xattr/go.mod
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
module main

go 1.13

require golang.org/x/sys v0.0.0-20210906170528-6f6e22806c34
2 changes: 2 additions & 0 deletions tests/syscall/xattr/go.sum
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
golang.org/x/sys v0.0.0-20210906170528-6f6e22806c34 h1:GkvMjFtXUmahfDtashnc1mnrCtuBVcwse5QV2lUk/tI=
golang.org/x/sys v0.0.0-20210906170528-6f6e22806c34/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
Binary file added tests/syscall/xattr/xattr-test
Binary file not shown.
174 changes: 174 additions & 0 deletions tests/syscall/xattr/xattr.bats
Original file line number Diff line number Diff line change
@@ -0,0 +1,174 @@
#!/usr/bin/env bats

#
# Verify trapping & emulation on "setxattr"
#

load ../../helpers/run
load ../../helpers/syscall
load ../../helpers/docker
load ../../helpers/environment
load ../../helpers/mounts
load ../../helpers/sysbox-health

function teardown() {
sysbox_log_check
}

@test "*xattr" {

mkdir /mnt/scratch/test
chown 165536:165536 /mnt/scratch/test

# deploy a sys container
local syscont=$(docker_run --rm -v /mnt/scratch/test:/mnt ${CTR_IMG_REPO}/alpine-docker-dbg:latest tail -f /dev/null)

# the attr package brings the setfattr and getfattr utils
docker exec "$syscont" sh -c "apk add attr"
[ "$status" -eq 0 ]

docker exec "$syscont" sh -c "mkdir /mnt/tdir && touch /mnt/tdir/tfile"
[ "$status" -eq 0 ]

# set some xattrs
docker exec "$syscont" sh -c 'setfattr -n trusted.overlay.opaque -v "y" /mnt/tdir/tfile'
[ "$status" -eq 0 ]

docker exec "$syscont" sh -c 'setfattr -n trusted.another -v "another value" /mnt/tdir/tfile'
[ "$status" -eq 1 ]

docker exec "$syscont" sh -c 'setfattr -n user.x -v "user value" /mnt/tdir/tfile'
[ "$status" -eq 0 ]

# getfattr -d will invoke the listxattr() syscall
docker exec "$syscont" sh -c 'cd /mnt && getfattr -d -m "trusted\." tdir/tfile'
[ "$status" -eq 0 ]
[[ "$output" =~ "trusted.overlay.opaque=\"y\"" ]]

# getfattr -n will invoke the getaxattr() syscall
docker exec "$syscont" sh -c 'cd /mnt && getfattr -n "trusted\.another" tdir/tfile'
[ "$status" -eq 1 ]
[[ "$output" =~ "Not supported" ]]

docker exec "$syscont" sh -c 'getfattr -d /mnt/tdir/tfile'
[ "$status" -eq 0 ]
[[ "$output" =~ "user.x=\"user value\"" ]]

# let's try again as a non-root user; the trusted.* xattr should be hidden
docker exec -u 1000:1000 "$syscont" sh -c 'cd /mnt/tdir && getfattr -d -m "trusted\." tfile'
[ "$status" -eq 0 ]
[[ "$output" =~ "" ]]

docker exec -u 1000:1000 "$syscont" sh -c 'cd /mnt/tdir && getfattr -d tfile'
[ "$status" -eq 0 ]
[[ "$output" =~ "user.x=\"user value\"" ]]

# remove the trusted.overlay.opaque attribute; the "cd" is used on purpose to
# check that sysbox-fs resolves non-absolute paths correctly
docker exec "$syscont" sh -c 'cd /mnt && setfattr -x trusted.overlay.opaque tdir/tfile'
[ "$status" -eq 0 ]

docker exec "$syscont" sh -c 'getfattr -n "trusted.overlay.opaque" tdir/tfile 2>/dev/null'
[ "$status" -eq 1 ]

docker_stop "$syscont"

rm -rf /mnt/scratch/test
}

@test "f*xattr & l*xattr" {

# build the xattr-test binary (tests the f*xattr and l*xattr syscalls)
pushd tests/syscall/xattr
make xattr-test
popd

mkdir /mnt/scratch/test
chown 165536:165536 /mnt/scratch/test

# deploy a sys container
local syscont=$(docker_run --rm -v /mnt/scratch/test:/mnt ${CTR_IMG_REPO}/alpine-docker-dbg:latest tail -f /dev/null)

# create a test file inside the container
docker exec "$syscont" sh -c "mkdir /mnt/tdir && touch /mnt/tdir/tfile"
[ "$status" -eq 0 ]

# copy the xattr-test file into the container
docker cp tests/syscall/xattr/xattr-test $syscont:/bin/xattr-test

# run the test
docker exec "$syscont" sh -c "xattr-test /mnt/tdir/tfile"
[ "$status" -eq 0 ]

docker_stop "$syscont"
rm -rf /mnt/scratch/test
}

@test "xattr: trusted.overlay.opaque" {

mkdir /mnt/scratch/test
chown 165536:165536 /mnt/scratch/test

# deploy a sys container
local syscont=$(docker_run --rm -v /mnt/scratch/test:/mnt ${CTR_IMG_REPO}/alpine-docker-dbg:latest tail -f /dev/null)

# the attr package brings the setfattr and getfattr utils
docker exec "$syscont" sh -c "apk add attr"
[ "$status" -eq 0 ]

# setup the overlayfs lower, upper, work, and merged dirs (but don't mount yet).
docker exec "$syscont" sh -c "mkdir /mnt/lower && mkdir /mnt/upper && mkdir /mnt/work && mkdir /mnt/merged"
[ "$status" -eq 0 ]

docker exec "$syscont" sh -c "mkdir /mnt/lower/ld1 && touch /mnt/lower/ld1/l1"
[ "$status" -eq 0 ]

docker exec "$syscont" sh -c "mkdir /mnt/upper/ld1"
[ "$status" -eq 0 ]

# adding trusted.overlay.opaque to /mnt/upper/ld1 hides the contents of the lower ld1
docker exec "$syscont" sh -c 'setfattr -n trusted.overlay.opaque -v "y" /mnt/upper/ld1'
[ "$status" -eq 0 ]

# the "cd" is used on purpose to check that sysbox-fs resolves non-absolute paths correctly
docker exec "$syscont" sh -c 'cd /mnt/upper && getfattr -n "trusted.overlay.opaque" ld1 2>/dev/null'
[ "$status" -eq 0 ]
[[ "${lines[1]}" =~ 'trusted.overlay.opaque="y"' ]]

# create the overlayfs mount and verify the opaque attribute took effect (/mnt/merged/ld1/l1 should be hidden).
docker exec "$syscont" sh -c "mount -t overlay overlay -olowerdir=/mnt/lower,upperdir=/mnt/upper,workdir=/mnt/work /mnt/merged"
[ "$status" -eq 0 ]

docker exec "$syscont" sh -c "ls /mnt/merged/ld1"
[ "$status" -eq 0 ]
[[ "$output" == "" ]]

# umount overlayfs
docker exec "$syscont" sh -c "umount /mnt/merged"
[ "$status" -eq 0 ]

# remove the trusted.overlay.opaque attribute; the "cd" is used on purpose to
# check that sysbox-fs resolves non-absolute paths correctly
docker exec "$syscont" sh -c 'cd /mnt && setfattr -x trusted.overlay.opaque upper/ld1'
[ "$status" -eq 0 ]

docker exec "$syscont" sh -c 'getfattr -n "trusted.overlay.opaque" /mnt/upper/ld1 2>/dev/null'
[ "$status" -eq 1 ]

# re-create the overlayfs mount
docker exec "$syscont" sh -c "mount -t overlay overlay -olowerdir=/mnt/lower,upperdir=/mnt/upper,workdir=/mnt/work /mnt/merged"
[ "$status" -eq 0 ]

# /mnt/merged/ld1/l1 should now be visible
docker exec "$syscont" sh -c "ls /mnt/merged/ld1"
[ "$status" -eq 0 ]
[[ "$output" == "l1" ]]

# umount overlayfs
docker exec "$syscont" sh -c "umount /mnt/merged"
[ "$status" -eq 0 ]

docker_stop "$syscont"

rm -rf /mnt/scratch/test
}
Loading

0 comments on commit c030ae4

Please sign in to comment.