mirror of https://github.com/containers/podman.git
vendor c/{buildah,common}: appendable containers.conf strings, Part 1
This change is the first step of integrating appendable string arrays into containers.conf and starts with enabling the `Env`, `Mounts`, and `Volumes` fields in the `[Containers]` table. Both, Buildah and Podman, read (and sometimes write) the fields of the `Config` struct at various places, so I decided to migrate the fields step-by-step. The ones in this change are most critical ones for customers. Once all string slices/arrays are migrated, the docs of containers.conf will be updated. The current changes are entirely transparent to users. Signed-off-by: Valentin Rothberg <vrothberg@redhat.com>
This commit is contained in:
parent
35121f67bf
commit
989afd910e
4
go.mod
4
go.mod
|
@ -12,8 +12,8 @@ require (
|
|||
github.com/container-orchestrated-devices/container-device-interface v0.6.1
|
||||
github.com/containernetworking/cni v1.1.2
|
||||
github.com/containernetworking/plugins v1.3.0
|
||||
github.com/containers/buildah v1.32.1-0.20231016164031-ade05159a485
|
||||
github.com/containers/common v0.56.1-0.20231023143107-8d0bd259cb7c
|
||||
github.com/containers/buildah v1.32.1-0.20231024182922-ea815fea26a9
|
||||
github.com/containers/common v0.56.1-0.20231024140609-79773286b53a
|
||||
github.com/containers/conmon v2.0.20+incompatible
|
||||
github.com/containers/gvisor-tap-vsock v0.7.1
|
||||
github.com/containers/image/v5 v5.28.0
|
||||
|
|
8
go.sum
8
go.sum
|
@ -249,10 +249,10 @@ github.com/containernetworking/plugins v0.8.6/go.mod h1:qnw5mN19D8fIwkqW7oHHYDHV
|
|||
github.com/containernetworking/plugins v0.9.1/go.mod h1:xP/idU2ldlzN6m4p5LmGiwRDjeJr6FLK6vuiUwoH7P8=
|
||||
github.com/containernetworking/plugins v1.3.0 h1:QVNXMT6XloyMUoO2wUOqWTC1hWFV62Q6mVDp5H1HnjM=
|
||||
github.com/containernetworking/plugins v1.3.0/go.mod h1:Pc2wcedTQQCVuROOOaLBPPxrEXqqXBFt3cZ+/yVg6l0=
|
||||
github.com/containers/buildah v1.32.1-0.20231016164031-ade05159a485 h1:RqgxHW2iP5QJ3aRahT+KGI2aGXVZeZHTeulmeZQV0y0=
|
||||
github.com/containers/buildah v1.32.1-0.20231016164031-ade05159a485/go.mod h1:gOMfotERP5Gz2pN+AnuM3ephId/YL9DmbOtVck6fWfE=
|
||||
github.com/containers/common v0.56.1-0.20231023143107-8d0bd259cb7c h1:+5wIm8TWi18iu/WZhF6T9x693nmfpP9yqyrKCreDOOU=
|
||||
github.com/containers/common v0.56.1-0.20231023143107-8d0bd259cb7c/go.mod h1:NGMoofxxOF8tno51JlwACw0HaUwaPS66h2N7CYJGFC0=
|
||||
github.com/containers/buildah v1.32.1-0.20231024182922-ea815fea26a9 h1:z8+hkCt6vFxvP7pdz69WSABkIZBNvdGBBMRLwE7UXpQ=
|
||||
github.com/containers/buildah v1.32.1-0.20231024182922-ea815fea26a9/go.mod h1:6SLsD6bQqppB1btFZSkdDHv2XxlXeqSyTUZsIroqssg=
|
||||
github.com/containers/common v0.56.1-0.20231024140609-79773286b53a h1:1baXG5fPFMWklhYamf88+1vF2D5PbB2yenSKd9xLwm8=
|
||||
github.com/containers/common v0.56.1-0.20231024140609-79773286b53a/go.mod h1:NGMoofxxOF8tno51JlwACw0HaUwaPS66h2N7CYJGFC0=
|
||||
github.com/containers/conmon v2.0.20+incompatible h1:YbCVSFSCqFjjVwHTPINGdMX1F6JXHGTUje2ZYobNrkg=
|
||||
github.com/containers/conmon v2.0.20+incompatible/go.mod h1:hgwZ2mtuDrppv78a/cOBNiCm6O0UMWGx1mu7P00nu5I=
|
||||
github.com/containers/gvisor-tap-vsock v0.7.1 h1:+Rc+sOPplrkQb/BUXeN0ug8TxjgyrIqo/9P/eNS2A4c=
|
||||
|
|
|
@ -111,6 +111,37 @@ See 'podman create --help'" "--module must be specified before the command"
|
|||
"--module=ENOENT"
|
||||
}
|
||||
|
||||
@test "podman --module - append arrays" {
|
||||
skip_if_remote "--module is not supported for remote clients"
|
||||
|
||||
random_data="expected_annotation_$(random_string 15)"
|
||||
conf1_tmp="$PODMAN_TMPDIR/test1.conf"
|
||||
conf2_tmp="$PODMAN_TMPDIR/test2.conf"
|
||||
conf2_off_tmp="$PODMAN_TMPDIR/test2_off.conf"
|
||||
cat > $conf1_tmp <<EOF
|
||||
[containers]
|
||||
env=["A=CONF1",{append=true}]
|
||||
EOF
|
||||
cat > $conf2_tmp <<EOF
|
||||
[containers]
|
||||
env=["B=CONF2"]
|
||||
EOF
|
||||
|
||||
cat > $conf2_off_tmp <<EOF
|
||||
[containers]
|
||||
env=["B=CONF2_OFF",{append=false}]
|
||||
EOF
|
||||
|
||||
# Once append is set, all subsequent loads (and the current) will be appended.
|
||||
run_podman --module=$conf1_tmp --module=$conf2_tmp run --rm $IMAGE printenv A B
|
||||
assert "$output" = "CONF1
|
||||
CONF2"
|
||||
|
||||
# When explicitly turned off, values are replaced/overriden again.
|
||||
run_podman 1 --module=$conf1_tmp --module=$conf2_off_tmp run --rm $IMAGE printenv A B
|
||||
assert "$output" = "CONF2_OFF"
|
||||
}
|
||||
|
||||
@test "podman --module - XDG_CONFIG_HOME" {
|
||||
skip_if_remote "--module is not supported for remote clients"
|
||||
skip_if_not_rootless "loading a module from XDG_CONFIG_HOME requires rootless"
|
||||
|
|
|
@ -32,7 +32,7 @@ env:
|
|||
DEBIAN_NAME: "debian-13"
|
||||
|
||||
# Image identifiers
|
||||
IMAGE_SUFFIX: "c20230816t191118z-f38f37d13"
|
||||
IMAGE_SUFFIX: "c20231004t194547z-f39f38d13"
|
||||
FEDORA_CACHE_IMAGE_NAME: "fedora-${IMAGE_SUFFIX}"
|
||||
PRIOR_FEDORA_CACHE_IMAGE_NAME: "prior-fedora-${IMAGE_SUFFIX}"
|
||||
DEBIAN_CACHE_IMAGE_NAME: "debian-${IMAGE_SUFFIX}"
|
||||
|
|
|
@ -229,6 +229,29 @@ func createPlatformContainer(options runUsingChrootExecSubprocOptions) error {
|
|||
return errors.New("unsupported createPlatformContainer")
|
||||
}
|
||||
|
||||
func mountFlagsForFSFlags(fsFlags uintptr) uintptr {
|
||||
var mountFlags uintptr
|
||||
for _, mapping := range []struct {
|
||||
fsFlag uintptr
|
||||
mountFlag uintptr
|
||||
}{
|
||||
{unix.ST_MANDLOCK, unix.MS_MANDLOCK},
|
||||
{unix.ST_NOATIME, unix.MS_NOATIME},
|
||||
{unix.ST_NODEV, unix.MS_NODEV},
|
||||
{unix.ST_NODIRATIME, unix.MS_NODIRATIME},
|
||||
{unix.ST_NOEXEC, unix.MS_NOEXEC},
|
||||
{unix.ST_NOSUID, unix.MS_NOSUID},
|
||||
{unix.ST_RDONLY, unix.MS_RDONLY},
|
||||
{unix.ST_RELATIME, unix.MS_RELATIME},
|
||||
{unix.ST_SYNCHRONOUS, unix.MS_SYNCHRONOUS},
|
||||
} {
|
||||
if fsFlags&mapping.fsFlag == mapping.fsFlag {
|
||||
mountFlags |= mapping.mountFlag
|
||||
}
|
||||
}
|
||||
return mountFlags
|
||||
}
|
||||
|
||||
func makeReadOnly(mntpoint string, flags uintptr) error {
|
||||
var fs unix.Statfs_t
|
||||
// Make sure it's read-only.
|
||||
|
@ -236,7 +259,9 @@ func makeReadOnly(mntpoint string, flags uintptr) error {
|
|||
return fmt.Errorf("checking if directory %q was bound read-only: %w", mntpoint, err)
|
||||
}
|
||||
if fs.Flags&unix.ST_RDONLY == 0 {
|
||||
if err := unix.Mount(mntpoint, mntpoint, "bind", flags|unix.MS_REMOUNT, ""); err != nil {
|
||||
// All callers currently pass MS_RDONLY in "flags", but in case they stop doing
|
||||
// that at some point in the future...
|
||||
if err := unix.Mount(mntpoint, mntpoint, "bind", flags|unix.MS_RDONLY|unix.MS_REMOUNT|unix.MS_BIND, ""); err != nil {
|
||||
return fmt.Errorf("remounting %s in mount namespace read-only: %w", mntpoint, err)
|
||||
}
|
||||
}
|
||||
|
@ -268,7 +293,7 @@ func setupChrootBindMounts(spec *specs.Spec, bundlePath string) (undoBinds func(
|
|||
// Now bind mount all of those things to be under the rootfs's location in this
|
||||
// mount namespace.
|
||||
commonFlags := uintptr(unix.MS_BIND | unix.MS_REC | unix.MS_PRIVATE)
|
||||
bindFlags := commonFlags | unix.MS_NODEV
|
||||
bindFlags := commonFlags
|
||||
devFlags := commonFlags | unix.MS_NOEXEC | unix.MS_NOSUID | unix.MS_RDONLY
|
||||
procFlags := devFlags | unix.MS_NODEV
|
||||
sysFlags := devFlags | unix.MS_NODEV
|
||||
|
@ -291,7 +316,7 @@ func setupChrootBindMounts(spec *specs.Spec, bundlePath string) (undoBinds func(
|
|||
return undoBinds, fmt.Errorf("checking if directory %q was bound read-only: %w", subDev, err)
|
||||
}
|
||||
if fs.Flags&unix.ST_RDONLY == 0 {
|
||||
if err := unix.Mount(subDev, subDev, "bind", devFlags|unix.MS_REMOUNT, ""); err != nil {
|
||||
if err := unix.Mount(subDev, subDev, "bind", devFlags|unix.MS_REMOUNT|unix.MS_BIND, ""); err != nil {
|
||||
return undoBinds, fmt.Errorf("remounting /dev in mount namespace read-only: %w", err)
|
||||
}
|
||||
}
|
||||
|
@ -351,7 +376,7 @@ func setupChrootBindMounts(spec *specs.Spec, bundlePath string) (undoBinds func(
|
|||
}
|
||||
logrus.Debugf("bind mounted %q to %q", "/sys", filepath.Join(spec.Root.Path, "/sys"))
|
||||
|
||||
// Bind mount in everything we've been asked to mount.
|
||||
// Bind, overlay, or tmpfs mount everything we've been asked to mount.
|
||||
for _, m := range spec.Mounts {
|
||||
// Skip anything that we just mounted.
|
||||
switch m.Destination {
|
||||
|
@ -369,12 +394,12 @@ func setupChrootBindMounts(spec *specs.Spec, bundlePath string) (undoBinds func(
|
|||
continue
|
||||
}
|
||||
}
|
||||
// Skip anything that isn't a bind or tmpfs mount.
|
||||
// Skip anything that isn't a bind or overlay or tmpfs mount.
|
||||
if m.Type != "bind" && m.Type != "tmpfs" && m.Type != "overlay" {
|
||||
logrus.Debugf("skipping mount of type %q on %q", m.Type, m.Destination)
|
||||
continue
|
||||
}
|
||||
// If the target is there, we can just mount it.
|
||||
// If the target is already there, we can just mount over it.
|
||||
var srcinfo os.FileInfo
|
||||
switch m.Type {
|
||||
case "bind":
|
||||
|
@ -382,24 +407,22 @@ func setupChrootBindMounts(spec *specs.Spec, bundlePath string) (undoBinds func(
|
|||
if err != nil {
|
||||
return undoBinds, fmt.Errorf("examining %q for mounting in mount namespace: %w", m.Source, err)
|
||||
}
|
||||
case "overlay":
|
||||
fallthrough
|
||||
case "tmpfs":
|
||||
case "overlay", "tmpfs":
|
||||
srcinfo, err = os.Stat("/")
|
||||
if err != nil {
|
||||
return undoBinds, fmt.Errorf("examining / to use as a template for a %s: %w", m.Type, err)
|
||||
return undoBinds, fmt.Errorf("examining / to use as a template for a %s mount: %w", m.Type, err)
|
||||
}
|
||||
}
|
||||
target := filepath.Join(spec.Root.Path, m.Destination)
|
||||
// Check if target is a symlink
|
||||
// Check if target is a symlink.
|
||||
stat, err := os.Lstat(target)
|
||||
// If target is a symlink, follow the link and ensure the destination exists
|
||||
// If target is a symlink, follow the link and ensure the destination exists.
|
||||
if err == nil && stat != nil && (stat.Mode()&os.ModeSymlink != 0) {
|
||||
target, err = copier.Eval(spec.Root.Path, m.Destination, copier.EvalOptions{})
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("evaluating symlink %q: %w", target, err)
|
||||
}
|
||||
// Stat the destination of the evaluated symlink
|
||||
// Stat the destination of the evaluated symlink.
|
||||
_, err = os.Stat(target)
|
||||
}
|
||||
if err != nil {
|
||||
|
@ -407,7 +430,8 @@ func setupChrootBindMounts(spec *specs.Spec, bundlePath string) (undoBinds func(
|
|||
if !errors.Is(err, os.ErrNotExist) {
|
||||
return undoBinds, fmt.Errorf("examining %q for mounting in mount namespace: %w", target, err)
|
||||
}
|
||||
// The target isn't there yet, so create it.
|
||||
// The target isn't there yet, so create it. If the source is a directory,
|
||||
// we need a directory, otherwise we need a non-directory (i.e., a file).
|
||||
if srcinfo.IsDir() {
|
||||
if err = os.MkdirAll(target, 0755); err != nil {
|
||||
return undoBinds, fmt.Errorf("creating mountpoint %q in mount namespace: %w", target, err)
|
||||
|
@ -423,79 +447,94 @@ func setupChrootBindMounts(spec *specs.Spec, bundlePath string) (undoBinds func(
|
|||
file.Close()
|
||||
}
|
||||
}
|
||||
// Sort out which flags we're asking for, and what statfs() should be telling us
|
||||
// if we successfully mounted with them.
|
||||
requestFlags := uintptr(0)
|
||||
expectedFlags := uintptr(0)
|
||||
expectedImportantFlags := uintptr(0)
|
||||
importantFlags := uintptr(0)
|
||||
possibleImportantFlags := uintptr(unix.ST_NODEV | unix.ST_NOEXEC | unix.ST_NOSUID | unix.ST_RDONLY)
|
||||
for _, option := range m.Options {
|
||||
switch option {
|
||||
case "nodev":
|
||||
requestFlags |= unix.MS_NODEV
|
||||
expectedFlags |= unix.ST_NODEV
|
||||
importantFlags |= unix.ST_NODEV
|
||||
expectedImportantFlags |= unix.ST_NODEV
|
||||
case "dev":
|
||||
requestFlags &= ^uintptr(unix.MS_NODEV)
|
||||
expectedFlags &= ^uintptr(unix.ST_NODEV)
|
||||
importantFlags |= unix.ST_NODEV
|
||||
expectedImportantFlags &= ^uintptr(unix.ST_NODEV)
|
||||
case "noexec":
|
||||
requestFlags |= unix.MS_NOEXEC
|
||||
expectedFlags |= unix.ST_NOEXEC
|
||||
importantFlags |= unix.ST_NOEXEC
|
||||
expectedImportantFlags |= unix.ST_NOEXEC
|
||||
case "exec":
|
||||
requestFlags &= ^uintptr(unix.MS_NOEXEC)
|
||||
expectedFlags &= ^uintptr(unix.ST_NOEXEC)
|
||||
importantFlags |= unix.ST_NOEXEC
|
||||
expectedImportantFlags &= ^uintptr(unix.ST_NOEXEC)
|
||||
case "nosuid":
|
||||
requestFlags |= unix.MS_NOSUID
|
||||
expectedFlags |= unix.ST_NOSUID
|
||||
importantFlags |= unix.ST_NOSUID
|
||||
expectedImportantFlags |= unix.ST_NOSUID
|
||||
case "suid":
|
||||
requestFlags &= ^uintptr(unix.MS_NOSUID)
|
||||
expectedFlags &= ^uintptr(unix.ST_NOSUID)
|
||||
importantFlags |= unix.ST_NOSUID
|
||||
expectedImportantFlags &= ^uintptr(unix.ST_NOSUID)
|
||||
case "ro":
|
||||
requestFlags |= unix.MS_RDONLY
|
||||
expectedFlags |= unix.ST_RDONLY
|
||||
importantFlags |= unix.ST_RDONLY
|
||||
expectedImportantFlags |= unix.ST_RDONLY
|
||||
case "rw":
|
||||
requestFlags &= ^uintptr(unix.MS_RDONLY)
|
||||
expectedFlags &= ^uintptr(unix.ST_RDONLY)
|
||||
importantFlags |= unix.ST_RDONLY
|
||||
expectedImportantFlags &= ^uintptr(unix.ST_RDONLY)
|
||||
}
|
||||
}
|
||||
switch m.Type {
|
||||
case "bind":
|
||||
// Do the bind mount.
|
||||
logrus.Debugf("bind mounting %q on %q", m.Destination, filepath.Join(spec.Root.Path, m.Destination))
|
||||
if err := unix.Mount(m.Source, target, "", bindFlags|requestFlags, ""); err != nil {
|
||||
// Do the initial bind mount. We'll worry about the flags in a bit.
|
||||
logrus.Debugf("bind mounting %q on %q %v", m.Destination, filepath.Join(spec.Root.Path, m.Destination), m.Options)
|
||||
if err = unix.Mount(m.Source, target, "", bindFlags|requestFlags, ""); err != nil {
|
||||
return undoBinds, fmt.Errorf("bind mounting %q from host to %q in mount namespace (%q): %w", m.Source, m.Destination, target, err)
|
||||
}
|
||||
if (requestFlags & unix.MS_RDONLY) != 0 {
|
||||
if err = unix.Statfs(target, &fs); err != nil {
|
||||
return undoBinds, fmt.Errorf("checking if directory %q was bound read-only: %w", target, err)
|
||||
}
|
||||
// we need to make sure these flags are maintained in the REMOUNT operation
|
||||
additionalFlags := uintptr(fs.Flags) & (unix.MS_NOEXEC | unix.MS_NOSUID | unix.MS_NODEV)
|
||||
if err := unix.Mount("", target, "", unix.MS_REMOUNT|unix.MS_BIND|unix.MS_RDONLY|additionalFlags, ""); err != nil {
|
||||
return undoBinds, fmt.Errorf("setting flags on the bind mount %q from host to %q in mount namespace (%q): %w", m.Source, m.Destination, target, err)
|
||||
}
|
||||
}
|
||||
logrus.Debugf("bind mounted %q to %q", m.Source, target)
|
||||
case "tmpfs":
|
||||
// Mount a tmpfs.
|
||||
if err := mount.Mount(m.Source, target, m.Type, strings.Join(append(m.Options, "private"), ",")); err != nil {
|
||||
return undoBinds, fmt.Errorf("mounting tmpfs to %q in mount namespace (%q, %q): %w", m.Destination, target, strings.Join(m.Options, ","), err)
|
||||
// Mount a tmpfs. We'll worry about the flags in a bit.
|
||||
if err = mount.Mount(m.Source, target, m.Type, strings.Join(append(m.Options, "private"), ",")); err != nil {
|
||||
return undoBinds, fmt.Errorf("mounting tmpfs to %q in mount namespace (%q, %q): %w", m.Destination, target, strings.Join(append(m.Options, "private"), ","), err)
|
||||
}
|
||||
logrus.Debugf("mounted a tmpfs to %q", target)
|
||||
case "overlay":
|
||||
// Mount a overlay.
|
||||
if err := mount.Mount(m.Source, target, m.Type, strings.Join(append(m.Options, "private"), ",")); err != nil {
|
||||
return undoBinds, fmt.Errorf("mounting overlay to %q in mount namespace (%q, %q): %w", m.Destination, target, strings.Join(m.Options, ","), err)
|
||||
// Mount an overlay. We'll worry about the flags in a bit.
|
||||
if err = mount.Mount(m.Source, target, m.Type, strings.Join(append(m.Options, "private"), ",")); err != nil {
|
||||
return undoBinds, fmt.Errorf("mounting overlay to %q in mount namespace (%q, %q): %w", m.Destination, target, strings.Join(append(m.Options, "private"), ","), err)
|
||||
}
|
||||
logrus.Debugf("mounted a overlay to %q", target)
|
||||
}
|
||||
// Time to worry about the flags.
|
||||
if err = unix.Statfs(target, &fs); err != nil {
|
||||
return undoBinds, fmt.Errorf("checking if directory %q was bound read-only: %w", target, err)
|
||||
return undoBinds, fmt.Errorf("checking if volume %q was mounted with requested flags: %w", target, err)
|
||||
}
|
||||
if uintptr(fs.Flags)&expectedFlags != expectedFlags {
|
||||
if err := unix.Mount(target, target, "bind", requestFlags|unix.MS_REMOUNT, ""); err != nil {
|
||||
return undoBinds, fmt.Errorf("remounting %q in mount namespace with expected flags: %w", target, err)
|
||||
effectiveImportantFlags := uintptr(fs.Flags) & importantFlags
|
||||
if effectiveImportantFlags != expectedImportantFlags {
|
||||
// Do a remount to try to get the desired flags to stick.
|
||||
effectiveUnimportantFlags := uintptr(fs.Flags) & ^possibleImportantFlags
|
||||
if err = unix.Mount(target, target, m.Type, unix.MS_REMOUNT|bindFlags|requestFlags|mountFlagsForFSFlags(effectiveUnimportantFlags), ""); err != nil {
|
||||
return undoBinds, fmt.Errorf("remounting %q in mount namespace with flags %#x instead of %#x: %w", target, requestFlags, effectiveImportantFlags, err)
|
||||
}
|
||||
// Check if the desired flags stuck.
|
||||
if err = unix.Statfs(target, &fs); err != nil {
|
||||
return undoBinds, fmt.Errorf("checking if directory %q was remounted with requested flags %#x instead of %#x: %w", target, requestFlags, effectiveImportantFlags, err)
|
||||
}
|
||||
newEffectiveImportantFlags := uintptr(fs.Flags) & importantFlags
|
||||
if newEffectiveImportantFlags != expectedImportantFlags {
|
||||
return undoBinds, fmt.Errorf("unable to remount %q with requested flags %#x instead of %#x, just got %#x back", target, requestFlags, effectiveImportantFlags, newEffectiveImportantFlags)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Set up any read-only paths that we need to. If we're running inside
|
||||
// of a container, some of these locations will already be read-only.
|
||||
// of a container, some of these locations will already be read-only, in
|
||||
// which case can declare victory and move on.
|
||||
for _, roPath := range spec.Linux.ReadonlyPaths {
|
||||
r := filepath.Join(spec.Root.Path, roPath)
|
||||
target, err := filepath.EvalSymlinks(r)
|
||||
|
@ -515,12 +554,13 @@ func setupChrootBindMounts(spec *specs.Spec, bundlePath string) (undoBinds func(
|
|||
}
|
||||
return undoBinds, fmt.Errorf("checking if directory %q is already read-only: %w", target, err)
|
||||
}
|
||||
if fs.Flags&unix.ST_RDONLY != 0 {
|
||||
if fs.Flags&unix.ST_RDONLY == unix.ST_RDONLY {
|
||||
continue
|
||||
}
|
||||
// Mount the location over itself, so that we can remount it as read-only.
|
||||
roFlags := uintptr(unix.MS_NODEV | unix.MS_NOEXEC | unix.MS_NOSUID | unix.MS_RDONLY)
|
||||
if err := unix.Mount(target, target, "", roFlags|unix.MS_BIND|unix.MS_REC, ""); err != nil {
|
||||
// Mount the location over itself, so that we can remount it as read-only, making
|
||||
// sure to preserve any combination of nodev/noexec/nosuid that's already in play.
|
||||
roFlags := mountFlagsForFSFlags(uintptr(fs.Flags)) | unix.MS_RDONLY
|
||||
if err := unix.Mount(target, target, "", bindFlags|roFlags, ""); err != nil {
|
||||
if errors.Is(err, os.ErrNotExist) {
|
||||
// No target, no problem.
|
||||
continue
|
||||
|
@ -532,7 +572,7 @@ func setupChrootBindMounts(spec *specs.Spec, bundlePath string) (undoBinds func(
|
|||
return undoBinds, fmt.Errorf("checking if directory %q was bound read-only: %w", target, err)
|
||||
}
|
||||
if fs.Flags&unix.ST_RDONLY == 0 {
|
||||
if err := unix.Mount(target, target, "", roFlags|unix.MS_BIND|unix.MS_REMOUNT, ""); err != nil {
|
||||
if err := unix.Mount(target, target, "", unix.MS_REMOUNT|unix.MS_RDONLY|bindFlags|mountFlagsForFSFlags(uintptr(fs.Flags)), ""); err != nil {
|
||||
return undoBinds, fmt.Errorf("remounting %q in mount namespace read-only: %w", target, err)
|
||||
}
|
||||
}
|
||||
|
@ -541,6 +581,7 @@ func setupChrootBindMounts(spec *specs.Spec, bundlePath string) (undoBinds func(
|
|||
return undoBinds, fmt.Errorf("checking if directory %q was remounted read-only: %w", target, err)
|
||||
}
|
||||
if fs.Flags&unix.ST_RDONLY == 0 {
|
||||
// Still not read only.
|
||||
return undoBinds, fmt.Errorf("verifying that %q in mount namespace was remounted read-only: %w", target, err)
|
||||
}
|
||||
}
|
||||
|
@ -578,7 +619,7 @@ func setupChrootBindMounts(spec *specs.Spec, bundlePath string) (undoBinds func(
|
|||
if err = unix.Statfs(target, &statfs); err != nil {
|
||||
return undoBinds, fmt.Errorf("checking if directory %q is a mountpoint: %w", target, err)
|
||||
}
|
||||
isReadOnly := statfs.Flags&unix.MS_RDONLY != 0
|
||||
isReadOnly := statfs.Flags&unix.ST_RDONLY == unix.ST_RDONLY
|
||||
// Check if any of the IDs we're mapping could read it.
|
||||
var stat unix.Stat_t
|
||||
if err = unix.Stat(target, &stat); err != nil {
|
||||
|
@ -641,11 +682,11 @@ func setupChrootBindMounts(spec *specs.Spec, bundlePath string) (undoBinds func(
|
|||
return undoBinds, fmt.Errorf("masking directory %q in mount namespace: %w", target, err)
|
||||
}
|
||||
if err = unix.Statfs(target, &fs); err != nil {
|
||||
return undoBinds, fmt.Errorf("checking if directory %q was mounted read-only in mount namespace: %w", target, err)
|
||||
return undoBinds, fmt.Errorf("checking if masked directory %q was mounted read-only in mount namespace: %w", target, err)
|
||||
}
|
||||
if fs.Flags&unix.ST_RDONLY == 0 {
|
||||
if err = unix.Mount(target, target, "", roFlags|syscall.MS_REMOUNT, ""); err != nil {
|
||||
return undoBinds, fmt.Errorf("making sure directory %q in mount namespace is read only: %w", target, err)
|
||||
if err = unix.Mount(target, target, "", syscall.MS_REMOUNT|roFlags|mountFlagsForFSFlags(uintptr(fs.Flags)), ""); err != nil {
|
||||
return undoBinds, fmt.Errorf("making sure masked directory %q in mount namespace is read only: %w", target, err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -13,6 +13,8 @@ import (
|
|||
"github.com/sirupsen/logrus"
|
||||
)
|
||||
|
||||
const seccompAvailable = true
|
||||
|
||||
// setSeccomp sets the seccomp filter for ourselves and any processes that we'll start.
|
||||
func setSeccomp(spec *specs.Spec) error {
|
||||
logrus.Debugf("setting seccomp configuration")
|
||||
|
|
|
@ -7,6 +7,8 @@ import (
|
|||
"github.com/opencontainers/runtime-spec/specs-go"
|
||||
)
|
||||
|
||||
const seccompAvailable = false
|
||||
|
||||
func setSeccomp(spec *specs.Spec) error {
|
||||
// Ignore this on FreeBSD
|
||||
return nil
|
||||
|
|
|
@ -9,6 +9,8 @@ import (
|
|||
"github.com/opencontainers/runtime-spec/specs-go"
|
||||
)
|
||||
|
||||
const seccompAvailable = false
|
||||
|
||||
func setSeccomp(spec *specs.Spec) error {
|
||||
if spec.Linux.Seccomp != nil {
|
||||
return errors.New("configured a seccomp filter without seccomp support?")
|
||||
|
|
|
@ -188,7 +188,7 @@ func newExecutor(logger *logrus.Logger, logPrefix string, store storage.Store, o
|
|||
}
|
||||
|
||||
transientMounts := []Mount{}
|
||||
for _, volume := range append(defaultContainerConfig.Containers.Volumes, options.TransientMounts...) {
|
||||
for _, volume := range append(defaultContainerConfig.Volumes(), options.TransientMounts...) {
|
||||
mount, err := parse.Volume(volume)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
|
|
Binary file not shown.
|
@ -374,7 +374,7 @@ func GetFromAndBudFlags(flags *FromAndBudResults, usernsResults *UserNSResults,
|
|||
fs.StringArrayVar(&flags.SecurityOpt, "security-opt", []string{}, "security options (default [])")
|
||||
fs.StringVar(&flags.ShmSize, "shm-size", defaultContainerConfig.Containers.ShmSize, "size of '/dev/shm'. The format is `<number><unit>`.")
|
||||
fs.StringSliceVar(&flags.Ulimit, "ulimit", defaultContainerConfig.Containers.DefaultUlimits, "ulimit options")
|
||||
fs.StringArrayVarP(&flags.Volumes, "volume", "v", defaultContainerConfig.Containers.Volumes, "bind mount a volume into the container")
|
||||
fs.StringArrayVarP(&flags.Volumes, "volume", "v", defaultContainerConfig.Volumes(), "bind mount a volume into the container")
|
||||
|
||||
// Add in the usernamespace and namespaceflags
|
||||
usernsFlags := GetUserNSFlags(usernsResults)
|
||||
|
|
92
vendor/github.com/containers/common/internal/attributedstring/slice.go
generated
vendored
Normal file
92
vendor/github.com/containers/common/internal/attributedstring/slice.go
generated
vendored
Normal file
|
@ -0,0 +1,92 @@
|
|||
package attributedstring
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
|
||||
"github.com/BurntSushi/toml"
|
||||
)
|
||||
|
||||
// Slice allows for extending a TOML string array with custom
|
||||
// attributes that control how the array is marshaled into a Go string.
|
||||
//
|
||||
// Specifically, an Slice can be configured to avoid it being
|
||||
// overridden by a subsequent unmarshal sequence. When the `append` attribute
|
||||
// is specified, the array will be appended instead (e.g., `array=["9",
|
||||
// {append=true}]`).
|
||||
type Slice struct { // A "mixed-type array" in TOML.
|
||||
// Note that the fields below _must_ be exported. Otherwise the TOML
|
||||
// encoder would fail during type reflection.
|
||||
Values []string
|
||||
Attributes struct { // Using a struct allows for adding more attributes in the future.
|
||||
Append *bool // Nil if not set by the user
|
||||
}
|
||||
}
|
||||
|
||||
// Get returns the Slice values or an empty string slice.
|
||||
func (a *Slice) Get() []string {
|
||||
if a.Values == nil {
|
||||
return []string{}
|
||||
}
|
||||
return a.Values
|
||||
}
|
||||
|
||||
// UnmarshalTOML is the custom unmarshal method for Slice.
|
||||
func (a *Slice) UnmarshalTOML(data interface{}) error {
|
||||
iFaceSlice, ok := data.([]interface{})
|
||||
if !ok {
|
||||
return fmt.Errorf("unable to cast to interface array: %v", data)
|
||||
}
|
||||
|
||||
var loadedStrings []string
|
||||
for _, x := range iFaceSlice { // Iterate over each item in the slice.
|
||||
switch val := x.(type) {
|
||||
case string: // Strings are directly appended to the slice.
|
||||
loadedStrings = append(loadedStrings, val)
|
||||
case map[string]interface{}: // The attribute struct is represented as a map.
|
||||
for k, v := range val { // Iterate over all _supported_ keys.
|
||||
switch k {
|
||||
case "append":
|
||||
boolVal, ok := v.(bool)
|
||||
if !ok {
|
||||
return fmt.Errorf("unable to cast append to bool: %v", k)
|
||||
}
|
||||
a.Attributes.Append = &boolVal
|
||||
default: // Unsupported map key.
|
||||
return fmt.Errorf("unsupported key %q in map: %v", k, val)
|
||||
}
|
||||
}
|
||||
default: // Unsupported item.
|
||||
return fmt.Errorf("unsupported item in attributed string slice: %v", x)
|
||||
}
|
||||
}
|
||||
|
||||
if a.Attributes.Append != nil && *a.Attributes.Append { // If _explicitly_ configured, append the loaded slice.
|
||||
a.Values = append(a.Values, loadedStrings...)
|
||||
} else { // Default: override the existing Slice.
|
||||
a.Values = loadedStrings
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// MarshalTOML is the custom marshal method for Slice.
|
||||
func (a *Slice) MarshalTOML() ([]byte, error) {
|
||||
iFaceSlice := make([]interface{}, 0, len(a.Values))
|
||||
|
||||
for _, x := range a.Values {
|
||||
iFaceSlice = append(iFaceSlice, x)
|
||||
}
|
||||
|
||||
if a.Attributes.Append != nil {
|
||||
Attributes := make(map[string]any)
|
||||
Attributes["append"] = *a.Attributes.Append
|
||||
iFaceSlice = append(iFaceSlice, Attributes)
|
||||
}
|
||||
|
||||
buf := new(bytes.Buffer)
|
||||
enc := toml.NewEncoder(buf)
|
||||
if err := enc.Encode(iFaceSlice); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return buf.Bytes(), nil
|
||||
}
|
|
@ -10,6 +10,7 @@ import (
|
|||
"strings"
|
||||
|
||||
"github.com/BurntSushi/toml"
|
||||
"github.com/containers/common/internal/attributedstring"
|
||||
"github.com/containers/common/libnetwork/types"
|
||||
"github.com/containers/common/pkg/capabilities"
|
||||
"github.com/containers/common/pkg/util"
|
||||
|
@ -71,7 +72,7 @@ type ContainersConfig struct {
|
|||
Devices []string `toml:"devices,omitempty"`
|
||||
|
||||
// Volumes to add to all containers
|
||||
Volumes []string `toml:"volumes,omitempty"`
|
||||
Volumes attributedstring.Slice `toml:"volumes,omitempty"`
|
||||
|
||||
// ApparmorProfile is the apparmor profile name which is used as the
|
||||
// default for the runtime.
|
||||
|
@ -133,7 +134,7 @@ type ContainersConfig struct {
|
|||
EnableLabeledUsers bool `toml:"label_users,omitempty"`
|
||||
|
||||
// Env is the environment variable list for container process.
|
||||
Env []string `toml:"env,omitempty"`
|
||||
Env attributedstring.Slice `toml:"env,omitempty"`
|
||||
|
||||
// EnvHost Pass all host environment variables into the container.
|
||||
EnvHost bool `toml:"env_host,omitempty"`
|
||||
|
@ -171,7 +172,7 @@ type ContainersConfig struct {
|
|||
LogTag string `toml:"log_tag,omitempty"`
|
||||
|
||||
// Mount to add to all containers
|
||||
Mounts []string `toml:"mounts,omitempty"`
|
||||
Mounts attributedstring.Slice `toml:"mounts,omitempty"`
|
||||
|
||||
// NetNS indicates how to create a network namespace for the container
|
||||
NetNS string `toml:"netns,omitempty"`
|
||||
|
@ -907,7 +908,7 @@ func (c *Config) GetDefaultEnvEx(envHost, httpProxy bool) []string {
|
|||
}
|
||||
}
|
||||
}
|
||||
return append(env, c.Containers.Env...)
|
||||
return append(env, c.Containers.Env.Get()...)
|
||||
}
|
||||
|
||||
// Capabilities returns the capabilities parses the Add and Drop capability
|
||||
|
|
|
@ -9,6 +9,7 @@ import (
|
|||
"runtime"
|
||||
"strings"
|
||||
|
||||
"github.com/containers/common/internal/attributedstring"
|
||||
nettypes "github.com/containers/common/libnetwork/types"
|
||||
"github.com/containers/common/pkg/apparmor"
|
||||
"github.com/containers/common/pkg/cgroupv2"
|
||||
|
@ -204,8 +205,8 @@ func defaultConfig() (*Config, error) {
|
|||
Devices: []string{},
|
||||
EnableKeyring: true,
|
||||
EnableLabeling: selinuxEnabled(),
|
||||
Env: []string{
|
||||
"PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin",
|
||||
Env: attributedstring.Slice{
|
||||
Values: []string{"PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"},
|
||||
},
|
||||
EnvHost: false,
|
||||
HTTPProxy: true,
|
||||
|
@ -214,7 +215,7 @@ func defaultConfig() (*Config, error) {
|
|||
InitPath: "",
|
||||
LogDriver: defaultLogDriver(),
|
||||
LogSizeMax: DefaultLogSizeMax,
|
||||
Mounts: []string{},
|
||||
Mounts: attributedstring.Slice{},
|
||||
NetNS: "private",
|
||||
NoHosts: false,
|
||||
PidNS: "private",
|
||||
|
@ -224,7 +225,7 @@ func defaultConfig() (*Config, error) {
|
|||
UTSNS: "private",
|
||||
Umask: "0022",
|
||||
UserNSSize: DefaultUserNSSize, // Deprecated
|
||||
Volumes: []string{},
|
||||
Volumes: attributedstring.Slice{},
|
||||
},
|
||||
Network: NetworkConfig{
|
||||
DefaultNetwork: "podman",
|
||||
|
@ -509,12 +510,12 @@ func (c *Config) Sysctls() []string {
|
|||
|
||||
// Volumes returns the default set of volumes that should be mounted in containers.
|
||||
func (c *Config) Volumes() []string {
|
||||
return c.Containers.Volumes
|
||||
return c.Containers.Volumes.Get()
|
||||
}
|
||||
|
||||
// Mounts returns the default set of mounts that should be mounted in containers.
|
||||
func (c *Config) Mounts() []string {
|
||||
return c.Containers.Mounts
|
||||
return c.Containers.Mounts.Get()
|
||||
}
|
||||
|
||||
// Devices returns the default additional devices for containers.
|
||||
|
@ -539,7 +540,7 @@ func (c *Config) DNSOptions() []string {
|
|||
|
||||
// Env returns the default additional environment variables to add to containers.
|
||||
func (c *Config) Env() []string {
|
||||
return c.Containers.Env
|
||||
return c.Containers.Env.Values
|
||||
}
|
||||
|
||||
// IPCNS returns the default IPC Namespace configuration to run containers with.
|
||||
|
|
|
@ -139,7 +139,7 @@ github.com/containernetworking/cni/pkg/version
|
|||
# github.com/containernetworking/plugins v1.3.0
|
||||
## explicit; go 1.20
|
||||
github.com/containernetworking/plugins/pkg/ns
|
||||
# github.com/containers/buildah v1.32.1-0.20231016164031-ade05159a485
|
||||
# github.com/containers/buildah v1.32.1-0.20231024182922-ea815fea26a9
|
||||
## explicit; go 1.18
|
||||
github.com/containers/buildah
|
||||
github.com/containers/buildah/bind
|
||||
|
@ -167,8 +167,9 @@ github.com/containers/buildah/pkg/sshagent
|
|||
github.com/containers/buildah/pkg/util
|
||||
github.com/containers/buildah/pkg/volumes
|
||||
github.com/containers/buildah/util
|
||||
# github.com/containers/common v0.56.1-0.20231023143107-8d0bd259cb7c
|
||||
# github.com/containers/common v0.56.1-0.20231024140609-79773286b53a
|
||||
## explicit; go 1.18
|
||||
github.com/containers/common/internal/attributedstring
|
||||
github.com/containers/common/libimage
|
||||
github.com/containers/common/libimage/define
|
||||
github.com/containers/common/libimage/filter
|
||||
|
|
Loading…
Reference in New Issue