Skip to content

Commit

Permalink
feat: machined: initial SELinux bring-up
Browse files Browse the repository at this point in the history
Part of: siderolabs#9127

Label executables and processes, build, load and manage SELinux policy, enable audit support.

Labeling filesystems, devices and runtime files will be done in further changes, see the full PR.

Signed-off-by: Dmitry Sharshakov <[email protected]>
  • Loading branch information
dsseng committed Nov 4, 2024
1 parent 7f3aaa2 commit 4f5b33c
Show file tree
Hide file tree
Showing 43 changed files with 1,617 additions and 4 deletions.
1 change: 1 addition & 0 deletions .dockerignore
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
**
!api
!selinux
!cmd
!docs
!hack
Expand Down
19 changes: 17 additions & 2 deletions Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -375,6 +375,13 @@ COPY --from=embed-abbrev-generate /src/pkg/machinery/gendata/data /pkg/machinery
COPY --from=embed-abbrev-generate /src/_out/talos-metadata /_out/talos-metadata
COPY --from=embed-abbrev-generate /src/_out/signing_key.x509 /_out/signing_key.x509

FROM tools AS selinux
COPY ./internal/pkg/selinux/policy/* /selinux/
RUN mkdir /policy; secilc -o /policy/policy.33 -f /policy/file_contexts -c 33 /selinux/**/*.cil -vvvvv -O

FROM scratch AS selinux-generate
COPY --from=selinux /policy /policy

FROM scratch AS ipxe-generate
COPY --from=pkg-ipxe-amd64 /usr/libexec/snp.efi /amd64/snp.efi
COPY --from=pkg-ipxe-arm64 /usr/libexec/snp.efi /arm64/snp.efi
Expand Down Expand Up @@ -412,6 +419,7 @@ COPY --from=go-generate /src/pkg/machinery/config/types/ /pkg/machinery/config/t
COPY --from=go-generate /src/pkg/machinery/nethelpers/ /pkg/machinery/nethelpers/
COPY --from=go-generate /src/pkg/machinery/extensions/ /pkg/machinery/extensions/
COPY --from=ipxe-generate / /pkg/provision/providers/vm/internal/ipxe/data/ipxe/
COPY --from=selinux-generate / /internal/pkg/selinux/
COPY --from=embed-abbrev / /
COPY --from=pkg-ca-certificates /etc/ssl/certs/ca-certificates /internal/app/machined/pkg/controllers/secrets/data/
COPY --from=microsoft-key-keys / /internal/pkg/secureboot/database/certs/
Expand All @@ -429,6 +437,7 @@ COPY --from=generate /pkg/imager/ ./pkg/imager/
COPY --from=generate /pkg/machinery/ ./pkg/machinery/
COPY --from=generate /internal/app/machined/pkg/controllers/secrets/data/ ./internal/app/machined/pkg/controllers/secrets/data/
COPY --from=generate /internal/pkg/secureboot/database/certs/ ./internal/pkg/secureboot/database/certs/
COPY --from=generate /internal/pkg/selinux/ ./internal/pkg/selinux/
COPY --from=embed / ./
RUN --mount=type=cache,target=/.cache go list all >/dev/null
WORKDIR /src/pkg/machinery
Expand Down Expand Up @@ -809,13 +818,19 @@ FROM rootfs-base-arm64 AS rootfs-squashfs-arm64
ARG ZSTD_COMPRESSION_LEVEL
RUN find /rootfs -print0 \
| xargs -0r touch --no-dereference --date="@${SOURCE_DATE_EPOCH}"
RUN mksquashfs /rootfs /rootfs.sqsh -all-root -noappend -comp zstd -Xcompression-level ${ZSTD_COMPRESSION_LEVEL} -no-progress
COPY --from=selinux-generate /policy/file_contexts /file_contexts
COPY ./hack/labeled-squashfs.sh /
ENV SHELL=/toolchain/bin/bash
RUN fakeroot /labeled-squashfs.sh /rootfs /rootfs.sqsh /file_contexts ${ZSTD_COMPRESSION_LEVEL}

FROM rootfs-base-amd64 AS rootfs-squashfs-amd64
ARG ZSTD_COMPRESSION_LEVEL
RUN find /rootfs -print0 \
| xargs -0r touch --no-dereference --date="@${SOURCE_DATE_EPOCH}"
RUN mksquashfs /rootfs /rootfs.sqsh -all-root -noappend -comp zstd -Xcompression-level ${ZSTD_COMPRESSION_LEVEL} -no-progress
COPY --from=selinux-generate /policy/file_contexts /file_contexts
COPY ./hack/labeled-squashfs.sh /
ENV SHELL=/toolchain/bin/bash
RUN fakeroot /labeled-squashfs.sh /rootfs /rootfs.sqsh /file_contexts ${ZSTD_COMPRESSION_LEVEL}

FROM scratch AS squashfs-arm64
COPY --from=rootfs-squashfs-arm64 /rootfs.sqsh /
Expand Down
6 changes: 6 additions & 0 deletions hack/labeled-squashfs.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
#!/toolchain/bin/bash

set -e
# set SELinux labels for files according to file_contexts supplied
/toolchain/sbin/setfiles -r $1 -F -vv $3 $1
mksquashfs $1 $2 -all-root -noappend -comp zstd -Xcompression-level $4 -no-progress
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,7 @@ import (
"github.com/siderolabs/talos/internal/pkg/partition"
"github.com/siderolabs/talos/internal/pkg/secureboot"
"github.com/siderolabs/talos/internal/pkg/secureboot/tpm2"
"github.com/siderolabs/talos/internal/pkg/selinux"
"github.com/siderolabs/talos/internal/pkg/zboot"
"github.com/siderolabs/talos/pkg/conditions"
"github.com/siderolabs/talos/pkg/images"
Expand Down Expand Up @@ -620,6 +621,10 @@ func WriteUdevRules(runtime.Sequence, any) (runtime.TaskExecutionFunc, string) {
return fmt.Errorf("failed writing custom udev rules: %w", err)
}

if err = selinux.SetLabel(constants.UdevRulesPath, constants.UdevRulesLabel); err != nil {
return fmt.Errorf("failed labeling custom udev rules: %w", err)
}

if len(rules) > 0 {
if _, err := cmd.RunContext(ctx, "/sbin/udevadm", "control", "--reload"); err != nil {
return err
Expand Down
16 changes: 16 additions & 0 deletions internal/app/machined/pkg/system/runner/containerd/containerd.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,8 @@ import (
"github.com/siderolabs/talos/internal/app/machined/pkg/system/events"
"github.com/siderolabs/talos/internal/app/machined/pkg/system/runner"
"github.com/siderolabs/talos/internal/pkg/cgroup"
"github.com/siderolabs/talos/internal/pkg/selinux"
"github.com/siderolabs/talos/pkg/machinery/constants"
)

// containerdRunner is a runner.Runner that runs container in containerd.
Expand Down Expand Up @@ -341,6 +343,20 @@ func (c *containerdRunner) newOCISpecOpts(image oci.Image) []oci.SpecOpts {
)
}

if selinux.IsEnabled() {
if c.opts.SelinuxLabel != "" {
specOpts = append(
specOpts,
oci.WithSelinuxLabel(c.opts.SelinuxLabel),
)
} else {
specOpts = append(
specOpts,
oci.WithSelinuxLabel(constants.SelinuxLabelUnconfinedSysContainer),
)
}
}

return specOpts
}

Expand Down
20 changes: 20 additions & 0 deletions internal/app/machined/pkg/system/runner/process/process.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import (
"fmt"
"io"
"io/fs"
"log"
"os"
"path"
"slices"
Expand All @@ -30,6 +31,7 @@ import (
"github.com/siderolabs/talos/internal/app/machined/pkg/system/events"
"github.com/siderolabs/talos/internal/app/machined/pkg/system/runner"
"github.com/siderolabs/talos/internal/pkg/cgroup"
"github.com/siderolabs/talos/internal/pkg/selinux"
"github.com/siderolabs/talos/pkg/machinery/constants"
)

Expand Down Expand Up @@ -92,6 +94,7 @@ func (p *processRunner) Close() error {
type commandWrapper struct {
launcher *cap.Launcher
ctty optional.Optional[int]
selinuxLabel string
cgroupFile *os.File
stdin *os.File
stdout *os.File
Expand Down Expand Up @@ -159,6 +162,22 @@ func beforeExecCallback(pa *syscall.ProcAttr, data any) error {
pa.Sys.CgroupFD = int(wrapper.cgroupFile.Fd())
}

// Use /proc/thread-self (Linux 3.17+) to avoid races between current
// process threads leading to loss of the domain transition
if selinux.IsEnabled() {
if wrapper.selinuxLabel != "" {
err := os.WriteFile("/proc/thread-self/attr/exec", []byte(wrapper.selinuxLabel), 0o777)
if err != nil {
log.Fatalf("%s", err)
}
} else {
err := os.WriteFile("/proc/thread-self/attr/exec", []byte(constants.SelinuxLabelUnconfinedService), 0o777)
if err != nil {
log.Fatalf("%s", err)
}
}
}

return nil
}

Expand Down Expand Up @@ -266,6 +285,7 @@ func (p *processRunner) build() (commandWrapper, error) {
wrapper.afterStart = func() { xslices.Map(afterStartClosers, io.Closer.Close) }
wrapper.afterTermination = closeLogging
wrapper.ctty = p.opts.Ctty
wrapper.selinuxLabel = p.opts.SelinuxLabel

cgroupFdSupported := false

Expand Down
9 changes: 9 additions & 0 deletions internal/app/machined/pkg/system/runner/runner.go
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,8 @@ type Options struct {
OverrideSeccompProfile func(*specs.LinuxSeccomp)
// DroppedCapabilities is the list of capabilities to drop.
DroppedCapabilities []string
// SelinuxLabel is the SELinux label to be assigned
SelinuxLabel string
// StdinFile is the path to the file to use as stdin.
StdinFile string
// StdoutFile is the path to the file to use as stdout.
Expand Down Expand Up @@ -175,6 +177,13 @@ func WithCgroupPath(path string) Option {
}
}

// WithSelinuxLabel sets the SELinux label.
func WithSelinuxLabel(label string) Option {
return func(args *Options) {
args.SelinuxLabel = label
}
}

// WithCustomSeccompProfile sets the function to override seccomp profile.
func WithCustomSeccompProfile(override func(*specs.LinuxSeccomp)) Option {
return func(args *Options) {
Expand Down
1 change: 1 addition & 0 deletions internal/app/machined/pkg/system/services/apid.go
Original file line number Diff line number Diff line change
Expand Up @@ -196,6 +196,7 @@ func (o *APID) Runner(r runtime.Runtime) (runner.Runner, error) {
runner.WithContainerdAddress(constants.SystemContainerdAddress),
runner.WithEnv(env),
runner.WithCgroupPath(constants.CgroupApid),
runner.WithSelinuxLabel(constants.SelinuxLabelApid),
runner.WithOCISpecOpts(
oci.WithDroppedCapabilities(cap.Known()),
oci.WithHostNamespace(specs.NetworkNamespace),
Expand Down
1 change: 1 addition & 0 deletions internal/app/machined/pkg/system/services/containerd.go
Original file line number Diff line number Diff line change
Expand Up @@ -112,6 +112,7 @@ func (c *Containerd) Runner(r runtime.Runtime) (runner.Runner, error) {
)),
runner.WithOOMScoreAdj(-999),
runner.WithCgroupPath(constants.CgroupSystemRuntime),
runner.WithSelinuxLabel(constants.SelinuxLabelSystemRuntime),
runner.WithDroppedCapabilities(constants.DefaultDroppedCapabilities),
),
restart.WithType(restart.Forever),
Expand Down
1 change: 1 addition & 0 deletions internal/app/machined/pkg/system/services/cri.go
Original file line number Diff line number Diff line change
Expand Up @@ -106,6 +106,7 @@ func (c *CRI) Runner(r runtime.Runtime) (runner.Runner, error) {
)),
runner.WithOOMScoreAdj(-500),
runner.WithCgroupPath(constants.CgroupPodRuntime),
runner.WithSelinuxLabel(constants.SelinuxLabelPodRuntime),
runner.WithDroppedCapabilities(constants.DefaultDroppedCapabilities),
),
restart.WithType(restart.Forever),
Expand Down
1 change: 1 addition & 0 deletions internal/app/machined/pkg/system/services/dashboard.go
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,7 @@ func (d *Dashboard) Runner(r runtime.Runtime) (runner.Runner, error) {
runner.WithCtty(0),
runner.WithOOMScoreAdj(-400),
runner.WithDroppedCapabilities(capability.AllCapabilitiesSetLowercase()),
runner.WithSelinuxLabel(constants.SelinuxLabelDashboard),
runner.WithCgroupPath(constants.CgroupDashboard),
runner.WithUID(constants.DashboardUserID),
),
Expand Down
1 change: 1 addition & 0 deletions internal/app/machined/pkg/system/services/etcd.go
Original file line number Diff line number Diff line change
Expand Up @@ -220,6 +220,7 @@ func (e *Etcd) Runner(r runtime.Runtime) (runner.Runner, error) {
runner.WithContainerImage(e.imgRef),
runner.WithEnv(env),
runner.WithCgroupPath(constants.CgroupEtcd),
runner.WithSelinuxLabel(constants.SELinuxLabelEtcd),
runner.WithOCISpecOpts(
oci.WithDroppedCapabilities(cap.Known()),
oci.WithHostNamespace(specs.NetworkNamespace),
Expand Down
2 changes: 1 addition & 1 deletion internal/app/machined/pkg/system/services/kubelet.go
Original file line number Diff line number Diff line change
Expand Up @@ -164,6 +164,7 @@ func (k *Kubelet) Runner(r runtime.Runtime) (runner.Runner, error) {
runner.WithContainerImage(k.imgRef),
runner.WithEnv(environment.Get(r.Config())),
runner.WithCgroupPath(constants.CgroupKubelet),
runner.WithSelinuxLabel(constants.SelinuxLabelKubelet),
runner.WithOCISpecOpts(
containerd.WithRootfsPropagation("shared"),
oci.WithMounts(mounts),
Expand All @@ -174,7 +175,6 @@ func (k *Kubelet) Runner(r runtime.Runtime) (runner.Runner, error) {
oci.WithReadonlyPaths(nil),
oci.WithWriteableSysfs,
oci.WithWriteableCgroupfs,
oci.WithSelinuxLabel(""),
oci.WithApparmorProfile(""),
oci.WithAllDevicesAllowed,
oci.WithCapabilities(capability.AllGrantableCapabilities()), // TODO: kubelet doesn't need all of these, we should consider limiting capabilities
Expand Down
1 change: 1 addition & 0 deletions internal/app/machined/pkg/system/services/trustd.go
Original file line number Diff line number Diff line change
Expand Up @@ -159,6 +159,7 @@ func (t *Trustd) Runner(r runtime.Runtime) (runner.Runner, error) {
runner.WithContainerdAddress(constants.SystemContainerdAddress),
runner.WithEnv(env),
runner.WithCgroupPath(constants.CgroupTrustd),
runner.WithSelinuxLabel(constants.SelinuxLabelTrustd),
runner.WithOCISpecOpts(
oci.WithDroppedCapabilities(cap.Known()),
oci.WithHostNamespace(specs.NetworkNamespace),
Expand Down
1 change: 1 addition & 0 deletions internal/app/machined/pkg/system/services/udevd.go
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,7 @@ func (c *Udevd) Runner(r runtime.Runtime) (runner.Runner, error) {
args,
runner.WithLoggingManager(r.Logging()),
runner.WithCgroupPath(constants.CgroupUdevd),
runner.WithSelinuxLabel(constants.SelinuxLabelUdevd),
runner.WithDroppedCapabilities(constants.UdevdDroppedCapabilities),
runner.WithEnv([]string{
// append a default value for XDG_RUNTIME_DIR for the services running on the host
Expand Down
Loading

0 comments on commit 4f5b33c

Please sign in to comment.