Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

optionally use image driver for squashfs and gocryptfs in setuid mode #183

Closed
wants to merge 1 commit into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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
Loading