mirror of
https://github.com/siderolabs/talos.git
synced 2025-10-15 09:31:19 +02:00
Now Go only sets the rlimit for the parent and any fork/exec'ed process
gets the rlimit that was the default before fork/exec. Ref: https://github.com/golang/go/issues/46279
This fix got backported to [Go 1.20.4](ecf7e00db8
) breaking Talos.
Talos used to set rlimit in the [`SetRLimit`](https://github.com/siderolabs/talos/blob/v1.4.2/internal/app/machined/pkg/runtime/v1alpha1/v1alpha1_sequencer_tasks.go#L302) sequencer task.
This means any process started by `wrapperd` gets the default Rlimit
(1024). Fix this by explicitly setting `rlimit` in `wrapperd` before we
drop any capabilities.
Fixes: #7198
Signed-off-by: Noel Georgi <git@frezbo.dev>
121 lines
3.6 KiB
Go
121 lines
3.6 KiB
Go
// This Source Code Form is subject to the terms of the Mozilla Public
|
|
// License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
// file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
|
|
|
// Package wrapperd provides a wrapper for running services.
|
|
package wrapperd
|
|
|
|
import (
|
|
"flag"
|
|
"log"
|
|
"os"
|
|
"strings"
|
|
|
|
"github.com/containerd/cgroups"
|
|
cgroupsv2 "github.com/containerd/cgroups/v2"
|
|
"github.com/containerd/containerd/sys"
|
|
"github.com/siderolabs/gen/slices"
|
|
"golang.org/x/sys/unix"
|
|
"kernel.org/pub/linux/libs/security/libcap/cap"
|
|
|
|
krnl "github.com/siderolabs/talos/pkg/kernel"
|
|
"github.com/siderolabs/talos/pkg/machinery/constants"
|
|
"github.com/siderolabs/talos/pkg/machinery/kernel"
|
|
)
|
|
|
|
var (
|
|
name string
|
|
droppedCaps string
|
|
cgroupPath string
|
|
oomScore int
|
|
uid int
|
|
)
|
|
|
|
// Main is the entrypoint into /sbin/wrapperd.
|
|
//
|
|
//nolint:gocyclo
|
|
func Main() {
|
|
flag.StringVar(&name, "name", "", "process name")
|
|
flag.StringVar(&droppedCaps, "dropped-caps", "", "comma-separated list of capabilities to drop")
|
|
flag.StringVar(&cgroupPath, "cgroup-path", "", "cgroup path to use")
|
|
flag.IntVar(&oomScore, "oom-score", 0, "oom score to set")
|
|
flag.IntVar(&uid, "uid", 0, "uid to set for the process")
|
|
flag.Parse()
|
|
|
|
currentPid := os.Getpid()
|
|
|
|
if oomScore != 0 {
|
|
if err := sys.AdjustOOMScore(currentPid, oomScore); err != nil {
|
|
log.Fatalf("Failed to change OOMScoreAdj of process %s to %d", name, oomScore)
|
|
}
|
|
}
|
|
|
|
// set the rlimit for the process before we drop privileges
|
|
// TODO: frezbo: see if we need to drop Rlimit from the boot sequence, the only downside maybe that some very early process might
|
|
// not have the higher rlimit set, but it seems we always use the wrapper to start processes.
|
|
if err := unix.Setrlimit(unix.RLIMIT_NOFILE, &unix.Rlimit{Max: 1048576, Cur: 1048576}); err != nil {
|
|
log.Fatalf("failed to set rlimit: %v", err)
|
|
}
|
|
|
|
// load the cgroup and put the process into the cgroup
|
|
if cgroupPath != "" {
|
|
if cgroups.Mode() == cgroups.Unified {
|
|
cgv2, err := cgroupsv2.LoadManager(constants.CgroupMountPath, cgroupPath)
|
|
if err != nil {
|
|
log.Fatalf("failed to load cgroup %s: %v", cgroupPath, err)
|
|
}
|
|
|
|
if err := cgv2.AddProc(uint64(currentPid)); err != nil {
|
|
log.Fatalf("Failed to move process %s to cgroup: %v", name, err)
|
|
}
|
|
} else {
|
|
cgv1, err := cgroups.Load(cgroups.V1, cgroups.StaticPath(cgroupPath))
|
|
if err != nil {
|
|
log.Fatalf("failed to load cgroup %s: %v", cgroupPath, err)
|
|
}
|
|
|
|
if err := cgv1.Add(cgroups.Process{
|
|
Pid: currentPid,
|
|
}); err != nil {
|
|
log.Fatalf("Failed to move process %s to cgroup: %v", name, err)
|
|
}
|
|
}
|
|
}
|
|
|
|
prop, err := krnl.ReadParam(&kernel.Param{Key: "proc.sys.kernel.kexec_load_disabled"})
|
|
if v := strings.TrimSpace(string(prop)); err == nil && v != "0" {
|
|
log.Printf("kernel.kexec_load_disabled is %v, skipping dropping capabilities", v)
|
|
} else if droppedCaps != "" {
|
|
caps := strings.Split(droppedCaps, ",")
|
|
dropCaps := slices.Map(caps, func(c string) cap.Value {
|
|
capability, capErr := cap.FromName(c)
|
|
if capErr != nil {
|
|
log.Fatalf("failed to parse capability: %v", capErr)
|
|
}
|
|
|
|
return capability
|
|
})
|
|
|
|
// drop capabilities
|
|
iab := cap.IABGetProc()
|
|
if err = iab.SetVector(cap.Bound, true, dropCaps...); err != nil {
|
|
log.Fatalf("failed to set capabilities: %v", err)
|
|
}
|
|
|
|
if err = iab.SetProc(); err != nil {
|
|
log.Fatalf("failed to apply capabilities: %v", err)
|
|
}
|
|
}
|
|
|
|
if uid > 0 {
|
|
err = unix.Setuid(uid)
|
|
if err != nil {
|
|
log.Fatalf("failed to setuid: %v", err)
|
|
}
|
|
}
|
|
|
|
if err := unix.Exec(flag.Args()[0], flag.Args()[0:], os.Environ()); err != nil {
|
|
log.Fatalf("failed to exec: %v", err)
|
|
}
|
|
}
|