mirror of
https://github.com/containers/podman.git
synced 2025-05-17 23:26:08 +08:00

Bump Buildah to v1.38.1 which addresses CVE-2024-11218. Signed-off-by: tomsweeneyredhat <tsweeney@redhat.com>
169 lines
4.8 KiB
Go
169 lines
4.8 KiB
Go
//go:build linux || freebsd || darwin
|
|
|
|
package open
|
|
|
|
import (
|
|
"bytes"
|
|
"encoding/json"
|
|
"errors"
|
|
"fmt"
|
|
"os"
|
|
"syscall"
|
|
|
|
"github.com/containers/storage/pkg/reexec"
|
|
"golang.org/x/sys/unix"
|
|
)
|
|
|
|
const (
|
|
inChrootCommand = "buildah-open-in-chroot"
|
|
)
|
|
|
|
func init() {
|
|
reexec.Register(inChrootCommand, inChrootMain)
|
|
}
|
|
|
|
func inChroot(requests requests) results {
|
|
sock, err := unix.Socketpair(unix.AF_UNIX, unix.SOCK_STREAM, 0)
|
|
if err != nil {
|
|
return results{Err: fmt.Errorf("creating socket pair: %w", err).Error()}
|
|
}
|
|
parentSock := sock[0]
|
|
childSock := sock[1]
|
|
parentEnd := os.NewFile(uintptr(parentSock), "parent end of socket pair")
|
|
childEnd := os.NewFile(uintptr(childSock), "child end of socket pair")
|
|
cmd := reexec.Command(inChrootCommand)
|
|
cmd.ExtraFiles = append(cmd.ExtraFiles, childEnd)
|
|
err = cmd.Start()
|
|
childEnd.Close()
|
|
defer parentEnd.Close()
|
|
if err != nil {
|
|
return results{Err: err.Error()}
|
|
}
|
|
encoder := json.NewEncoder(parentEnd)
|
|
if err := encoder.Encode(&requests); err != nil {
|
|
return results{Err: fmt.Errorf("sending request down socket: %w", err).Error()}
|
|
}
|
|
if err := unix.Shutdown(parentSock, unix.SHUT_WR); err != nil {
|
|
return results{Err: fmt.Errorf("finishing sending request down socket: %w", err).Error()}
|
|
}
|
|
b := make([]byte, 65536)
|
|
oob := make([]byte, 65536)
|
|
n, oobn, _, _, err := unix.Recvmsg(parentSock, b, oob, 0)
|
|
if err != nil {
|
|
return results{Err: fmt.Errorf("receiving message: %w", err).Error()}
|
|
}
|
|
if err := unix.Shutdown(parentSock, unix.SHUT_RD); err != nil {
|
|
return results{Err: fmt.Errorf("finishing socket: %w", err).Error()}
|
|
}
|
|
if n > len(b) {
|
|
return results{Err: fmt.Errorf("too much regular data: %d > %d", n, len(b)).Error()}
|
|
}
|
|
if oobn > len(oob) {
|
|
return results{Err: fmt.Errorf("too much OOB data: %d > %d", oobn, len(oob)).Error()}
|
|
}
|
|
scms, err := unix.ParseSocketControlMessage(oob[:oobn])
|
|
if err != nil {
|
|
return results{Err: fmt.Errorf("parsing control message: %w", err).Error()}
|
|
}
|
|
var receivedFds []int
|
|
for i := range scms {
|
|
fds, err := unix.ParseUnixRights(&scms[i])
|
|
if err != nil {
|
|
return results{Err: fmt.Errorf("parsing rights message %d: %w", i, err).Error()}
|
|
}
|
|
receivedFds = append(receivedFds, fds...)
|
|
}
|
|
decoder := json.NewDecoder(bytes.NewReader(b[:n]))
|
|
var result results
|
|
if err := decoder.Decode(&result); err != nil {
|
|
return results{Err: fmt.Errorf("decoding results: %w", err).Error()}
|
|
}
|
|
j := 0
|
|
for i := range result.Open {
|
|
if result.Open[i].Err == "" {
|
|
if j >= len(receivedFds) {
|
|
for _, fd := range receivedFds {
|
|
unix.Close(fd)
|
|
}
|
|
return results{Err: fmt.Errorf("didn't receive enough FDs").Error()}
|
|
}
|
|
result.Open[i].Fd = uintptr(receivedFds[j])
|
|
j++
|
|
}
|
|
}
|
|
return result
|
|
}
|
|
|
|
func inChrootMain() {
|
|
var theseRequests requests
|
|
var theseResults results
|
|
sockFd := 3
|
|
sock := os.NewFile(uintptr(sockFd), "socket connection to parent process")
|
|
defer sock.Close()
|
|
encoder := json.NewEncoder(sock)
|
|
decoder := json.NewDecoder(sock)
|
|
if err := decoder.Decode(&theseRequests); err != nil {
|
|
if err := encoder.Encode(results{Err: fmt.Errorf("decoding request: %w", err).Error()}); err != nil {
|
|
os.Exit(1)
|
|
}
|
|
}
|
|
if theseRequests.Root != "" {
|
|
if err := os.Chdir(theseRequests.Root); err != nil {
|
|
if err := encoder.Encode(results{Err: fmt.Errorf("changing to %q: %w", theseRequests.Root, err).Error()}); err != nil {
|
|
os.Exit(1)
|
|
}
|
|
os.Exit(1)
|
|
}
|
|
if err := unix.Chroot(theseRequests.Root); err != nil {
|
|
if err := encoder.Encode(results{Err: fmt.Errorf("chrooting to %q: %w", theseRequests.Root, err).Error()}); err != nil {
|
|
os.Exit(1)
|
|
}
|
|
os.Exit(1)
|
|
}
|
|
if err := os.Chdir("/"); err != nil {
|
|
if err := encoder.Encode(results{Err: fmt.Errorf("changing to new root: %w", err).Error()}); err != nil {
|
|
os.Exit(1)
|
|
}
|
|
os.Exit(1)
|
|
}
|
|
}
|
|
if theseRequests.Wd != "" {
|
|
if err := os.Chdir(theseRequests.Wd); err != nil {
|
|
if err := encoder.Encode(results{Err: fmt.Errorf("changing to %q in chroot: %w", theseRequests.Wd, err).Error()}); err != nil {
|
|
os.Exit(1)
|
|
}
|
|
os.Exit(1)
|
|
}
|
|
}
|
|
var fds []int
|
|
for _, request := range theseRequests.Open {
|
|
fd, err := unix.Open(request.Path, request.Mode, request.Perms)
|
|
thisResult := result{Fd: uintptr(fd)}
|
|
if err == nil {
|
|
fds = append(fds, fd)
|
|
} else {
|
|
var errno syscall.Errno
|
|
thisResult.Err = err.Error()
|
|
if errors.As(err, &errno) {
|
|
thisResult.Errno = errno
|
|
}
|
|
}
|
|
theseResults.Open = append(theseResults.Open, thisResult)
|
|
}
|
|
rights := unix.UnixRights(fds...)
|
|
inband, err := json.Marshal(&theseResults)
|
|
if err != nil {
|
|
if err := encoder.Encode(results{Err: fmt.Errorf("sending response: %w", err).Error()}); err != nil {
|
|
os.Exit(1)
|
|
}
|
|
os.Exit(1)
|
|
}
|
|
if err := unix.Sendmsg(sockFd, inband, rights, nil, 0); err != nil {
|
|
if err := encoder.Encode(results{Err: fmt.Errorf("sending response: %w", err).Error()}); err != nil {
|
|
os.Exit(1)
|
|
}
|
|
os.Exit(1)
|
|
}
|
|
os.Exit(0)
|
|
}
|