mirror of
https://github.com/coder/coder.git
synced 2026-09-24 15:04:27 +08:00
fix: fix oom_score adjustments failing if caps set (#15758)
- Fixes an issue where oom scores would fail to be adjusted in cases where the `coder` binary has capabilities set on it. This is because `PR_SET_DUMPABLE` is set to `0` when a process is executed with elevated capabilities. The fix is to flip `PR_SET_DUMPABLE` to `1` prior to writing to `oom_score_adj`.
This commit is contained in:
@@ -18,6 +18,7 @@ import (
|
||||
|
||||
"github.com/stretchr/testify/require"
|
||||
"golang.org/x/sys/unix"
|
||||
"golang.org/x/xerrors"
|
||||
|
||||
"github.com/coder/coder/v2/testutil"
|
||||
)
|
||||
@@ -50,6 +51,32 @@ func TestCLI(t *testing.T) {
|
||||
requireOOMScore(t, cmd.Process.Pid, expectedOOM)
|
||||
requireNiceScore(t, cmd.Process.Pid, expectedNice)
|
||||
})
|
||||
|
||||
t.Run("Capabilities", func(t *testing.T) {
|
||||
testdir := filepath.Dir(TestBin)
|
||||
capDir := filepath.Join(testdir, "caps")
|
||||
err := os.Mkdir(capDir, 0o755)
|
||||
require.NoError(t, err)
|
||||
bin := buildBinary(capDir)
|
||||
// Try to set capabilities on the binary. This should work fine in CI but
|
||||
// it's possible some developers may be working in an environment where they don't have the necessary permissions.
|
||||
err = setCaps(t, bin, "cap_net_admin")
|
||||
if os.Getenv("CI") != "" {
|
||||
require.NoError(t, err)
|
||||
} else if err != nil {
|
||||
t.Skipf("unable to set capabilities for test: %v", err)
|
||||
}
|
||||
ctx := testutil.Context(t, testutil.WaitMedium)
|
||||
cmd, path := binCmd(ctx, t, bin, 123, 12)
|
||||
err = cmd.Start()
|
||||
require.NoError(t, err)
|
||||
go cmd.Wait()
|
||||
|
||||
waitForSentinel(ctx, t, cmd, path)
|
||||
// This is what we're really testing, a binary with added capabilities requires setting dumpable.
|
||||
requireOOMScore(t, cmd.Process.Pid, 123)
|
||||
requireNiceScore(t, cmd.Process.Pid, 12)
|
||||
})
|
||||
}
|
||||
|
||||
func requireNiceScore(t *testing.T, pid int, score int) {
|
||||
@@ -94,7 +121,7 @@ func waitForSentinel(ctx context.Context, t *testing.T, cmd *exec.Cmd, path stri
|
||||
}
|
||||
}
|
||||
|
||||
func cmd(ctx context.Context, t *testing.T, oom, nice int) (*exec.Cmd, string) {
|
||||
func binCmd(ctx context.Context, t *testing.T, bin string, oom, nice int) (*exec.Cmd, string) {
|
||||
var (
|
||||
args = execArgs(oom, nice)
|
||||
dir = t.TempDir()
|
||||
@@ -103,7 +130,7 @@ func cmd(ctx context.Context, t *testing.T, oom, nice int) (*exec.Cmd, string) {
|
||||
|
||||
args = append(args, "sh", "-c", fmt.Sprintf("touch %s && sleep 10m", file))
|
||||
//nolint:gosec
|
||||
cmd := exec.CommandContext(ctx, TestBin, args...)
|
||||
cmd := exec.CommandContext(ctx, bin, args...)
|
||||
|
||||
// We set this so we can also easily kill the sleep process the shell spawns.
|
||||
cmd.SysProcAttr = &syscall.SysProcAttr{
|
||||
@@ -127,6 +154,10 @@ func cmd(ctx context.Context, t *testing.T, oom, nice int) (*exec.Cmd, string) {
|
||||
return cmd, file
|
||||
}
|
||||
|
||||
func cmd(ctx context.Context, t *testing.T, oom, nice int) (*exec.Cmd, string) {
|
||||
return binCmd(ctx, t, TestBin, oom, nice)
|
||||
}
|
||||
|
||||
func expectedOOMScore(t *testing.T) int {
|
||||
t.Helper()
|
||||
|
||||
@@ -171,3 +202,14 @@ func execArgs(oom int, nice int) []string {
|
||||
execArgs = append(execArgs, "--")
|
||||
return execArgs
|
||||
}
|
||||
|
||||
func setCaps(t *testing.T, bin string, caps ...string) error {
|
||||
t.Helper()
|
||||
|
||||
setcap := fmt.Sprintf("sudo -n setcap %s=ep %s", strings.Join(caps, ", "), bin)
|
||||
out, err := exec.CommandContext(context.Background(), "sh", "-c", setcap).CombinedOutput()
|
||||
if err != nil {
|
||||
return xerrors.Errorf("setcap %q (%s): %w", setcap, out, err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user