github.com/containers/podman/v2@v2.2.2-0.20210501105131-c1e07d070c4c/pkg/cgroups/cgroups_supported.go (about)

     1  // +build linux
     2  
     3  package cgroups
     4  
     5  import (
     6  	"bufio"
     7  	"fmt"
     8  	"os"
     9  	"path/filepath"
    10  	"strings"
    11  	"sync"
    12  	"syscall"
    13  
    14  	"github.com/pkg/errors"
    15  	"golang.org/x/sys/unix"
    16  )
    17  
    18  var (
    19  	isUnifiedOnce sync.Once
    20  	isUnified     bool
    21  	isUnifiedErr  error
    22  )
    23  
    24  // IsCgroup2UnifiedMode returns whether we are running in cgroup 2 cgroup2 mode.
    25  func IsCgroup2UnifiedMode() (bool, error) {
    26  	isUnifiedOnce.Do(func() {
    27  		var st syscall.Statfs_t
    28  		if err := syscall.Statfs("/sys/fs/cgroup", &st); err != nil {
    29  			isUnified, isUnifiedErr = false, err
    30  		} else {
    31  			isUnified, isUnifiedErr = st.Type == unix.CGROUP2_SUPER_MAGIC, nil
    32  		}
    33  	})
    34  	return isUnified, isUnifiedErr
    35  }
    36  
    37  // UserOwnsCurrentSystemdCgroup checks whether the current EUID owns the
    38  // current cgroup.
    39  func UserOwnsCurrentSystemdCgroup() (bool, error) {
    40  	uid := os.Geteuid()
    41  
    42  	cgroup2, err := IsCgroup2UnifiedMode()
    43  	if err != nil {
    44  		return false, err
    45  	}
    46  
    47  	f, err := os.Open("/proc/self/cgroup")
    48  	if err != nil {
    49  		return false, err
    50  	}
    51  	defer f.Close()
    52  
    53  	scanner := bufio.NewScanner(f)
    54  	for scanner.Scan() {
    55  		line := scanner.Text()
    56  		parts := strings.SplitN(line, ":", 3)
    57  
    58  		if len(parts) < 3 {
    59  			continue
    60  		}
    61  
    62  		var cgroupPath string
    63  
    64  		if cgroup2 {
    65  			cgroupPath = filepath.Join(cgroupRoot, parts[2])
    66  		} else {
    67  			if parts[1] != "name=systemd" {
    68  				continue
    69  			}
    70  			cgroupPath = filepath.Join(cgroupRoot, "systemd", parts[2])
    71  		}
    72  
    73  		st, err := os.Stat(cgroupPath)
    74  		if err != nil {
    75  			return false, err
    76  		}
    77  		s := st.Sys()
    78  		if s == nil {
    79  			return false, fmt.Errorf("error stat cgroup path %s", cgroupPath)
    80  		}
    81  
    82  		if int(s.(*syscall.Stat_t).Uid) != uid {
    83  			return false, nil
    84  		}
    85  	}
    86  	if err := scanner.Err(); err != nil {
    87  		return false, errors.Wrapf(err, "parsing file /proc/self/cgroup")
    88  	}
    89  	return true, nil
    90  }