Validate that we're in rootful podman
As this is a footgun that multiple people have run into. Signed-off-by: Colin Walters <walters@verbum.org>
This commit is contained in:
parent
402c3955b9
commit
214fcda30e
2 changed files with 59 additions and 1 deletions
38
bib/internal/podmanutil/podmanutils.go
Normal file
38
bib/internal/podmanutil/podmanutils.go
Normal file
|
|
@ -0,0 +1,38 @@
|
||||||
|
package podmanutil
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bufio"
|
||||||
|
"bytes"
|
||||||
|
"errors"
|
||||||
|
"fmt"
|
||||||
|
"io/fs"
|
||||||
|
"os"
|
||||||
|
)
|
||||||
|
|
||||||
|
// envPath is written by podman
|
||||||
|
const envPath = "/run/.containerenv"
|
||||||
|
|
||||||
|
// rootlessKey is set when we are rootless
|
||||||
|
const rootlessKey = "rootless=1"
|
||||||
|
|
||||||
|
// IsRootless detects if we are running rootless in podman;
|
||||||
|
// other situations (e.g. docker) will successfuly return false.
|
||||||
|
func IsRootless() (bool, error) {
|
||||||
|
buf, err := os.ReadFile(envPath)
|
||||||
|
if err != nil {
|
||||||
|
if errors.Is(err, fs.ErrNotExist) {
|
||||||
|
return false, nil
|
||||||
|
}
|
||||||
|
return false, err
|
||||||
|
}
|
||||||
|
scanner := bufio.NewScanner(bytes.NewReader(buf))
|
||||||
|
for scanner.Scan() {
|
||||||
|
if scanner.Text() == rootlessKey {
|
||||||
|
return true, nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if err := scanner.Err(); err != nil {
|
||||||
|
return false, fmt.Errorf("parsing %s: %w", envPath, err)
|
||||||
|
}
|
||||||
|
return false, nil
|
||||||
|
}
|
||||||
|
|
@ -7,7 +7,9 @@ import (
|
||||||
"os/exec"
|
"os/exec"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
|
|
||||||
|
"github.com/osbuild/bootc-image-builder/bib/internal/podmanutil"
|
||||||
"github.com/osbuild/bootc-image-builder/bib/internal/utils"
|
"github.com/osbuild/bootc-image-builder/bib/internal/utils"
|
||||||
|
"golang.org/x/sys/unix"
|
||||||
)
|
)
|
||||||
|
|
||||||
// EnsureEnvironment mutates external filesystem state as necessary
|
// EnsureEnvironment mutates external filesystem state as necessary
|
||||||
|
|
@ -74,5 +76,23 @@ func EnsureEnvironment() error {
|
||||||
// Validate checks that the environment is supported (e.g. caller set up the
|
// Validate checks that the environment is supported (e.g. caller set up the
|
||||||
// container correctly)
|
// container correctly)
|
||||||
func Validate() error {
|
func Validate() error {
|
||||||
|
isRootless, err := podmanutil.IsRootless()
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("checking rootless: %w", err)
|
||||||
|
}
|
||||||
|
if isRootless {
|
||||||
|
return fmt.Errorf("this command must be run in rootful (not rootless) podman")
|
||||||
|
}
|
||||||
|
|
||||||
|
// Having /sys be writable is an easy to check proxy for privileges; more effective
|
||||||
|
// is really looking for CAP_SYS_ADMIN, but that involves more Go libraries.
|
||||||
|
var stvfsbuf unix.Statfs_t
|
||||||
|
if err := unix.Statfs("/sys", &stvfsbuf); err != nil {
|
||||||
|
return fmt.Errorf("failed to stat /sys: %w", err)
|
||||||
|
}
|
||||||
|
if (stvfsbuf.Flags & unix.ST_RDONLY) > 0 {
|
||||||
|
return fmt.Errorf("this command requires a privileged container")
|
||||||
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue