github.com/nicocha30/gvisor-ligolo@v0.0.0-20230726075806-989fa2c0a413/pkg/seccomp/seccomp_rules.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 package seccomp 16 17 import ( 18 "fmt" 19 20 "golang.org/x/sys/unix" 21 ) 22 23 // The offsets are based on the following struct in include/linux/seccomp.h. 24 // 25 // struct seccomp_data { 26 // int nr; 27 // __u32 arch; 28 // __u64 instruction_pointer; 29 // __u64 args[6]; 30 // }; 31 const ( 32 seccompDataOffsetNR = 0 33 seccompDataOffsetArch = 4 34 seccompDataOffsetIPLow = 8 35 seccompDataOffsetIPHigh = 12 36 seccompDataOffsetArgs = 16 37 ) 38 39 func seccompDataOffsetArgLow(i int) uint32 { 40 return uint32(seccompDataOffsetArgs + i*8) 41 } 42 43 func seccompDataOffsetArgHigh(i int) uint32 { 44 return seccompDataOffsetArgLow(i) + 4 45 } 46 47 // MatchAny is marker to indicate any value will be accepted. 48 type MatchAny struct{} 49 50 func (a MatchAny) String() (s string) { 51 return "*" 52 } 53 54 // EqualTo specifies a value that needs to be strictly matched. 55 type EqualTo uintptr 56 57 func (a EqualTo) String() (s string) { 58 return fmt.Sprintf("== %#x", uintptr(a)) 59 } 60 61 // NotEqual specifies a value that is strictly not equal. 62 type NotEqual uintptr 63 64 func (a NotEqual) String() (s string) { 65 return fmt.Sprintf("!= %#x", uintptr(a)) 66 } 67 68 // GreaterThan specifies a value that needs to be strictly smaller. 69 type GreaterThan uintptr 70 71 func (a GreaterThan) String() (s string) { 72 return fmt.Sprintf("> %#x", uintptr(a)) 73 } 74 75 // GreaterThanOrEqual specifies a value that needs to be smaller or equal. 76 type GreaterThanOrEqual uintptr 77 78 func (a GreaterThanOrEqual) String() (s string) { 79 return fmt.Sprintf(">= %#x", uintptr(a)) 80 } 81 82 // LessThan specifies a value that needs to be strictly greater. 83 type LessThan uintptr 84 85 func (a LessThan) String() (s string) { 86 return fmt.Sprintf("< %#x", uintptr(a)) 87 } 88 89 // LessThanOrEqual specifies a value that needs to be greater or equal. 90 type LessThanOrEqual uintptr 91 92 func (a LessThanOrEqual) String() (s string) { 93 return fmt.Sprintf("<= %#x", uintptr(a)) 94 } 95 96 type maskedEqual struct { 97 mask uintptr 98 value uintptr 99 } 100 101 func (a maskedEqual) String() (s string) { 102 return fmt.Sprintf("& %#x == %#x", a.mask, a.value) 103 } 104 105 // MaskedEqual specifies a value that matches the input after the input is 106 // masked (bitwise &) against the given mask. Can be used to verify that input 107 // only includes certain approved flags. 108 func MaskedEqual(mask, value uintptr) any { 109 return maskedEqual{ 110 mask: mask, 111 value: value, 112 } 113 } 114 115 // Rule stores the allowed syscall arguments. 116 // 117 // For example: 118 // 119 // rule := Rule { 120 // EqualTo(linux.ARCH_GET_FS | linux.ARCH_SET_FS), // arg0 121 // } 122 type Rule [7]any // 6 arguments + RIP 123 124 // RuleIP indicates what rules in the Rule array have to be applied to 125 // instruction pointer. 126 const RuleIP = 6 127 128 func (r Rule) String() (s string) { 129 if len(r) == 0 { 130 return 131 } 132 s += "( " 133 for _, arg := range r { 134 if arg != nil { 135 s += fmt.Sprintf("%v ", arg) 136 } 137 } 138 s += ")" 139 return 140 } 141 142 // SyscallRules stores a map of OR'ed argument rules indexed by the syscall number. 143 // If the 'Rules' is empty, we treat it as any argument is allowed. 144 // 145 // For example: 146 // 147 // rules := SyscallRules{ 148 // syscall.SYS_FUTEX: []Rule{ 149 // { 150 // MatchAny{}, 151 // EqualTo(linux.FUTEX_WAIT | linux.FUTEX_PRIVATE_FLAG), 152 // }, // OR 153 // { 154 // MatchAny{}, 155 // EqualTo(linux.FUTEX_WAKE | linux.FUTEX_PRIVATE_FLAG), 156 // }, 157 // }, 158 // syscall.SYS_GETPID: []Rule{}, 159 // 160 // } 161 type SyscallRules map[uintptr][]Rule 162 163 // NewSyscallRules returns a new SyscallRules. 164 func NewSyscallRules() SyscallRules { 165 return make(map[uintptr][]Rule) 166 } 167 168 // AddRule adds the given rule. It will create a new entry for a new syscall, otherwise 169 // it will append to the existing rules. 170 func (sr SyscallRules) AddRule(sysno uintptr, r Rule) { 171 if cur, ok := sr[sysno]; ok { 172 // An empty rules means allow all. Honor it when more rules are added. 173 if len(cur) == 0 { 174 sr[sysno] = append(sr[sysno], Rule{}) 175 } 176 sr[sysno] = append(sr[sysno], r) 177 } else { 178 sr[sysno] = []Rule{r} 179 } 180 } 181 182 // Merge merges the given SyscallRules. 183 func (sr SyscallRules) Merge(rules SyscallRules) { 184 for sysno, rs := range rules { 185 if cur, ok := sr[sysno]; ok { 186 // An empty rules means allow all. Honor it when more rules are added. 187 if len(cur) == 0 { 188 sr[sysno] = append(sr[sysno], Rule{}) 189 } 190 if len(rs) == 0 { 191 rs = []Rule{{}} 192 } 193 sr[sysno] = append(sr[sysno], rs...) 194 } else { 195 sr[sysno] = rs 196 } 197 } 198 } 199 200 // DenyNewExecMappings is a set of rules that denies creating new executable 201 // mappings and converting existing ones. 202 var DenyNewExecMappings = SyscallRules{ 203 unix.SYS_MMAP: []Rule{ 204 { 205 MatchAny{}, 206 MatchAny{}, 207 MaskedEqual(unix.PROT_EXEC, unix.PROT_EXEC), 208 }, 209 }, 210 unix.SYS_MPROTECT: []Rule{ 211 { 212 MatchAny{}, 213 MatchAny{}, 214 MaskedEqual(unix.PROT_EXEC, unix.PROT_EXEC), 215 }, 216 }, 217 }