github.com/ttpreport/gvisor-ligolo@v0.0.0-20240123134145-a858404967ba/runsc/cmd/trace/create.go (about) 1 // Copyright 2020 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 package trace 16 17 import ( 18 "context" 19 "encoding/json" 20 "fmt" 21 "os" 22 23 "github.com/google/subcommands" 24 "github.com/ttpreport/gvisor-ligolo/pkg/log" 25 "github.com/ttpreport/gvisor-ligolo/pkg/sentry/seccheck" 26 "github.com/ttpreport/gvisor-ligolo/runsc/boot" 27 "github.com/ttpreport/gvisor-ligolo/runsc/cmd/util" 28 "github.com/ttpreport/gvisor-ligolo/runsc/config" 29 "github.com/ttpreport/gvisor-ligolo/runsc/container" 30 "github.com/ttpreport/gvisor-ligolo/runsc/flag" 31 ) 32 33 // create implements subcommands.Command for the "create" command. 34 type create struct { 35 config string 36 force bool 37 } 38 39 // Name implements subcommands.Command. 40 func (*create) Name() string { 41 return "create" 42 } 43 44 // Synopsis implements subcommands.Command. 45 func (*create) Synopsis() string { 46 return "create a trace session" 47 } 48 49 // Usage implements subcommands.Command. 50 func (*create) Usage() string { 51 return `create [flags] <sandbox id> - create a trace session 52 ` 53 } 54 55 // SetFlags implements subcommands.Command. 56 func (l *create) SetFlags(f *flag.FlagSet) { 57 f.StringVar(&l.config, "config", "", "path to the JSON file that describes the session being created") 58 f.BoolVar(&l.force, "force", false, "deletes a conflicting session, if one exists") 59 } 60 61 // Execute implements subcommands.Command. 62 func (l *create) Execute(_ context.Context, f *flag.FlagSet, args ...any) subcommands.ExitStatus { 63 if f.NArg() != 1 { 64 f.Usage() 65 return subcommands.ExitUsageError 66 } 67 if len(l.config) == 0 { 68 f.Usage() 69 return util.Errorf("missing path to configuration file, please set --config=[path]") 70 } 71 72 sessionConfig, err := decodeTraceConfig(l.config) 73 if err != nil { 74 return util.Errorf("loading config file: %v", err) 75 } 76 77 id := f.Arg(0) 78 conf := args[0].(*config.Config) 79 80 opts := container.LoadOpts{ 81 SkipCheck: true, 82 RootContainer: true, 83 } 84 c, err := container.Load(conf.RootDir, container.FullID{ContainerID: id}, opts) 85 if err != nil { 86 util.Fatalf("loading sandbox: %v", err) 87 } 88 89 if err := c.Sandbox.CreateTraceSession(sessionConfig, l.force); err != nil { 90 util.Fatalf("creating session: %v", err) 91 } 92 93 fmt.Printf("Trace session %q created.\n", sessionConfig.Name) 94 return subcommands.ExitSuccess 95 } 96 97 func decodeTraceConfig(path string) (*seccheck.SessionConfig, error) { 98 file, err := os.Open(path) 99 if err != nil { 100 return nil, err 101 } 102 defer file.Close() 103 104 decoder := json.NewDecoder(file) 105 decoder.DisallowUnknownFields() 106 sessionConfig := &seccheck.SessionConfig{} 107 err = decoder.Decode(sessionConfig) 108 if err == nil { 109 // Success, we're done. 110 return sessionConfig, nil 111 } 112 113 // If file cannot be decoded as a SessionConfig, try with InitConfig as 114 // convenience in case the caller wants to reuse a trace session from 115 // InitConfig file. 116 log.Debugf("Config file is not a seccheck.SessionConfig, try with boot.InitConfig instead: %v", err) 117 if _, err := file.Seek(0, 0); err != nil { 118 return nil, err 119 } 120 initConfig := &boot.InitConfig{} 121 if err := decoder.Decode(initConfig); err != nil { 122 return nil, fmt.Errorf("invalid configuration file: %w", err) 123 } 124 return &initConfig.TraceSession, nil 125 }