Skip to content

Commit

Permalink
testutils: newNS() works in a rootless user namespace
Browse files Browse the repository at this point in the history
When running in a user namespace created by an unprivileged user the
owner of /var/run will be reported as the unknown user (as defined in
/proc/sys/kernel/overflowuid) so any access to the directory will
fail.

If the XDG_RUNTIME_DIR environment variable is set, check whether the
current user is also the owner of /var/run.  If the owner is different
than the current user, use the $XDG_RUNTIME_DIR/netns directory.

Signed-off-by: Giuseppe Scrivano <gscrivan@redhat.com>
  • Loading branch information
giuseppe committed Oct 19, 2019
1 parent 411d060 commit d0431b7
Show file tree
Hide file tree
Showing 2 changed files with 25 additions and 2 deletions.
23 changes: 21 additions & 2 deletions pkg/testutils/netns_linux.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,17 +22,36 @@ import (
"runtime"
"strings"
"sync"
"syscall"

"github.com/containernetworking/plugins/pkg/ns"
"golang.org/x/sys/unix"
)

const nsRunDir = "/var/run/netns"
func getNsRunDir() string {
xdgRuntimeDir := os.Getenv("XDG_RUNTIME_DIR")

/// If XDG_RUNTIME_DIR is set, check if the current user owns /var/run. If
// the owner is different, we are most likely running in a user namespace.
// In that case use $XDG_RUNTIME_DIR/netns as runtime dir.
if xdgRuntimeDir != "" {
if s, err := os.Stat("/var/run"); err == nil {
st, ok := s.Sys().(*syscall.Stat_t)
if ok && int(st.Uid) != os.Geteuid() {
return path.Join(xdgRuntimeDir, "netns")
}
}
}

return "/var/run/netns"
}

// Creates a new persistent (bind-mounted) network namespace and returns an object
// representing that namespace, without switching to it.
func NewNS() (ns.NetNS, error) {

nsRunDir := getNsRunDir()

b := make([]byte, 16)
_, err := rand.Reader.Read(b)
if err != nil {
Expand Down Expand Up @@ -135,7 +154,7 @@ func NewNS() (ns.NetNS, error) {
func UnmountNS(ns ns.NetNS) error {
nsPath := ns.Path()
// Only unmount if it's been bind-mounted (don't touch namespaces in /proc...)
if strings.HasPrefix(nsPath, nsRunDir) {
if strings.HasPrefix(nsPath, getNsRunDir()) {
if err := unix.Unmount(nsPath, 0); err != nil {
return fmt.Errorf("failed to unmount NS: at %s: %v", nsPath, err)
}
Expand Down
4 changes: 4 additions & 0 deletions test_linux.sh
Original file line number Diff line number Diff line change
Expand Up @@ -57,3 +57,7 @@ if [ -n "${vetRes}" ]; then
echo -e "govet checking failed:\n${vetRes}"
exit 255
fi

# Run the pkg/ns tests as non root user
mkdir /tmp/cni-rootless
(export XDG_RUNTIME_DIR=/tmp/cni-rootless; cd pkg/ns/; unshare -rmn go test)

0 comments on commit d0431b7

Please sign in to comment.