diff --git a/define/build.go b/define/build.go index 359eec7d16e..256197f3f7c 100644 --- a/define/build.go +++ b/define/build.go @@ -62,6 +62,8 @@ type CommonBuildOptions struct { // LabelOpts is a slice of the fields of an SELinux context, given in "field:pair" format, or "disable". // Recognized field names are "role", "type", and "level". LabelOpts []string + // Paths to mask + Masks []string // MemorySwap limits the amount of memory and swap together. MemorySwap int64 // NoHostname tells the builder not to create /etc/hostname content when running @@ -109,6 +111,8 @@ type CommonBuildOptions struct { SSHSources []string // OCIHooksDir is the location of OCI hooks for the build containers OCIHooksDir []string + // Paths to unmask + Unmasks []string } // BuildOptions can be used to alter how an image is built. diff --git a/docs/buildah-build.1.md b/docs/buildah-build.1.md index 6fe68e7ed40..c27fb29fd36 100644 --- a/docs/buildah-build.1.md +++ b/docs/buildah-build.1.md @@ -935,11 +935,17 @@ Security Options "label=type:TYPE" : Set the label type for the container "label=level:LEVEL" : Set the label level for the container "label=disable" : Turn off label confinement for the container + + "mask=_/path/1:/path/2_": The paths to mask separated by a colon. A masked path cannot be accessed inside the container. + "no-new-privileges" : Disable container processes from gaining additional privileges "seccomp=unconfined" : Turn off seccomp confinement for the container "seccomp=profile.json : JSON configuration for a seccomp filter + "unmask=_ALL_ or _/path/1:/path/2_, or shell expanded paths (/proc/*): Paths to unmask separated by a colon. If set to **ALL**, it unmasks all the paths that are masked or made read-only by default. + The default masked paths are **/proc/acpi, /proc/kcore, /proc/keys, /proc/latency_stats, /proc/sched_debug, /proc/scsi, /proc/timer_list, /proc/timer_stats, /sys/firmware, and /sys/fs/selinux**, **/sys/devices/virtual/powercap**. The default paths that are read-only are **/proc/asound**, **/proc/bus**, **/proc/fs**, **/proc/irq**, **/proc/sys**, **/proc/sysrq-trigger**, **/sys/fs/cgroup**. + **--shm-size**="" Size of `/dev/shm`. The format is ``. `number` must be greater than `0`. diff --git a/internal/mkcw/embed/entrypoint_amd64.gz b/internal/mkcw/embed/entrypoint_amd64.gz index 947bed9b688..953670818fe 100755 Binary files a/internal/mkcw/embed/entrypoint_amd64.gz and b/internal/mkcw/embed/entrypoint_amd64.gz differ diff --git a/pkg/parse/parse.go b/pkg/parse/parse.go index 695b9c334d1..15b520cfa11 100644 --- a/pkg/parse/parse.go +++ b/pkg/parse/parse.go @@ -249,6 +249,18 @@ func parseSecurityOpts(securityOpts []string, commonOpts *define.CommonBuildOpti commonOpts.ApparmorProfile = con[1] case "seccomp": commonOpts.SeccompProfilePath = con[1] + case "mask": + commonOpts.Masks = append(commonOpts.Masks, strings.Split(con[1], ":")...) + case "unmask": + unmasks := strings.Split(con[1], ":") + for _, unmask := range unmasks { + matches, _ := filepath.Glob(unmask) + if len(matches) > 0 { + commonOpts.Unmasks = append(commonOpts.Unmasks, matches...) + continue + } + commonOpts.Unmasks = append(commonOpts.Unmasks, unmask) + } default: return fmt.Errorf("invalid --security-opt 2: %q", opt) } diff --git a/run_linux.go b/run_linux.go index 0acee7ac84e..ec7c264338d 100644 --- a/run_linux.go +++ b/run_linux.go @@ -328,7 +328,7 @@ func (b *Builder) Run(command []string, options RunOptions) error { } } - setupMaskedPaths(g) + setupMaskedPaths(g, b.CommonBuildOpts) setupReadOnlyPaths(g) setupTerminal(g, options.Terminal, options.TerminalSize) @@ -1199,8 +1199,20 @@ func (b *Builder) runSetupVolumeMounts(mountLabel string, volumeMounts []string, return mounts, nil } -func setupMaskedPaths(g *generate.Generator) { +func setupMaskedPaths(g *generate.Generator, opts *define.CommonBuildOptions) { + if slices.Contains(opts.Unmasks, "all") { + return + } for _, mp := range config.DefaultMaskedPaths { + if slices.Contains(opts.Unmasks, mp) { + continue + } + g.AddLinuxMaskedPaths(mp) + } + for _, mp := range opts.Masks { + if slices.Contains(opts.Unmasks, mp) { + continue + } g.AddLinuxMaskedPaths(mp) } } diff --git a/tests/bud.bats b/tests/bud.bats index 8eae1d30672..36aa3be79c6 100644 --- a/tests/bud.bats +++ b/tests/bud.bats @@ -7123,3 +7123,16 @@ EOF echo RUN --mount=type=tmpfs,target=tmpfssubdir test '`stat -f -c %i .`' '!=' '`stat -f -c %i tmpfssubdir`' >> ${TEST_SCRATCH_DIR}/Containerfile run_buildah build --security-opt label=disable ${TEST_SCRATCH_DIR} } + +@test "build-security-opt-mask" { + base=busybox + _prefetch $base + run_buildah build bud/masks + expect_output --substring "masked" "Everything should be masked" + run_buildah build --security-opt unmask=all bud/masks + expect_output --substring "unmasked" "Everything should be masked" + run_buildah build --security-opt unmask=/proc/* bud/masks + expect_output --substring "unmasked" "Everything should be masked" + run_buildah build --security-opt unmask=/proc/acpi bud/masks + expect_output --substring "unmasked" "Everything should be masked" +} diff --git a/tests/bud/masks/Containerfile b/tests/bud/masks/Containerfile new file mode 100644 index 00000000000..8d7cfd0be6a --- /dev/null +++ b/tests/bud/masks/Containerfile @@ -0,0 +1,4 @@ +FROM alpine +COPY --chmod=700 test.sh / +RUN /test.sh + diff --git a/tests/bud/masks/test.sh b/tests/bud/masks/test.sh new file mode 100644 index 00000000000..9a88dac9bd2 --- /dev/null +++ b/tests/bud/masks/test.sh @@ -0,0 +1,15 @@ +# !/bin/sh + +function output { + for mask in /proc/acpi /proc/kcore /proc/keys /proc/latency_stats /proc/sched_debug /proc/scsi /proc/timer_list /proc/timer_stats /sys/dev/block /sys/devices/virtual/powercap /sys/firmware /sys/fs/selinux; do + test -e $mask || continue + test -f $mask && cat $mask 2> /dev/null + test -d $mask && ls $mask + done +} +output=$(output | wc -c ) +if [ $output == 0 ]; then + echo "masked" +else + echo "unmasked" +fi