github.com/opencontainers/runc@v1.2.0-rc.1.0.20240520010911-492dc558cdd6/libcontainer/userns/userns_linux.go (about)

     1  package userns
     2  
     3  import (
     4  	"bufio"
     5  	"fmt"
     6  	"os"
     7  	"sync"
     8  )
     9  
    10  var (
    11  	inUserNS bool
    12  	nsOnce   sync.Once
    13  )
    14  
    15  // runningInUserNS detects whether we are currently running in a user namespace.
    16  //
    17  // Originally copied from https://github.com/lxc/incus/blob/e45085dd42f826b3c8c3228e9733c0b6f998eafe/shared/util.go#L678-L700.
    18  func runningInUserNS() bool {
    19  	nsOnce.Do(func() {
    20  		file, err := os.Open("/proc/self/uid_map")
    21  		if err != nil {
    22  			// This kernel-provided file only exists if user namespaces are supported.
    23  			return
    24  		}
    25  		defer file.Close()
    26  
    27  		buf := bufio.NewReader(file)
    28  		l, _, err := buf.ReadLine()
    29  		if err != nil {
    30  			return
    31  		}
    32  
    33  		inUserNS = uidMapInUserNS(string(l))
    34  	})
    35  	return inUserNS
    36  }
    37  
    38  func uidMapInUserNS(uidMap string) bool {
    39  	if uidMap == "" {
    40  		// File exist but empty (the initial state when userns is created,
    41  		// see user_namespaces(7)).
    42  		return true
    43  	}
    44  
    45  	var a, b, c int64
    46  	if _, err := fmt.Sscanf(uidMap, "%d %d %d", &a, &b, &c); err != nil {
    47  		// Assume we are in a regular, non user namespace.
    48  		return false
    49  	}
    50  
    51  	// As per user_namespaces(7), /proc/self/uid_map of
    52  	// the initial user namespace shows 0 0 4294967295.
    53  	initNS := a == 0 && b == 0 && c == 4294967295
    54  	return !initNS
    55  }