Documentation
¶
Overview ¶
Package execve is a wrapper around the system execve(2) and fexecve(3) system calls.
Index ¶
Examples ¶
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
func Execveat ¶
Execveat executes at program at a path using a file descriptor. The go runtime process image is replaced by the executable described by the directory file descriptor and pathname.
Example ¶
package main import ( "fmt" "os" "codeberg.org/msantos/execve" "golang.org/x/sys/unix" ) func main() { if err := os.Chdir("/bin"); err != nil { fmt.Fprintln(os.Stderr, err) return } n := int32(unix.AT_FDCWD) AT_FDCWD := uintptr(uint32(n)) if err := execve.Execveat( AT_FDCWD, "sh", []string{"sh", "-c", "echo test"}, []string{}, 0, ); err != nil { fmt.Fprintln(os.Stderr, err) return } }
Output:
func Fexecve ¶
Fexecve executes the program referred to by a file descriptor. The go runtime process image is replaced with the executable referred to by the file descriptor. The file descriptor should be opened with the O_CLOEXEC flag set (the default when using os.Open) to prevent the fd from leaking to the new process image.
The exception to this rule is running scripts: the file descriptor must be opened without O_CLOEXEC.
BUG(fexecve): If fd refers to a script (i.e., it is an executable text file that names a script interpreter with a first line that begins with the characters #!) and the close-on-exec flag has been set for fd, then fexecve() fails with the error ENOENT. This error occurs because, by the time the script interpreter is executed, fd has already been closed because of the close-on-exec flag. Thus, the close-on-exec flag can't be set on fd if it refers to a script, leading to the problems described in NOTES (fexecve(3)).
Example ¶
package main import ( "fmt" "os" "codeberg.org/msantos/execve" ) func main() { fd, err := os.Open("/bin/sh") if err != nil { fmt.Fprintln(os.Stderr, err) return } if err := execve.Fexecve( fd.Fd(), []string{"sh", "-c", "echo test"}, []string{}, ); err != nil { fmt.Fprintln(os.Stderr, err) return } }
Output:
Example (Memfd) ¶
ExampleFexecve_memfd is an example of running an executable from memory.
package main import ( "fmt" "io" "os" "os/exec" "codeberg.org/msantos/execve" "golang.org/x/sys/unix" ) func main() { path, err := exec.LookPath("echo") if err != nil { fmt.Fprintf(os.Stderr, "LookPath: %v", err) return } exe, err := os.Open(path) if err != nil { fmt.Fprintf(os.Stderr, "Open: %v", err) return } fd, err := unix.MemfdCreate("ExampleFexecve_memfd", unix.MFD_CLOEXEC) if err != nil { fmt.Fprintf(os.Stderr, "MemfdCreate: %v", err) return } f := os.NewFile(uintptr(fd), "ExampleFexecve_memfd") if _, err := io.Copy(f, exe); err != nil { fmt.Fprintf(os.Stderr, "Copy: %v", err) return } if err := execve.Fexecve(f.Fd(), []string{"-n", "test"}, os.Environ()); err != nil { fmt.Fprintf(os.Stderr, "Fexecve: %v", err) return } }
Output:
Example (Script) ¶
package main import ( "fmt" "os" "syscall" "codeberg.org/msantos/execve" ) func main() { // Make a shell script file, err := os.CreateTemp("", "script") if err != nil { fmt.Fprintln(os.Stderr, err) return } name := file.Name() if _, err := file.Write([]byte("#!/bin/sh\necho $@")); err != nil { fmt.Fprintln(os.Stderr, err) return } if err := file.Chmod(0o755); err != nil { fmt.Fprintln(os.Stderr, err) return } if err := file.Close(); err != nil { fmt.Fprintln(os.Stderr, err) return } // Get a file descriptor with O_CLOEXEC unset fd, err := syscall.Open(name, syscall.O_RDONLY, 0) if err != nil { fmt.Fprintln(os.Stderr, err) return } sh := fmt.Sprintf("/dev/fd/%d", fd) if err := execve.Fexecve( uintptr(fd), []string{sh, "test"}, []string{}, ); err != nil { fmt.Fprintln(os.Stderr, err) return } }
Output:
Types ¶
This section is empty.
Notes ¶
Bugs ¶
If fd refers to a script (i.e., it is an executable text file that names a script interpreter with a first line that begins with the characters #!) and the close-on-exec flag has been set for fd, then fexecve() fails with the error ENOENT. This error occurs because, by the time the script interpreter is executed, fd has already been closed because of the close-on-exec flag. Thus, the close-on-exec flag can't be set on fd if it refers to a script, leading to the problems described in NOTES (fexecve(3)).
Directories
¶
Path | Synopsis |
---|---|
examples
|
|
dfdexe
Dfdexe embeds and runs a directory of executables from memory.
|
Dfdexe embeds and runs a directory of executables from memory. |
fdexe
Fdexe embeds and runs an executable from memory.
|
Fdexe embeds and runs an executable from memory. |
ioexe
Ioexe reads and runs an executable from stdin.
|
Ioexe reads and runs an executable from stdin. |