github.com/zhuohuang-hust/src-cbuild@v0.0.0-20230105071821-c7aab3e7c840/mergeCode/runc/libcontainer/seccomp/seccomp_linux.go (about) 1 // +build linux,cgo,seccomp 2 3 package seccomp 4 5 import ( 6 "bufio" 7 "fmt" 8 "os" 9 "strings" 10 "syscall" 11 12 "github.com/opencontainers/runc/libcontainer/configs" 13 libseccomp "github.com/seccomp/libseccomp-golang" 14 ) 15 16 var ( 17 actAllow = libseccomp.ActAllow 18 actTrap = libseccomp.ActTrap 19 actKill = libseccomp.ActKill 20 actTrace = libseccomp.ActTrace.SetReturnCode(int16(syscall.EPERM)) 21 actErrno = libseccomp.ActErrno.SetReturnCode(int16(syscall.EPERM)) 22 23 // SeccompModeFilter refers to the syscall argument SECCOMP_MODE_FILTER. 24 SeccompModeFilter = uintptr(2) 25 ) 26 27 // Filters given syscalls in a container, preventing them from being used 28 // Started in the container init process, and carried over to all child processes 29 // Setns calls, however, require a separate invocation, as they are not children 30 // of the init until they join the namespace 31 func InitSeccomp(config *configs.Seccomp) error { 32 if config == nil { 33 return fmt.Errorf("cannot initialize Seccomp - nil config passed") 34 } 35 36 defaultAction, err := getAction(config.DefaultAction) 37 if err != nil { 38 return fmt.Errorf("error initializing seccomp - invalid default action") 39 } 40 41 filter, err := libseccomp.NewFilter(defaultAction) 42 if err != nil { 43 return fmt.Errorf("error creating filter: %s", err) 44 } 45 46 // Add extra architectures 47 for _, arch := range config.Architectures { 48 scmpArch, err := libseccomp.GetArchFromString(arch) 49 if err != nil { 50 return err 51 } 52 53 if err := filter.AddArch(scmpArch); err != nil { 54 return err 55 } 56 } 57 58 // Unset no new privs bit 59 if err := filter.SetNoNewPrivsBit(false); err != nil { 60 return fmt.Errorf("error setting no new privileges: %s", err) 61 } 62 63 // Add a rule for each syscall 64 for _, call := range config.Syscalls { 65 if call == nil { 66 return fmt.Errorf("encountered nil syscall while initializing Seccomp") 67 } 68 69 if err = matchCall(filter, call); err != nil { 70 return err 71 } 72 } 73 74 if err = filter.Load(); err != nil { 75 return fmt.Errorf("error loading seccomp filter into kernel: %s", err) 76 } 77 78 return nil 79 } 80 81 // IsEnabled returns if the kernel has been configured to support seccomp. 82 func IsEnabled() bool { 83 // Try to read from /proc/self/status for kernels > 3.8 84 s, err := parseStatusFile("/proc/self/status") 85 if err != nil { 86 // Check if Seccomp is supported, via CONFIG_SECCOMP. 87 if _, _, err := syscall.RawSyscall(syscall.SYS_PRCTL, syscall.PR_GET_SECCOMP, 0, 0); err != syscall.EINVAL { 88 // Make sure the kernel has CONFIG_SECCOMP_FILTER. 89 if _, _, err := syscall.RawSyscall(syscall.SYS_PRCTL, syscall.PR_SET_SECCOMP, SeccompModeFilter, 0); err != syscall.EINVAL { 90 return true 91 } 92 } 93 return false 94 } 95 _, ok := s["Seccomp"] 96 return ok 97 } 98 99 // Convert Libcontainer Action to Libseccomp ScmpAction 100 func getAction(act configs.Action) (libseccomp.ScmpAction, error) { 101 switch act { 102 case configs.Kill: 103 return actKill, nil 104 case configs.Errno: 105 return actErrno, nil 106 case configs.Trap: 107 return actTrap, nil 108 case configs.Allow: 109 return actAllow, nil 110 case configs.Trace: 111 return actTrace, nil 112 default: 113 return libseccomp.ActInvalid, fmt.Errorf("invalid action, cannot use in rule") 114 } 115 } 116 117 // Convert Libcontainer Operator to Libseccomp ScmpCompareOp 118 func getOperator(op configs.Operator) (libseccomp.ScmpCompareOp, error) { 119 switch op { 120 case configs.EqualTo: 121 return libseccomp.CompareEqual, nil 122 case configs.NotEqualTo: 123 return libseccomp.CompareNotEqual, nil 124 case configs.GreaterThan: 125 return libseccomp.CompareGreater, nil 126 case configs.GreaterThanOrEqualTo: 127 return libseccomp.CompareGreaterEqual, nil 128 case configs.LessThan: 129 return libseccomp.CompareLess, nil 130 case configs.LessThanOrEqualTo: 131 return libseccomp.CompareLessOrEqual, nil 132 case configs.MaskEqualTo: 133 return libseccomp.CompareMaskedEqual, nil 134 default: 135 return libseccomp.CompareInvalid, fmt.Errorf("invalid operator, cannot use in rule") 136 } 137 } 138 139 // Convert Libcontainer Arg to Libseccomp ScmpCondition 140 func getCondition(arg *configs.Arg) (libseccomp.ScmpCondition, error) { 141 cond := libseccomp.ScmpCondition{} 142 143 if arg == nil { 144 return cond, fmt.Errorf("cannot convert nil to syscall condition") 145 } 146 147 op, err := getOperator(arg.Op) 148 if err != nil { 149 return cond, err 150 } 151 152 return libseccomp.MakeCondition(arg.Index, op, arg.Value, arg.ValueTwo) 153 } 154 155 // Add a rule to match a single syscall 156 func matchCall(filter *libseccomp.ScmpFilter, call *configs.Syscall) error { 157 if call == nil || filter == nil { 158 return fmt.Errorf("cannot use nil as syscall to block") 159 } 160 161 if len(call.Name) == 0 { 162 return fmt.Errorf("empty string is not a valid syscall") 163 } 164 165 // If we can't resolve the syscall, assume it's not supported on this kernel 166 // Ignore it, don't error out 167 callNum, err := libseccomp.GetSyscallFromName(call.Name) 168 if err != nil { 169 return nil 170 } 171 172 // Convert the call's action to the libseccomp equivalent 173 callAct, err := getAction(call.Action) 174 if err != nil { 175 return err 176 } 177 178 // Unconditional match - just add the rule 179 if len(call.Args) == 0 { 180 if err = filter.AddRule(callNum, callAct); err != nil { 181 return err 182 } 183 } else { 184 // Conditional match - convert the per-arg rules into library format 185 conditions := []libseccomp.ScmpCondition{} 186 187 for _, cond := range call.Args { 188 newCond, err := getCondition(cond) 189 if err != nil { 190 return err 191 } 192 193 conditions = append(conditions, newCond) 194 } 195 196 if err = filter.AddRuleConditional(callNum, callAct, conditions); err != nil { 197 return err 198 } 199 } 200 201 return nil 202 } 203 204 func parseStatusFile(path string) (map[string]string, error) { 205 f, err := os.Open(path) 206 if err != nil { 207 return nil, err 208 } 209 defer f.Close() 210 211 s := bufio.NewScanner(f) 212 status := make(map[string]string) 213 214 for s.Scan() { 215 if err := s.Err(); err != nil { 216 return nil, err 217 } 218 219 text := s.Text() 220 parts := strings.Split(text, ":") 221 222 if len(parts) <= 1 { 223 continue 224 } 225 226 status[parts[0]] = parts[1] 227 } 228 return status, nil 229 }