File: sysctl_linux.go

package info (click to toggle)
runc 1.3.3%2Bds1-3
  • links: PTS, VCS
  • area: main
  • in suites: experimental
  • size: 3,136 kB
  • sloc: sh: 2,298; ansic: 1,125; makefile: 229
file content (54 lines) | stat: -rw-r--r-- 1,436 bytes parent folder | download | duplicates (2)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
package sys

import (
	"fmt"
	"io"
	"os"
	"strings"

	"golang.org/x/sys/unix"

	"github.com/cyphar/filepath-securejoin/pathrs-lite"
	"github.com/cyphar/filepath-securejoin/pathrs-lite/procfs"
)

func procfsOpenRoot(proc *procfs.Handle, subpath string, flags int) (*os.File, error) {
	handle, err := proc.OpenRoot(subpath)
	if err != nil {
		return nil, err
	}
	defer handle.Close()

	return pathrs.Reopen(handle, flags)
}

// WriteSysctls sets the given sysctls to the requested values.
func WriteSysctls(sysctls map[string]string) error {
	// We are going to write multiple sysctls, which require writing to an
	// unmasked procfs which is not going to be cached. To avoid creating a new
	// procfs instance for each one, just allocate one handle for all of them.
	proc, err := procfs.OpenUnsafeProcRoot()
	if err != nil {
		return err
	}
	defer proc.Close()

	for key, value := range sysctls {
		keyPath := strings.ReplaceAll(key, ".", "/")

		sysctlFile, err := procfsOpenRoot(proc, "sys/"+keyPath, unix.O_WRONLY|unix.O_TRUNC|unix.O_CLOEXEC)
		if err != nil {
			return fmt.Errorf("open sysctl %s file: %w", key, err)
		}
		defer sysctlFile.Close()

		n, err := io.WriteString(sysctlFile, value)
		if n != len(value) && err == nil {
			err = fmt.Errorf("short write to file (%d bytes != %d bytes)", n, len(value))
		}
		if err != nil {
			return fmt.Errorf("failed to write sysctl %s = %q: %w", key, value, err)
		}
	}
	return nil
}