github.com/MerlinKodo/gvisor@v0.0.0-20231110090155-957f62ecf90e/pkg/sentry/limits/limits.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 limits provides resource limits. 16 package limits 17 18 import ( 19 "github.com/MerlinKodo/gvisor/pkg/sync" 20 "golang.org/x/sys/unix" 21 ) 22 23 // LimitType defines a type of resource limit. 24 type LimitType int 25 26 // Set of constants defining the different types of resource limits. 27 const ( 28 CPU LimitType = iota 29 FileSize 30 Data 31 Stack 32 Core 33 Rss 34 ProcessCount 35 NumberOfFiles 36 MemoryLocked 37 AS 38 Locks 39 SignalsPending 40 MessageQueueBytes 41 Nice 42 RealTimePriority 43 Rttime 44 ) 45 46 // AllLimitTypes contains all types in the order how they are presented in 47 // /proc/pid/limits. 48 var AllLimitTypes = []LimitType{ 49 CPU, 50 FileSize, 51 Data, 52 Stack, 53 Core, 54 Rss, 55 ProcessCount, 56 NumberOfFiles, 57 MemoryLocked, 58 AS, 59 Locks, 60 SignalsPending, 61 MessageQueueBytes, 62 Nice, 63 RealTimePriority, 64 Rttime, 65 } 66 67 // Name returns the kernel name of the limit 68 func (lt LimitType) Name() string { 69 switch lt { 70 case CPU: 71 return "Max cpu time" 72 case FileSize: 73 return "Max file size" 74 case Data: 75 return "Max data size" 76 case Stack: 77 return "Max stack size" 78 case Core: 79 return "Max core file size" 80 case Rss: 81 return "Max resident set" 82 case ProcessCount: 83 return "Max processes" 84 case NumberOfFiles: 85 return "Max open files" 86 case MemoryLocked: 87 return "Max locked memory" 88 case AS: 89 return "Max address space" 90 case Locks: 91 return "Max file locks" 92 case SignalsPending: 93 return "Max pending signals" 94 case MessageQueueBytes: 95 return "Max msgqueue size" 96 case Nice: 97 return "Max nice priority" 98 case RealTimePriority: 99 return "Max realtime priority" 100 case Rttime: 101 return "Max realtime timeout" 102 } 103 return "unknown" 104 } 105 106 // Unit returns the unit string for a limit 107 func (lt LimitType) Unit() string { 108 switch lt { 109 case CPU: 110 return "seconds" 111 case FileSize: 112 return "bytes" 113 case Data: 114 return "bytes" 115 case Stack: 116 return "bytes" 117 case Core: 118 return "bytes" 119 case Rss: 120 return "bytes" 121 case ProcessCount: 122 return "processes" 123 case NumberOfFiles: 124 return "files" 125 case MemoryLocked: 126 return "bytes" 127 case AS: 128 return "bytes" 129 case Locks: 130 return "locks" 131 case SignalsPending: 132 return "signals" 133 case MessageQueueBytes: 134 return "bytes" 135 case Nice: 136 return "" 137 case RealTimePriority: 138 return "" 139 case Rttime: 140 return "us" 141 } 142 return "" 143 } 144 145 // Infinity is a constant representing a resource with no limit. 146 const Infinity = ^uint64(0) 147 148 // Limit specifies a system limit. 149 // 150 // +stateify savable 151 type Limit struct { 152 // Cur specifies the current limit. 153 Cur uint64 `json:"cur,omitempty"` 154 // Max specifies the maximum settable limit. 155 Max uint64 `json:"max,omitempty"` 156 } 157 158 // LimitSet represents the Limits that correspond to each LimitType. 159 // 160 // +stateify savable 161 type LimitSet struct { 162 mu sync.Mutex `state:"nosave"` 163 data map[LimitType]Limit 164 } 165 166 // NewLimitSet creates a new, empty LimitSet. 167 func NewLimitSet() *LimitSet { 168 return &LimitSet{ 169 data: make(map[LimitType]Limit), 170 } 171 } 172 173 // GetCopy returns a clone of the LimitSet. 174 func (l *LimitSet) GetCopy() *LimitSet { 175 l.mu.Lock() 176 defer l.mu.Unlock() 177 copyData := make(map[LimitType]Limit) 178 for k, v := range l.data { 179 copyData[k] = v 180 } 181 return &LimitSet{ 182 data: copyData, 183 } 184 } 185 186 // Get returns the resource limit associated with LimitType t. 187 // If no limit is provided, it defaults to an infinite limit.Infinity. 188 func (l *LimitSet) Get(t LimitType) Limit { 189 l.mu.Lock() 190 defer l.mu.Unlock() 191 s, ok := l.data[t] 192 if !ok { 193 return Limit{Cur: Infinity, Max: Infinity} 194 } 195 return s 196 } 197 198 // GetCapped returns the current value for the limit, capped as specified. 199 func (l *LimitSet) GetCapped(t LimitType, max uint64) uint64 { 200 s := l.Get(t) 201 if s.Cur == Infinity || s.Cur > max { 202 return max 203 } 204 return s.Cur 205 } 206 207 // SetUnchecked assigns value v to resource of LimitType t. 208 func (l *LimitSet) SetUnchecked(t LimitType, v Limit) { 209 l.mu.Lock() 210 defer l.mu.Unlock() 211 l.data[t] = v 212 } 213 214 // Set assigns value v to resource of LimitType t and returns the old value. 215 // privileged should be true only when either the caller has CAP_SYS_RESOURCE 216 // or when creating limits for a new kernel. 217 func (l *LimitSet) Set(t LimitType, v Limit, privileged bool) (Limit, error) { 218 l.mu.Lock() 219 defer l.mu.Unlock() 220 221 // If a limit is already set, make sure the new limit doesn't 222 // exceed the previous max limit. 223 if _, ok := l.data[t]; ok { 224 // Unprivileged users can only lower their hard limits. 225 if l.data[t].Max < v.Max && !privileged { 226 return Limit{}, unix.EPERM 227 } 228 if v.Cur > v.Max { 229 return Limit{}, unix.EINVAL 230 } 231 } 232 old := l.data[t] 233 l.data[t] = v 234 return old, nil 235 }