github.com/containerd/nerdctl/v2@v2.0.0-beta.5.0.20240520001846-b5758f54fa28/pkg/rootlessutil/parent_linux.go (about)

     1  /*
     2     Copyright The containerd Authors.
     3  
     4     Licensed under the Apache License, Version 2.0 (the "License");
     5     you may not use this file except in compliance with the License.
     6     You may obtain a copy of the License at
     7  
     8         http://www.apache.org/licenses/LICENSE-2.0
     9  
    10     Unless required by applicable law or agreed to in writing, software
    11     distributed under the License is distributed on an "AS IS" BASIS,
    12     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    13     See the License for the specific language governing permissions and
    14     limitations under the License.
    15  */
    16  
    17  package rootlessutil
    18  
    19  import (
    20  	"errors"
    21  	"fmt"
    22  	"os"
    23  	"os/exec"
    24  	"path/filepath"
    25  	"strconv"
    26  	"strings"
    27  	"syscall"
    28  
    29  	"github.com/containerd/log"
    30  )
    31  
    32  func IsRootlessParent() bool {
    33  	return os.Geteuid() != 0
    34  }
    35  
    36  func RootlessKitStateDir() (string, error) {
    37  	if v := os.Getenv("ROOTLESSKIT_STATE_DIR"); v != "" {
    38  		return v, nil
    39  	}
    40  	xdr, err := XDGRuntimeDir()
    41  	if err != nil {
    42  		return "", err
    43  	}
    44  	// "${XDG_RUNTIME_DIR}/containerd-rootless" is hardcoded in containerd-rootless.sh
    45  	stateDir := filepath.Join(xdr, "containerd-rootless")
    46  	if _, err := os.Stat(stateDir); err != nil {
    47  		return "", err
    48  	}
    49  	return stateDir, nil
    50  }
    51  
    52  func RootlessKitChildPid(stateDir string) (int, error) {
    53  	pidFilePath := filepath.Join(stateDir, "child_pid")
    54  	if _, err := os.Stat(pidFilePath); err != nil {
    55  		return 0, err
    56  	}
    57  
    58  	pidFileBytes, err := os.ReadFile(pidFilePath)
    59  	if err != nil {
    60  		return 0, err
    61  	}
    62  	pidStr := strings.TrimSpace(string(pidFileBytes))
    63  	return strconv.Atoi(pidStr)
    64  }
    65  
    66  func ParentMain(hostGatewayIP string) error {
    67  	if !IsRootlessParent() {
    68  		return errors.New("should not be called when !IsRootlessParent()")
    69  	}
    70  	stateDir, err := RootlessKitStateDir()
    71  	log.L.Debugf("stateDir: %s", stateDir)
    72  	if err != nil {
    73  		return fmt.Errorf("rootless containerd not running? (hint: use `containerd-rootless-setuptool.sh install` to start rootless containerd): %w", err)
    74  	}
    75  	childPid, err := RootlessKitChildPid(stateDir)
    76  	if err != nil {
    77  		return err
    78  	}
    79  
    80  	detachedNetNSPath, err := detachedNetNS(stateDir)
    81  	if err != nil {
    82  		return err
    83  	}
    84  	detachNetNSMode := detachedNetNSPath != ""
    85  	log.L.Debugf("RootlessKit detach-netns mode: %v", detachNetNSMode)
    86  
    87  	wd, err := os.Getwd()
    88  	if err != nil {
    89  		return err
    90  	}
    91  
    92  	// FIXME: remove dependency on `nsenter` binary
    93  	arg0, err := exec.LookPath("nsenter")
    94  	if err != nil {
    95  		return err
    96  	}
    97  	// args are compatible with both util-linux nsenter and busybox nsenter
    98  	args := []string{
    99  		"-r/",     // root dir (busybox nsenter wants this to be explicitly specified),
   100  		"-w" + wd, // work dir
   101  		"--preserve-credentials",
   102  		"-m", "-U",
   103  		"-t", strconv.Itoa(childPid),
   104  		"-F", // no fork
   105  	}
   106  	if !detachNetNSMode {
   107  		args = append(args, "-n")
   108  	}
   109  	args = append(args, os.Args...)
   110  	log.L.Debugf("rootless parent main: executing %q with %v", arg0, args)
   111  
   112  	// Env vars corresponds to RootlessKit spec:
   113  	// https://github.com/rootless-containers/rootlesskit/tree/v0.13.1#environment-variables
   114  	os.Setenv("ROOTLESSKIT_STATE_DIR", stateDir)
   115  	os.Setenv("ROOTLESSKIT_PARENT_EUID", strconv.Itoa(os.Geteuid()))
   116  	os.Setenv("ROOTLESSKIT_PARENT_EGID", strconv.Itoa(os.Getegid()))
   117  	os.Setenv("NERDCTL_HOST_GATEWAY_IP", hostGatewayIP)
   118  	return syscall.Exec(arg0, args, os.Environ())
   119  }