github.com/nicocha30/gvisor-ligolo@v0.0.0-20230726075806-989fa2c0a413/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/nicocha30/gvisor-ligolo/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  // 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  }