github.com/schwarzm/garden-linux@v0.0.0-20150507151835-33bca2147c47/old/integration/wshd/main_test.go (about)

     1  // +build linux
     2  
     3  package wshd_test
     4  
     5  import (
     6  	"fmt"
     7  	"io"
     8  	"io/ioutil"
     9  	"net"
    10  	"os"
    11  	"os/exec"
    12  	"path"
    13  	"path/filepath"
    14  	"syscall"
    15  
    16  	. "github.com/onsi/ginkgo"
    17  	. "github.com/onsi/gomega"
    18  	. "github.com/onsi/gomega/gbytes"
    19  	. "github.com/onsi/gomega/gexec"
    20  )
    21  
    22  var _ = Describe("Running wshd", func() {
    23  	wshd := "../../linux_backend/skeleton/bin/wshd"
    24  
    25  	wsh := "../../linux_backend/skeleton/bin/wsh"
    26  
    27  	shmTest, err := Build("github.com/cloudfoundry-incubator/garden-linux/old/integration/wshd/shm_test")
    28  	if err != nil {
    29  		panic(err)
    30  	}
    31  
    32  	var socketPath string
    33  	var containerPath string
    34  
    35  	var binDir string
    36  	var libDir string
    37  	var runDir string
    38  	var mntDir string
    39  
    40  	var userNs string
    41  
    42  	var beforeWshd func()
    43  
    44  	BeforeEach(func() {
    45  		var err error
    46  
    47  		containerPath, err = ioutil.TempDir(os.TempDir(), "wshd-test-container")
    48  		Expect(err).ToNot(HaveOccurred())
    49  
    50  		userNs = "disabled"
    51  		beforeWshd = func() {}
    52  
    53  		binDir = path.Join(containerPath, "bin")
    54  		libDir = path.Join(containerPath, "lib")
    55  		runDir = path.Join(containerPath, "run")
    56  		mntDir = path.Join(containerPath, "mnt")
    57  
    58  		os.Mkdir(binDir, 0755)
    59  		os.Mkdir(libDir, 0755)
    60  		os.Mkdir(runDir, 0755)
    61  
    62  		err = copyFile(wshd, path.Join(binDir, "wshd"))
    63  		Expect(err).ToNot(HaveOccurred())
    64  
    65  		hookPath, err := Build("github.com/cloudfoundry-incubator/garden-linux/old/integration/wshd/fake_hook")
    66  		Expect(err).ToNot(HaveOccurred())
    67  		err = copyFile(hookPath, path.Join(libDir, "hook"))
    68  		Expect(err).ToNot(HaveOccurred())
    69  
    70  		ioutil.WriteFile(path.Join(libDir, "hook-parent-before-clone.sh"), []byte(`#!/bin/sh
    71  
    72  set -o nounset
    73  set -o errexit
    74  
    75  cd $(dirname $0)/../
    76  
    77  cp bin/wshd mnt/sbin/wshd
    78  chmod 700 mnt/sbin/wshd
    79  `), 0755)
    80  
    81  		ioutil.WriteFile(path.Join(libDir, "hook-parent-after-clone.sh"), []byte(`#!/bin/sh
    82  set -o nounset
    83  set -o errexit
    84  
    85  cd $(dirname $0)/../
    86  
    87  cat > /proc/$PID/uid_map 2> /dev/null <<EOF || true
    88  0 0 1
    89  10000 10000 1
    90  EOF
    91  
    92  cat > /proc/$PID/gid_map 2> /dev/null <<EOF || true
    93  0 0 1
    94  10000 10000 1
    95  EOF
    96  
    97  echo $PID > ./run/wshd.pid
    98  `), 0755)
    99  
   100  		ioutil.WriteFile(path.Join(libDir, "hook-child-after-pivot.sh"), []byte(`#!/bin/sh
   101  
   102  set -o nounset
   103  set -o errexit
   104  
   105  cd $(dirname $0)/../
   106  
   107  mkdir -p /proc
   108  mount -t proc none /proc
   109  
   110  adduser -u 10000 -g 10000 -s /bin/sh -D vcap
   111  `), 0755)
   112  
   113  		ioutil.WriteFile(path.Join(libDir, "set-up-root.sh"), []byte(`#!/bin/bash
   114  
   115  set -o nounset
   116  set -o errexit
   117  
   118  rootfs_path=$1
   119  
   120  function overlay_directory_in_rootfs() {
   121    # Skip if exists
   122    if [ ! -d tmp/rootfs/$1 ]
   123    then
   124      if [ -d mnt/$1 ]
   125      then
   126        cp -r mnt/$1 tmp/rootfs/
   127      else
   128        mkdir -p tmp/rootfs/$1
   129      fi
   130    fi
   131  
   132    mount -n --bind tmp/rootfs/$1 mnt/$1
   133    mount -n --bind -o remount,$2 tmp/rootfs/$1 mnt/$1
   134  }
   135  
   136  function setup_fs() {
   137    mkdir -p tmp/rootfs mnt
   138  
   139    mkdir -p $rootfs_path/proc
   140  
   141    mount -n --bind $rootfs_path mnt
   142    mount -n --bind -o remount,ro $rootfs_path mnt
   143  
   144    overlay_directory_in_rootfs /dev rw
   145    overlay_directory_in_rootfs /etc rw
   146    overlay_directory_in_rootfs /home rw
   147    overlay_directory_in_rootfs /sbin rw
   148    overlay_directory_in_rootfs /var rw
   149  
   150    mkdir -p tmp/rootfs/tmp
   151  
   152    # test asserts that wshd changes this to 0777
   153    chmod 755 tmp/rootfs/tmp
   154  
   155    overlay_directory_in_rootfs /tmp rw
   156  }
   157  
   158  setup_fs
   159  `), 0755)
   160  
   161  		setUpRoot := exec.Command(path.Join(libDir, "set-up-root.sh"), os.Getenv("GARDEN_TEST_ROOTFS"))
   162  		setUpRoot.Dir = containerPath
   163  
   164  		setUpRootSession, err := Start(setUpRoot, GinkgoWriter, GinkgoWriter)
   165  		Expect(err).ToNot(HaveOccurred())
   166  		Eventually(setUpRootSession, 5.0).Should(Exit(0))
   167  	})
   168  
   169  	JustBeforeEach(func() {
   170  
   171  		beforeWshd()
   172  
   173  		wshdCommand := exec.Command(
   174  			wshd,
   175  			"--run", runDir,
   176  			"--lib", libDir,
   177  			"--root", mntDir,
   178  			"--title", "test wshd",
   179  			"--userns", userNs,
   180  		)
   181  
   182  		socketPath = path.Join(runDir, "wshd.sock")
   183  
   184  		wshdSession, err := Start(wshdCommand, GinkgoWriter, GinkgoWriter)
   185  		Expect(err).ToNot(HaveOccurred())
   186  
   187  		Eventually(wshdSession, 30).Should(Exit(0))
   188  
   189  		Eventually(ErrorDialingUnix(socketPath)).ShouldNot(HaveOccurred())
   190  	})
   191  
   192  	AfterEach(func() {
   193  		wshdPidfile, err := os.Open(path.Join(containerPath, "run", "wshd.pid"))
   194  		Expect(err).ToNot(HaveOccurred())
   195  
   196  		var wshdPid int
   197  		_, err = fmt.Fscanf(wshdPidfile, "%d", &wshdPid)
   198  		Expect(err).ToNot(HaveOccurred())
   199  
   200  		proc, err := os.FindProcess(wshdPid)
   201  		Expect(err).ToNot(HaveOccurred())
   202  
   203  		err = proc.Kill()
   204  		Expect(err).ToNot(HaveOccurred())
   205  
   206  		for _, submount := range []string{"dev", "etc", "home", "sbin", "var", "tmp"} {
   207  			mountPoint := path.Join(containerPath, "mnt", submount)
   208  
   209  			err := syscall.Unmount(mountPoint, 0)
   210  			Expect(err).ToNot(HaveOccurred())
   211  		}
   212  
   213  		err = syscall.Unmount(path.Join(containerPath, "mnt"), 0)
   214  		Expect(err).ToNot(HaveOccurred())
   215  
   216  		Eventually(func() error {
   217  			return os.RemoveAll(containerPath)
   218  		}, 10).ShouldNot(HaveOccurred())
   219  	})
   220  
   221  	It("starts the daemon as a session leader with process isolation and the given title", func() {
   222  		ps := exec.Command(wsh, "--socket", socketPath, "/bin/ps", "-o", "pid,comm")
   223  
   224  		psSession, err := Start(ps, GinkgoWriter, GinkgoWriter)
   225  		Expect(err).ToNot(HaveOccurred())
   226  
   227  		Eventually(psSession).Should(Say(`\s+1\s+wshd`))
   228  		Eventually(psSession).Should(Exit(0))
   229  	})
   230  
   231  	It("starts the daemon with mount space isolation", func() {
   232  		mkdir := exec.Command(wsh, "--socket", socketPath, "/bin/mkdir", "/home/vcap/lawn")
   233  		mkdirSession, err := Start(mkdir, GinkgoWriter, GinkgoWriter)
   234  		Expect(err).ToNot(HaveOccurred())
   235  		Eventually(mkdirSession).Should(Exit(0))
   236  
   237  		mkdir = exec.Command(wsh, "--socket", socketPath, "/bin/mkdir", "/home/vcap/gnome")
   238  		mkdirSession, err = Start(mkdir, GinkgoWriter, GinkgoWriter)
   239  		Expect(err).ToNot(HaveOccurred())
   240  		Eventually(mkdirSession).Should(Exit(0))
   241  
   242  		mount := exec.Command(wsh, "--socket", socketPath, "/bin/mount", "--bind", "/home/vcap/lawn", "/home/vcap/gnome")
   243  		mountSession, err := Start(mount, GinkgoWriter, GinkgoWriter)
   244  		Expect(err).ToNot(HaveOccurred())
   245  		Eventually(mountSession).Should(Exit(0))
   246  
   247  		cat := exec.Command("/bin/cat", "/proc/mounts")
   248  		catSession, err := Start(cat, GinkgoWriter, GinkgoWriter)
   249  		Expect(err).ToNot(HaveOccurred())
   250  		Eventually(catSession).Should(Exit(0))
   251  		Expect(catSession).ToNot(Say("gnome"))
   252  	})
   253  
   254  	It("places the daemon in each cgroup subsystem", func() {
   255  		cat := exec.Command(wsh, "--socket", socketPath, "sh", "-c", "cat /proc/$$/cgroup")
   256  		catSession, err := Start(cat, GinkgoWriter, GinkgoWriter)
   257  		Expect(err).ToNot(HaveOccurred())
   258  		Eventually(catSession).Should(Exit(0))
   259  		Expect(catSession.Out.Contents()).To(MatchRegexp(`\bcpu\b`))
   260  		Expect(catSession.Out.Contents()).To(MatchRegexp(`\bcpuacct\b`))
   261  		Expect(catSession.Out.Contents()).To(MatchRegexp(`\bcpuset\b`))
   262  		Expect(catSession.Out.Contents()).To(MatchRegexp(`\bdevices\b`))
   263  		Expect(catSession.Out.Contents()).To(MatchRegexp(`\bmemory\b`))
   264  	})
   265  
   266  	It("starts the daemon with network namespace isolation", func() {
   267  		ifconfig := exec.Command(wsh, "--socket", socketPath, "/sbin/ifconfig", "lo:0", "1.2.3.4", "up")
   268  		ifconfigSession, err := Start(ifconfig, GinkgoWriter, GinkgoWriter)
   269  		Expect(err).ToNot(HaveOccurred())
   270  		Eventually(ifconfigSession).Should(Exit(0))
   271  
   272  		localIfconfig := exec.Command("ifconfig")
   273  		localIfconfigSession, err := Start(localIfconfig, GinkgoWriter, GinkgoWriter)
   274  		Expect(err).ToNot(HaveOccurred())
   275  		Eventually(localIfconfigSession).Should(Exit(0))
   276  		Expect(localIfconfigSession).ToNot(Say("lo:0"))
   277  	})
   278  
   279  	It("starts the daemon with a new IPC namespace", func() {
   280  		err = copyFile(shmTest, path.Join(mntDir, "sbin", "shmtest"))
   281  		Expect(err).ToNot(HaveOccurred())
   282  
   283  		localSHM := exec.Command(shmTest)
   284  		createLocal, err := Start(
   285  			localSHM,
   286  			GinkgoWriter,
   287  			GinkgoWriter,
   288  		)
   289  		Expect(err).ToNot(HaveOccurred())
   290  
   291  		Eventually(createLocal).Should(Say("ok"))
   292  
   293  		createRemote, err := Start(
   294  			exec.Command(wsh, "--socket", socketPath, "/sbin/shmtest", "create"),
   295  			GinkgoWriter,
   296  			GinkgoWriter,
   297  		)
   298  		Expect(err).ToNot(HaveOccurred())
   299  		Eventually(createRemote).Should(Say("ok"))
   300  
   301  		localSHM.Process.Signal(syscall.SIGUSR2)
   302  
   303  		Eventually(createLocal).Should(Exit(0))
   304  	})
   305  
   306  	It("starts the daemon with a new UTS namespace", func() {
   307  		hostname := exec.Command(wsh, "--socket", socketPath, "/bin/hostname", "newhostname")
   308  		hostnameSession, err := Start(hostname, GinkgoWriter, GinkgoWriter)
   309  		Expect(err).ToNot(HaveOccurred())
   310  		Eventually(hostnameSession).Should(Exit(0))
   311  
   312  		localHostname := exec.Command("hostname")
   313  		localHostnameSession, err := Start(localHostname, GinkgoWriter, GinkgoWriter)
   314  		Eventually(localHostnameSession).Should(Exit(0))
   315  		Expect(localHostnameSession).ToNot(Say("newhostname"))
   316  	})
   317  
   318  	It("does not leak any shared memory to the child", func() {
   319  		ipcs, err := Start(
   320  			exec.Command(wsh, "--socket", socketPath, "ipcs"),
   321  			GinkgoWriter,
   322  			GinkgoWriter,
   323  		)
   324  		Expect(err).ToNot(HaveOccurred())
   325  		Eventually(ipcs).Should(Exit(0))
   326  		Expect(ipcs).ToNot(Say("deadbeef"))
   327  	})
   328  
   329  	It("ensures /tmp is world-writable", func() {
   330  		ls, err := Start(
   331  			exec.Command(wsh, "--socket", socketPath, "ls", "-al", "/tmp"),
   332  			GinkgoWriter,
   333  			GinkgoWriter,
   334  		)
   335  		Expect(err).ToNot(HaveOccurred())
   336  		Eventually(ls).Should(Exit(0))
   337  
   338  		Expect(ls).To(Say(`drwxrwxrwt`))
   339  	})
   340  
   341  	It("unmounts /tmp/garden-host* in the child", func() {
   342  		cat := exec.Command(wsh, "--socket", socketPath, "/bin/cat", "/proc/mounts")
   343  
   344  		catSession, err := Start(cat, GinkgoWriter, GinkgoWriter)
   345  		Expect(err).ToNot(HaveOccurred())
   346  
   347  		Eventually(catSession).Should(Exit(0))
   348  		Expect(catSession).ToNot(Say(" /tmp/garden-host"))
   349  	})
   350  
   351  	Context("when mount points on the host are deleted", func() {
   352  		BeforeEach(func() {
   353  			tmpdir, err := ioutil.TempDir("", "wshd-bogus-mount")
   354  			Expect(err).ToNot(HaveOccurred())
   355  
   356  			fooDir := filepath.Join(tmpdir, "foo")
   357  			barDir := filepath.Join(tmpdir, "bar")
   358  
   359  			err = os.MkdirAll(fooDir, 0755)
   360  			Expect(err).ToNot(HaveOccurred())
   361  
   362  			err = os.MkdirAll(barDir, 0755)
   363  			Expect(err).ToNot(HaveOccurred())
   364  
   365  			mount := exec.Command("mount", "--bind", fooDir, barDir)
   366  			mountSession, err := Start(mount, GinkgoWriter, GinkgoWriter)
   367  			Expect(err).ToNot(HaveOccurred())
   368  			Eventually(mountSession).Should(Exit(0))
   369  
   370  			err = os.RemoveAll(fooDir)
   371  			Expect(err).ToNot(HaveOccurred())
   372  
   373  			cat := exec.Command("/bin/cat", "/proc/mounts")
   374  			catSession, err := Start(cat, GinkgoWriter, GinkgoWriter)
   375  			Expect(err).ToNot(HaveOccurred())
   376  			Eventually(catSession).Should(Say("(deleted)"))
   377  			Eventually(catSession).Should(Exit(0))
   378  		})
   379  
   380  		It("unmounts the un-mangled mount point name", func() {
   381  			cat := exec.Command(wsh, "--socket", socketPath, "/bin/cat", "/proc/mounts")
   382  
   383  			catSession, err := Start(cat, GinkgoWriter, GinkgoWriter)
   384  			Expect(err).ToNot(HaveOccurred())
   385  
   386  			Eventually(catSession).Should(Exit(0))
   387  			Expect(catSession).ToNot(Say("(deleted)"))
   388  		})
   389  	})
   390  
   391  	Context("when running a command in a working dir", func() {
   392  		It("executes with setuid and setgid", func() {
   393  			pwd := exec.Command(wsh, "--socket", socketPath, "--dir", "/usr", "pwd")
   394  
   395  			pwdSession, err := Start(pwd, GinkgoWriter, GinkgoWriter)
   396  			Expect(err).ToNot(HaveOccurred())
   397  
   398  			Eventually(pwdSession).Should(Say("^/usr\n"))
   399  			Eventually(pwdSession).Should(Exit(0))
   400  		})
   401  	})
   402  
   403  	Context("when running without specifying a --pidfile", func() {
   404  		It("should exit cleanly with the correct status", func() {
   405  			pwd := exec.Command(wsh, "--socket", socketPath, "--dir", "/usr", "/bin/sh", "-c", "exit 3")
   406  
   407  			stdout := NewBuffer()
   408  			stderr := NewBuffer()
   409  			pwdSession, err := Start(pwd, io.MultiWriter(stdout, GinkgoWriter), io.MultiWriter(stderr, GinkgoWriter))
   410  			Expect(err).ToNot(HaveOccurred())
   411  
   412  			Eventually(pwdSession).Should(Exit(3))
   413  			Expect(string(stderr.Contents())).To(Equal(""))
   414  			Expect(string(stdout.Contents())).To(Equal(""))
   415  		})
   416  	})
   417  
   418  	It("allows children to receive SIGCHLD when grandchildren die", func() {
   419  		trap := exec.Command(wsh, "--socket", socketPath, "--dir", "/usr", "/bin/sh", "-c", "trap 'echo caught sigchld' SIGCHLD; $(ls / >/dev/null 2>&1); sleep 5;")
   420  
   421  		trapSession, err := Start(trap, GinkgoWriter, GinkgoWriter)
   422  		Expect(err).ToNot(HaveOccurred())
   423  
   424  		Eventually(trapSession).Should(Say("caught sigchld"))
   425  	})
   426  
   427  	Context("when running a command as a user", func() {
   428  		It("executes with setuid and setgid", func() {
   429  			sh := exec.Command(wsh, "--socket", socketPath, "--user", "vcap", "/bin/sh", "-c", "id -u; id -g")
   430  
   431  			shSession, err := Start(sh, GinkgoWriter, GinkgoWriter)
   432  			Expect(err).ToNot(HaveOccurred())
   433  
   434  			Eventually(shSession).Should(Say("^10000\n"))
   435  			Eventually(shSession).Should(Say("^10000\n"))
   436  			Eventually(shSession).Should(Exit(0))
   437  		})
   438  
   439  		It("sets $HOME, $USER, and $PATH", func() {
   440  			sh := exec.Command(wsh, "--socket", socketPath, "--user", "vcap", "/bin/sh", "-c", "env | sort")
   441  
   442  			shSession, err := Start(sh, GinkgoWriter, GinkgoWriter)
   443  			Expect(err).ToNot(HaveOccurred())
   444  
   445  			Eventually(shSession).Should(Say("HOME=/home/vcap\n"))
   446  			Eventually(shSession).Should(Say("PATH=/usr/local/bin:/usr/bin:/bin\n"))
   447  			Eventually(shSession).Should(Say("USER=vcap\n"))
   448  			Eventually(shSession).Should(Exit(0))
   449  		})
   450  
   451  		It("executes in their home directory", func() {
   452  			pwd := exec.Command(wsh, "--socket", socketPath, "--user", "vcap", "/bin/pwd")
   453  
   454  			pwdSession, err := Start(pwd, GinkgoWriter, GinkgoWriter)
   455  			Expect(err).ToNot(HaveOccurred())
   456  
   457  			Eventually(pwdSession).Should(Say("/home/vcap\n"))
   458  			Eventually(pwdSession).Should(Exit(0))
   459  		})
   460  
   461  		It("sets the specified environment variables", func() {
   462  			pwd := exec.Command(wsh,
   463  				"--socket", socketPath,
   464  				"--user", "vcap",
   465  				"--env", "VAR1=VALUE1",
   466  				"--env", "VAR2=VALUE2",
   467  				"sh", "-c", "env | sort",
   468  			)
   469  
   470  			session, err := Start(pwd, GinkgoWriter, GinkgoWriter)
   471  			Expect(err).ToNot(HaveOccurred())
   472  
   473  			Eventually(session).Should(Say("VAR1=VALUE1\n"))
   474  			Eventually(session).Should(Say("VAR2=VALUE2\n"))
   475  		})
   476  
   477  		It("searches a sanitized path not including sbin for the executable", func() {
   478  			ls := exec.Command(wsh,
   479  				"--socket", socketPath,
   480  				"--user", "vcap",
   481  				"ls",
   482  			)
   483  
   484  			session, err := Start(ls, GinkgoWriter, GinkgoWriter)
   485  			Expect(err).ToNot(HaveOccurred())
   486  
   487  			Eventually(session).Should(Exit(0))
   488  
   489  			onlyInSbin := exec.Command(wsh,
   490  				"--socket", socketPath,
   491  				"--user", "vcap",
   492  				"ifconfig",
   493  			)
   494  
   495  			session, err = Start(onlyInSbin, GinkgoWriter, GinkgoWriter)
   496  			Expect(err).ToNot(HaveOccurred())
   497  
   498  			Eventually(session).Should(Exit(255))
   499  		})
   500  
   501  		It("saves the child's pid in a pidfile and cleans the pidfile up after the process exits", func() {
   502  			tmp, err := ioutil.TempDir("", "wshdchildpid")
   503  			Expect(err).ToNot(HaveOccurred())
   504  
   505  			pwd := exec.Command(wsh,
   506  				"--socket", socketPath,
   507  				"--user", "vcap",
   508  				"--pidfile", filepath.Join(tmp, "foo.pid"),
   509  				"sh", "-c", "echo $$; read",
   510  			)
   511  
   512  			in, err := pwd.StdinPipe()
   513  			Expect(err).ToNot(HaveOccurred())
   514  
   515  			session, err := Start(pwd, GinkgoWriter, GinkgoWriter)
   516  			Expect(err).ToNot(HaveOccurred())
   517  
   518  			Eventually(func() error {
   519  				_, err := os.Stat(filepath.Join(tmp, "foo.pid"))
   520  				return err
   521  			}).Should(BeNil())
   522  
   523  			read, err := ioutil.ReadFile(filepath.Join(tmp, "foo.pid"))
   524  			Expect(err).ToNot(HaveOccurred())
   525  
   526  			in.Write([]byte("\n"))
   527  
   528  			Eventually(session).Should(Exit())
   529  			Expect(string(read)).To(Equal(string(session.Out.Contents())))
   530  
   531  			_, err = os.Stat(filepath.Join(tmp, "foo.pid"))
   532  			Expect(err).To(HaveOccurred(), "pid file was not cleaned up")
   533  		})
   534  	})
   535  
   536  	Context("when running a command as root", func() {
   537  		It("executes with setuid and setgid", func() {
   538  			sh := exec.Command(wsh, "--socket", socketPath, "--user", "root", "/bin/sh", "-c", "id -u; id -g")
   539  
   540  			shSession, err := Start(sh, GinkgoWriter, GinkgoWriter)
   541  			Expect(err).ToNot(HaveOccurred())
   542  
   543  			Eventually(shSession).Should(Say("^0\n"))
   544  			Eventually(shSession).Should(Say("^0\n"))
   545  			Eventually(shSession).Should(Exit(0))
   546  		})
   547  
   548  		It("sets $HOME, $USER, and a $PATH with sbin dirs", func() {
   549  			sh := exec.Command(wsh, "--socket", socketPath, "--user", "root", "/bin/sh", "-c", "env | sort")
   550  
   551  			shSession, err := Start(sh, GinkgoWriter, GinkgoWriter)
   552  			Expect(err).ToNot(HaveOccurred())
   553  
   554  			Eventually(shSession).Should(Say("HOME=/root\n"))
   555  			Eventually(shSession).Should(Say("PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin\n"))
   556  			Eventually(shSession).Should(Say("USER=root\n"))
   557  			Eventually(shSession).Should(Exit(0))
   558  		})
   559  
   560  		It("searches a sanitized path for the executable containing sbin directories", func() {
   561  			onlyInSbin := exec.Command(wsh,
   562  				"--socket", socketPath,
   563  				"--user", "root",
   564  				"ifconfig",
   565  			)
   566  
   567  			session, err := Start(onlyInSbin, GinkgoWriter, GinkgoWriter)
   568  			Expect(err).ToNot(HaveOccurred())
   569  
   570  			Eventually(session).Should(Exit(0))
   571  		})
   572  
   573  		It("executes in their home directory", func() {
   574  			pwd := exec.Command(wsh, "--socket", socketPath, "--user", "root", "/bin/pwd")
   575  
   576  			pwdSession, err := Start(pwd, GinkgoWriter, GinkgoWriter)
   577  			Expect(err).ToNot(HaveOccurred())
   578  
   579  			Eventually(pwdSession).Should(Say("/root\n"))
   580  			Eventually(pwdSession).Should(Exit(0))
   581  		})
   582  	})
   583  
   584  	Context("when piping stdin", func() {
   585  		It("terminates when the input stream terminates", func() {
   586  			sh := exec.Command(wsh, "--socket", socketPath, "/bin/sh")
   587  
   588  			stdin, err := sh.StdinPipe()
   589  			Expect(err).ToNot(HaveOccurred())
   590  
   591  			shSession, err := Start(sh, GinkgoWriter, GinkgoWriter)
   592  			Expect(err).ToNot(HaveOccurred())
   593  
   594  			stdin.Write([]byte("echo hello"))
   595  			stdin.Close()
   596  
   597  			Eventually(shSession).Should(Say("hello\n"))
   598  			Eventually(shSession).Should(Exit(0))
   599  		})
   600  	})
   601  
   602  	Context("setting rlimits", func() {
   603  		shouldSetRlimit := func(env []string, limitQueryCmd, expectedValue string) {
   604  			ulimit := exec.Command(wsh, "--socket", socketPath, "--user", "root", "/bin/sh", "-c", limitQueryCmd)
   605  			ulimit.Env = env
   606  
   607  			ulimitSession, err := Start(ulimit, GinkgoWriter, GinkgoWriter)
   608  			Expect(err).ToNot(HaveOccurred())
   609  
   610  			Eventually(ulimitSession).Should(Say(expectedValue))
   611  			Eventually(ulimitSession).Should(Exit(0))
   612  		}
   613  
   614  		var (
   615  			rlimitResource               int      // the resource being limited, e.g. RLIMIT_CORE
   616  			limit                        string   // the string suffix of the resource being limited, e.g. "CORE"
   617  			limitValue                   uint64   // a (non-default) limit for the resource, e.g. 4096
   618  			overrideEnv                  []string // environment specifying a (non-default) limit to wshd, e.g. ["RLIMIT_CORE=4096"]
   619  			limitQueryCmd                string   // a command used to query a limit inside a container, e.g. "ulimit -c"
   620  			expectedDefaultQueryResponse string   // the expected query response for the default limit, e.g. "0"
   621  			expectedQueryResponse        string   // the expected query response for the non-default limit, e.g. "8"
   622  
   623  			originalRlimit *syscall.Rlimit
   624  		)
   625  
   626  		JustBeforeEach(func() {
   627  			overrideEnv = []string{fmt.Sprintf("RLIMIT_%s=%d", limit, limitValue)}
   628  		})
   629  
   630  		BeforeEach(func() {
   631  			// Ensure the resource limit being tested is set to a low value.
   632  			// beforeWshd is called just before wshd is launched.
   633  			beforeWshd = func() {
   634  				originalRlimit = getAndReduceRlimit(rlimitResource, limitValue/2)
   635  			}
   636  		})
   637  
   638  		AfterEach(func() {
   639  			Expect(syscall.Setrlimit(rlimitResource, originalRlimit)).To(Succeed())
   640  		})
   641  
   642  		Describe("AS", func() {
   643  			BeforeEach(func() {
   644  				rlimitResource = RLIMIT_AS
   645  				limit = "AS"
   646  				limitValue = 2147483648 * 2
   647  
   648  				limitQueryCmd = "ulimit -v"
   649  				expectedDefaultQueryResponse = "unlimited"
   650  				expectedQueryResponse = "4194304"
   651  			})
   652  
   653  			Context("when user namespacing is disabled", func() {
   654  				BeforeEach(func() {
   655  					userNs = "disabled"
   656  				})
   657  				It("defaults the rlimit when the environment variable is not set", func() {
   658  					shouldSetRlimit([]string{}, limitQueryCmd, expectedDefaultQueryResponse)
   659  				})
   660  				It("overrides the rlimit when the environment variable is set", func() {
   661  					shouldSetRlimit(overrideEnv, limitQueryCmd, expectedQueryResponse)
   662  				})
   663  			})
   664  
   665  			Context("when user namespacing is enabled", func() {
   666  				BeforeEach(func() {
   667  					userNs = "enabled"
   668  				})
   669  				It("defaults the rlimit when the environment variable is not set", func() {
   670  					shouldSetRlimit([]string{}, limitQueryCmd, expectedDefaultQueryResponse)
   671  				})
   672  				It("overrides the rlimit when the environment variable is set", func() {
   673  					shouldSetRlimit(overrideEnv, limitQueryCmd, expectedQueryResponse)
   674  				})
   675  			})
   676  		})
   677  
   678  		Describe("CORE", func() {
   679  			BeforeEach(func() {
   680  				rlimitResource = RLIMIT_CORE
   681  				limit = "CORE"
   682  				limitValue = 4096
   683  
   684  				limitQueryCmd = "ulimit -c"
   685  				expectedDefaultQueryResponse = "0"
   686  				expectedQueryResponse = "8"
   687  			})
   688  
   689  			Context("when user namespacing is disabled", func() {
   690  				BeforeEach(func() {
   691  					userNs = "disabled"
   692  				})
   693  				It("defaults the rlimit when the environment variable is not set", func() {
   694  					shouldSetRlimit([]string{}, limitQueryCmd, expectedDefaultQueryResponse)
   695  				})
   696  				It("overrides the rlimit when the environment variable is set", func() {
   697  					shouldSetRlimit(overrideEnv, limitQueryCmd, expectedQueryResponse)
   698  				})
   699  			})
   700  
   701  			Context("when user namespacing is enabled", func() {
   702  				BeforeEach(func() {
   703  					userNs = "enabled"
   704  				})
   705  				It("defaults the rlimit when the environment variable is not set", func() {
   706  					shouldSetRlimit([]string{}, limitQueryCmd, expectedDefaultQueryResponse)
   707  				})
   708  				It("overrides the rlimit when the environment variable is set", func() {
   709  					shouldSetRlimit(overrideEnv, limitQueryCmd, expectedQueryResponse)
   710  				})
   711  			})
   712  		})
   713  
   714  		Describe("CPU", func() {
   715  			BeforeEach(func() {
   716  				rlimitResource = RLIMIT_CPU
   717  				limit = "CPU"
   718  				limitValue = 3600
   719  
   720  				limitQueryCmd = "ulimit -t"
   721  				expectedDefaultQueryResponse = "unlimited"
   722  				expectedQueryResponse = "3600"
   723  			})
   724  
   725  			Context("when user namespacing is disabled", func() {
   726  				BeforeEach(func() {
   727  					userNs = "disabled"
   728  				})
   729  				It("defaults the rlimit when the environment variable is not set", func() {
   730  					shouldSetRlimit([]string{}, limitQueryCmd, expectedDefaultQueryResponse)
   731  				})
   732  				It("overrides the rlimit when the environment variable is set", func() {
   733  					shouldSetRlimit(overrideEnv, limitQueryCmd, expectedQueryResponse)
   734  				})
   735  			})
   736  
   737  			Context("when user namespacing is enabled", func() {
   738  				BeforeEach(func() {
   739  					userNs = "enabled"
   740  				})
   741  				It("defaults the rlimit when the environment variable is not set", func() {
   742  					shouldSetRlimit([]string{}, limitQueryCmd, expectedDefaultQueryResponse)
   743  				})
   744  				It("overrides the rlimit when the environment variable is set", func() {
   745  					shouldSetRlimit(overrideEnv, limitQueryCmd, expectedQueryResponse)
   746  				})
   747  			})
   748  		})
   749  
   750  		Describe("DATA", func() {
   751  			BeforeEach(func() {
   752  				rlimitResource = RLIMIT_DATA
   753  				limit = "DATA"
   754  				limitValue = 1024 * 1024
   755  
   756  				limitQueryCmd = "ulimit -d"
   757  				expectedDefaultQueryResponse = "unlimited"
   758  				expectedQueryResponse = "1024"
   759  			})
   760  
   761  			Context("when user namespacing is disabled", func() {
   762  				BeforeEach(func() {
   763  					userNs = "disabled"
   764  				})
   765  				It("defaults the rlimit when the environment variable is not set", func() {
   766  					shouldSetRlimit([]string{}, limitQueryCmd, expectedDefaultQueryResponse)
   767  				})
   768  				It("overrides the rlimit when the environment variable is set", func() {
   769  					shouldSetRlimit(overrideEnv, limitQueryCmd, expectedQueryResponse)
   770  				})
   771  			})
   772  
   773  			Context("when user namespacing is enabled", func() {
   774  				BeforeEach(func() {
   775  					userNs = "enabled"
   776  				})
   777  				It("defaults the rlimit when the environment variable is not set", func() {
   778  					shouldSetRlimit([]string{}, limitQueryCmd, expectedDefaultQueryResponse)
   779  				})
   780  				It("overrides the rlimit when the environment variable is set", func() {
   781  					shouldSetRlimit(overrideEnv, limitQueryCmd, expectedQueryResponse)
   782  				})
   783  			})
   784  		})
   785  
   786  		Describe("FSIZE", func() {
   787  			BeforeEach(func() {
   788  				rlimitResource = RLIMIT_FSIZE
   789  				limit = "FSIZE"
   790  				limitValue = 4096 * 1024
   791  
   792  				limitQueryCmd = "ulimit -f"
   793  				expectedDefaultQueryResponse = "unlimited"
   794  				expectedQueryResponse = "8192"
   795  			})
   796  
   797  			Context("when user namespacing is disabled", func() {
   798  				BeforeEach(func() {
   799  					userNs = "disabled"
   800  				})
   801  				It("defaults the rlimit when the environment variable is not set", func() {
   802  					shouldSetRlimit([]string{}, limitQueryCmd, expectedDefaultQueryResponse)
   803  				})
   804  				It("overrides the rlimit when the environment variable is set", func() {
   805  					shouldSetRlimit(overrideEnv, limitQueryCmd, expectedQueryResponse)
   806  				})
   807  			})
   808  
   809  			Context("when user namespacing is enabled", func() {
   810  				BeforeEach(func() {
   811  					userNs = "enabled"
   812  				})
   813  				It("defaults the rlimit when the environment variable is not set", func() {
   814  					shouldSetRlimit([]string{}, limitQueryCmd, expectedDefaultQueryResponse)
   815  				})
   816  				It("overrides the rlimit when the environment variable is set", func() {
   817  					shouldSetRlimit(overrideEnv, limitQueryCmd, expectedQueryResponse)
   818  				})
   819  			})
   820  		})
   821  
   822  		Describe("LOCKS", func() {
   823  			BeforeEach(func() {
   824  				rlimitResource = RLIMIT_LOCKS
   825  				limit = "LOCKS"
   826  				limitValue = 1024
   827  
   828  				limitQueryCmd = "ulimit -w"
   829  				expectedDefaultQueryResponse = "unlimited"
   830  				expectedQueryResponse = "1024"
   831  			})
   832  
   833  			Context("when user namespacing is disabled", func() {
   834  				BeforeEach(func() {
   835  					userNs = "disabled"
   836  				})
   837  				It("defaults the rlimit when the environment variable is not set", func() {
   838  					shouldSetRlimit([]string{}, limitQueryCmd, expectedDefaultQueryResponse)
   839  				})
   840  				It("overrides the rlimit when the environment variable is set", func() {
   841  					shouldSetRlimit(overrideEnv, limitQueryCmd, expectedQueryResponse)
   842  				})
   843  			})
   844  
   845  			Context("when user namespacing is enabled", func() {
   846  				BeforeEach(func() {
   847  					userNs = "enabled"
   848  				})
   849  				It("defaults the rlimit when the environment variable is not set", func() {
   850  					shouldSetRlimit([]string{}, limitQueryCmd, expectedDefaultQueryResponse)
   851  				})
   852  				It("overrides the rlimit when the environment variable is set", func() {
   853  					shouldSetRlimit(overrideEnv, limitQueryCmd, expectedQueryResponse)
   854  				})
   855  			})
   856  		})
   857  
   858  		Describe("MEMLOCK", func() {
   859  			BeforeEach(func() {
   860  				rlimitResource = RLIMIT_MEMLOCK
   861  				limit = "MEMLOCK"
   862  				limitValue = 1024 * 32
   863  
   864  				limitQueryCmd = "ulimit -l"
   865  				expectedDefaultQueryResponse = "64"
   866  				expectedQueryResponse = "32"
   867  			})
   868  
   869  			Context("when user namespacing is disabled", func() {
   870  				BeforeEach(func() {
   871  					userNs = "disabled"
   872  				})
   873  				It("defaults the rlimit when the environment variable is not set", func() {
   874  					shouldSetRlimit([]string{}, limitQueryCmd, expectedDefaultQueryResponse)
   875  				})
   876  				It("overrides the rlimit when the environment variable is set", func() {
   877  					shouldSetRlimit(overrideEnv, limitQueryCmd, expectedQueryResponse)
   878  				})
   879  			})
   880  
   881  			Context("when user namespacing is enabled", func() {
   882  				BeforeEach(func() {
   883  					userNs = "enabled"
   884  				})
   885  				It("defaults the rlimit when the environment variable is not set", func() {
   886  					shouldSetRlimit([]string{}, limitQueryCmd, expectedDefaultQueryResponse)
   887  				})
   888  				It("overrides the rlimit when the environment variable is set", func() {
   889  					shouldSetRlimit(overrideEnv, limitQueryCmd, expectedQueryResponse)
   890  				})
   891  			})
   892  		})
   893  
   894  		Describe("MSGQUEUE", func() {
   895  			BeforeEach(func() {
   896  				rlimitResource = RLIMIT_MSGQUEUE
   897  				limit = "MSGQUEUE"
   898  				limitValue = 1024 * 100
   899  
   900  				limitQueryCmd = "echo RLIMIT_MSGQUEUE not queryable"
   901  				expectedDefaultQueryResponse = "RLIMIT_MSGQUEUE not queryable"
   902  				expectedQueryResponse = "RLIMIT_MSGQUEUE not queryable"
   903  			})
   904  
   905  			Context("when user namespacing is disabled", func() {
   906  				BeforeEach(func() {
   907  					userNs = "disabled"
   908  				})
   909  				It("defaults the rlimit when the environment variable is not set", func() {
   910  					shouldSetRlimit([]string{}, limitQueryCmd, expectedDefaultQueryResponse)
   911  				})
   912  				It("overrides the rlimit when the environment variable is set", func() {
   913  					shouldSetRlimit(overrideEnv, limitQueryCmd, expectedQueryResponse)
   914  				})
   915  			})
   916  
   917  			Context("when user namespacing is enabled", func() {
   918  				BeforeEach(func() {
   919  					userNs = "enabled"
   920  				})
   921  				It("defaults the rlimit when the environment variable is not set", func() {
   922  					shouldSetRlimit([]string{}, limitQueryCmd, expectedDefaultQueryResponse)
   923  				})
   924  				It("overrides the rlimit when the environment variable is set", func() {
   925  					shouldSetRlimit(overrideEnv, limitQueryCmd, expectedQueryResponse)
   926  				})
   927  			})
   928  		})
   929  
   930  		Describe("NICE", func() {
   931  			BeforeEach(func() {
   932  				rlimitResource = RLIMIT_NICE
   933  				limit = "NICE"
   934  				limitValue = 100
   935  
   936  				limitQueryCmd = "ulimit -e"
   937  				expectedDefaultQueryResponse = "0"
   938  				expectedQueryResponse = "100"
   939  			})
   940  
   941  			Context("when user namespacing is disabled", func() {
   942  				BeforeEach(func() {
   943  					userNs = "disabled"
   944  				})
   945  				It("defaults the rlimit when the environment variable is not set", func() {
   946  					shouldSetRlimit([]string{}, limitQueryCmd, expectedDefaultQueryResponse)
   947  				})
   948  				It("overrides the rlimit when the environment variable is set", func() {
   949  					shouldSetRlimit(overrideEnv, limitQueryCmd, expectedQueryResponse)
   950  				})
   951  			})
   952  
   953  			Context("when user namespacing is enabled", func() {
   954  				BeforeEach(func() {
   955  					userNs = "enabled"
   956  				})
   957  				It("defaults the rlimit when the environment variable is not set", func() {
   958  					shouldSetRlimit([]string{}, limitQueryCmd, expectedDefaultQueryResponse)
   959  				})
   960  				It("overrides the rlimit when the environment variable is set", func() {
   961  					shouldSetRlimit(overrideEnv, limitQueryCmd, expectedQueryResponse)
   962  				})
   963  			})
   964  		})
   965  
   966  		Describe("NOFILE", func() {
   967  			BeforeEach(func() {
   968  				rlimitResource = RLIMIT_NOFILE
   969  				limit = "NOFILE"
   970  				limitValue = 4096
   971  
   972  				limitQueryCmd = "ulimit -n"
   973  				expectedDefaultQueryResponse = "1024"
   974  				expectedQueryResponse = "4096"
   975  			})
   976  
   977  			Context("when user namespacing is disabled", func() {
   978  				BeforeEach(func() {
   979  					userNs = "disabled"
   980  				})
   981  				It("defaults the rlimit when the environment variable is not set", func() {
   982  					shouldSetRlimit([]string{}, limitQueryCmd, expectedDefaultQueryResponse)
   983  				})
   984  				It("overrides the rlimit when the environment variable is set", func() {
   985  					shouldSetRlimit(overrideEnv, limitQueryCmd, expectedQueryResponse)
   986  				})
   987  			})
   988  
   989  			Context("when user namespacing is enabled", func() {
   990  				BeforeEach(func() {
   991  					userNs = "enabled"
   992  				})
   993  				It("defaults the rlimit when the environment variable is not set", func() {
   994  					shouldSetRlimit([]string{}, limitQueryCmd, expectedDefaultQueryResponse)
   995  				})
   996  				It("overrides the rlimit when the environment variable is set", func() {
   997  					shouldSetRlimit(overrideEnv, limitQueryCmd, expectedQueryResponse)
   998  				})
   999  			})
  1000  		})
  1001  
  1002  		Describe("NPROC", func() {
  1003  			BeforeEach(func() {
  1004  				rlimitResource = RLIMIT_NPROC
  1005  				limit = "NPROC"
  1006  				limitValue = 4096
  1007  
  1008  				limitQueryCmd = "ulimit -p"
  1009  				expectedDefaultQueryResponse = "1024"
  1010  				expectedQueryResponse = "4096"
  1011  			})
  1012  
  1013  			Context("when user namespacing is disabled", func() {
  1014  				BeforeEach(func() {
  1015  					userNs = "disabled"
  1016  				})
  1017  				It("defaults the rlimit when the environment variable is not set", func() {
  1018  					shouldSetRlimit([]string{}, limitQueryCmd, expectedDefaultQueryResponse)
  1019  				})
  1020  				It("overrides the rlimit when the environment variable is set", func() {
  1021  					shouldSetRlimit(overrideEnv, limitQueryCmd, expectedQueryResponse)
  1022  				})
  1023  			})
  1024  
  1025  			Context("when user namespacing is enabled", func() {
  1026  				BeforeEach(func() {
  1027  					userNs = "enabled"
  1028  				})
  1029  				It("defaults the rlimit when the environment variable is not set", func() {
  1030  					shouldSetRlimit([]string{}, limitQueryCmd, expectedDefaultQueryResponse)
  1031  				})
  1032  				It("overrides the rlimit when the environment variable is set", func() {
  1033  					shouldSetRlimit(overrideEnv, limitQueryCmd, expectedQueryResponse)
  1034  				})
  1035  			})
  1036  		})
  1037  
  1038  		Describe("RSS", func() {
  1039  			BeforeEach(func() {
  1040  				rlimitResource = RLIMIT_RSS
  1041  				limit = "RSS"
  1042  				limitValue = 4096 * 1024
  1043  
  1044  				limitQueryCmd = "ulimit -m"
  1045  				expectedDefaultQueryResponse = "unlimited"
  1046  				expectedQueryResponse = "4096"
  1047  			})
  1048  
  1049  			Context("when user namespacing is disabled", func() {
  1050  				BeforeEach(func() {
  1051  					userNs = "disabled"
  1052  				})
  1053  				It("defaults the rlimit when the environment variable is not set", func() {
  1054  					shouldSetRlimit([]string{}, limitQueryCmd, expectedDefaultQueryResponse)
  1055  				})
  1056  				It("overrides the rlimit when the environment variable is set", func() {
  1057  					shouldSetRlimit(overrideEnv, limitQueryCmd, expectedQueryResponse)
  1058  				})
  1059  			})
  1060  
  1061  			Context("when user namespacing is enabled", func() {
  1062  				BeforeEach(func() {
  1063  					userNs = "enabled"
  1064  				})
  1065  				It("defaults the rlimit when the environment variable is not set", func() {
  1066  					shouldSetRlimit([]string{}, limitQueryCmd, expectedDefaultQueryResponse)
  1067  				})
  1068  				It("overrides the rlimit when the environment variable is set", func() {
  1069  					shouldSetRlimit(overrideEnv, limitQueryCmd, expectedQueryResponse)
  1070  				})
  1071  			})
  1072  		})
  1073  
  1074  		Describe("RTPRIO", func() {
  1075  			BeforeEach(func() {
  1076  				rlimitResource = RLIMIT_RTPRIO
  1077  				limit = "RTPRIO"
  1078  				limitValue = 100
  1079  
  1080  				limitQueryCmd = "ulimit -r"
  1081  				expectedDefaultQueryResponse = "0"
  1082  				expectedQueryResponse = "100"
  1083  			})
  1084  
  1085  			Context("when user namespacing is disabled", func() {
  1086  				BeforeEach(func() {
  1087  					userNs = "disabled"
  1088  				})
  1089  				It("defaults the rlimit when the environment variable is not set", func() {
  1090  					shouldSetRlimit([]string{}, limitQueryCmd, expectedDefaultQueryResponse)
  1091  				})
  1092  				It("overrides the rlimit when the environment variable is set", func() {
  1093  					shouldSetRlimit(overrideEnv, limitQueryCmd, expectedQueryResponse)
  1094  				})
  1095  			})
  1096  
  1097  			Context("when user namespacing is enabled", func() {
  1098  				BeforeEach(func() {
  1099  					userNs = "enabled"
  1100  				})
  1101  				It("defaults the rlimit when the environment variable is not set", func() {
  1102  					shouldSetRlimit([]string{}, limitQueryCmd, expectedDefaultQueryResponse)
  1103  				})
  1104  				It("overrides the rlimit when the environment variable is set", func() {
  1105  					shouldSetRlimit(overrideEnv, limitQueryCmd, expectedQueryResponse)
  1106  				})
  1107  			})
  1108  		})
  1109  
  1110  		Describe("SIGPENDING", func() {
  1111  			BeforeEach(func() {
  1112  				rlimitResource = RLIMIT_SIGPENDING
  1113  				limit = "SIGPENDING"
  1114  				limitValue = 1024 * 4
  1115  
  1116  				limitQueryCmd = "echo RLIMIT_SIGPENDING not queryable"
  1117  				expectedDefaultQueryResponse = "RLIMIT_SIGPENDING not queryable"
  1118  				expectedQueryResponse = "RLIMIT_SIGPENDING not queryable"
  1119  			})
  1120  
  1121  			Context("when user namespacing is disabled", func() {
  1122  				BeforeEach(func() {
  1123  					userNs = "disabled"
  1124  				})
  1125  				It("defaults the rlimit when the environment variable is not set", func() {
  1126  					shouldSetRlimit([]string{}, limitQueryCmd, expectedDefaultQueryResponse)
  1127  				})
  1128  				It("overrides the rlimit when the environment variable is set", func() {
  1129  					shouldSetRlimit(overrideEnv, limitQueryCmd, expectedQueryResponse)
  1130  				})
  1131  			})
  1132  
  1133  			Context("when user namespacing is enabled", func() {
  1134  				BeforeEach(func() {
  1135  					userNs = "enabled"
  1136  				})
  1137  				It("defaults the rlimit when the environment variable is not set", func() {
  1138  					shouldSetRlimit([]string{}, limitQueryCmd, expectedDefaultQueryResponse)
  1139  				})
  1140  				It("overrides the rlimit when the environment variable is set", func() {
  1141  					shouldSetRlimit(overrideEnv, limitQueryCmd, expectedQueryResponse)
  1142  				})
  1143  			})
  1144  		})
  1145  
  1146  		Describe("STACK", func() {
  1147  			BeforeEach(func() {
  1148  				rlimitResource = RLIMIT_STACK
  1149  				limit = "STACK"
  1150  				limitValue = 4 * 1024 * 1024
  1151  
  1152  				limitQueryCmd = "ulimit -s"
  1153  				expectedDefaultQueryResponse = "8192"
  1154  				expectedQueryResponse = "4096"
  1155  			})
  1156  
  1157  			Context("when user namespacing is disabled", func() {
  1158  				BeforeEach(func() {
  1159  					userNs = "disabled"
  1160  				})
  1161  				It("defaults the rlimit when the environment variable is not set", func() {
  1162  					shouldSetRlimit([]string{}, limitQueryCmd, expectedDefaultQueryResponse)
  1163  				})
  1164  				It("overrides the rlimit when the environment variable is set", func() {
  1165  					shouldSetRlimit(overrideEnv, limitQueryCmd, expectedQueryResponse)
  1166  				})
  1167  			})
  1168  
  1169  			Context("when user namespacing is enabled", func() {
  1170  				BeforeEach(func() {
  1171  					userNs = "enabled"
  1172  				})
  1173  				It("defaults the rlimit when the environment variable is not set", func() {
  1174  					shouldSetRlimit([]string{}, limitQueryCmd, expectedDefaultQueryResponse)
  1175  				})
  1176  				It("overrides the rlimit when the environment variable is set", func() {
  1177  					shouldSetRlimit(overrideEnv, limitQueryCmd, expectedQueryResponse)
  1178  				})
  1179  			})
  1180  		})
  1181  	})
  1182  })
  1183  
  1184  func copyFile(src, dst string) error {
  1185  	s, err := os.Open(src)
  1186  	if err != nil {
  1187  		return err
  1188  	}
  1189  
  1190  	defer s.Close()
  1191  
  1192  	d, err := os.OpenFile(dst, os.O_WRONLY|os.O_CREATE, 0755)
  1193  	if err != nil {
  1194  		return err
  1195  	}
  1196  
  1197  	_, err = io.Copy(d, s)
  1198  	if err != nil {
  1199  		d.Close()
  1200  		return err
  1201  	}
  1202  
  1203  	return d.Close()
  1204  }
  1205  
  1206  func ErrorDialingUnix(socketPath string) func() error {
  1207  	return func() error {
  1208  		conn, err := net.Dial("unix", socketPath)
  1209  		if err == nil {
  1210  			conn.Close()
  1211  		}
  1212  
  1213  		return err
  1214  	}
  1215  }
  1216  
  1217  func getAndReduceRlimit(rlimitResource int, limitVal uint64) *syscall.Rlimit {
  1218  	var curLimit syscall.Rlimit
  1219  	Expect(syscall.Getrlimit(rlimitResource, &curLimit)).To(Succeed())
  1220  
  1221  	Expect(syscall.Setrlimit(rlimitResource, &syscall.Rlimit{Cur: limitVal, Max: limitVal})).To(Succeed())
  1222  	return &curLimit
  1223  }