-
Notifications
You must be signed in to change notification settings - Fork 100
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
fix: CNI: avoid error with iptables setuid check
Newer versions of the `iptables` command use a real vs effective uid check whether they are being called from a setuid script, and exit if that's the case. This check was added because iptables can call out to binaries / libraries on `PATH` / `LD_LIBRARY_PATH`, and these are generally under control of the user - allowing privilege escalation attackes. Singularity sanitizes the environment before running CNI plugins, which will call `iptables`, so we can set both real and effective uid to 0 to avoid the error. While we are here, make `PATH` sanitization the default in the network code, rather than relying on the caller applying it. Add some tests around the priv escalation / drop code. Fixes #3318
- Loading branch information
Showing
6 changed files
with
102 additions
and
32 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,30 +1,36 @@ | ||
// Copyright (c) 2018-2022, Sylabs Inc. All rights reserved. | ||
// Copyright (c) 2018-2024, Sylabs Inc. All rights reserved. | ||
// This software is licensed under a 3-clause BSD license. Please consult the | ||
// LICENSE.md file distributed with the sources of this project regarding your | ||
// rights to use or distribute this software. | ||
|
||
package priv | ||
|
||
import ( | ||
"os" | ||
"runtime" | ||
"syscall" | ||
|
||
"github.com/sylabs/singularity/v4/pkg/sylog" | ||
"golang.org/x/sys/unix" | ||
) | ||
|
||
// Escalate escalates privileges of the thread or process. | ||
// Since Go 1.16 syscall.Setresuid is an all-thread operation. | ||
// A runtime.LockOSThread operation remains for older versions of Go. | ||
func Escalate() error { | ||
type DropPrivsFunc func() error | ||
|
||
// EscalateRealEffective locks the current goroutine to execute on the current | ||
// OS thread, and then escalates the real and effective uid of the current OS | ||
// thread to root (uid 0). The previous real uid is set as the saved | ||
// set-user-ID. A dropPrivsFunc is returned, which must be called to drop | ||
// privileges and unlock the goroutine at the earliest suitable point. | ||
func EscalateRealEffective() (DropPrivsFunc, error) { | ||
runtime.LockOSThread() | ||
uid := os.Getuid() | ||
return syscall.Setresuid(uid, 0, uid) | ||
} | ||
uid, _, _ := unix.Getresuid() | ||
|
||
dropPrivsFunc := func() error { | ||
defer runtime.UnlockOSThread() | ||
sylog.Debugf("Drop r/e/s: %d/%d/%d", uid, uid, 0) | ||
return unix.Setresuid(uid, uid, 0) | ||
} | ||
|
||
// Drop drops privileges of the thread or process. | ||
// Since Go 1.16 syscall.Setresuid is an all-thread operation. | ||
// A runtime.LockOSThread operation remains for older versions of Go. | ||
func Drop() error { | ||
defer runtime.UnlockOSThread() | ||
uid := os.Getuid() | ||
return syscall.Setresuid(uid, uid, 0) | ||
sylog.Debugf("Escalate r/e/s: %d/%d/%d", 0, 0, uid) | ||
// Note - unix.Setresuid makes a direct syscall which performs a single | ||
// thread escalation. Since Go 1.16, syscall.Setresuid is all-thread. | ||
return dropPrivsFunc, unix.Setresuid(0, 0, uid) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,46 @@ | ||
// Copyright (c) 2024, Sylabs Inc. All rights reserved. | ||
// This software is licensed under a 3-clause BSD license. Please consult the | ||
// LICENSE.md file distributed with the sources of this project regarding your | ||
// rights to use or distribute this software. | ||
|
||
package priv | ||
|
||
import ( | ||
"testing" | ||
|
||
"github.com/sylabs/singularity/v4/internal/pkg/test" | ||
"golang.org/x/sys/unix" | ||
) | ||
|
||
func TestEscalateRealEffective(t *testing.T) { | ||
test.EnsurePrivilege(t) | ||
test.DropPrivilege(t) | ||
defer test.ResetPrivilege(t) | ||
|
||
r, e, s := unix.Getresuid() | ||
if r == 0 || e == 0 { | ||
t.Fatalf("real / effective ID must be non-zero before escalation. Got r/e/s %d/%d/%d", r, e, s) | ||
} | ||
unprivUID := r | ||
|
||
drop, err := EscalateRealEffective() | ||
if err != nil { | ||
t.Fatal(err) | ||
} | ||
|
||
r, e, s = unix.Getresuid() | ||
t.Logf("Escalated r/e/s: %d/%d/%d", r, e, s) | ||
if r != 0 || e != 0 || s != unprivUID { | ||
t.Fatalf("Expected escalated r/e/s %d/%d/%d, Got r/e/s %d/%d/%d", 0, 0, unprivUID, r, e, s) | ||
} | ||
|
||
if err := drop(); err != nil { | ||
t.Fatal(err) | ||
} | ||
|
||
r, e, s = unix.Getresuid() | ||
t.Logf("Dropped r/e/s: %d/%d/%d", r, e, s) | ||
if r != unprivUID || e != unprivUID || s != 0 { | ||
t.Fatalf("Expected dropped r/e/s %d/%d/%d, Got r/e/s %d/%d/%d", unprivUID, unprivUID, 0, r, e, s) | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters