github.com/apptainer/singularity@v3.1.1+incompatible/pkg/util/fs/proc/proc_linux_test.go (about) 1 // Copyright (c) 2018, Sylabs Inc. All rights reserved. 2 // This software is licensed under a 3-clause BSD license. Please consult the 3 // LICENSE.md file distributed with the sources of this project regarding your 4 // rights to use or distribute this software. 5 6 package proc 7 8 import ( 9 "io/ioutil" 10 "os" 11 "os/exec" 12 "syscall" 13 "testing" 14 15 "github.com/sylabs/singularity/internal/pkg/test" 16 ) 17 18 func TestHasFilesystem(t *testing.T) { 19 test.DropPrivilege(t) 20 defer test.ResetPrivilege(t) 21 22 p, err := HasFilesystem("proc") 23 if err != nil { 24 t.Error(err) 25 } 26 if !p { 27 t.Errorf("proc filesystem not present") 28 } 29 30 p, err = HasFilesystem("42fs") 31 if err != nil { 32 t.Error(err) 33 } 34 if p { 35 t.Errorf("42fs should not be in supported filesystems") 36 } 37 } 38 39 var mountInfoData = `22 28 0:21 / /sys rw,nosuid,nodev,noexec,relatime shared:7 - sysfs sysfs rw 40 23 28 0:4 / /proc rw,nosuid,nodev,noexec,relatime shared:13 - proc proc rw 41 24 28 0:6 / /dev rw,nosuid,relatime shared:2 - devtmpfs udev rw,size=8110616k,nr_inodes=2027654,mode=755 42 25 24 0:22 / /dev/pts rw,nosuid,noexec,relatime shared:3 - devpts devpts rw,gid=5,mode=620,ptmxmode=000 43 26 28 0:23 / /run rw,nosuid,noexec,relatime shared:5 - tmpfs tmpfs rw,size=1635872k,mode=755 44 28 0 8:1 / / rw,noatime,nodiratime shared:1 - ext4 /dev/sda1 rw,discard,errors=remount-ro,data=ordered 45 29 22 0:7 / /sys/kernel/security rw,nosuid,nodev,noexec,relatime shared:8 - securityfs securityfs rw 46 30 24 0:25 / /dev/shm rw,nosuid,nodev shared:4 - tmpfs tmpfs rw 47 31 26 0:26 / /run/lock rw,nosuid,nodev,noexec,relatime shared:6 - tmpfs tmpfs rw,size=5120k 48 32 22 0:27 / /sys/fs/cgroup ro,nosuid,nodev,noexec shared:9 - tmpfs tmpfs ro,mode=755 49 33 32 0:28 / /sys/fs/cgroup/unified rw,nosuid,nodev,noexec,relatime shared:10 - cgroup2 cgroup rw,nsdelegate 50 34 32 0:29 / /sys/fs/cgroup/systemd rw,nosuid,nodev,noexec,relatime shared:11 - cgroup cgroup rw,xattr,name=systemd 51 35 22 0:30 / /sys/fs/pstore rw,nosuid,nodev,noexec,relatime shared:12 - pstore pstore rw 52 36 32 0:31 / /sys/fs/cgroup/devices rw,nosuid,nodev,noexec,relatime shared:14 - cgroup cgroup rw,devices 53 37 32 0:32 / /sys/fs/cgroup/rdma rw,nosuid,nodev,noexec,relatime shared:15 - cgroup cgroup rw,rdma 54 38 32 0:33 / /sys/fs/cgroup/cpuset rw,nosuid,nodev,noexec,relatime shared:16 - cgroup cgroup rw,cpuset 55 39 32 0:34 / /sys/fs/cgroup/cpu,cpuacct rw,nosuid,nodev,noexec,relatime shared:17 - cgroup cgroup rw,cpu,cpuacct 56 40 32 0:35 / /sys/fs/cgroup/pids rw,nosuid,nodev,noexec,relatime shared:18 - cgroup cgroup rw,pids 57 41 32 0:36 / /sys/fs/cgroup/hugetlb rw,nosuid,nodev,noexec,relatime shared:19 - cgroup cgroup rw,hugetlb 58 42 32 0:37 / /sys/fs/cgroup/net_cls,net_prio rw,nosuid,nodev,noexec,relatime shared:20 - cgroup cgroup rw,net_cls,net_prio 59 43 32 0:38 / /sys/fs/cgroup/freezer rw,nosuid,nodev,noexec,relatime shared:21 - cgroup cgroup rw,freezer 60 44 32 0:39 / /sys/fs/cgroup/perf_event rw,nosuid,nodev,noexec,relatime shared:22 - cgroup cgroup rw,perf_event 61 45 32 0:40 / /sys/fs/cgroup/memory rw,nosuid,nodev,noexec,relatime shared:23 - cgroup cgroup rw,memory 62 46 32 0:41 / /sys/fs/cgroup/blkio rw,nosuid,nodev,noexec,relatime shared:24 - cgroup cgroup rw,blkio 63 47 23 0:42 / /proc/sys/fs/binfmt_misc rw,relatime shared:25 - autofs systemd-1 rw,fd=36,pgrp=1,timeout=0,minproto=5,maxproto=5,direct,pipe_ino=1423 64 48 24 0:19 / /dev/mqueue rw,relatime shared:26 - mqueue mqueue rw 65 49 24 0:43 / /dev/hugepages rw,relatime shared:27 - hugetlbfs hugetlbfs rw,pagesize=2M 66 50 22 0:8 / /sys/kernel/debug rw,relatime shared:28 - debugfs debugfs rw 67 51 26 0:44 / /run/rpc_pipefs rw,relatime shared:29 - rpc_pipefs sunrpc rw 68 52 22 0:20 / /sys/kernel/config rw,relatime shared:30 - configfs configfs rw 69 53 22 0:45 / /sys/fs/fuse/connections rw,relatime shared:31 - fusectl fusectl rw 70 54 23 0:46 / /proc/fs/nfsd rw,relatime shared:32 - nfsd nfsd rw 71 88 28 253:1 / /home rw,noatime,nodiratime shared:33 - ext4 /dev/mapper/pdc_egggdecf1 rw,errors=remount-ro,stripe=64 72 90 47 0:47 / /proc/sys/fs/binfmt_misc rw,relatime shared:34 - binfmt_misc binfmt_misc rw 73 381 26 0:54 / /run/user/1000 rw,nosuid,nodev,relatime shared:245 - tmpfs tmpfs rw,size=1635868k,mode=700,uid=1000,gid=1000 74 363 381 0:52 / /run/user/1000/gvfs rw,nosuid,nodev,relatime shared:233 - fuse.gvfsd-fuse gvfsd-fuse rw,user_id=1000,group_id=1000` 75 76 func TestParseMountInfo(t *testing.T) { 77 test.DropPrivilege(t) 78 defer test.ResetPrivilege(t) 79 80 if _, err := ParseMountInfo("/proc/self/fakemountinfo"); err == nil { 81 t.Errorf("should have failed with non existent path") 82 } 83 tmpfile, err := ioutil.TempFile("", "mountinfo") 84 if err != nil { 85 t.Fatal(err) 86 } 87 defer os.Remove(tmpfile.Name()) 88 89 if _, err := tmpfile.Write([]byte(mountInfoData)); err != nil { 90 t.Fatal(err) 91 } 92 if err := tmpfile.Close(); err != nil { 93 t.Fatal(err) 94 } 95 m, err := ParseMountInfo(tmpfile.Name()) 96 if err != nil { 97 t.Fatal(err) 98 } 99 if len(m) != 7 { 100 t.Errorf("got %d main parent mount point instead of 7", len(m)) 101 } 102 if len(m["/"]) != 5 { 103 t.Errorf("got %d child mount point for '/' instead of 5", len(m["/"])) 104 } 105 if len(m["/dev"]) != 4 { 106 t.Errorf("got %d child mount point for '/dev' instead of 4", len(m["/dev"])) 107 } 108 if len(m["/sys"]) != 6 { 109 t.Errorf("got %d child mount point for '/sys' instead of 6", len(m["/sys"])) 110 } 111 if len(m["/sys/fs/cgroup"]) != 13 { 112 t.Errorf("got %d child mount point for '/sys/fs/cgroup' instead of 13", len(m["/sys/fs/cgroup"])) 113 } 114 if len(m["/proc"]) != 2 { 115 t.Errorf("got %d child mount point for '/proc' instead of 2", len(m["/proc"])) 116 } 117 if len(m["/run"]) != 3 { 118 t.Errorf("got %d child mount point for '/run' instead of 3", len(m["/run"])) 119 } 120 if len(m["/run/user/1000"]) != 1 { 121 t.Errorf("got %d child mount point for '/run/user/1000' instead of 1", len(m["/run/user/1000"])) 122 } 123 } 124 125 func TestExtractPid(t *testing.T) { 126 procList := []struct { 127 path string 128 pid uint 129 fail bool 130 }{ 131 {"/proc/1/fd", 1, false}, 132 {"/proc/self", 0, true}, 133 {"/proc/123/ns/pid", 123, false}, 134 {"/proc/-1", 0, true}, 135 {"/etc/../proc/1/fd", 0, true}, 136 } 137 for _, pl := range procList { 138 pid, err := ExtractPid(pl.path) 139 if err != nil && !pl.fail { 140 t.Fatal(err) 141 } 142 if !pl.fail && pid != pl.pid { 143 t.Fatalf("should have returned %d as PID instead of %d", pid, pl.pid) 144 } 145 if pl.fail && err == nil { 146 t.Fatalf("extract path %s should have failed", pl.path) 147 } 148 } 149 } 150 151 func TestCountChilds(t *testing.T) { 152 test.DropPrivilege(t) 153 defer test.ResetPrivilege(t) 154 155 childs, err := CountChilds(1) 156 if err != nil { 157 t.Fatal(err) 158 } 159 if childs == 0 { 160 t.Fatal("init have no child processes") 161 } 162 childs, err = CountChilds(0) 163 if err == nil { 164 t.Fatal("no error reported with PID 0") 165 } 166 } 167 168 func TestReadIDMap(t *testing.T) { 169 test.DropPrivilege(t) 170 defer test.ResetPrivilege(t) 171 172 // skip tests if uid_map doesn't exists 173 if _, err := os.Stat("/proc/self/uid_map"); os.IsNotExist(err) { 174 return 175 } 176 containerID, hostID, err := ReadIDMap("/proc/self/uid_map") 177 if err != nil { 178 t.Fatal(err) 179 } 180 if containerID != 0 || containerID != hostID { 181 t.Errorf("") 182 } 183 containerID, hostID, err = ReadIDMap("/proc/self/gid_map") 184 if err != nil { 185 t.Fatal(err) 186 } 187 if containerID != 0 || containerID != hostID { 188 t.Errorf("") 189 } 190 } 191 192 func TestParentMount(t *testing.T) { 193 test.DropPrivilege(t) 194 defer test.ResetPrivilege(t) 195 196 list := []struct { 197 path string 198 parent string 199 fail bool 200 }{ 201 {"/proc_", "", true}, 202 {"/proc", "/proc", false}, 203 {"/dev/null", "/dev", false}, 204 {"/proc/self", "/proc", false}, 205 {"/proc/fake", "", true}, 206 } 207 208 for _, l := range list { 209 parent, err := ParentMount(l.path) 210 if l.fail && err == nil { 211 t.Errorf("%s should fail", l.path) 212 } else if !l.fail { 213 if err != nil { 214 t.Error(err) 215 } else if parent != l.parent { 216 t.Errorf("mount parent of %s should be %s not %s", l.path, l.parent, parent) 217 } 218 } 219 220 } 221 } 222 223 func TestSetOOMScoreAdj(t *testing.T) { 224 test.EnsurePrivilege(t) 225 226 pid := os.Getpid() 227 228 list := []struct { 229 pid int 230 score int 231 fail bool 232 }{ 233 {pid, 0, false}, 234 {pid, 10, false}, 235 {0, 0, true}, 236 } 237 238 for _, l := range list { 239 err := SetOOMScoreAdj(l.pid, &l.score) 240 if l.fail && err == nil { 241 t.Errorf("writing %d in /proc/%d/oom_score_adj should have failed", l.score, l.pid) 242 } else if !l.fail && err != nil { 243 t.Error(err) 244 } 245 } 246 } 247 248 func TestHasNamespace(t *testing.T) { 249 test.EnsurePrivilege(t) 250 251 ppid := os.Getppid() 252 has, err := HasNamespace(ppid, "net") 253 if err != nil { 254 t.Error(err) 255 } 256 if has { 257 t.Errorf("namespaces should be identical") 258 } 259 260 cmd := exec.Command("/bin/cat") 261 pipe, err := cmd.StdinPipe() 262 if err != nil { 263 t.Fatal(err) 264 } 265 266 cmd.SysProcAttr = &syscall.SysProcAttr{} 267 cmd.SysProcAttr.Cloneflags = syscall.CLONE_NEWPID 268 269 if err := cmd.Start(); err != nil { 270 t.Fatal(err) 271 } 272 273 has, err = HasNamespace(cmd.Process.Pid, "pid") 274 if !has { 275 t.Errorf("pid namespace should be different") 276 } 277 278 pipe.Close() 279 280 cmd.Wait() 281 }