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