Skip to content

Commit

Permalink
optionally use image driver for squashfs and gocryptfs in setuid mode
Browse files Browse the repository at this point in the history
Signed-off-by: Dave Dykstra <2129743+DrDaveD@users.noreply.github.com>
  • Loading branch information
DrDaveD committed Nov 30, 2023
1 parent d02cad4 commit a5fd197
Show file tree
Hide file tree
Showing 20 changed files with 585 additions and 273 deletions.
14 changes: 11 additions & 3 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -322,10 +322,18 @@ jobs:

- name: Fetch deps
if: env.run_tests
run: sudo apt-get -q update && sudo DEBIAN_FRONTEND=noninteractive apt-get install -y build-essential uidmap squashfs-tools squashfuse fuse-overlayfs fakeroot fuse2fs libseccomp-dev cryptsetup dbus-user-session
run: |
set -e
sudo apt-get -q update
sudo DEBIAN_FRONTEND=noninteractive apt-get install -y build-essential uidmap squashfs-tools squashfuse fuse-overlayfs fakeroot fuse2fs libseccomp-dev cryptsetup dbus-user-session
sudo DEBIAN_FRONTEND=noninteractive apt-get install -y autoconf automake libtool pkg-config libfuse3-dev zlib1g-dev
- name: Fetch gocryptfs
run: wget -O gocryptfs.tar.gz https://github.com/rfjakob/gocryptfs/releases/download/v2.3/gocryptfs_v2.3_linux-static_amd64.tar.gz && sudo tar xzvf gocryptfs.tar.gz -C /usr/local/bin gocryptfs
- name: Download, compile, and install dependent packages
run: |
set -ex
mlocal/scripts/download-dependencies .
mlocal/scripts/compile-dependencies
sudo cp gocryptfs*/gocryptfs squashfuse*/squashfuse_ll /usr/local/bin
# The fuse-overlayfs version from ubuntu-22.04, 1.7, is buggy,
# so update to version 1.9
Expand Down
10 changes: 10 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,16 @@ For older changes see the [archived Singularity change log](https://github.com/a

### Changed defaults / behaviours

- In setuid privileged mode, if `allow setuid-mount squashfs = no` then
the squashfuse image driver will be used to mount squash images
instead of the kernel squashfs driver. This eliminates the
vulnerability of using a kernel filesystem driver to mount a file
writable by an unprivileged user. Likewise, if
`allow setuid-mount encrypted = no` then the unprivileged gocryptfs
format will be used for encrypting SIF files instead of the kernel
device-mapper. If a SIF file was encrypted using the gocryptfs
format, it can now be mounted in setuid mode in addition to
non-setuid mode.
- `--cwd` is now the preferred form of the flag for setting the container's
working directory, though `--pwd` is still supported for compatibility.
- When building RPM, we will now use `/var/lib/apptainer` (rather than
Expand Down
3 changes: 2 additions & 1 deletion INSTALL.md
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ sudo apt-get install -y \
fuse-overlayfs \
fakeroot \
cryptsetup \
tzdata \
curl wget git
```

Expand Down Expand Up @@ -182,7 +183,7 @@ Instructions for installing it from source follow here.
First, make sure that additional required packages are installed. On Debian:

```sh
apt-get install -y autoconf automake libtool pkg-config libfuse-dev zlib1g-dev
apt-get install -y autoconf automake libtool pkg-config libfuse3-dev zlib1g-dev
```

On CentOS/RHEL:
Expand Down
2 changes: 1 addition & 1 deletion dist/debian/control
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ Build-Depends:
automake,
libtool,
pkg-config,
libfuse-dev,
libfuse3-dev,
zlib1g-dev
Standards-Version: 3.9.8
Homepage: http://apptainer.org
Expand Down
30 changes: 8 additions & 22 deletions dist/debian/rules
Original file line number Diff line number Diff line change
Expand Up @@ -64,35 +64,21 @@ export APPTAINER_CACHEDIR=$(pkgdir)/var/lib/apptainer/cache
dh $@ --with=autoreconf

override_dh_auto_configure:
@SQUASHFUSETGZ="`echo debian/squashfuse-*.tar.gz`"; \
if [ -f "$$SQUASHFUSETGZ" ]; then \
set -x; \
tar -C debian -xf $$SQUASHFUSETGZ; \
cd $${SQUASHFUSETGZ%.tar.gz}; \
./autogen.sh; \
FLAGS=-std=c99 ./configure --enable-multithreading; \
make squashfuse_ll; \
fi
@export PATH=$(GOROOT)/bin:$$PATH; \
@export GOPATH=$(GOROOT)/bin PATH=$(GOROOT)/bin:$$PATH GOCACHE=$(GOCACHE); \
set -ex; \
if ! ./mlocal/scripts/check-min-go-version go $(MINGO_VERSION); then \
set -e; \
if [ -d $(GOROOT) ]; then rm -rf $(GOROOT); fi; \
mkdir -p $(GOROOT); \
HERE=$$PWD; \
cd $(GOROOT)/..; \
tar -xf $$HERE/debian/go$(MINGO_VERSION).src.tar.gz; \
cd go/src; \
GOCACHE=$(GOCACHE) ./make.bash; \
fi
@GOCRYPTFSTGZ="`echo debian/gocryptfs-*.tar.gz`"; \
if [ -f "$$GOCRYPTFSTGZ" ]; then \
set -x; \
tar -C debian -xf $$GOCRYPTFSTGZ; \
cd $${GOCRYPTFSTGZ%.tar.gz}; \
export GOCACHE=$(GOCACHE); \
export GOPATH=$(GOROOT)/bin; \
PATH=$(GOROOT)/bin:$$PATH ./build-without-openssl.bash; \
fi
./make.bash; \
cd $$HERE; \
fi; \
cd debian; \
../mlocal/scripts/compile-dependencies; \
cd ..
ifneq ($(NEW_VERSION),)
$(warning "Setting new version in debian changelog: $(NEW_VERSION)")
@debchange -v $(NEW_VERSION)$(VERSION_POSTFIX) "Version $(NEW_VERSION)" && debchange -m -r ""
Expand Down
32 changes: 16 additions & 16 deletions dist/rpm/apptainer.spec.in
Original file line number Diff line number Diff line change
Expand Up @@ -151,22 +151,6 @@ Provides the optional setuid-root portion of Apptainer.
%endif

%build
%if "%{?gocryptfs_version}" != ""
pushd ../gocryptfs-%{gocryptfs_version}
if [ ! -d vendor ]; then
(
export GOPATH="`pwd`/gopath"
go mod vendor
go clean -modcache
)
fi
# GOPROXY=off makes sure we fail instead of making network requests
# the -B ldflags prevent rpm complaints about "No build ID note found"
CGO_ENABLED=0 GOPROXY=off ./build.bash -mod=vendor -tags without_openssl \
-ldflags="-X main.GitVersion=%{gocryptfs_version} -B 0x`head -c20 /dev/urandom|od -An -tx1|tr -d ' \n'`"
popd
%endif

%if "%{?squashfuse_version}" != ""
pushd ../squashfuse-%{squashfuse_version}
./autogen.sh
Expand All @@ -189,6 +173,22 @@ if ! ./mlocal/scripts/check-min-go-version go $GOVERSION; then
fi
%endif

%if "%{?gocryptfs_version}" != ""
pushd ../gocryptfs-%{gocryptfs_version}
if [ ! -d vendor ]; then
(
export GOPATH="`pwd`/gopath"
go mod vendor
go clean -modcache
)
fi
# GOPROXY=off makes sure we fail instead of making network requests
# the -B ldflags prevent rpm complaints about "No build ID note found"
CGO_ENABLED=0 GOPROXY=off ./build.bash -mod=vendor -tags without_openssl \
-ldflags="-X main.GitVersion=%{gocryptfs_version} -B 0x`head -c20 /dev/urandom|od -An -tx1|tr -d ' \n'`"
popd
%endif

# Not all of these parameters currently have an effect, but they might be
# used someday. They are the same parameters as in the configure macro.
./mconfig %{?mconfig_opts} -V %{version}-%{release} --with-suid \
Expand Down
48 changes: 33 additions & 15 deletions e2e/config/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -123,6 +123,8 @@ func (c *configTests) prepImages(t *testing.T) (cleanup func(t *testing.T)) {
return cleanup
}

const findsquash = "pstree $PPID|grep squashfuse"

//nolint:maintidx
func (c configTests) configGlobal(t *testing.T) {
cleanup := c.prepImages(t)
Expand Down Expand Up @@ -506,6 +508,14 @@ func (c configTests) configGlobal(t *testing.T) {
directiveValue: "no",
exit: 255,
},
{
name: "AllowSetuidMountEncryptedNoUnpriv",
argv: []string{"--pem-path", c.pemPrivate, c.encryptedUnprivImage, "true"},
profile: e2e.UserProfile,
directive: "allow setuid-mount encrypted",
directiveValue: "no",
exit: 0,
},
{
name: "AllowSetuidMountEncryptedNoUserns",
argv: []string{"--pem-path", c.pemPrivate, c.encryptedUnprivImage, "true"},
Expand All @@ -522,77 +532,85 @@ func (c configTests) configGlobal(t *testing.T) {
directiveValue: "yes",
exit: 0,
},
{
name: "AllowSetuidMountEncryptedYesUnpriv",
argv: []string{"--pem-path", c.pemPrivate, c.encryptedUnprivImage, "true"},
profile: e2e.UserProfile,
directive: "allow setuid-mount encrypted",
directiveValue: "yes",
exit: 0,
},
{
name: "AllowSetuidMountSquashfsNo",
argv: []string{c.squashfsImage, "true"},
argv: []string{c.squashfsImage, "sh", "-c", findsquash},
profile: e2e.UserProfile,
directive: "allow setuid-mount squashfs",
directiveValue: "no",
exit: 255,
exit: 0,
},
{
name: "AllowSetuidMountSquashfsNoSif",
argv: []string{c.sifImage, "true"},
argv: []string{c.sifImage, "sh", "-c", findsquash},
profile: e2e.UserProfile,
directive: "allow setuid-mount squashfs",
directiveValue: "no",
exit: 255,
exit: 0,
},
{
name: "AllowSetuidMountSquashfsNoBind",
argv: []string{"-B", c.squashfsImage + ":/sqsh:image-src=/", c.sifImage, "true"},
argv: []string{"-B", c.squashfsImage + ":/sqsh:image-src=/", c.sifImage, "sh", "-c", findsquash},
profile: e2e.UserProfile,
directive: "allow setuid-mount squashfs",
directiveValue: "no",
exit: 255,
exit: 0,
},
{
name: "AllowSetuidMountSquashfsNoUserns",
argv: []string{c.squashfsImage, "true"},
argv: []string{c.squashfsImage, "sh", "-c", findsquash},
profile: e2e.UserNamespaceProfile,
directive: "allow setuid-mount squashfs",
directiveValue: "no",
exit: 0,
},
{
name: "AllowSetuidMountSquashfsNoUsernsSif",
argv: []string{c.sifImage, "true"},
argv: []string{c.sifImage, "sh", "-c", findsquash},
profile: e2e.UserNamespaceProfile,
directive: "allow setuid-mount squashfs",
directiveValue: "no",
exit: 0,
},
{
name: "AllowSetuidMountSquashfsNoUsernsBind",
argv: []string{"-B", c.squashfsImage + ":/sqsh:image-src=/", c.sifImage, "true"},
argv: []string{"-B", c.squashfsImage + ":/sqsh:image-src=/", c.sifImage, "sh", "-c", findsquash},
profile: e2e.UserNamespaceProfile,
directive: "allow setuid-mount squashfs",
directiveValue: "no",
exit: 0,
},
{
name: "AllowSetuidMountSquashfsYes",
argv: []string{c.squashfsImage, "true"},
argv: []string{c.squashfsImage, "sh", "-c", findsquash},
profile: e2e.UserProfile,
directive: "allow setuid-mount squashfs",
directiveValue: "yes",
exit: 0,
exit: 1,
},
{
name: "AllowSetuidMountSquashfsYesSif",
argv: []string{c.sifImage, "true"},
argv: []string{c.sifImage, "sh", "-c", findsquash},
profile: e2e.UserProfile,
directive: "allow setuid-mount squashfs",
directiveValue: "yes",
exit: 0,
exit: 1,
},
{
name: "AllowSetuidMountSquashfsYesBind",
argv: []string{"-B", c.squashfsImage + ":/sqsh:image-src=/", c.sifImage, "true"},
argv: []string{"-B", c.squashfsImage + ":/sqsh:image-src=/", c.sifImage, "sh", "-c", findsquash},
profile: e2e.UserProfile,
directive: "allow setuid-mount squashfs",
directiveValue: "yes",
exit: 0,
exit: 1,
},
{
name: "AllowSetuidMountExtfsNo",
Expand Down
5 changes: 5 additions & 0 deletions examples/plugins/ubuntu-userns-overlay-plugin/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import (
"fmt"
"os/exec"
"strings"
"syscall"

"github.com/apptainer/apptainer/pkg/image"
pluginapi "github.com/apptainer/apptainer/pkg/plugin"
Expand Down Expand Up @@ -70,6 +71,10 @@ func (d *ubuntuOvlDriver) Stop(target string) error {
return nil
}

func (d *ubuntuOvlDriver) Stopped(int, syscall.WaitStatus) error {
return nil
}

// setConfiguration sets "image driver" and "enable overlay" configuration directives
// during apptainer plugin install step.
func setConfiguration(_ string) error {
Expand Down
Loading

0 comments on commit a5fd197

Please sign in to comment.