Vendor Buildah v1.8.3

Vendor in Buildah v1.8.3

Signed-off-by: TomSweeneyRedHat <tsweeney@redhat.com>
This commit is contained in:
TomSweeneyRedHat
2019-06-04 12:58:16 -04:00
parent 7b0d6fcf0e
commit 14ec550ec3
14 changed files with 238 additions and 177 deletions

View File

@ -211,7 +211,7 @@ func copyBetweenHostAndContainer(runtime *libpod.Runtime, src string, dest strin
}
func getUser(mountPoint string, userspec string) (specs.User, error) {
uid, gid, err := chrootuser.GetUser(mountPoint, userspec)
uid, gid, _, err := chrootuser.GetUser(mountPoint, userspec)
u := specs.User{
UID: uid,
GID: gid,

View File

@ -93,7 +93,7 @@ k8s.io/api kubernetes-1.10.13-beta.0 https://github.com/kubernetes/api
k8s.io/apimachinery kubernetes-1.10.13-beta.0 https://github.com/kubernetes/apimachinery
k8s.io/client-go kubernetes-1.10.13-beta.0 https://github.com/kubernetes/client-go
github.com/mrunalp/fileutils 7d4729fb36185a7c1719923406c9d40e54fb93c7
github.com/containers/buildah bcc5e51a948c1847fab1c932f1a343696a96cafd
github.com/containers/buildah v1.8.3
github.com/varlink/go 0f1d566d194b9d6d48e0d47c5e4d822628919066
# TODO: Gotty has not been updated since 2012. Can we find replacement?
github.com/Nvveen/Gotty cd527374f1e5bff4938207604a14f2e38a9cf512

View File

@ -14,6 +14,7 @@ import (
"github.com/containers/buildah/pkg/chrootuser"
"github.com/containers/buildah/util"
"github.com/containers/storage/pkg/archive"
"github.com/containers/storage/pkg/fileutils"
"github.com/containers/storage/pkg/idtools"
"github.com/containers/storage/pkg/system"
"github.com/opencontainers/runtime-spec/specs-go"
@ -89,7 +90,10 @@ func addURL(destination, srcurl string, owner idtools.IDPair, hasher io.Writer)
// filesystem, optionally extracting contents of local files that look like
// non-empty archives.
func (b *Builder) Add(destination string, extract bool, options AddAndCopyOptions, source ...string) error {
excludes := dockerIgnoreHelper(options.Excludes, options.ContextDir)
excludes, err := dockerIgnoreMatcher(options.Excludes, options.ContextDir)
if err != nil {
return err
}
mountPoint, err := b.Mount(b.MountLabel)
if err != nil {
return err
@ -100,7 +104,7 @@ func (b *Builder) Add(destination string, extract bool, options AddAndCopyOption
}
}()
// Find out which user (and group) the destination should belong to.
user, err := b.user(mountPoint, options.Chown)
user, _, err := b.user(mountPoint, options.Chown)
if err != nil {
return err
}
@ -153,12 +157,12 @@ func (b *Builder) Add(destination string, extract bool, options AddAndCopyOption
}
// user returns the user (and group) information which the destination should belong to.
func (b *Builder) user(mountPoint string, userspec string) (specs.User, error) {
func (b *Builder) user(mountPoint string, userspec string) (specs.User, string, error) {
if userspec == "" {
userspec = b.User()
}
uid, gid, err := chrootuser.GetUser(mountPoint, userspec)
uid, gid, homeDir, err := chrootuser.GetUser(mountPoint, userspec)
u := specs.User{
UID: uid,
GID: gid,
@ -175,45 +179,48 @@ func (b *Builder) user(mountPoint string, userspec string) (specs.User, error) {
}
}
return u, err
return u, homeDir, err
}
// dockerIgnore struct keep info from .dockerignore
type dockerIgnore struct {
ExcludePath string
IsExcluded bool
}
// dockerIgnoreHelper returns the lines from .dockerignore file without the comments
// and reverses the order
func dockerIgnoreHelper(lines []string, contextDir string) []dockerIgnore {
var excludes []dockerIgnore
// the last match of a file in the .dockerignmatches determines whether it is included or excluded
// reverse the order
for i := len(lines) - 1; i >= 0; i-- {
exclude := lines[i]
// ignore the comment in .dockerignore
if strings.HasPrefix(exclude, "#") || len(exclude) == 0 {
// dockerIgnoreMatcher returns a matcher based on the contents of the .dockerignore file under contextDir
func dockerIgnoreMatcher(lines []string, contextDir string) (*fileutils.PatternMatcher, error) {
// if there's no context dir, there's no .dockerignore file to consult
if contextDir == "" {
return nil, nil
}
patterns := []string{".dockerignore"}
for _, ignoreSpec := range lines {
ignoreSpec = strings.TrimSpace(ignoreSpec)
// ignore comments passed back from .dockerignore
if ignoreSpec == "" || ignoreSpec[0] == '#' {
continue
}
excludeFlag := true
if strings.HasPrefix(exclude, "!") {
exclude = strings.TrimPrefix(exclude, "!")
excludeFlag = false
// if the spec starts with '!' it means the pattern
// should be included. make a note so that we can move
// it to the front of the updated pattern
includeFlag := ""
if strings.HasPrefix(ignoreSpec, "!") {
includeFlag = "!"
ignoreSpec = ignoreSpec[1:]
}
excludes = append(excludes, dockerIgnore{ExcludePath: filepath.Join(contextDir, exclude), IsExcluded: excludeFlag})
if ignoreSpec == "" {
continue
}
patterns = append(patterns, includeFlag+filepath.Join(contextDir, ignoreSpec))
}
if len(excludes) != 0 {
excludes = append(excludes, dockerIgnore{ExcludePath: filepath.Join(contextDir, ".dockerignore"), IsExcluded: true})
// if there are no patterns, save time by not constructing the object
if len(patterns) == 0 {
return nil, nil
}
return excludes
// return a matcher object
matcher, err := fileutils.NewPatternMatcher(patterns)
if err != nil {
return nil, errors.Wrapf(err, "error creating file matcher using patterns %v", patterns)
}
return matcher, nil
}
func addHelper(excludes []dockerIgnore, extract bool, dest string, destfi os.FileInfo, hostOwner idtools.IDPair, options AddAndCopyOptions, copyFileWithTar, copyWithTar, untarPath func(src, dest string) error, source ...string) error {
dirsInDockerignore, err := getDirsInDockerignore(options.ContextDir, excludes)
if err != nil {
return errors.Wrapf(err, "error checking directories in .dockerignore")
}
func addHelper(excludes *fileutils.PatternMatcher, extract bool, dest string, destfi os.FileInfo, hostOwner idtools.IDPair, options AddAndCopyOptions, copyFileWithTar, copyWithTar, untarPath func(src, dest string) error, source ...string) error {
for _, src := range source {
if strings.HasPrefix(src, "http://") || strings.HasPrefix(src, "https://") {
// We assume that source is a file, and we're copying
@ -242,7 +249,7 @@ func addHelper(excludes []dockerIgnore, extract bool, dest string, destfi os.Fil
if len(glob) == 0 {
return errors.Wrapf(syscall.ENOENT, "no files found matching %q", src)
}
outer:
for _, gsrc := range glob {
esrc, err := filepath.EvalSymlinks(gsrc)
if err != nil {
@ -261,7 +268,7 @@ func addHelper(excludes []dockerIgnore, extract bool, dest string, destfi os.Fil
return errors.Wrapf(err, "error creating directory %q", dest)
}
logrus.Debugf("copying %q to %q", esrc+string(os.PathSeparator)+"*", dest+string(os.PathSeparator)+"*")
if len(excludes) == 0 {
if excludes == nil {
if err = copyWithTar(esrc, dest); err != nil {
return errors.Wrapf(err, "error copying %q to %q", esrc, dest)
}
@ -271,23 +278,12 @@ func addHelper(excludes []dockerIgnore, extract bool, dest string, destfi os.Fil
if err != nil {
return err
}
for _, exclude := range excludes {
match, err := filepath.Match(filepath.Clean(exclude.ExcludePath), filepath.Clean(path))
if err != nil {
return err
}
prefix, exist := dirsInDockerignore[exclude.ExcludePath]
hasPrefix := false
if exist {
hasPrefix = filepath.HasPrefix(path, prefix)
}
if !(match || hasPrefix) {
continue
}
if (hasPrefix && exclude.IsExcluded) || (match && exclude.IsExcluded) {
return nil
}
break
skip, err := excludes.Matches(path)
if err != nil {
return errors.Wrapf(err, "error checking if %s is an excluded path", path)
}
if skip {
return nil
}
// combine the filename with the dest directory
fpath, err := filepath.Rel(esrc, path)
@ -297,8 +293,8 @@ func addHelper(excludes []dockerIgnore, extract bool, dest string, destfi os.Fil
mtime := info.ModTime()
atime := mtime
times := []syscall.Timespec{
{Sec: atime.Unix(), Nsec: atime.UnixNano() % 1000000000},
{Sec: mtime.Unix(), Nsec: mtime.UnixNano() % 1000000000},
syscall.NsecToTimespec(atime.Unix()),
syscall.NsecToTimespec(mtime.Unix()),
}
if info.IsDir() {
return addHelperDirectory(esrc, path, filepath.Join(dest, fpath), info, hostOwner, times)
@ -320,20 +316,6 @@ func addHelper(excludes []dockerIgnore, extract bool, dest string, destfi os.Fil
continue
}
for _, exclude := range excludes {
match, err := filepath.Match(filepath.Clean(exclude.ExcludePath), esrc)
if err != nil {
return err
}
if !match {
continue
}
if exclude.IsExcluded {
continue outer
}
break
}
if !extract || !archive.IsArchivePath(esrc) {
// This source is a file, and either it's not an
// archive, or we don't care whether or not it's an
@ -349,6 +331,7 @@ func addHelper(excludes []dockerIgnore, extract bool, dest string, destfi os.Fil
}
continue
}
// We're extracting an archive into the destination directory.
logrus.Debugf("extracting contents of %q into %q", esrc, dest)
if err = untarPath(esrc, dest); err != nil {
@ -381,7 +364,15 @@ func addHelperSymlink(src, dest string, info os.FileInfo, hostOwner idtools.IDPa
return errors.Wrapf(err, "error reading contents of symbolic link at %q", src)
}
if err = os.Symlink(linkContents, dest); err != nil {
return errors.Wrapf(err, "error creating symbolic link to %q at %q", linkContents, dest)
if !os.IsExist(err) {
return errors.Wrapf(err, "error creating symbolic link to %q at %q", linkContents, dest)
}
if err = os.RemoveAll(dest); err != nil {
return errors.Wrapf(err, "error clearing symbolic link target %q", dest)
}
if err = os.Symlink(linkContents, dest); err != nil {
return errors.Wrapf(err, "error creating symbolic link to %q at %q (second try)", linkContents, dest)
}
}
if err = idtools.SafeLchown(dest, hostOwner.UID, hostOwner.GID); err != nil {
return errors.Wrapf(err, "error setting owner of symbolic link %q to %d:%d", dest, hostOwner.UID, hostOwner.GID)
@ -392,35 +383,3 @@ func addHelperSymlink(src, dest string, info os.FileInfo, hostOwner idtools.IDPa
logrus.Debugf("Symlink(%s, %s)", linkContents, dest)
return nil
}
func getDirsInDockerignore(srcAbsPath string, excludes []dockerIgnore) (map[string]string, error) {
visitedDir := make(map[string]string)
if len(excludes) == 0 {
return visitedDir, nil
}
err := filepath.Walk(srcAbsPath, func(path string, info os.FileInfo, err error) error {
if err != nil {
return err
}
if info.IsDir() {
for _, exclude := range excludes {
match, err := filepath.Match(filepath.Clean(exclude.ExcludePath), filepath.Clean(path))
if err != nil {
return err
}
if !match {
continue
}
if _, exist := visitedDir[exclude.ExcludePath]; exist {
continue
}
visitedDir[exclude.ExcludePath] = path
}
}
return nil
})
if err != nil {
return visitedDir, err
}
return visitedDir, nil
}

View File

@ -26,7 +26,7 @@ const (
Package = "buildah"
// Version for the Package. Bump version in contrib/rpm/buildah.spec
// too.
Version = "1.9.0-dev"
Version = "1.8.3"
// The value we use to identify what type of information, currently a
// serialized Builder structure, we are using as per-container state.
// This should only be changed when we make incompatible changes to

View File

@ -84,9 +84,18 @@ type runUsingChrootExecSubprocOptions struct {
// RunUsingChroot runs a chrooted process, using some of the settings from the
// passed-in spec, and using the specified bundlePath to hold temporary files,
// directories, and mountpoints.
func RunUsingChroot(spec *specs.Spec, bundlePath string, stdin io.Reader, stdout, stderr io.Writer) (err error) {
func RunUsingChroot(spec *specs.Spec, bundlePath, homeDir string, stdin io.Reader, stdout, stderr io.Writer) (err error) {
var confwg sync.WaitGroup
var homeFound bool
for _, env := range spec.Process.Env {
if strings.HasPrefix(env, "HOME=") {
homeFound = true
break
}
}
if !homeFound {
spec.Process.Env = append(spec.Process.Env, fmt.Sprintf("HOME=%s", homeDir))
}
runtime.LockOSThread()
defer runtime.UnlockOSThread()

View File

@ -3,7 +3,6 @@ package buildah
import (
"context"
"encoding/json"
"os"
"runtime"
"strings"
"time"
@ -269,21 +268,11 @@ func (b *Builder) Env() []string {
// built using an image built from this container.
func (b *Builder) SetEnv(k string, v string) {
reset := func(s *[]string) {
getenv := func(name string) string {
for i := range *s {
val := strings.SplitN((*s)[i], "=", 2)
if len(val) == 2 && val[0] == name {
return val[1]
}
}
return name
}
n := []string{}
for i := range *s {
if !strings.HasPrefix((*s)[i], k+"=") {
n = append(n, (*s)[i])
}
v = os.Expand(v, getenv)
}
n = append(n, k+"="+v)
*s = n

View File

@ -487,6 +487,7 @@ func (s *StageExecutor) Copy(excludes []string, copies ...imagebuilder.Copy) err
// Check the file and see if part of it is a symlink.
// Convert it to the target if so. To be ultrasafe
// do the same for the mountpoint.
hadFinalPathSeparator := len(copy.Dest) > 0 && copy.Dest[len(copy.Dest)-1] == os.PathSeparator
secureMountPoint, err := securejoin.SecureJoin("", s.mountPoint)
finalPath, err := securejoin.SecureJoin(secureMountPoint, copy.Dest)
if err != nil {
@ -496,6 +497,11 @@ func (s *StageExecutor) Copy(excludes []string, copies ...imagebuilder.Copy) err
return errors.Wrapf(err, "error resolving copy destination %s", copy.Dest)
}
copy.Dest = strings.TrimPrefix(finalPath, secureMountPoint)
if len(copy.Dest) == 0 || copy.Dest[len(copy.Dest)-1] != os.PathSeparator {
if hadFinalPathSeparator {
copy.Dest += string(os.PathSeparator)
}
}
if copy.Download {
logrus.Debugf("ADD %#v, %#v", excludes, copy)
@ -507,29 +513,32 @@ func (s *StageExecutor) Copy(excludes []string, copies ...imagebuilder.Copy) err
}
sources := []string{}
for _, src := range copy.Src {
contextDir := s.executor.contextDir
copyExcludes := excludes
if strings.HasPrefix(src, "http://") || strings.HasPrefix(src, "https://") {
sources = append(sources, src)
} else if len(copy.From) > 0 {
if other, ok := s.executor.stages[copy.From]; ok && other.index < s.index {
sources = append(sources, filepath.Join(other.mountPoint, src))
contextDir = other.mountPoint
} else if builder, ok := s.executor.containerMap[copy.From]; ok {
sources = append(sources, filepath.Join(builder.MountPoint, src))
contextDir = builder.MountPoint
} else {
return errors.Errorf("the stage %q has not been built", copy.From)
}
} else {
sources = append(sources, filepath.Join(s.executor.contextDir, src))
copyExcludes = append(s.executor.excludes, excludes...)
}
options := buildah.AddAndCopyOptions{
Chown: copy.Chown,
ContextDir: contextDir,
Excludes: copyExcludes,
}
if err := s.builder.Add(copy.Dest, copy.Download, options, sources...); err != nil {
return err
}
}
options := buildah.AddAndCopyOptions{
Chown: copy.Chown,
ContextDir: s.executor.contextDir,
Excludes: s.executor.excludes,
}
if err := s.builder.Add(copy.Dest, copy.Download, options, sources...); err != nil {
return err
}
}
return nil
@ -590,7 +599,11 @@ func (s *StageExecutor) Run(run imagebuilder.Run, config docker.Config) error {
args := run.Args
if run.Shell {
args = append([]string{"/bin/sh", "-c"}, args...)
if len(config.Shell) > 0 && s.builder.Format == buildah.Dockerv2ImageManifest {
args = append(config.Shell, args...)
} else {
args = append([]string{"/bin/sh", "-c"}, args...)
}
}
if err := s.volumeCacheSave(); err != nil {
return err

View File

@ -17,7 +17,7 @@ import (
)
func cloneToDirectory(url, dir string) error {
if !strings.HasPrefix(url, "git://") {
if !strings.HasPrefix(url, "git://") && !strings.HasSuffix(url, ".git") {
url = "git://" + url
}
logrus.Debugf("cloning %q to %q", url, dir)
@ -72,7 +72,7 @@ func TempDirForURL(dir, prefix, url string) (name string, subdir string, err err
if err != nil {
return "", "", errors.Wrapf(err, "error creating temporary directory for %q", url)
}
if strings.HasPrefix(url, "git://") {
if strings.HasPrefix(url, "git://") || strings.HasSuffix(url, ".git") {
err = cloneToDirectory(url, name)
if err != nil {
if err2 := os.Remove(name); err2 != nil {

View File

@ -18,7 +18,7 @@ var (
// it will use the /etc/passwd and /etc/group files inside of the rootdir
// to return this information.
// userspec format [user | user:group | uid | uid:gid | user:gid | uid:group ]
func GetUser(rootdir, userspec string) (uint32, uint32, error) {
func GetUser(rootdir, userspec string) (uint32, uint32, string, error) {
var gid64 uint64
var gerr error = user.UnknownGroupError("error looking up group")
@ -26,7 +26,7 @@ func GetUser(rootdir, userspec string) (uint32, uint32, error) {
userspec = spec[0]
groupspec := ""
if userspec == "" {
return 0, 0, nil
return 0, 0, "/", nil
}
if len(spec) > 1 {
groupspec = spec[1]
@ -65,15 +65,21 @@ func GetUser(rootdir, userspec string) (uint32, uint32, error) {
}
}
if uerr == nil && gerr == nil {
return uint32(uid64), uint32(gid64), nil
homedir, err := lookupHomedirInContainer(rootdir, uid64)
if err != nil {
homedir = "/"
}
err := errors.Wrapf(uerr, "error determining run uid")
if uerr == nil && gerr == nil {
return uint32(uid64), uint32(gid64), homedir, nil
}
err = errors.Wrapf(uerr, "error determining run uid")
if uerr == nil {
err = errors.Wrapf(gerr, "error determining run gid")
}
return 0, 0, err
return 0, 0, homedir, err
}
// GetGroup returns the gid by looking it up in the /etc/group file

View File

@ -25,3 +25,7 @@ func lookupAdditionalGroupsForUIDInContainer(rootdir string, userid uint64) (gid
func lookupUIDInContainer(rootdir string, uid uint64) (string, uint64, error) {
return "", 0, errors.New("UID lookup not supported")
}
func lookupHomedirInContainer(rootdir string, uid uint64) (string, error) {
return "", errors.New("Home directory lookup not supported")
}

View File

@ -84,6 +84,7 @@ type lookupPasswdEntry struct {
name string
uid uint64
gid uint64
home string
}
type lookupGroupEntry struct {
name string
@ -135,6 +136,7 @@ func parseNextPasswd(rc *bufio.Reader) *lookupPasswdEntry {
name: fields[0],
uid: uid,
gid: gid,
home: fields[5],
}
}
@ -291,3 +293,29 @@ func lookupUIDInContainer(rootdir string, uid uint64) (string, uint64, error) {
return "", 0, user.UnknownUserError(fmt.Sprintf("error looking up uid %q", uid))
}
func lookupHomedirInContainer(rootdir string, uid uint64) (string, error) {
cmd, f, err := openChrootedFile(rootdir, "/etc/passwd")
if err != nil {
return "", err
}
defer func() {
_ = cmd.Wait()
}()
rc := bufio.NewReader(f)
defer f.Close()
lookupUser.Lock()
defer lookupUser.Unlock()
pwd := parseNextPasswd(rc)
for pwd != nil {
if pwd.uid != uid {
pwd = parseNextPasswd(rc)
continue
}
return pwd.home, nil
}
return "", user.UnknownUserError(fmt.Sprintf("error looking up uid %q for homedir", uid))
}

View File

@ -117,7 +117,12 @@ func getMounts(filePath string) []string {
}
var mounts []string
for scanner.Scan() {
mounts = append(mounts, scanner.Text())
if strings.HasPrefix(strings.TrimSpace(scanner.Text()), "/") {
mounts = append(mounts, scanner.Text())
} else {
logrus.Debugf("skipping unrecognized mount in %v: %q",
filePath, scanner.Text())
}
}
return mounts
}
@ -190,58 +195,79 @@ func addSecretsFromMountsFile(filePath, mountLabel, containerWorkingDir, mountPr
var mounts []rspec.Mount
defaultMountsPaths := getMounts(filePath)
for _, path := range defaultMountsPaths {
hostDir, ctrDir, err := getMountsMap(path)
hostDirOrFile, ctrDirOrFile, err := getMountsMap(path)
if err != nil {
return nil, err
}
// skip if the hostDir path doesn't exist
if _, err = os.Stat(hostDir); err != nil {
// skip if the hostDirOrFile path doesn't exist
fileInfo, err := os.Stat(hostDirOrFile)
if err != nil {
if os.IsNotExist(err) {
logrus.Warnf("Path %q from %q doesn't exist, skipping", hostDir, filePath)
logrus.Warnf("Path %q from %q doesn't exist, skipping", hostDirOrFile, filePath)
continue
}
return nil, errors.Wrapf(err, "failed to stat %q", hostDir)
return nil, errors.Wrapf(err, "failed to stat %q", hostDirOrFile)
}
ctrDirOnHost := filepath.Join(containerWorkingDir, ctrDir)
ctrDirOrFileOnHost := filepath.Join(containerWorkingDir, ctrDirOrFile)
// In the event of a restart, don't want to copy secrets over again as they already would exist in ctrDirOnHost
_, err = os.Stat(ctrDirOnHost)
// In the event of a restart, don't want to copy secrets over again as they already would exist in ctrDirOrFileOnHost
_, err = os.Stat(ctrDirOrFileOnHost)
if os.IsNotExist(err) {
if err = os.MkdirAll(ctrDirOnHost, 0755); err != nil {
return nil, errors.Wrapf(err, "making container directory %q failed", ctrDirOnHost)
}
hostDir, err = resolveSymbolicLink(hostDir)
hostDirOrFile, err = resolveSymbolicLink(hostDirOrFile)
if err != nil {
return nil, err
}
data, err := getHostSecretData(hostDir)
if err != nil {
return nil, errors.Wrapf(err, "getting host secret data failed")
}
for _, s := range data {
if err := s.saveTo(ctrDirOnHost); err != nil {
return nil, errors.Wrapf(err, "error saving data to container filesystem on host %q", ctrDirOnHost)
switch mode := fileInfo.Mode(); {
case mode.IsDir():
if err = os.MkdirAll(ctrDirOrFileOnHost, 0755); err != nil {
return nil, errors.Wrapf(err, "making container directory %q failed", ctrDirOrFileOnHost)
}
data, err := getHostSecretData(hostDirOrFile)
if err != nil {
return nil, errors.Wrapf(err, "getting host secret data failed")
}
for _, s := range data {
if err := s.saveTo(ctrDirOrFileOnHost); err != nil {
return nil, errors.Wrapf(err, "error saving data to container filesystem on host %q", ctrDirOrFileOnHost)
}
}
case mode.IsRegular():
data, err := readFile("", hostDirOrFile)
if err != nil {
return nil, errors.Wrapf(err, "error reading file %q", hostDirOrFile)
}
for _, s := range data {
if err := os.MkdirAll(filepath.Dir(ctrDirOrFileOnHost), 0700); err != nil {
return nil, err
}
if err := ioutil.WriteFile(ctrDirOrFileOnHost, s.data, 0700); err != nil {
return nil, errors.Wrapf(err, "error saving data to container filesystem on host %q", ctrDirOrFileOnHost)
}
}
default:
return nil, errors.Errorf("unsupported file type for: %q", hostDirOrFile)
}
err = label.Relabel(ctrDirOnHost, mountLabel, false)
err = label.Relabel(ctrDirOrFileOnHost, mountLabel, false)
if err != nil {
return nil, errors.Wrap(err, "error applying correct labels")
}
if uid != 0 || gid != 0 {
if err := rchown(ctrDirOnHost, uid, gid); err != nil {
if err := rchown(ctrDirOrFileOnHost, uid, gid); err != nil {
return nil, err
}
}
} else if err != nil {
return nil, errors.Wrapf(err, "error getting status of %q", ctrDirOnHost)
return nil, errors.Wrapf(err, "error getting status of %q", ctrDirOrFileOnHost)
}
m := rspec.Mount{
Source: filepath.Join(mountPrefix, ctrDir),
Destination: ctrDir,
Source: filepath.Join(mountPrefix, ctrDirOrFile),
Destination: ctrDirOrFile,
Type: "bind",
Options: []string{"bind", "rprivate"},
}

View File

@ -64,6 +64,7 @@ func (c *Cmd) Start() error {
if os.Geteuid() != 0 {
c.Env = append(c.Env, "_CONTAINERS_USERNS_CONFIGURED=done")
c.Env = append(c.Env, fmt.Sprintf("_CONTAINERS_ROOTLESS_UID=%d", os.Geteuid()))
c.Env = append(c.Env, fmt.Sprintf("_CONTAINERS_ROOTLESS_GID=%d", os.Getegid()))
}
// Create the pipe for reading the child's PID.
@ -183,6 +184,7 @@ func (c *Cmd) Start() error {
for _, m := range c.GidMappings {
fmt.Fprintf(g, "%d %d %d\n", m.ContainerID, m.HostID, m.Size)
}
gidmapSet := false
// Set the GID map.
if c.UseNewgidmap {
cmd := exec.Command("newgidmap", append([]string{pidString}, strings.Fields(strings.Replace(g.String(), "\n", " ", -1))...)...)
@ -190,11 +192,16 @@ func (c *Cmd) Start() error {
cmd.Stdout = g
cmd.Stderr = g
err := cmd.Run()
if err != nil {
if err == nil {
gidmapSet = true
} else {
fmt.Fprintf(continueWrite, "error running newgidmap: %v: %s", err, g.String())
return errors.Wrapf(err, "error running newgidmap: %s", g.String())
fmt.Fprintf(continueWrite, "falling back to single mapping\n")
g.Reset()
g.Write([]byte(fmt.Sprintf("0 %d 1\n", os.Getegid())))
}
} else {
}
if !gidmapSet {
gidmap, err := os.OpenFile(fmt.Sprintf("/proc/%s/gid_map", pidString), os.O_TRUNC|os.O_WRONLY, 0)
if err != nil {
fmt.Fprintf(continueWrite, "error opening /proc/%s/gid_map: %v", pidString, err)
@ -214,6 +221,7 @@ func (c *Cmd) Start() error {
for _, m := range c.UidMappings {
fmt.Fprintf(u, "%d %d %d\n", m.ContainerID, m.HostID, m.Size)
}
uidmapSet := false
// Set the GID map.
if c.UseNewuidmap {
cmd := exec.Command("newuidmap", append([]string{pidString}, strings.Fields(strings.Replace(u.String(), "\n", " ", -1))...)...)
@ -221,11 +229,16 @@ func (c *Cmd) Start() error {
cmd.Stdout = u
cmd.Stderr = u
err := cmd.Run()
if err != nil {
if err == nil {
uidmapSet = true
} else {
fmt.Fprintf(continueWrite, "error running newuidmap: %v: %s", err, u.String())
return errors.Wrapf(err, "error running newuidmap: %s", u.String())
fmt.Fprintf(continueWrite, "falling back to single mapping\n")
u.Reset()
u.Write([]byte(fmt.Sprintf("0 %d 1\n", os.Geteuid())))
}
} else {
}
if !uidmapSet {
uidmap, err := os.OpenFile(fmt.Sprintf("/proc/%s/uid_map", pidString), os.O_TRUNC|os.O_WRONLY, 0)
if err != nil {
fmt.Fprintf(continueWrite, "error opening /proc/%s/uid_map: %v", pidString, err)
@ -354,7 +367,9 @@ func MaybeReexecUsingUserNamespace(evenForRoot bool) {
// range in /etc/subuid and /etc/subgid file is a starting host
// ID and a range size.
uidmap, gidmap, err = GetSubIDMappings(me.Username, me.Username)
bailOnError(err, "error reading allowed ID mappings")
if err != nil {
logrus.Warnf("error reading allowed ID mappings: %v", err)
}
if len(uidmap) == 0 {
logrus.Warnf("Found no UID ranges set aside for user %q in /etc/subuid.", me.Username)
}

View File

@ -131,7 +131,8 @@ func (b *Builder) Run(command []string, options RunOptions) error {
return err
}
if err := b.configureUIDGID(g, mountPoint, options); err != nil {
homeDir, err := b.configureUIDGID(g, mountPoint, options)
if err != nil {
return err
}
@ -210,7 +211,7 @@ func (b *Builder) Run(command []string, options RunOptions) error {
}
err = b.runUsingRuntimeSubproc(isolation, options, configureNetwork, configureNetworks, moreCreateArgs, spec, mountPoint, path, Package+"-"+filepath.Base(path))
case IsolationChroot:
err = chroot.RunUsingChroot(spec, path, options.Stdin, options.Stdout, options.Stderr)
err = chroot.RunUsingChroot(spec, path, homeDir, options.Stdin, options.Stdout, options.Stderr)
case IsolationOCIRootless:
moreCreateArgs := []string{"--no-new-keyring"}
if options.NoPivot {
@ -1454,7 +1455,18 @@ func setupNamespaces(g *generate.Generator, namespaceOptions NamespaceOptions, i
}
if configureNetwork {
for name, val := range util.DefaultNetworkSysctl {
g.AddLinuxSysctl(name, val)
// Check that the sysctl we are adding is actually supported
// by the kernel
p := filepath.Join("/proc/sys", strings.Replace(name, ".", "/", -1))
_, err := os.Stat(p)
if err != nil && !os.IsNotExist(err) {
return false, nil, false, errors.Wrapf(err, "cannot stat %s", p)
}
if err == nil {
g.AddLinuxSysctl(name, val)
} else {
logrus.Warnf("ignoring sysctl %s since %s doesn't exist", name, p)
}
}
}
return configureNetwork, configureNetworks, configureUTS, nil
@ -1775,14 +1787,14 @@ func getDNSIP(dnsServers []string) (dns []net.IP, err error) {
return dns, nil
}
func (b *Builder) configureUIDGID(g *generate.Generator, mountPoint string, options RunOptions) error {
func (b *Builder) configureUIDGID(g *generate.Generator, mountPoint string, options RunOptions) (string, error) {
// Set the user UID/GID/supplemental group list/capabilities lists.
user, err := b.user(mountPoint, options.User)
user, homeDir, err := b.user(mountPoint, options.User)
if err != nil {
return err
return "", err
}
if err := setupCapabilities(g, b.AddCapabilities, b.DropCapabilities, options.AddCapabilities, options.DropCapabilities); err != nil {
return err
return "", err
}
g.SetProcessUID(user.UID)
g.SetProcessGID(user.GID)
@ -1797,7 +1809,7 @@ func (b *Builder) configureUIDGID(g *generate.Generator, mountPoint string, opti
g.Config.Process.Capabilities.Bounding = bounding
}
return nil
return homeDir, nil
}
func (b *Builder) configureEnvironment(g *generate.Generator, options RunOptions) {