github.com/SagerNet/gvisor@v0.0.0-20210707092255-7731c139d75c/test/cmd/test_app/main.go (about) 1 // Copyright 2018 The gVisor Authors. 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 // Binary test_app is like a swiss knife for tests that need to run anything 16 // inside the sandbox. New functionality can be added with new commands. 17 package main 18 19 import ( 20 "context" 21 "fmt" 22 "io" 23 "io/ioutil" 24 "log" 25 "net" 26 "os" 27 "os/exec" 28 "regexp" 29 "strconv" 30 sys "syscall" 31 "time" 32 33 "github.com/google/subcommands" 34 "github.com/kr/pty" 35 "github.com/SagerNet/gvisor/pkg/test/testutil" 36 "github.com/SagerNet/gvisor/runsc/flag" 37 ) 38 39 func main() { 40 subcommands.Register(subcommands.HelpCommand(), "") 41 subcommands.Register(subcommands.FlagsCommand(), "") 42 subcommands.Register(new(capability), "") 43 subcommands.Register(new(fdReceiver), "") 44 subcommands.Register(new(fdSender), "") 45 subcommands.Register(new(forkBomb), "") 46 subcommands.Register(new(ptyRunner), "") 47 subcommands.Register(new(reaper), "") 48 subcommands.Register(new(syscall), "") 49 subcommands.Register(new(taskTree), "") 50 subcommands.Register(new(uds), "") 51 52 flag.Parse() 53 54 exitCode := subcommands.Execute(context.Background()) 55 os.Exit(int(exitCode)) 56 } 57 58 type uds struct { 59 fileName string 60 socketPath string 61 } 62 63 // Name implements subcommands.Command.Name. 64 func (*uds) Name() string { 65 return "uds" 66 } 67 68 // Synopsis implements subcommands.Command.Synopsys. 69 func (*uds) Synopsis() string { 70 return "creates unix domain socket client and server. Client sends a contant flow of sequential numbers. Server prints them to --file" 71 } 72 73 // Usage implements subcommands.Command.Usage. 74 func (*uds) Usage() string { 75 return "uds <flags>" 76 } 77 78 // SetFlags implements subcommands.Command.SetFlags. 79 func (c *uds) SetFlags(f *flag.FlagSet) { 80 f.StringVar(&c.fileName, "file", "", "name of output file") 81 f.StringVar(&c.socketPath, "socket", "", "path to socket") 82 } 83 84 // Execute implements subcommands.Command.Execute. 85 func (c *uds) Execute(ctx context.Context, f *flag.FlagSet, args ...interface{}) subcommands.ExitStatus { 86 if c.fileName == "" || c.socketPath == "" { 87 log.Fatalf("Flags cannot be empty, given: fileName: %q, socketPath: %q", c.fileName, c.socketPath) 88 return subcommands.ExitFailure 89 } 90 outputFile, err := os.OpenFile(c.fileName, os.O_WRONLY|os.O_CREATE, 0666) 91 if err != nil { 92 log.Fatal("error opening output file:", err) 93 } 94 95 defer os.Remove(c.socketPath) 96 97 listener, err := net.Listen("unix", c.socketPath) 98 if err != nil { 99 log.Fatalf("error listening on socket %q: %v", c.socketPath, err) 100 } 101 102 go server(listener, outputFile) 103 for i := 0; ; i++ { 104 conn, err := net.Dial("unix", c.socketPath) 105 if err != nil { 106 log.Fatal("error dialing:", err) 107 } 108 if _, err := conn.Write([]byte(strconv.Itoa(i))); err != nil { 109 log.Fatal("error writing:", err) 110 } 111 conn.Close() 112 time.Sleep(100 * time.Millisecond) 113 } 114 } 115 116 func server(listener net.Listener, out *os.File) { 117 buf := make([]byte, 16) 118 119 for { 120 c, err := listener.Accept() 121 if err != nil { 122 log.Fatal("error accepting connection:", err) 123 } 124 nr, err := c.Read(buf) 125 if err != nil { 126 log.Fatal("error reading from buf:", err) 127 } 128 data := buf[0:nr] 129 fmt.Fprint(out, string(data)+"\n") 130 } 131 } 132 133 type taskTree struct { 134 depth int 135 width int 136 pause bool 137 } 138 139 // Name implements subcommands.Command. 140 func (*taskTree) Name() string { 141 return "task-tree" 142 } 143 144 // Synopsis implements subcommands.Command. 145 func (*taskTree) Synopsis() string { 146 return "creates a tree of tasks" 147 } 148 149 // Usage implements subcommands.Command. 150 func (*taskTree) Usage() string { 151 return "task-tree <flags>" 152 } 153 154 // SetFlags implements subcommands.Command. 155 func (c *taskTree) SetFlags(f *flag.FlagSet) { 156 f.IntVar(&c.depth, "depth", 1, "number of levels to create") 157 f.IntVar(&c.width, "width", 1, "number of tasks at each level") 158 f.BoolVar(&c.pause, "pause", false, "whether the tasks should pause perpetually") 159 } 160 161 // Execute implements subcommands.Command. 162 func (c *taskTree) Execute(ctx context.Context, f *flag.FlagSet, args ...interface{}) subcommands.ExitStatus { 163 if c.depth == 0 { 164 log.Printf("Child sleeping, PID: %d\n", os.Getpid()) 165 for { 166 time.Sleep(time.Hour) 167 } 168 } 169 170 log.Printf("Parent %d creating %d children, PID: %d\n", c.depth, c.width, os.Getpid()) 171 172 stop := testutil.StartReaper() 173 defer stop() 174 175 var cmds []*exec.Cmd 176 for i := 0; i < c.width; i++ { 177 cmd := exec.Command( 178 "/proc/self/exe", c.Name(), 179 "--depth", strconv.Itoa(c.depth-1), 180 "--width", strconv.Itoa(c.width), 181 fmt.Sprintf("--pause=%t", c.pause)) 182 cmd.Stdout = os.Stdout 183 cmd.Stderr = os.Stderr 184 185 if err := cmd.Start(); err != nil { 186 log.Fatal("failed to call self:", err) 187 } 188 cmds = append(cmds, cmd) 189 } 190 191 for _, c := range cmds { 192 c.Wait() 193 } 194 195 if c.pause { 196 log.Printf("Parent %d sleeping, PID: %d\n", c.depth, os.Getpid()) 197 for { 198 time.Sleep(time.Hour) 199 } 200 } 201 202 return subcommands.ExitSuccess 203 } 204 205 type forkBomb struct { 206 delay time.Duration 207 } 208 209 // Name implements subcommands.Command. 210 func (*forkBomb) Name() string { 211 return "fork-bomb" 212 } 213 214 // Synopsis implements subcommands.Command. 215 func (*forkBomb) Synopsis() string { 216 return "creates child process until the end of times" 217 } 218 219 // Usage implements subcommands.Command. 220 func (*forkBomb) Usage() string { 221 return "fork-bomb <flags>" 222 } 223 224 // SetFlags implements subcommands.Command. 225 func (c *forkBomb) SetFlags(f *flag.FlagSet) { 226 f.DurationVar(&c.delay, "delay", 100*time.Millisecond, "amount of time to delay creation of child") 227 } 228 229 // Execute implements subcommands.Command. 230 func (c *forkBomb) Execute(ctx context.Context, f *flag.FlagSet, args ...interface{}) subcommands.ExitStatus { 231 time.Sleep(c.delay) 232 233 cmd := exec.Command("/proc/self/exe", c.Name()) 234 cmd.Stdout = os.Stdout 235 cmd.Stderr = os.Stderr 236 if err := cmd.Run(); err != nil { 237 log.Fatal("failed to call self:", err) 238 } 239 return subcommands.ExitSuccess 240 } 241 242 type reaper struct{} 243 244 // Name implements subcommands.Command. 245 func (*reaper) Name() string { 246 return "reaper" 247 } 248 249 // Synopsis implements subcommands.Command. 250 func (*reaper) Synopsis() string { 251 return "reaps all children in a loop" 252 } 253 254 // Usage implements subcommands.Command. 255 func (*reaper) Usage() string { 256 return "reaper <flags>" 257 } 258 259 // SetFlags implements subcommands.Command. 260 func (*reaper) SetFlags(*flag.FlagSet) {} 261 262 // Execute implements subcommands.Command. 263 func (c *reaper) Execute(ctx context.Context, f *flag.FlagSet, args ...interface{}) subcommands.ExitStatus { 264 stop := testutil.StartReaper() 265 defer stop() 266 select {} 267 } 268 269 type syscall struct { 270 sysno uint64 271 } 272 273 // Name implements subcommands.Command. 274 func (*syscall) Name() string { 275 return "syscall" 276 } 277 278 // Synopsis implements subcommands.Command. 279 func (*syscall) Synopsis() string { 280 return "syscall makes a syscall" 281 } 282 283 // Usage implements subcommands.Command. 284 func (*syscall) Usage() string { 285 return "syscall <flags>" 286 } 287 288 // SetFlags implements subcommands.Command. 289 func (s *syscall) SetFlags(f *flag.FlagSet) { 290 f.Uint64Var(&s.sysno, "syscall", 0, "syscall to call") 291 } 292 293 // Execute implements subcommands.Command. 294 func (s *syscall) Execute(ctx context.Context, f *flag.FlagSet, args ...interface{}) subcommands.ExitStatus { 295 if _, _, errno := sys.Syscall(uintptr(s.sysno), 0, 0, 0); errno != 0 { 296 fmt.Printf("syscall(%d, 0, 0...) failed: %v\n", s.sysno, errno) 297 } else { 298 fmt.Printf("syscall(%d, 0, 0...) success\n", s.sysno) 299 } 300 return subcommands.ExitSuccess 301 } 302 303 type capability struct { 304 enabled uint64 305 disabled uint64 306 } 307 308 // Name implements subcommands.Command. 309 func (*capability) Name() string { 310 return "capability" 311 } 312 313 // Synopsis implements subcommands.Command. 314 func (*capability) Synopsis() string { 315 return "checks if effective capabilities are set/unset" 316 } 317 318 // Usage implements subcommands.Command. 319 func (*capability) Usage() string { 320 return "capability [--enabled=number] [--disabled=number]" 321 } 322 323 // SetFlags implements subcommands.Command. 324 func (c *capability) SetFlags(f *flag.FlagSet) { 325 f.Uint64Var(&c.enabled, "enabled", 0, "") 326 f.Uint64Var(&c.disabled, "disabled", 0, "") 327 } 328 329 // Execute implements subcommands.Command. 330 func (c *capability) Execute(ctx context.Context, f *flag.FlagSet, args ...interface{}) subcommands.ExitStatus { 331 if c.enabled == 0 && c.disabled == 0 { 332 fmt.Println("One of the flags must be set") 333 return subcommands.ExitUsageError 334 } 335 336 status, err := ioutil.ReadFile("/proc/self/status") 337 if err != nil { 338 fmt.Printf("Error reading %q: %v\n", "proc/self/status", err) 339 return subcommands.ExitFailure 340 } 341 re := regexp.MustCompile("CapEff:\t([0-9a-f]+)\n") 342 matches := re.FindStringSubmatch(string(status)) 343 if matches == nil || len(matches) != 2 { 344 fmt.Printf("Effective capabilities not found in\n%s\n", status) 345 return subcommands.ExitFailure 346 } 347 caps, err := strconv.ParseUint(matches[1], 16, 64) 348 if err != nil { 349 fmt.Printf("failed to convert capabilities %q: %v\n", matches[1], err) 350 return subcommands.ExitFailure 351 } 352 353 if c.enabled != 0 && (caps&c.enabled) != c.enabled { 354 fmt.Printf("Missing capabilities, want: %#x: got: %#x\n", c.enabled, caps) 355 return subcommands.ExitFailure 356 } 357 if c.disabled != 0 && (caps&c.disabled) != 0 { 358 fmt.Printf("Extra capabilities found, dont_want: %#x: got: %#x\n", c.disabled, caps) 359 return subcommands.ExitFailure 360 } 361 362 return subcommands.ExitSuccess 363 } 364 365 type ptyRunner struct{} 366 367 // Name implements subcommands.Command. 368 func (*ptyRunner) Name() string { 369 return "pty-runner" 370 } 371 372 // Synopsis implements subcommands.Command. 373 func (*ptyRunner) Synopsis() string { 374 return "runs the given command with an open pty terminal" 375 } 376 377 // Usage implements subcommands.Command. 378 func (*ptyRunner) Usage() string { 379 return "pty-runner [command]" 380 } 381 382 // SetFlags implements subcommands.Command.SetFlags. 383 func (*ptyRunner) SetFlags(f *flag.FlagSet) {} 384 385 // Execute implements subcommands.Command. 386 func (*ptyRunner) Execute(_ context.Context, fs *flag.FlagSet, _ ...interface{}) subcommands.ExitStatus { 387 c := exec.Command(fs.Args()[0], fs.Args()[1:]...) 388 f, err := pty.Start(c) 389 if err != nil { 390 fmt.Printf("pty.Start failed: %v", err) 391 return subcommands.ExitFailure 392 } 393 defer f.Close() 394 395 // Copy stdout from the command to keep this process alive until the 396 // subprocess exits. 397 io.Copy(os.Stdout, f) 398 399 return subcommands.ExitSuccess 400 }