summaryrefslogtreecommitdiff
path: root/internal/namespace/namespace.go
diff options
context:
space:
mode:
Diffstat (limited to 'internal/namespace/namespace.go')
-rw-r--r--internal/namespace/namespace.go42
1 files changed, 13 insertions, 29 deletions
diff --git a/internal/namespace/namespace.go b/internal/namespace/namespace.go
index 6f56a84..54414a9 100644
--- a/internal/namespace/namespace.go
+++ b/internal/namespace/namespace.go
@@ -68,7 +68,8 @@ func VerifyArguments(args []string) error {
}
// Bootstrap ensures the process is running in an isolated user and network namespace.
-// It writes the embedded C launcher to a temporary file and replaces the current process.
+// It uses memfd_create to run the embedded C launcher from memory, bypassing
+// disk-based noexec restrictions.
func Bootstrap() (err error) {
if IsIsolated() {
return nil
@@ -97,12 +98,11 @@ func Bootstrap() (err error) {
return fmt.Errorf("failed to get executable path: %w", err)
}
- execFd, launcherPath, err := prepareLauncher()
+ execFd, err := prepareLauncher()
if err != nil {
return err
}
fdsToClose = append(fdsToClose, execFd)
- _ = os.Remove(launcherPath) // Unlink early; fd remains valid
// Clear close-on-exec
if flags, err := unix.FcntlInt(uintptr(execFd), unix.F_GETFD, 0); err == nil {
@@ -187,12 +187,11 @@ func BootstrapJoin(targetPid int) (err error) {
return fmt.Errorf("failed to get executable path: %w", err)
}
- execFd, launcherPath, err := prepareLauncher()
+ execFd, err := prepareLauncher()
if err != nil {
return err
}
fdsToClose = append(fdsToClose, execFd)
- _ = os.Remove(launcherPath)
if flags, err := unix.FcntlInt(uintptr(execFd), unix.F_GETFD, 0); err == nil {
_, _ = unix.FcntlInt(uintptr(execFd), unix.F_SETFD, flags&^unix.FD_CLOEXEC)
@@ -222,33 +221,18 @@ func BootstrapJoin(targetPid int) (err error) {
return nil
}
-func prepareLauncher() (int, string, error) {
- tmpFile, err := os.CreateTemp("", "wg-wrap-launcher-")
+func prepareLauncher() (int, error) {
+ // Use memfd_create to create an anonymous file in memory.
+ // This bypasses the need for a temporary disk file and avoids noexec restrictions.
+ fd, err := unix.MemfdCreate("wg-wrap-launcher", 0)
if err != nil {
- return 0, "", fmt.Errorf("failed to create temp launcher file: %w", err)
+ return 0, fmt.Errorf("failed to create memfd: %w", err)
}
- launcherPath := tmpFile.Name()
- defer func() {
- if err != nil {
- _ = tmpFile.Close()
- _ = os.Remove(launcherPath)
- }
- }()
-
- if _, err = tmpFile.Write(launcherBytes); err != nil {
- return 0, "", fmt.Errorf("failed to write launcher binary: %w", err)
- }
-
- if err = tmpFile.Chmod(0700); err != nil {
- return 0, "", fmt.Errorf("failed to set launcher permissions: %w", err)
- }
-
- execFd, err := syscall.Open(launcherPath, syscall.O_RDONLY, 0)
- if err != nil {
- return 0, "", fmt.Errorf("failed to open launcher for exec: %w", err)
+ if _, err = unix.Write(fd, launcherBytes); err != nil {
+ _ = unix.Close(fd)
+ return 0, fmt.Errorf("failed to write launcher binary to memfd: %w", err)
}
- _ = tmpFile.Close()
- return execFd, launcherPath, nil
+ return fd, nil
}