github.com/SagerNet/gvisor@v0.0.0-20210707092255-7731c139d75c/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 "golang.org/x/sys/unix" 20 "github.com/SagerNet/gvisor/pkg/sync" 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 // Infinity is a constant representing a resource with no limit. 47 const Infinity = ^uint64(0) 48 49 // Limit specifies a system limit. 50 // 51 // +stateify savable 52 type Limit struct { 53 // Cur specifies the current limit. 54 Cur uint64 55 // Max specifies the maximum settable limit. 56 Max uint64 57 } 58 59 // LimitSet represents the Limits that correspond to each LimitType. 60 // 61 // +stateify savable 62 type LimitSet struct { 63 mu sync.Mutex `state:"nosave"` 64 data map[LimitType]Limit 65 } 66 67 // NewLimitSet creates a new, empty LimitSet. 68 func NewLimitSet() *LimitSet { 69 return &LimitSet{ 70 data: make(map[LimitType]Limit), 71 } 72 } 73 74 // GetCopy returns a clone of the LimitSet. 75 func (l *LimitSet) GetCopy() *LimitSet { 76 l.mu.Lock() 77 defer l.mu.Unlock() 78 copyData := make(map[LimitType]Limit) 79 for k, v := range l.data { 80 copyData[k] = v 81 } 82 return &LimitSet{ 83 data: copyData, 84 } 85 } 86 87 // Get returns the resource limit associated with LimitType t. 88 // If no limit is provided, it defaults to an infinite limit.Infinity. 89 func (l *LimitSet) Get(t LimitType) Limit { 90 l.mu.Lock() 91 defer l.mu.Unlock() 92 s, ok := l.data[t] 93 if !ok { 94 return Limit{Cur: Infinity, Max: Infinity} 95 } 96 return s 97 } 98 99 // GetCapped returns the current value for the limit, capped as specified. 100 func (l *LimitSet) GetCapped(t LimitType, max uint64) uint64 { 101 s := l.Get(t) 102 if s.Cur == Infinity || s.Cur > max { 103 return max 104 } 105 return s.Cur 106 } 107 108 // SetUnchecked assigns value v to resource of LimitType t. 109 func (l *LimitSet) SetUnchecked(t LimitType, v Limit) { 110 l.mu.Lock() 111 defer l.mu.Unlock() 112 l.data[t] = v 113 } 114 115 // Set assigns value v to resource of LimitType t and returns the old value. 116 // privileged should be true only when either the caller has CAP_SYS_RESOURCE 117 // or when creating limits for a new kernel. 118 func (l *LimitSet) Set(t LimitType, v Limit, privileged bool) (Limit, error) { 119 l.mu.Lock() 120 defer l.mu.Unlock() 121 122 // If a limit is already set, make sure the new limit doesn't 123 // exceed the previous max limit. 124 if _, ok := l.data[t]; ok { 125 // Unprivileged users can only lower their hard limits. 126 if l.data[t].Max < v.Max && !privileged { 127 return Limit{}, unix.EPERM 128 } 129 if v.Cur > v.Max { 130 return Limit{}, unix.EINVAL 131 } 132 } 133 old := l.data[t] 134 l.data[t] = v 135 return old, nil 136 }