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  }