Check that kaniko is being run from inside a container. (#81)
Signed-off-by: dlorenc <dlorenc@google.com>
This commit is contained in:
		
							parent
							
								
									ca57c6cef4
								
							
						
					
					
						commit
						20b659aa32
					
				|  | @ -32,6 +32,22 @@ | ||||||
|   revision = "859166bbd7810e3c3fc072f1c33ad57b9f4acbd0" |   revision = "859166bbd7810e3c3fc072f1c33ad57b9f4acbd0" | ||||||
|   source = "github.com/GoogleCloudPlatform/container-diff" |   source = "github.com/GoogleCloudPlatform/container-diff" | ||||||
| 
 | 
 | ||||||
|  | [[projects]] | ||||||
|  |   branch = "master" | ||||||
|  |   name = "github.com/GoogleCloudPlatform/kaniko" | ||||||
|  |   packages = [ | ||||||
|  |     "executor/cmd", | ||||||
|  |     "kaniko/cmd", | ||||||
|  |     "pkg/commands", | ||||||
|  |     "pkg/constants", | ||||||
|  |     "pkg/dockerfile", | ||||||
|  |     "pkg/image", | ||||||
|  |     "pkg/snapshot", | ||||||
|  |     "pkg/util", | ||||||
|  |     "testutil" | ||||||
|  |   ] | ||||||
|  |   revision = "eb891c1ab9b051260b34f0d2f1a13438fabbd6f5" | ||||||
|  | 
 | ||||||
| [[projects]] | [[projects]] | ||||||
|   name = "github.com/Microsoft/go-winio" |   name = "github.com/Microsoft/go-winio" | ||||||
|   packages = [ |   packages = [ | ||||||
|  | @ -227,6 +243,16 @@ | ||||||
|   packages = ["."] |   packages = ["."] | ||||||
|   revision = "aabc10ec26b754e797f9028f4589c5b7bd90dc20" |   revision = "aabc10ec26b754e797f9028f4589c5b7bd90dc20" | ||||||
| 
 | 
 | ||||||
|  | [[projects]] | ||||||
|  |   name = "github.com/genuinetools/amicontained" | ||||||
|  |   packages = [ | ||||||
|  |     ".", | ||||||
|  |     "container", | ||||||
|  |     "version" | ||||||
|  |   ] | ||||||
|  |   revision = "fcae88544f0212fbb1e20699c41566655b68679b" | ||||||
|  |   version = "v0.4.0" | ||||||
|  | 
 | ||||||
| [[projects]] | [[projects]] | ||||||
|   name = "github.com/ghodss/yaml" |   name = "github.com/ghodss/yaml" | ||||||
|   packages = ["."] |   packages = ["."] | ||||||
|  | @ -423,6 +449,12 @@ | ||||||
|   revision = "583c0c0531f06d5278b7d917446061adc344b5cd" |   revision = "583c0c0531f06d5278b7d917446061adc344b5cd" | ||||||
|   version = "v1.0.1" |   version = "v1.0.1" | ||||||
| 
 | 
 | ||||||
|  | [[projects]] | ||||||
|  |   branch = "master" | ||||||
|  |   name = "github.com/syndtr/gocapability" | ||||||
|  |   packages = ["capability"] | ||||||
|  |   revision = "33e07d32887e1e06b7c025f27ce52f62c7990bc0" | ||||||
|  | 
 | ||||||
| [[projects]] | [[projects]] | ||||||
|   name = "github.com/tchap/go-patricia" |   name = "github.com/tchap/go-patricia" | ||||||
|   packages = ["patricia"] |   packages = ["patricia"] | ||||||
|  | @ -627,6 +659,6 @@ | ||||||
| [solve-meta] | [solve-meta] | ||||||
|   analyzer-name = "dep" |   analyzer-name = "dep" | ||||||
|   analyzer-version = 1 |   analyzer-version = 1 | ||||||
|   inputs-digest = "9d9dcea86069309f0002357a58daae091899741c5c23ec056a37021c560facef" |   inputs-digest = "94d3267001478b2c4cff40adbfb2219ebbca52d2ce8957b178b7ed38ba4ab91a" | ||||||
|   solver-name = "gps-cdcl" |   solver-name = "gps-cdcl" | ||||||
|   solver-version = 1 |   solver-version = 1 | ||||||
|  |  | ||||||
|  | @ -27,3 +27,7 @@ | ||||||
|   name = "github.com/docker/docker" |   name = "github.com/docker/docker" | ||||||
|   revision = "b1a1234c60cf87048814aa37da523b03a7b0d344" |   revision = "b1a1234c60cf87048814aa37da523b03a7b0d344" | ||||||
|   source = "github.com/docker/docker" |   source = "github.com/docker/docker" | ||||||
|  | 
 | ||||||
|  | [[constraint]] | ||||||
|  |   name = "github.com/genuinetools/amicontained" | ||||||
|  |   version = "0.4.0" | ||||||
|  |  | ||||||
|  | @ -18,6 +18,12 @@ package cmd | ||||||
| 
 | 
 | ||||||
| import ( | import ( | ||||||
| 	"fmt" | 	"fmt" | ||||||
|  | 	"io/ioutil" | ||||||
|  | 	"os" | ||||||
|  | 	"path/filepath" | ||||||
|  | 
 | ||||||
|  | 	"github.com/genuinetools/amicontained/container" | ||||||
|  | 
 | ||||||
| 	"github.com/GoogleCloudPlatform/kaniko/pkg/commands" | 	"github.com/GoogleCloudPlatform/kaniko/pkg/commands" | ||||||
| 	"github.com/GoogleCloudPlatform/kaniko/pkg/constants" | 	"github.com/GoogleCloudPlatform/kaniko/pkg/constants" | ||||||
| 	"github.com/GoogleCloudPlatform/kaniko/pkg/dockerfile" | 	"github.com/GoogleCloudPlatform/kaniko/pkg/dockerfile" | ||||||
|  | @ -29,9 +35,6 @@ import ( | ||||||
| 	"github.com/pkg/errors" | 	"github.com/pkg/errors" | ||||||
| 	"github.com/sirupsen/logrus" | 	"github.com/sirupsen/logrus" | ||||||
| 	"github.com/spf13/cobra" | 	"github.com/spf13/cobra" | ||||||
| 	"io/ioutil" |  | ||||||
| 	"os" |  | ||||||
| 	"path/filepath" |  | ||||||
| ) | ) | ||||||
| 
 | 
 | ||||||
| var ( | var ( | ||||||
|  | @ -41,6 +44,7 @@ var ( | ||||||
| 	snapshotMode   string | 	snapshotMode   string | ||||||
| 	bucket         string | 	bucket         string | ||||||
| 	logLevel       string | 	logLevel       string | ||||||
|  | 	force          bool | ||||||
| ) | ) | ||||||
| 
 | 
 | ||||||
| func init() { | func init() { | ||||||
|  | @ -50,6 +54,7 @@ func init() { | ||||||
| 	RootCmd.PersistentFlags().StringVarP(&destination, "destination", "d", "", "Registry the final image should be pushed to (ex: gcr.io/test/example:latest)") | 	RootCmd.PersistentFlags().StringVarP(&destination, "destination", "d", "", "Registry the final image should be pushed to (ex: gcr.io/test/example:latest)") | ||||||
| 	RootCmd.PersistentFlags().StringVarP(&snapshotMode, "snapshotMode", "", "full", "Set this flag to change the file attributes inspected during snapshotting") | 	RootCmd.PersistentFlags().StringVarP(&snapshotMode, "snapshotMode", "", "full", "Set this flag to change the file attributes inspected during snapshotting") | ||||||
| 	RootCmd.PersistentFlags().StringVarP(&logLevel, "verbosity", "v", constants.DefaultLogLevel, "Log level (debug, info, warn, error, fatal, panic") | 	RootCmd.PersistentFlags().StringVarP(&logLevel, "verbosity", "v", constants.DefaultLogLevel, "Log level (debug, info, warn, error, fatal, panic") | ||||||
|  | 	RootCmd.PersistentFlags().BoolVarP(&force, "force", "", false, "Force running outside of a container.") | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| var RootCmd = &cobra.Command{ | var RootCmd = &cobra.Command{ | ||||||
|  | @ -105,7 +110,21 @@ func resolveSourceContext() error { | ||||||
| 	return nil | 	return nil | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | func checkContained() bool { | ||||||
|  | 	_, err := container.DetectRuntime() | ||||||
|  | 	return err == nil | ||||||
|  | } | ||||||
|  | 
 | ||||||
| func execute() error { | func execute() error { | ||||||
|  | 
 | ||||||
|  | 	if !checkContained() { | ||||||
|  | 		if !force { | ||||||
|  | 			logrus.Error("kaniko should only be run inside of a container, run with the --force flag if you are sure you want to continue.") | ||||||
|  | 			return errors.New("kaniko should only be run inside of a container") | ||||||
|  | 		} | ||||||
|  | 		logrus.Warn("kaniko is being run outside of a container. This can have dangerous effects on your system") | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
| 	// Parse dockerfile and unpack base image to root
 | 	// Parse dockerfile and unpack base image to root
 | ||||||
| 	d, err := ioutil.ReadFile(dockerfilePath) | 	d, err := ioutil.ReadFile(dockerfilePath) | ||||||
| 	if err != nil { | 	if err != nil { | ||||||
|  |  | ||||||
|  | @ -18,8 +18,9 @@ package main | ||||||
| 
 | 
 | ||||||
| import ( | import ( | ||||||
| 	"fmt" | 	"fmt" | ||||||
| 	"github.com/GoogleCloudPlatform/kaniko/executor/cmd" |  | ||||||
| 	"os" | 	"os" | ||||||
|  | 
 | ||||||
|  | 	"github.com/GoogleCloudPlatform/kaniko/executor/cmd" | ||||||
| ) | ) | ||||||
| 
 | 
 | ||||||
| func main() { | func main() { | ||||||
|  |  | ||||||
|  | @ -0,0 +1,21 @@ | ||||||
|  | The MIT License (MIT) | ||||||
|  | 
 | ||||||
|  | Copyright (c) 2018 The Genuinetools Authors | ||||||
|  | 
 | ||||||
|  | Permission is hereby granted, free of charge, to any person obtaining a copy | ||||||
|  | of this software and associated documentation files (the "Software"), to deal | ||||||
|  | in the Software without restriction, including without limitation the rights | ||||||
|  | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | ||||||
|  | copies of the Software, and to permit persons to whom the Software is | ||||||
|  | furnished to do so, subject to the following conditions: | ||||||
|  | 
 | ||||||
|  | The above copyright notice and this permission notice shall be included in all | ||||||
|  | copies or substantial portions of the Software. | ||||||
|  | 
 | ||||||
|  | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||||||
|  | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||||||
|  | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | ||||||
|  | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||||||
|  | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | ||||||
|  | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE | ||||||
|  | SOFTWARE. | ||||||
							
								
								
									
										287
									
								
								vendor/github.com/genuinetools/amicontained/container/container.go
								
								
									generated
								
								
									vendored
								
								
									Normal file
								
							
							
						
						
									
										287
									
								
								vendor/github.com/genuinetools/amicontained/container/container.go
								
								
									generated
								
								
									vendored
								
								
									Normal file
								
							|  | @ -0,0 +1,287 @@ | ||||||
|  | // Package container provides tools for introspecting containers.
 | ||||||
|  | package container | ||||||
|  | 
 | ||||||
|  | import ( | ||||||
|  | 	"errors" | ||||||
|  | 	"fmt" | ||||||
|  | 	"io/ioutil" | ||||||
|  | 	"os" | ||||||
|  | 	"strconv" | ||||||
|  | 	"strings" | ||||||
|  | 	"syscall" | ||||||
|  | 
 | ||||||
|  | 	"github.com/syndtr/gocapability/capability" | ||||||
|  | 	"golang.org/x/sys/unix" | ||||||
|  | ) | ||||||
|  | 
 | ||||||
|  | const ( | ||||||
|  | 	// RuntimeDocker is the string for the docker runtime.
 | ||||||
|  | 	RuntimeDocker = "docker" | ||||||
|  | 	// RuntimeRkt is the string for the rkt runtime.
 | ||||||
|  | 	RuntimeRkt = "rkt" | ||||||
|  | 	// RuntimeNspawn is the string for the systemd-nspawn runtime.
 | ||||||
|  | 	RuntimeNspawn = "systemd-nspawn" | ||||||
|  | 	// RuntimeLXC is the string for the lxc runtime.
 | ||||||
|  | 	RuntimeLXC = "lxc" | ||||||
|  | 	// RuntimeLXCLibvirt is the string for the lxc-libvirt runtime.
 | ||||||
|  | 	RuntimeLXCLibvirt = "lxc-libvirt" | ||||||
|  | 	// RuntimeOpenVZ is the string for the openvz runtime.
 | ||||||
|  | 	RuntimeOpenVZ = "openvz" | ||||||
|  | 	// RuntimeKubernetes is the string for the kubernetes runtime.
 | ||||||
|  | 	RuntimeKubernetes = "kube" | ||||||
|  | 	// RuntimeGarden is the string for the garden runtime.
 | ||||||
|  | 	RuntimeGarden = "garden" | ||||||
|  | 
 | ||||||
|  | 	uint32Max = 4294967295 | ||||||
|  | ) | ||||||
|  | 
 | ||||||
|  | var ( | ||||||
|  | 	// ErrContainerRuntimeNotFound describes when a container runtime could not be found.
 | ||||||
|  | 	ErrContainerRuntimeNotFound = errors.New("container runtime could not be found") | ||||||
|  | 
 | ||||||
|  | 	runtimes = []string{RuntimeDocker, RuntimeRkt, RuntimeNspawn, RuntimeLXC, RuntimeLXCLibvirt, RuntimeOpenVZ, RuntimeKubernetes, RuntimeGarden} | ||||||
|  | ) | ||||||
|  | 
 | ||||||
|  | // DetectRuntime returns the container runtime the process is running in.
 | ||||||
|  | func DetectRuntime() (string, error) { | ||||||
|  | 	// read the cgroups file
 | ||||||
|  | 	cgroups := readFile("/proc/self/cgroup") | ||||||
|  | 	if len(cgroups) > 0 { | ||||||
|  | 		for _, runtime := range runtimes { | ||||||
|  | 			if strings.Contains(cgroups, runtime) { | ||||||
|  | 				return runtime, nil | ||||||
|  | 			} | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	// /proc/vz exists in container and outside of the container, /proc/bc only outside of the container.
 | ||||||
|  | 	if fileExists("/proc/vz") && !fileExists("/proc/bc") { | ||||||
|  | 		return RuntimeOpenVZ, nil | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	ctrenv := os.Getenv("container") | ||||||
|  | 	if ctrenv != "" { | ||||||
|  | 		for _, runtime := range runtimes { | ||||||
|  | 			if ctrenv == runtime { | ||||||
|  | 				return runtime, nil | ||||||
|  | 			} | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	// PID 1 might have dropped this information into a file in /run.
 | ||||||
|  | 	// Read from /run/systemd/container since it is better than accessing /proc/1/environ,
 | ||||||
|  | 	// which needs CAP_SYS_PTRACE
 | ||||||
|  | 	f := readFile("/run/systemd/container") | ||||||
|  | 	if len(f) > 0 { | ||||||
|  | 		for _, runtime := range runtimes { | ||||||
|  | 			if f == runtime { | ||||||
|  | 				return runtime, nil | ||||||
|  | 			} | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	return "not-found", ErrContainerRuntimeNotFound | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | // HasNamespace determines if the container is using a particular namespace or the
 | ||||||
|  | // host namespace.
 | ||||||
|  | // The device number of an unnamespaced /proc/1/ns/{ns} is 4 and anything else is
 | ||||||
|  | // higher.
 | ||||||
|  | func HasNamespace(ns string) (bool, error) { | ||||||
|  | 	file := fmt.Sprintf("/proc/1/ns/%s", ns) | ||||||
|  | 
 | ||||||
|  | 	// Use Lstat to not follow the symlink.
 | ||||||
|  | 	var info syscall.Stat_t | ||||||
|  | 	if err := syscall.Lstat(file, &info); err != nil { | ||||||
|  | 		return false, &os.PathError{Op: "lstat", Path: file, Err: err} | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	// Get the device number. If it is higher than 4 it is in a namespace.
 | ||||||
|  | 	if info.Dev > 4 { | ||||||
|  | 		return true, nil | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	return false, nil | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | // AppArmorProfile determines the apparmor profile for a container.
 | ||||||
|  | func AppArmorProfile() string { | ||||||
|  | 	f := readFile("/proc/self/attr/current") | ||||||
|  | 	if f == "" { | ||||||
|  | 		return "none" | ||||||
|  | 	} | ||||||
|  | 	return f | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | // UserMapping holds the values for a {uid,gid}_map.
 | ||||||
|  | type UserMapping struct { | ||||||
|  | 	ContainerID int64 | ||||||
|  | 	HostID      int64 | ||||||
|  | 	Range       int64 | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | // UserNamespace determines if the container is running in a UserNamespace and returns the mappings if so.
 | ||||||
|  | func UserNamespace() (bool, []UserMapping) { | ||||||
|  | 	f := readFile("/proc/self/uid_map") | ||||||
|  | 	if len(f) < 0 { | ||||||
|  | 		// user namespace is uninitialized
 | ||||||
|  | 		return true, nil | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	userNs, mappings, err := readUserMappings(f) | ||||||
|  | 	if err != nil { | ||||||
|  | 		return false, nil | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	return userNs, mappings | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | func readUserMappings(f string) (iuserNS bool, mappings []UserMapping, err error) { | ||||||
|  | 	parts := strings.Split(f, " ") | ||||||
|  | 	parts = deleteEmpty(parts) | ||||||
|  | 	if len(parts) < 3 { | ||||||
|  | 		return false, nil, nil | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	for i := 0; i < len(parts); i += 3 { | ||||||
|  | 		nsu, hu, r := parts[i], parts[i+1], parts[i+2] | ||||||
|  | 		mapping := UserMapping{} | ||||||
|  | 
 | ||||||
|  | 		mapping.ContainerID, err = strconv.ParseInt(nsu, 10, 0) | ||||||
|  | 		if err != nil { | ||||||
|  | 			return false, nil, nil | ||||||
|  | 		} | ||||||
|  | 		mapping.HostID, err = strconv.ParseInt(hu, 10, 0) | ||||||
|  | 		if err != nil { | ||||||
|  | 			return false, nil, nil | ||||||
|  | 		} | ||||||
|  | 		mapping.Range, err = strconv.ParseInt(r, 10, 0) | ||||||
|  | 		if err != nil { | ||||||
|  | 			return false, nil, nil | ||||||
|  | 		} | ||||||
|  | 
 | ||||||
|  | 		if mapping.ContainerID == 0 && mapping.HostID == 0 && mapping.Range == uint32Max { | ||||||
|  | 			return false, nil, nil | ||||||
|  | 		} | ||||||
|  | 
 | ||||||
|  | 		mappings = append(mappings, mapping) | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	return true, mappings, nil | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | // Capabilities returns the allowed capabilities in the container.
 | ||||||
|  | func Capabilities() (map[string][]string, error) { | ||||||
|  | 	allCaps := capability.List() | ||||||
|  | 
 | ||||||
|  | 	caps, err := capability.NewPid(0) | ||||||
|  | 	if err != nil { | ||||||
|  | 		return nil, err | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	allowedCaps := map[string][]string{} | ||||||
|  | 	allowedCaps["EFFECTIVE | PERMITTED | INHERITABLE"] = []string{} | ||||||
|  | 	allowedCaps["BOUNDING"] = []string{} | ||||||
|  | 	allowedCaps["AMBIENT"] = []string{} | ||||||
|  | 
 | ||||||
|  | 	for _, cap := range allCaps { | ||||||
|  | 		if caps.Get(capability.CAPS, cap) { | ||||||
|  | 			allowedCaps["EFFECTIVE | PERMITTED | INHERITABLE"] = append(allowedCaps["EFFECTIVE | PERMITTED | INHERITABLE"], cap.String()) | ||||||
|  | 		} | ||||||
|  | 		if caps.Get(capability.BOUNDING, cap) { | ||||||
|  | 			allowedCaps["BOUNDING"] = append(allowedCaps["BOUNDING"], cap.String()) | ||||||
|  | 		} | ||||||
|  | 		if caps.Get(capability.AMBIENT, cap) { | ||||||
|  | 			allowedCaps["AMBIENT"] = append(allowedCaps["AMBIENT"], cap.String()) | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	return allowedCaps, nil | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | // Chroot detects if we are running in a chroot or a pivot_root.
 | ||||||
|  | // Currently, we can not distinguish between the two.
 | ||||||
|  | func Chroot() (bool, error) { | ||||||
|  | 	var a, b syscall.Stat_t | ||||||
|  | 
 | ||||||
|  | 	if err := syscall.Lstat("/proc/1/root", &a); err != nil { | ||||||
|  | 		return false, err | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	if err := syscall.Lstat("/", &b); err != nil { | ||||||
|  | 		return false, err | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	return a.Ino == b.Ino && a.Dev == b.Dev, nil | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | // SeccompEnforcingMode returns the seccomp enforcing level (disabled, filtering, strict)
 | ||||||
|  | func SeccompEnforcingMode() (string, error) { | ||||||
|  | 	// Read from /proc/self/status Linux 3.8+
 | ||||||
|  | 	s := readFile("/proc/self/status") | ||||||
|  | 
 | ||||||
|  | 	// Pre linux 3.8
 | ||||||
|  | 	if !strings.Contains(s, "Seccomp") { | ||||||
|  | 		// Check if Seccomp is supported, via CONFIG_SECCOMP.
 | ||||||
|  | 		if err := unix.Prctl(unix.PR_GET_SECCOMP, 0, 0, 0, 0); err != unix.EINVAL { | ||||||
|  | 			// Make sure the kernel has CONFIG_SECCOMP_FILTER.
 | ||||||
|  | 			if err := unix.Prctl(unix.PR_SET_SECCOMP, unix.SECCOMP_MODE_FILTER, 0, 0, 0); err != unix.EINVAL { | ||||||
|  | 				return "strict", nil | ||||||
|  | 			} | ||||||
|  | 		} | ||||||
|  | 		return "disabled", nil | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	// Split status file string by line
 | ||||||
|  | 	statusMappings := strings.Split(s, "\n") | ||||||
|  | 	statusMappings = deleteEmpty(statusMappings) | ||||||
|  | 
 | ||||||
|  | 	mode := "-1" | ||||||
|  | 	for _, line := range statusMappings { | ||||||
|  | 		if strings.Contains(line, "Seccomp:") { | ||||||
|  | 			mode = string(line[len(line)-1]) | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	seccompModes := map[string]string{ | ||||||
|  | 		"0": "disabled", | ||||||
|  | 		"1": "strict", | ||||||
|  | 		"2": "filtering", | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	seccompMode, ok := seccompModes[mode] | ||||||
|  | 	if !ok { | ||||||
|  | 		return "", errors.New("could not retrieve seccomp filtering status") | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	return seccompMode, nil | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | func fileExists(file string) bool { | ||||||
|  | 	if _, err := os.Stat(file); !os.IsNotExist(err) { | ||||||
|  | 		return true | ||||||
|  | 	} | ||||||
|  | 	return false | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | func readFile(file string) string { | ||||||
|  | 	if !fileExists(file) { | ||||||
|  | 		return "" | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	b, err := ioutil.ReadFile(file) | ||||||
|  | 	if err != nil { | ||||||
|  | 		return "" | ||||||
|  | 	} | ||||||
|  | 	return strings.TrimSpace(string(b)) | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | func deleteEmpty(s []string) []string { | ||||||
|  | 	var r []string | ||||||
|  | 	for _, str := range s { | ||||||
|  | 		if strings.TrimSpace(str) != "" { | ||||||
|  | 			r = append(r, strings.TrimSpace(str)) | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | 	return r | ||||||
|  | } | ||||||
|  | @ -0,0 +1,145 @@ | ||||||
|  | package main | ||||||
|  | 
 | ||||||
|  | import ( | ||||||
|  | 	"flag" | ||||||
|  | 	"fmt" | ||||||
|  | 	"log" | ||||||
|  | 	"os" | ||||||
|  | 	"strings" | ||||||
|  | 
 | ||||||
|  | 	"github.com/genuinetools/amicontained/container" | ||||||
|  | 	"github.com/genuinetools/amicontained/version" | ||||||
|  | 	"github.com/sirupsen/logrus" | ||||||
|  | ) | ||||||
|  | 
 | ||||||
|  | const ( | ||||||
|  | 	// BANNER is what is printed for help/info output
 | ||||||
|  | 	BANNER = `                 _                 _        _                _ | ||||||
|  |   __ _ _ __ ___ (_) ___ ___  _ __ | |_ __ _(_)_ __   ___  __| | | ||||||
|  |  / _` + "`" + ` | '_ ` + "`" + ` _ \| |/ __/ _ \| '_ \| __/ _` + "`" + ` | | '_ \ / _ \/ _` + "`" + ` | | ||||||
|  | | (_| | | | | | | | (_| (_) | | | | || (_| | | | | |  __/ (_| | | ||||||
|  |  \__,_|_| |_| |_|_|\___\___/|_| |_|\__\__,_|_|_| |_|\___|\__,_| | ||||||
|  |  Container introspection tool. | ||||||
|  |  Version: %s | ||||||
|  | 
 | ||||||
|  | ` | ||||||
|  | ) | ||||||
|  | 
 | ||||||
|  | var ( | ||||||
|  | 	debug bool | ||||||
|  | 	vrsn  bool | ||||||
|  | ) | ||||||
|  | 
 | ||||||
|  | func init() { | ||||||
|  | 	// parse flags
 | ||||||
|  | 	flag.BoolVar(&vrsn, "version", false, "print version and exit") | ||||||
|  | 	flag.BoolVar(&vrsn, "v", false, "print version and exit (shorthand)") | ||||||
|  | 	flag.BoolVar(&debug, "d", false, "run in debug mode") | ||||||
|  | 
 | ||||||
|  | 	flag.Usage = func() { | ||||||
|  | 		fmt.Fprint(os.Stderr, fmt.Sprintf(BANNER, version.VERSION)) | ||||||
|  | 		flag.PrintDefaults() | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	flag.Parse() | ||||||
|  | 
 | ||||||
|  | 	// set log level
 | ||||||
|  | 	if debug { | ||||||
|  | 		logrus.SetLevel(logrus.DebugLevel) | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	if vrsn { | ||||||
|  | 		fmt.Printf("amicontained version %s, build %s\n", version.VERSION, version.GITCOMMIT) | ||||||
|  | 		os.Exit(0) | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	if flag.NArg() < 1 { | ||||||
|  | 		return | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	// parse the arg
 | ||||||
|  | 	arg := flag.Args()[0] | ||||||
|  | 
 | ||||||
|  | 	if arg == "help" { | ||||||
|  | 		usageAndExit("", 0) | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	if arg == "version" { | ||||||
|  | 		fmt.Printf("amicontained version %s, build %s\n", version.VERSION, version.GITCOMMIT) | ||||||
|  | 		os.Exit(0) | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | func main() { | ||||||
|  | 	// Container Runtime
 | ||||||
|  | 	runtime, err := container.DetectRuntime() | ||||||
|  | 	if err != nil && err != container.ErrContainerRuntimeNotFound { | ||||||
|  | 		log.Fatal(err) | ||||||
|  | 		return | ||||||
|  | 	} | ||||||
|  | 	fmt.Printf("Container Runtime: %s\n", runtime) | ||||||
|  | 
 | ||||||
|  | 	// Namespaces
 | ||||||
|  | 	namespaces := []string{"pid"} | ||||||
|  | 	fmt.Println("Has Namespaces:") | ||||||
|  | 	for _, namespace := range namespaces { | ||||||
|  | 		ns, err := container.HasNamespace(namespace) | ||||||
|  | 		if err != nil { | ||||||
|  | 			fmt.Printf("\t%s: error -> %v\n", namespace, err) | ||||||
|  | 			continue | ||||||
|  | 		} | ||||||
|  | 		fmt.Printf("\t%s: %t\n", namespace, ns) | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	// User Namespaces
 | ||||||
|  | 	userNS, userMappings := container.UserNamespace() | ||||||
|  | 	fmt.Printf("\tuser: %t\n", userNS) | ||||||
|  | 	if len(userMappings) > 0 { | ||||||
|  | 		fmt.Println("User Namespace Mappings:") | ||||||
|  | 		for _, userMapping := range userMappings { | ||||||
|  | 			fmt.Printf("\tContainer -> %d\tHost -> %d\tRange -> %d\n", userMapping.ContainerID, userMapping.HostID, userMapping.Range) | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	// AppArmor Profile
 | ||||||
|  | 	aaprof := container.AppArmorProfile() | ||||||
|  | 	fmt.Printf("AppArmor Profile: %s\n", aaprof) | ||||||
|  | 
 | ||||||
|  | 	// Capabilities
 | ||||||
|  | 	caps, err := container.Capabilities() | ||||||
|  | 	if err != nil { | ||||||
|  | 		logrus.Warnf("getting capabilities failed: %v", err) | ||||||
|  | 	} | ||||||
|  | 	if len(caps) > 0 { | ||||||
|  | 		fmt.Println("Capabilities:") | ||||||
|  | 		for k, v := range caps { | ||||||
|  | 			if len(v) > 0 { | ||||||
|  | 				fmt.Printf("\t%s -> %s\n", k, strings.Join(v, " ")) | ||||||
|  | 			} | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	// Chroot
 | ||||||
|  | 	chroot, err := container.Chroot() | ||||||
|  | 	if err != nil { | ||||||
|  | 		logrus.Debugf("chroot check error: %v", err) | ||||||
|  | 	} | ||||||
|  | 	fmt.Printf("Chroot (not pivot_root): %t\n", chroot) | ||||||
|  | 
 | ||||||
|  | 	// Seccomp
 | ||||||
|  | 	seccompMode, err := container.SeccompEnforcingMode() | ||||||
|  | 	if err != nil { | ||||||
|  | 		logrus.Debugf("error: %v", err) | ||||||
|  | 	} | ||||||
|  | 	fmt.Printf("Seccomp: %s\n", seccompMode) | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | func usageAndExit(message string, exitCode int) { | ||||||
|  | 	if message != "" { | ||||||
|  | 		fmt.Fprintf(os.Stderr, message) | ||||||
|  | 		fmt.Fprintf(os.Stderr, "\n\n") | ||||||
|  | 	} | ||||||
|  | 	flag.Usage() | ||||||
|  | 	fmt.Fprintf(os.Stderr, "\n") | ||||||
|  | 	os.Exit(exitCode) | ||||||
|  | } | ||||||
|  | @ -0,0 +1,7 @@ | ||||||
|  | package version | ||||||
|  | 
 | ||||||
|  | // VERSION indicates which version of the binary is running.
 | ||||||
|  | var VERSION string | ||||||
|  | 
 | ||||||
|  | // GITCOMMIT indicates which git hash the binary was built off of
 | ||||||
|  | var GITCOMMIT string | ||||||
|  | @ -0,0 +1,24 @@ | ||||||
|  | Copyright 2013 Suryandaru Triandana <syndtr@gmail.com> | ||||||
|  | All rights reserved. | ||||||
|  | 
 | ||||||
|  | Redistribution and use in source and binary forms, with or without | ||||||
|  | modification, are permitted provided that the following conditions are | ||||||
|  | met: | ||||||
|  | 
 | ||||||
|  |     * Redistributions of source code must retain the above copyright | ||||||
|  | notice, this list of conditions and the following disclaimer. | ||||||
|  |     * Redistributions in binary form must reproduce the above copyright | ||||||
|  | notice, this list of conditions and the following disclaimer in the | ||||||
|  | documentation and/or other materials provided with the distribution. | ||||||
|  | 
 | ||||||
|  | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS | ||||||
|  | "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT | ||||||
|  | LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR | ||||||
|  | A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT | ||||||
|  | HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, | ||||||
|  | SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT | ||||||
|  | LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, | ||||||
|  | DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY | ||||||
|  | THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | ||||||
|  | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE | ||||||
|  | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | ||||||
|  | @ -0,0 +1,133 @@ | ||||||
|  | // Copyright (c) 2013, Suryandaru Triandana <syndtr@gmail.com>
 | ||||||
|  | // All rights reserved.
 | ||||||
|  | //
 | ||||||
|  | // Use of this source code is governed by a BSD-style license that can be
 | ||||||
|  | // found in the LICENSE file.
 | ||||||
|  | 
 | ||||||
|  | // Package capability provides utilities for manipulating POSIX capabilities.
 | ||||||
|  | package capability | ||||||
|  | 
 | ||||||
|  | type Capabilities interface { | ||||||
|  | 	// Get check whether a capability present in the given
 | ||||||
|  | 	// capabilities set. The 'which' value should be one of EFFECTIVE,
 | ||||||
|  | 	// PERMITTED, INHERITABLE, BOUNDING or AMBIENT.
 | ||||||
|  | 	Get(which CapType, what Cap) bool | ||||||
|  | 
 | ||||||
|  | 	// Empty check whether all capability bits of the given capabilities
 | ||||||
|  | 	// set are zero. The 'which' value should be one of EFFECTIVE,
 | ||||||
|  | 	// PERMITTED, INHERITABLE, BOUNDING or AMBIENT.
 | ||||||
|  | 	Empty(which CapType) bool | ||||||
|  | 
 | ||||||
|  | 	// Full check whether all capability bits of the given capabilities
 | ||||||
|  | 	// set are one. The 'which' value should be one of EFFECTIVE,
 | ||||||
|  | 	// PERMITTED, INHERITABLE, BOUNDING or AMBIENT.
 | ||||||
|  | 	Full(which CapType) bool | ||||||
|  | 
 | ||||||
|  | 	// Set sets capabilities of the given capabilities sets. The
 | ||||||
|  | 	// 'which' value should be one or combination (OR'ed) of EFFECTIVE,
 | ||||||
|  | 	// PERMITTED, INHERITABLE, BOUNDING or AMBIENT.
 | ||||||
|  | 	Set(which CapType, caps ...Cap) | ||||||
|  | 
 | ||||||
|  | 	// Unset unsets capabilities of the given capabilities sets. The
 | ||||||
|  | 	// 'which' value should be one or combination (OR'ed) of EFFECTIVE,
 | ||||||
|  | 	// PERMITTED, INHERITABLE, BOUNDING or AMBIENT.
 | ||||||
|  | 	Unset(which CapType, caps ...Cap) | ||||||
|  | 
 | ||||||
|  | 	// Fill sets all bits of the given capabilities kind to one. The
 | ||||||
|  | 	// 'kind' value should be one or combination (OR'ed) of CAPS,
 | ||||||
|  | 	// BOUNDS or AMBS.
 | ||||||
|  | 	Fill(kind CapType) | ||||||
|  | 
 | ||||||
|  | 	// Clear sets all bits of the given capabilities kind to zero. The
 | ||||||
|  | 	// 'kind' value should be one or combination (OR'ed) of CAPS,
 | ||||||
|  | 	// BOUNDS or AMBS.
 | ||||||
|  | 	Clear(kind CapType) | ||||||
|  | 
 | ||||||
|  | 	// String return current capabilities state of the given capabilities
 | ||||||
|  | 	// set as string. The 'which' value should be one of EFFECTIVE,
 | ||||||
|  | 	// PERMITTED, INHERITABLE BOUNDING or AMBIENT
 | ||||||
|  | 	StringCap(which CapType) string | ||||||
|  | 
 | ||||||
|  | 	// String return current capabilities state as string.
 | ||||||
|  | 	String() string | ||||||
|  | 
 | ||||||
|  | 	// Load load actual capabilities value. This will overwrite all
 | ||||||
|  | 	// outstanding changes.
 | ||||||
|  | 	Load() error | ||||||
|  | 
 | ||||||
|  | 	// Apply apply the capabilities settings, so all changes will take
 | ||||||
|  | 	// effect.
 | ||||||
|  | 	Apply(kind CapType) error | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | // NewPid initializes a new Capabilities object for given pid when
 | ||||||
|  | // it is nonzero, or for the current process if pid is 0.
 | ||||||
|  | //
 | ||||||
|  | // Deprecated: Replace with NewPid2.  For example, replace:
 | ||||||
|  | //
 | ||||||
|  | //    c, err := NewPid(0)
 | ||||||
|  | //    if err != nil {
 | ||||||
|  | //      return err
 | ||||||
|  | //    }
 | ||||||
|  | //
 | ||||||
|  | // with:
 | ||||||
|  | //
 | ||||||
|  | //    c, err := NewPid2(0)
 | ||||||
|  | //    if err != nil {
 | ||||||
|  | //      return err
 | ||||||
|  | //    }
 | ||||||
|  | //    err = c.Load()
 | ||||||
|  | //    if err != nil {
 | ||||||
|  | //      return err
 | ||||||
|  | //    }
 | ||||||
|  | func NewPid(pid int) (Capabilities, error) { | ||||||
|  | 	c, err := newPid(pid) | ||||||
|  | 	if err != nil { | ||||||
|  | 		return c, err | ||||||
|  | 	} | ||||||
|  | 	err = c.Load() | ||||||
|  | 	return c, err | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | // NewPid2 initializes a new Capabilities object for given pid when
 | ||||||
|  | // it is nonzero, or for the current process if pid is 0.  This
 | ||||||
|  | // does not load the process's current capabilities; to do that you
 | ||||||
|  | // must call Load explicitly.
 | ||||||
|  | func NewPid2(pid int) (Capabilities, error) { | ||||||
|  | 	return newPid(pid) | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | // NewFile initializes a new Capabilities object for given file path.
 | ||||||
|  | //
 | ||||||
|  | // Deprecated: Replace with NewFile2.  For example, replace:
 | ||||||
|  | //
 | ||||||
|  | //    c, err := NewFile(path)
 | ||||||
|  | //    if err != nil {
 | ||||||
|  | //      return err
 | ||||||
|  | //    }
 | ||||||
|  | //
 | ||||||
|  | // with:
 | ||||||
|  | //
 | ||||||
|  | //    c, err := NewFile2(path)
 | ||||||
|  | //    if err != nil {
 | ||||||
|  | //      return err
 | ||||||
|  | //    }
 | ||||||
|  | //    err = c.Load()
 | ||||||
|  | //    if err != nil {
 | ||||||
|  | //      return err
 | ||||||
|  | //    }
 | ||||||
|  | func NewFile(path string) (Capabilities, error) { | ||||||
|  | 	c, err := newFile(path) | ||||||
|  | 	if err != nil { | ||||||
|  | 		return c, err | ||||||
|  | 	} | ||||||
|  | 	err = c.Load() | ||||||
|  | 	return c, err | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | // NewFile2 creates a new initialized Capabilities object for given
 | ||||||
|  | // file path.  This does not load the process's current capabilities;
 | ||||||
|  | // to do that you must call Load explicitly.
 | ||||||
|  | func NewFile2(path string) (Capabilities, error) { | ||||||
|  | 	return newFile(path) | ||||||
|  | } | ||||||
							
								
								
									
										642
									
								
								vendor/github.com/syndtr/gocapability/capability/capability_linux.go
								
								
									generated
								
								
									vendored
								
								
									Normal file
								
							
							
						
						
									
										642
									
								
								vendor/github.com/syndtr/gocapability/capability/capability_linux.go
								
								
									generated
								
								
									vendored
								
								
									Normal file
								
							|  | @ -0,0 +1,642 @@ | ||||||
|  | // Copyright (c) 2013, Suryandaru Triandana <syndtr@gmail.com>
 | ||||||
|  | // All rights reserved.
 | ||||||
|  | //
 | ||||||
|  | // Use of this source code is governed by a BSD-style license that can be
 | ||||||
|  | // found in the LICENSE file.
 | ||||||
|  | 
 | ||||||
|  | package capability | ||||||
|  | 
 | ||||||
|  | import ( | ||||||
|  | 	"bufio" | ||||||
|  | 	"errors" | ||||||
|  | 	"fmt" | ||||||
|  | 	"io" | ||||||
|  | 	"os" | ||||||
|  | 	"strings" | ||||||
|  | 	"syscall" | ||||||
|  | ) | ||||||
|  | 
 | ||||||
|  | var errUnknownVers = errors.New("unknown capability version") | ||||||
|  | 
 | ||||||
|  | const ( | ||||||
|  | 	linuxCapVer1 = 0x19980330 | ||||||
|  | 	linuxCapVer2 = 0x20071026 | ||||||
|  | 	linuxCapVer3 = 0x20080522 | ||||||
|  | ) | ||||||
|  | 
 | ||||||
|  | var ( | ||||||
|  | 	capVers    uint32 | ||||||
|  | 	capLastCap Cap | ||||||
|  | ) | ||||||
|  | 
 | ||||||
|  | func init() { | ||||||
|  | 	var hdr capHeader | ||||||
|  | 	capget(&hdr, nil) | ||||||
|  | 	capVers = hdr.version | ||||||
|  | 
 | ||||||
|  | 	if initLastCap() == nil { | ||||||
|  | 		CAP_LAST_CAP = capLastCap | ||||||
|  | 		if capLastCap > 31 { | ||||||
|  | 			capUpperMask = (uint32(1) << (uint(capLastCap) - 31)) - 1 | ||||||
|  | 		} else { | ||||||
|  | 			capUpperMask = 0 | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | func initLastCap() error { | ||||||
|  | 	if capLastCap != 0 { | ||||||
|  | 		return nil | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	f, err := os.Open("/proc/sys/kernel/cap_last_cap") | ||||||
|  | 	if err != nil { | ||||||
|  | 		return err | ||||||
|  | 	} | ||||||
|  | 	defer f.Close() | ||||||
|  | 
 | ||||||
|  | 	var b []byte = make([]byte, 11) | ||||||
|  | 	_, err = f.Read(b) | ||||||
|  | 	if err != nil { | ||||||
|  | 		return err | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	fmt.Sscanf(string(b), "%d", &capLastCap) | ||||||
|  | 
 | ||||||
|  | 	return nil | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | func mkStringCap(c Capabilities, which CapType) (ret string) { | ||||||
|  | 	for i, first := Cap(0), true; i <= CAP_LAST_CAP; i++ { | ||||||
|  | 		if !c.Get(which, i) { | ||||||
|  | 			continue | ||||||
|  | 		} | ||||||
|  | 		if first { | ||||||
|  | 			first = false | ||||||
|  | 		} else { | ||||||
|  | 			ret += ", " | ||||||
|  | 		} | ||||||
|  | 		ret += i.String() | ||||||
|  | 	} | ||||||
|  | 	return | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | func mkString(c Capabilities, max CapType) (ret string) { | ||||||
|  | 	ret = "{" | ||||||
|  | 	for i := CapType(1); i <= max; i <<= 1 { | ||||||
|  | 		ret += " " + i.String() + "=\"" | ||||||
|  | 		if c.Empty(i) { | ||||||
|  | 			ret += "empty" | ||||||
|  | 		} else if c.Full(i) { | ||||||
|  | 			ret += "full" | ||||||
|  | 		} else { | ||||||
|  | 			ret += c.StringCap(i) | ||||||
|  | 		} | ||||||
|  | 		ret += "\"" | ||||||
|  | 	} | ||||||
|  | 	ret += " }" | ||||||
|  | 	return | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | func newPid(pid int) (c Capabilities, err error) { | ||||||
|  | 	switch capVers { | ||||||
|  | 	case linuxCapVer1: | ||||||
|  | 		p := new(capsV1) | ||||||
|  | 		p.hdr.version = capVers | ||||||
|  | 		p.hdr.pid = pid | ||||||
|  | 		c = p | ||||||
|  | 	case linuxCapVer2, linuxCapVer3: | ||||||
|  | 		p := new(capsV3) | ||||||
|  | 		p.hdr.version = capVers | ||||||
|  | 		p.hdr.pid = pid | ||||||
|  | 		c = p | ||||||
|  | 	default: | ||||||
|  | 		err = errUnknownVers | ||||||
|  | 		return | ||||||
|  | 	} | ||||||
|  | 	return | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | type capsV1 struct { | ||||||
|  | 	hdr  capHeader | ||||||
|  | 	data capData | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | func (c *capsV1) Get(which CapType, what Cap) bool { | ||||||
|  | 	if what > 32 { | ||||||
|  | 		return false | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	switch which { | ||||||
|  | 	case EFFECTIVE: | ||||||
|  | 		return (1<<uint(what))&c.data.effective != 0 | ||||||
|  | 	case PERMITTED: | ||||||
|  | 		return (1<<uint(what))&c.data.permitted != 0 | ||||||
|  | 	case INHERITABLE: | ||||||
|  | 		return (1<<uint(what))&c.data.inheritable != 0 | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	return false | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | func (c *capsV1) getData(which CapType) (ret uint32) { | ||||||
|  | 	switch which { | ||||||
|  | 	case EFFECTIVE: | ||||||
|  | 		ret = c.data.effective | ||||||
|  | 	case PERMITTED: | ||||||
|  | 		ret = c.data.permitted | ||||||
|  | 	case INHERITABLE: | ||||||
|  | 		ret = c.data.inheritable | ||||||
|  | 	} | ||||||
|  | 	return | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | func (c *capsV1) Empty(which CapType) bool { | ||||||
|  | 	return c.getData(which) == 0 | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | func (c *capsV1) Full(which CapType) bool { | ||||||
|  | 	return (c.getData(which) & 0x7fffffff) == 0x7fffffff | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | func (c *capsV1) Set(which CapType, caps ...Cap) { | ||||||
|  | 	for _, what := range caps { | ||||||
|  | 		if what > 32 { | ||||||
|  | 			continue | ||||||
|  | 		} | ||||||
|  | 
 | ||||||
|  | 		if which&EFFECTIVE != 0 { | ||||||
|  | 			c.data.effective |= 1 << uint(what) | ||||||
|  | 		} | ||||||
|  | 		if which&PERMITTED != 0 { | ||||||
|  | 			c.data.permitted |= 1 << uint(what) | ||||||
|  | 		} | ||||||
|  | 		if which&INHERITABLE != 0 { | ||||||
|  | 			c.data.inheritable |= 1 << uint(what) | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | func (c *capsV1) Unset(which CapType, caps ...Cap) { | ||||||
|  | 	for _, what := range caps { | ||||||
|  | 		if what > 32 { | ||||||
|  | 			continue | ||||||
|  | 		} | ||||||
|  | 
 | ||||||
|  | 		if which&EFFECTIVE != 0 { | ||||||
|  | 			c.data.effective &= ^(1 << uint(what)) | ||||||
|  | 		} | ||||||
|  | 		if which&PERMITTED != 0 { | ||||||
|  | 			c.data.permitted &= ^(1 << uint(what)) | ||||||
|  | 		} | ||||||
|  | 		if which&INHERITABLE != 0 { | ||||||
|  | 			c.data.inheritable &= ^(1 << uint(what)) | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | func (c *capsV1) Fill(kind CapType) { | ||||||
|  | 	if kind&CAPS == CAPS { | ||||||
|  | 		c.data.effective = 0x7fffffff | ||||||
|  | 		c.data.permitted = 0x7fffffff | ||||||
|  | 		c.data.inheritable = 0 | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | func (c *capsV1) Clear(kind CapType) { | ||||||
|  | 	if kind&CAPS == CAPS { | ||||||
|  | 		c.data.effective = 0 | ||||||
|  | 		c.data.permitted = 0 | ||||||
|  | 		c.data.inheritable = 0 | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | func (c *capsV1) StringCap(which CapType) (ret string) { | ||||||
|  | 	return mkStringCap(c, which) | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | func (c *capsV1) String() (ret string) { | ||||||
|  | 	return mkString(c, BOUNDING) | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | func (c *capsV1) Load() (err error) { | ||||||
|  | 	return capget(&c.hdr, &c.data) | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | func (c *capsV1) Apply(kind CapType) error { | ||||||
|  | 	if kind&CAPS == CAPS { | ||||||
|  | 		return capset(&c.hdr, &c.data) | ||||||
|  | 	} | ||||||
|  | 	return nil | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | type capsV3 struct { | ||||||
|  | 	hdr     capHeader | ||||||
|  | 	data    [2]capData | ||||||
|  | 	bounds  [2]uint32 | ||||||
|  | 	ambient [2]uint32 | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | func (c *capsV3) Get(which CapType, what Cap) bool { | ||||||
|  | 	var i uint | ||||||
|  | 	if what > 31 { | ||||||
|  | 		i = uint(what) >> 5 | ||||||
|  | 		what %= 32 | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	switch which { | ||||||
|  | 	case EFFECTIVE: | ||||||
|  | 		return (1<<uint(what))&c.data[i].effective != 0 | ||||||
|  | 	case PERMITTED: | ||||||
|  | 		return (1<<uint(what))&c.data[i].permitted != 0 | ||||||
|  | 	case INHERITABLE: | ||||||
|  | 		return (1<<uint(what))&c.data[i].inheritable != 0 | ||||||
|  | 	case BOUNDING: | ||||||
|  | 		return (1<<uint(what))&c.bounds[i] != 0 | ||||||
|  | 	case AMBIENT: | ||||||
|  | 		return (1<<uint(what))&c.ambient[i] != 0 | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	return false | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | func (c *capsV3) getData(which CapType, dest []uint32) { | ||||||
|  | 	switch which { | ||||||
|  | 	case EFFECTIVE: | ||||||
|  | 		dest[0] = c.data[0].effective | ||||||
|  | 		dest[1] = c.data[1].effective | ||||||
|  | 	case PERMITTED: | ||||||
|  | 		dest[0] = c.data[0].permitted | ||||||
|  | 		dest[1] = c.data[1].permitted | ||||||
|  | 	case INHERITABLE: | ||||||
|  | 		dest[0] = c.data[0].inheritable | ||||||
|  | 		dest[1] = c.data[1].inheritable | ||||||
|  | 	case BOUNDING: | ||||||
|  | 		dest[0] = c.bounds[0] | ||||||
|  | 		dest[1] = c.bounds[1] | ||||||
|  | 	case AMBIENT: | ||||||
|  | 		dest[0] = c.ambient[0] | ||||||
|  | 		dest[1] = c.ambient[1] | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | func (c *capsV3) Empty(which CapType) bool { | ||||||
|  | 	var data [2]uint32 | ||||||
|  | 	c.getData(which, data[:]) | ||||||
|  | 	return data[0] == 0 && data[1] == 0 | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | func (c *capsV3) Full(which CapType) bool { | ||||||
|  | 	var data [2]uint32 | ||||||
|  | 	c.getData(which, data[:]) | ||||||
|  | 	if (data[0] & 0xffffffff) != 0xffffffff { | ||||||
|  | 		return false | ||||||
|  | 	} | ||||||
|  | 	return (data[1] & capUpperMask) == capUpperMask | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | func (c *capsV3) Set(which CapType, caps ...Cap) { | ||||||
|  | 	for _, what := range caps { | ||||||
|  | 		var i uint | ||||||
|  | 		if what > 31 { | ||||||
|  | 			i = uint(what) >> 5 | ||||||
|  | 			what %= 32 | ||||||
|  | 		} | ||||||
|  | 
 | ||||||
|  | 		if which&EFFECTIVE != 0 { | ||||||
|  | 			c.data[i].effective |= 1 << uint(what) | ||||||
|  | 		} | ||||||
|  | 		if which&PERMITTED != 0 { | ||||||
|  | 			c.data[i].permitted |= 1 << uint(what) | ||||||
|  | 		} | ||||||
|  | 		if which&INHERITABLE != 0 { | ||||||
|  | 			c.data[i].inheritable |= 1 << uint(what) | ||||||
|  | 		} | ||||||
|  | 		if which&BOUNDING != 0 { | ||||||
|  | 			c.bounds[i] |= 1 << uint(what) | ||||||
|  | 		} | ||||||
|  | 		if which&AMBIENT != 0 { | ||||||
|  | 			c.ambient[i] |= 1 << uint(what) | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | func (c *capsV3) Unset(which CapType, caps ...Cap) { | ||||||
|  | 	for _, what := range caps { | ||||||
|  | 		var i uint | ||||||
|  | 		if what > 31 { | ||||||
|  | 			i = uint(what) >> 5 | ||||||
|  | 			what %= 32 | ||||||
|  | 		} | ||||||
|  | 
 | ||||||
|  | 		if which&EFFECTIVE != 0 { | ||||||
|  | 			c.data[i].effective &= ^(1 << uint(what)) | ||||||
|  | 		} | ||||||
|  | 		if which&PERMITTED != 0 { | ||||||
|  | 			c.data[i].permitted &= ^(1 << uint(what)) | ||||||
|  | 		} | ||||||
|  | 		if which&INHERITABLE != 0 { | ||||||
|  | 			c.data[i].inheritable &= ^(1 << uint(what)) | ||||||
|  | 		} | ||||||
|  | 		if which&BOUNDING != 0 { | ||||||
|  | 			c.bounds[i] &= ^(1 << uint(what)) | ||||||
|  | 		} | ||||||
|  | 		if which&AMBIENT != 0 { | ||||||
|  | 			c.ambient[i] &= ^(1 << uint(what)) | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | func (c *capsV3) Fill(kind CapType) { | ||||||
|  | 	if kind&CAPS == CAPS { | ||||||
|  | 		c.data[0].effective = 0xffffffff | ||||||
|  | 		c.data[0].permitted = 0xffffffff | ||||||
|  | 		c.data[0].inheritable = 0 | ||||||
|  | 		c.data[1].effective = 0xffffffff | ||||||
|  | 		c.data[1].permitted = 0xffffffff | ||||||
|  | 		c.data[1].inheritable = 0 | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	if kind&BOUNDS == BOUNDS { | ||||||
|  | 		c.bounds[0] = 0xffffffff | ||||||
|  | 		c.bounds[1] = 0xffffffff | ||||||
|  | 	} | ||||||
|  | 	if kind&AMBS == AMBS { | ||||||
|  | 		c.ambient[0] = 0xffffffff | ||||||
|  | 		c.ambient[1] = 0xffffffff | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | func (c *capsV3) Clear(kind CapType) { | ||||||
|  | 	if kind&CAPS == CAPS { | ||||||
|  | 		c.data[0].effective = 0 | ||||||
|  | 		c.data[0].permitted = 0 | ||||||
|  | 		c.data[0].inheritable = 0 | ||||||
|  | 		c.data[1].effective = 0 | ||||||
|  | 		c.data[1].permitted = 0 | ||||||
|  | 		c.data[1].inheritable = 0 | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	if kind&BOUNDS == BOUNDS { | ||||||
|  | 		c.bounds[0] = 0 | ||||||
|  | 		c.bounds[1] = 0 | ||||||
|  | 	} | ||||||
|  | 	if kind&AMBS == AMBS { | ||||||
|  | 		c.ambient[0] = 0 | ||||||
|  | 		c.ambient[1] = 0 | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | func (c *capsV3) StringCap(which CapType) (ret string) { | ||||||
|  | 	return mkStringCap(c, which) | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | func (c *capsV3) String() (ret string) { | ||||||
|  | 	return mkString(c, BOUNDING) | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | func (c *capsV3) Load() (err error) { | ||||||
|  | 	err = capget(&c.hdr, &c.data[0]) | ||||||
|  | 	if err != nil { | ||||||
|  | 		return | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	var status_path string | ||||||
|  | 
 | ||||||
|  | 	if c.hdr.pid == 0 { | ||||||
|  | 		status_path = fmt.Sprintf("/proc/self/status") | ||||||
|  | 	} else { | ||||||
|  | 		status_path = fmt.Sprintf("/proc/%d/status", c.hdr.pid) | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	f, err := os.Open(status_path) | ||||||
|  | 	if err != nil { | ||||||
|  | 		return | ||||||
|  | 	} | ||||||
|  | 	b := bufio.NewReader(f) | ||||||
|  | 	for { | ||||||
|  | 		line, e := b.ReadString('\n') | ||||||
|  | 		if e != nil { | ||||||
|  | 			if e != io.EOF { | ||||||
|  | 				err = e | ||||||
|  | 			} | ||||||
|  | 			break | ||||||
|  | 		} | ||||||
|  | 		if strings.HasPrefix(line, "CapB") { | ||||||
|  | 			fmt.Sscanf(line[4:], "nd:  %08x%08x", &c.bounds[1], &c.bounds[0]) | ||||||
|  | 			continue | ||||||
|  | 		} | ||||||
|  | 		if strings.HasPrefix(line, "CapA") { | ||||||
|  | 			fmt.Sscanf(line[4:], "mb:  %08x%08x", &c.ambient[1], &c.ambient[0]) | ||||||
|  | 			continue | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | 	f.Close() | ||||||
|  | 
 | ||||||
|  | 	return | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | func (c *capsV3) Apply(kind CapType) (err error) { | ||||||
|  | 	if kind&BOUNDS == BOUNDS { | ||||||
|  | 		var data [2]capData | ||||||
|  | 		err = capget(&c.hdr, &data[0]) | ||||||
|  | 		if err != nil { | ||||||
|  | 			return | ||||||
|  | 		} | ||||||
|  | 		if (1<<uint(CAP_SETPCAP))&data[0].effective != 0 { | ||||||
|  | 			for i := Cap(0); i <= CAP_LAST_CAP; i++ { | ||||||
|  | 				if c.Get(BOUNDING, i) { | ||||||
|  | 					continue | ||||||
|  | 				} | ||||||
|  | 				err = prctl(syscall.PR_CAPBSET_DROP, uintptr(i), 0, 0, 0) | ||||||
|  | 				if err != nil { | ||||||
|  | 					// Ignore EINVAL since the capability may not be supported in this system.
 | ||||||
|  | 					if errno, ok := err.(syscall.Errno); ok && errno == syscall.EINVAL { | ||||||
|  | 						err = nil | ||||||
|  | 						continue | ||||||
|  | 					} | ||||||
|  | 					return | ||||||
|  | 				} | ||||||
|  | 			} | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	if kind&CAPS == CAPS { | ||||||
|  | 		err = capset(&c.hdr, &c.data[0]) | ||||||
|  | 		if err != nil { | ||||||
|  | 			return | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	if kind&AMBS == AMBS { | ||||||
|  | 		for i := Cap(0); i <= CAP_LAST_CAP; i++ { | ||||||
|  | 			action := pr_CAP_AMBIENT_LOWER | ||||||
|  | 			if c.Get(AMBIENT, i) { | ||||||
|  | 				action = pr_CAP_AMBIENT_RAISE | ||||||
|  | 			} | ||||||
|  | 			err := prctl(pr_CAP_AMBIENT, action, uintptr(i), 0, 0) | ||||||
|  | 			// Ignore EINVAL as not supported on kernels before 4.3
 | ||||||
|  | 			if errno, ok := err.(syscall.Errno); ok && errno == syscall.EINVAL { | ||||||
|  | 				err = nil | ||||||
|  | 				continue | ||||||
|  | 			} | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	return | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | func newFile(path string) (c Capabilities, err error) { | ||||||
|  | 	c = &capsFile{path: path} | ||||||
|  | 	return | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | type capsFile struct { | ||||||
|  | 	path string | ||||||
|  | 	data vfscapData | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | func (c *capsFile) Get(which CapType, what Cap) bool { | ||||||
|  | 	var i uint | ||||||
|  | 	if what > 31 { | ||||||
|  | 		if c.data.version == 1 { | ||||||
|  | 			return false | ||||||
|  | 		} | ||||||
|  | 		i = uint(what) >> 5 | ||||||
|  | 		what %= 32 | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	switch which { | ||||||
|  | 	case EFFECTIVE: | ||||||
|  | 		return (1<<uint(what))&c.data.effective[i] != 0 | ||||||
|  | 	case PERMITTED: | ||||||
|  | 		return (1<<uint(what))&c.data.data[i].permitted != 0 | ||||||
|  | 	case INHERITABLE: | ||||||
|  | 		return (1<<uint(what))&c.data.data[i].inheritable != 0 | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	return false | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | func (c *capsFile) getData(which CapType, dest []uint32) { | ||||||
|  | 	switch which { | ||||||
|  | 	case EFFECTIVE: | ||||||
|  | 		dest[0] = c.data.effective[0] | ||||||
|  | 		dest[1] = c.data.effective[1] | ||||||
|  | 	case PERMITTED: | ||||||
|  | 		dest[0] = c.data.data[0].permitted | ||||||
|  | 		dest[1] = c.data.data[1].permitted | ||||||
|  | 	case INHERITABLE: | ||||||
|  | 		dest[0] = c.data.data[0].inheritable | ||||||
|  | 		dest[1] = c.data.data[1].inheritable | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | func (c *capsFile) Empty(which CapType) bool { | ||||||
|  | 	var data [2]uint32 | ||||||
|  | 	c.getData(which, data[:]) | ||||||
|  | 	return data[0] == 0 && data[1] == 0 | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | func (c *capsFile) Full(which CapType) bool { | ||||||
|  | 	var data [2]uint32 | ||||||
|  | 	c.getData(which, data[:]) | ||||||
|  | 	if c.data.version == 0 { | ||||||
|  | 		return (data[0] & 0x7fffffff) == 0x7fffffff | ||||||
|  | 	} | ||||||
|  | 	if (data[0] & 0xffffffff) != 0xffffffff { | ||||||
|  | 		return false | ||||||
|  | 	} | ||||||
|  | 	return (data[1] & capUpperMask) == capUpperMask | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | func (c *capsFile) Set(which CapType, caps ...Cap) { | ||||||
|  | 	for _, what := range caps { | ||||||
|  | 		var i uint | ||||||
|  | 		if what > 31 { | ||||||
|  | 			if c.data.version == 1 { | ||||||
|  | 				continue | ||||||
|  | 			} | ||||||
|  | 			i = uint(what) >> 5 | ||||||
|  | 			what %= 32 | ||||||
|  | 		} | ||||||
|  | 
 | ||||||
|  | 		if which&EFFECTIVE != 0 { | ||||||
|  | 			c.data.effective[i] |= 1 << uint(what) | ||||||
|  | 		} | ||||||
|  | 		if which&PERMITTED != 0 { | ||||||
|  | 			c.data.data[i].permitted |= 1 << uint(what) | ||||||
|  | 		} | ||||||
|  | 		if which&INHERITABLE != 0 { | ||||||
|  | 			c.data.data[i].inheritable |= 1 << uint(what) | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | func (c *capsFile) Unset(which CapType, caps ...Cap) { | ||||||
|  | 	for _, what := range caps { | ||||||
|  | 		var i uint | ||||||
|  | 		if what > 31 { | ||||||
|  | 			if c.data.version == 1 { | ||||||
|  | 				continue | ||||||
|  | 			} | ||||||
|  | 			i = uint(what) >> 5 | ||||||
|  | 			what %= 32 | ||||||
|  | 		} | ||||||
|  | 
 | ||||||
|  | 		if which&EFFECTIVE != 0 { | ||||||
|  | 			c.data.effective[i] &= ^(1 << uint(what)) | ||||||
|  | 		} | ||||||
|  | 		if which&PERMITTED != 0 { | ||||||
|  | 			c.data.data[i].permitted &= ^(1 << uint(what)) | ||||||
|  | 		} | ||||||
|  | 		if which&INHERITABLE != 0 { | ||||||
|  | 			c.data.data[i].inheritable &= ^(1 << uint(what)) | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | func (c *capsFile) Fill(kind CapType) { | ||||||
|  | 	if kind&CAPS == CAPS { | ||||||
|  | 		c.data.effective[0] = 0xffffffff | ||||||
|  | 		c.data.data[0].permitted = 0xffffffff | ||||||
|  | 		c.data.data[0].inheritable = 0 | ||||||
|  | 		if c.data.version == 2 { | ||||||
|  | 			c.data.effective[1] = 0xffffffff | ||||||
|  | 			c.data.data[1].permitted = 0xffffffff | ||||||
|  | 			c.data.data[1].inheritable = 0 | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | func (c *capsFile) Clear(kind CapType) { | ||||||
|  | 	if kind&CAPS == CAPS { | ||||||
|  | 		c.data.effective[0] = 0 | ||||||
|  | 		c.data.data[0].permitted = 0 | ||||||
|  | 		c.data.data[0].inheritable = 0 | ||||||
|  | 		if c.data.version == 2 { | ||||||
|  | 			c.data.effective[1] = 0 | ||||||
|  | 			c.data.data[1].permitted = 0 | ||||||
|  | 			c.data.data[1].inheritable = 0 | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | func (c *capsFile) StringCap(which CapType) (ret string) { | ||||||
|  | 	return mkStringCap(c, which) | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | func (c *capsFile) String() (ret string) { | ||||||
|  | 	return mkString(c, INHERITABLE) | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | func (c *capsFile) Load() (err error) { | ||||||
|  | 	return getVfsCap(c.path, &c.data) | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | func (c *capsFile) Apply(kind CapType) (err error) { | ||||||
|  | 	if kind&CAPS == CAPS { | ||||||
|  | 		return setVfsCap(c.path, &c.data) | ||||||
|  | 	} | ||||||
|  | 	return | ||||||
|  | } | ||||||
							
								
								
									
										19
									
								
								vendor/github.com/syndtr/gocapability/capability/capability_noop.go
								
								
									generated
								
								
									vendored
								
								
									Normal file
								
							
							
						
						
									
										19
									
								
								vendor/github.com/syndtr/gocapability/capability/capability_noop.go
								
								
									generated
								
								
									vendored
								
								
									Normal file
								
							|  | @ -0,0 +1,19 @@ | ||||||
|  | // Copyright (c) 2013, Suryandaru Triandana <syndtr@gmail.com>
 | ||||||
|  | // All rights reserved.
 | ||||||
|  | //
 | ||||||
|  | // Use of this source code is governed by a BSD-style license that can be
 | ||||||
|  | // found in the LICENSE file.
 | ||||||
|  | 
 | ||||||
|  | // +build !linux
 | ||||||
|  | 
 | ||||||
|  | package capability | ||||||
|  | 
 | ||||||
|  | import "errors" | ||||||
|  | 
 | ||||||
|  | func newPid(pid int) (Capabilities, error) { | ||||||
|  | 	return nil, errors.New("not supported") | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | func newFile(path string) (Capabilities, error) { | ||||||
|  | 	return nil, errors.New("not supported") | ||||||
|  | } | ||||||
|  | @ -0,0 +1,268 @@ | ||||||
|  | // Copyright (c) 2013, Suryandaru Triandana <syndtr@gmail.com>
 | ||||||
|  | // All rights reserved.
 | ||||||
|  | //
 | ||||||
|  | // Use of this source code is governed by a BSD-style license that can be
 | ||||||
|  | // found in the LICENSE file.
 | ||||||
|  | 
 | ||||||
|  | package capability | ||||||
|  | 
 | ||||||
|  | type CapType uint | ||||||
|  | 
 | ||||||
|  | func (c CapType) String() string { | ||||||
|  | 	switch c { | ||||||
|  | 	case EFFECTIVE: | ||||||
|  | 		return "effective" | ||||||
|  | 	case PERMITTED: | ||||||
|  | 		return "permitted" | ||||||
|  | 	case INHERITABLE: | ||||||
|  | 		return "inheritable" | ||||||
|  | 	case BOUNDING: | ||||||
|  | 		return "bounding" | ||||||
|  | 	case CAPS: | ||||||
|  | 		return "caps" | ||||||
|  | 	case AMBIENT: | ||||||
|  | 		return "ambient" | ||||||
|  | 	} | ||||||
|  | 	return "unknown" | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | const ( | ||||||
|  | 	EFFECTIVE CapType = 1 << iota | ||||||
|  | 	PERMITTED | ||||||
|  | 	INHERITABLE | ||||||
|  | 	BOUNDING | ||||||
|  | 	AMBIENT | ||||||
|  | 
 | ||||||
|  | 	CAPS   = EFFECTIVE | PERMITTED | INHERITABLE | ||||||
|  | 	BOUNDS = BOUNDING | ||||||
|  | 	AMBS   = AMBIENT | ||||||
|  | ) | ||||||
|  | 
 | ||||||
|  | //go:generate go run enumgen/gen.go
 | ||||||
|  | type Cap int | ||||||
|  | 
 | ||||||
|  | // POSIX-draft defined capabilities.
 | ||||||
|  | const ( | ||||||
|  | 	// In a system with the [_POSIX_CHOWN_RESTRICTED] option defined, this
 | ||||||
|  | 	// overrides the restriction of changing file ownership and group
 | ||||||
|  | 	// ownership.
 | ||||||
|  | 	CAP_CHOWN = Cap(0) | ||||||
|  | 
 | ||||||
|  | 	// Override all DAC access, including ACL execute access if
 | ||||||
|  | 	// [_POSIX_ACL] is defined. Excluding DAC access covered by
 | ||||||
|  | 	// CAP_LINUX_IMMUTABLE.
 | ||||||
|  | 	CAP_DAC_OVERRIDE = Cap(1) | ||||||
|  | 
 | ||||||
|  | 	// Overrides all DAC restrictions regarding read and search on files
 | ||||||
|  | 	// and directories, including ACL restrictions if [_POSIX_ACL] is
 | ||||||
|  | 	// defined. Excluding DAC access covered by CAP_LINUX_IMMUTABLE.
 | ||||||
|  | 	CAP_DAC_READ_SEARCH = Cap(2) | ||||||
|  | 
 | ||||||
|  | 	// Overrides all restrictions about allowed operations on files, where
 | ||||||
|  | 	// file owner ID must be equal to the user ID, except where CAP_FSETID
 | ||||||
|  | 	// is applicable. It doesn't override MAC and DAC restrictions.
 | ||||||
|  | 	CAP_FOWNER = Cap(3) | ||||||
|  | 
 | ||||||
|  | 	// Overrides the following restrictions that the effective user ID
 | ||||||
|  | 	// shall match the file owner ID when setting the S_ISUID and S_ISGID
 | ||||||
|  | 	// bits on that file; that the effective group ID (or one of the
 | ||||||
|  | 	// supplementary group IDs) shall match the file owner ID when setting
 | ||||||
|  | 	// the S_ISGID bit on that file; that the S_ISUID and S_ISGID bits are
 | ||||||
|  | 	// cleared on successful return from chown(2) (not implemented).
 | ||||||
|  | 	CAP_FSETID = Cap(4) | ||||||
|  | 
 | ||||||
|  | 	// Overrides the restriction that the real or effective user ID of a
 | ||||||
|  | 	// process sending a signal must match the real or effective user ID
 | ||||||
|  | 	// of the process receiving the signal.
 | ||||||
|  | 	CAP_KILL = Cap(5) | ||||||
|  | 
 | ||||||
|  | 	// Allows setgid(2) manipulation
 | ||||||
|  | 	// Allows setgroups(2)
 | ||||||
|  | 	// Allows forged gids on socket credentials passing.
 | ||||||
|  | 	CAP_SETGID = Cap(6) | ||||||
|  | 
 | ||||||
|  | 	// Allows set*uid(2) manipulation (including fsuid).
 | ||||||
|  | 	// Allows forged pids on socket credentials passing.
 | ||||||
|  | 	CAP_SETUID = Cap(7) | ||||||
|  | 
 | ||||||
|  | 	// Linux-specific capabilities
 | ||||||
|  | 
 | ||||||
|  | 	// Without VFS support for capabilities:
 | ||||||
|  | 	//   Transfer any capability in your permitted set to any pid,
 | ||||||
|  | 	//   remove any capability in your permitted set from any pid
 | ||||||
|  | 	// With VFS support for capabilities (neither of above, but)
 | ||||||
|  | 	//   Add any capability from current's capability bounding set
 | ||||||
|  | 	//     to the current process' inheritable set
 | ||||||
|  | 	//   Allow taking bits out of capability bounding set
 | ||||||
|  | 	//   Allow modification of the securebits for a process
 | ||||||
|  | 	CAP_SETPCAP = Cap(8) | ||||||
|  | 
 | ||||||
|  | 	// Allow modification of S_IMMUTABLE and S_APPEND file attributes
 | ||||||
|  | 	CAP_LINUX_IMMUTABLE = Cap(9) | ||||||
|  | 
 | ||||||
|  | 	// Allows binding to TCP/UDP sockets below 1024
 | ||||||
|  | 	// Allows binding to ATM VCIs below 32
 | ||||||
|  | 	CAP_NET_BIND_SERVICE = Cap(10) | ||||||
|  | 
 | ||||||
|  | 	// Allow broadcasting, listen to multicast
 | ||||||
|  | 	CAP_NET_BROADCAST = Cap(11) | ||||||
|  | 
 | ||||||
|  | 	// Allow interface configuration
 | ||||||
|  | 	// Allow administration of IP firewall, masquerading and accounting
 | ||||||
|  | 	// Allow setting debug option on sockets
 | ||||||
|  | 	// Allow modification of routing tables
 | ||||||
|  | 	// Allow setting arbitrary process / process group ownership on
 | ||||||
|  | 	// sockets
 | ||||||
|  | 	// Allow binding to any address for transparent proxying (also via NET_RAW)
 | ||||||
|  | 	// Allow setting TOS (type of service)
 | ||||||
|  | 	// Allow setting promiscuous mode
 | ||||||
|  | 	// Allow clearing driver statistics
 | ||||||
|  | 	// Allow multicasting
 | ||||||
|  | 	// Allow read/write of device-specific registers
 | ||||||
|  | 	// Allow activation of ATM control sockets
 | ||||||
|  | 	CAP_NET_ADMIN = Cap(12) | ||||||
|  | 
 | ||||||
|  | 	// Allow use of RAW sockets
 | ||||||
|  | 	// Allow use of PACKET sockets
 | ||||||
|  | 	// Allow binding to any address for transparent proxying (also via NET_ADMIN)
 | ||||||
|  | 	CAP_NET_RAW = Cap(13) | ||||||
|  | 
 | ||||||
|  | 	// Allow locking of shared memory segments
 | ||||||
|  | 	// Allow mlock and mlockall (which doesn't really have anything to do
 | ||||||
|  | 	// with IPC)
 | ||||||
|  | 	CAP_IPC_LOCK = Cap(14) | ||||||
|  | 
 | ||||||
|  | 	// Override IPC ownership checks
 | ||||||
|  | 	CAP_IPC_OWNER = Cap(15) | ||||||
|  | 
 | ||||||
|  | 	// Insert and remove kernel modules - modify kernel without limit
 | ||||||
|  | 	CAP_SYS_MODULE = Cap(16) | ||||||
|  | 
 | ||||||
|  | 	// Allow ioperm/iopl access
 | ||||||
|  | 	// Allow sending USB messages to any device via /proc/bus/usb
 | ||||||
|  | 	CAP_SYS_RAWIO = Cap(17) | ||||||
|  | 
 | ||||||
|  | 	// Allow use of chroot()
 | ||||||
|  | 	CAP_SYS_CHROOT = Cap(18) | ||||||
|  | 
 | ||||||
|  | 	// Allow ptrace() of any process
 | ||||||
|  | 	CAP_SYS_PTRACE = Cap(19) | ||||||
|  | 
 | ||||||
|  | 	// Allow configuration of process accounting
 | ||||||
|  | 	CAP_SYS_PACCT = Cap(20) | ||||||
|  | 
 | ||||||
|  | 	// Allow configuration of the secure attention key
 | ||||||
|  | 	// Allow administration of the random device
 | ||||||
|  | 	// Allow examination and configuration of disk quotas
 | ||||||
|  | 	// Allow setting the domainname
 | ||||||
|  | 	// Allow setting the hostname
 | ||||||
|  | 	// Allow calling bdflush()
 | ||||||
|  | 	// Allow mount() and umount(), setting up new smb connection
 | ||||||
|  | 	// Allow some autofs root ioctls
 | ||||||
|  | 	// Allow nfsservctl
 | ||||||
|  | 	// Allow VM86_REQUEST_IRQ
 | ||||||
|  | 	// Allow to read/write pci config on alpha
 | ||||||
|  | 	// Allow irix_prctl on mips (setstacksize)
 | ||||||
|  | 	// Allow flushing all cache on m68k (sys_cacheflush)
 | ||||||
|  | 	// Allow removing semaphores
 | ||||||
|  | 	// Used instead of CAP_CHOWN to "chown" IPC message queues, semaphores
 | ||||||
|  | 	// and shared memory
 | ||||||
|  | 	// Allow locking/unlocking of shared memory segment
 | ||||||
|  | 	// Allow turning swap on/off
 | ||||||
|  | 	// Allow forged pids on socket credentials passing
 | ||||||
|  | 	// Allow setting readahead and flushing buffers on block devices
 | ||||||
|  | 	// Allow setting geometry in floppy driver
 | ||||||
|  | 	// Allow turning DMA on/off in xd driver
 | ||||||
|  | 	// Allow administration of md devices (mostly the above, but some
 | ||||||
|  | 	// extra ioctls)
 | ||||||
|  | 	// Allow tuning the ide driver
 | ||||||
|  | 	// Allow access to the nvram device
 | ||||||
|  | 	// Allow administration of apm_bios, serial and bttv (TV) device
 | ||||||
|  | 	// Allow manufacturer commands in isdn CAPI support driver
 | ||||||
|  | 	// Allow reading non-standardized portions of pci configuration space
 | ||||||
|  | 	// Allow DDI debug ioctl on sbpcd driver
 | ||||||
|  | 	// Allow setting up serial ports
 | ||||||
|  | 	// Allow sending raw qic-117 commands
 | ||||||
|  | 	// Allow enabling/disabling tagged queuing on SCSI controllers and sending
 | ||||||
|  | 	// arbitrary SCSI commands
 | ||||||
|  | 	// Allow setting encryption key on loopback filesystem
 | ||||||
|  | 	// Allow setting zone reclaim policy
 | ||||||
|  | 	CAP_SYS_ADMIN = Cap(21) | ||||||
|  | 
 | ||||||
|  | 	// Allow use of reboot()
 | ||||||
|  | 	CAP_SYS_BOOT = Cap(22) | ||||||
|  | 
 | ||||||
|  | 	// Allow raising priority and setting priority on other (different
 | ||||||
|  | 	// UID) processes
 | ||||||
|  | 	// Allow use of FIFO and round-robin (realtime) scheduling on own
 | ||||||
|  | 	// processes and setting the scheduling algorithm used by another
 | ||||||
|  | 	// process.
 | ||||||
|  | 	// Allow setting cpu affinity on other processes
 | ||||||
|  | 	CAP_SYS_NICE = Cap(23) | ||||||
|  | 
 | ||||||
|  | 	// Override resource limits. Set resource limits.
 | ||||||
|  | 	// Override quota limits.
 | ||||||
|  | 	// Override reserved space on ext2 filesystem
 | ||||||
|  | 	// Modify data journaling mode on ext3 filesystem (uses journaling
 | ||||||
|  | 	// resources)
 | ||||||
|  | 	// NOTE: ext2 honors fsuid when checking for resource overrides, so
 | ||||||
|  | 	// you can override using fsuid too
 | ||||||
|  | 	// Override size restrictions on IPC message queues
 | ||||||
|  | 	// Allow more than 64hz interrupts from the real-time clock
 | ||||||
|  | 	// Override max number of consoles on console allocation
 | ||||||
|  | 	// Override max number of keymaps
 | ||||||
|  | 	CAP_SYS_RESOURCE = Cap(24) | ||||||
|  | 
 | ||||||
|  | 	// Allow manipulation of system clock
 | ||||||
|  | 	// Allow irix_stime on mips
 | ||||||
|  | 	// Allow setting the real-time clock
 | ||||||
|  | 	CAP_SYS_TIME = Cap(25) | ||||||
|  | 
 | ||||||
|  | 	// Allow configuration of tty devices
 | ||||||
|  | 	// Allow vhangup() of tty
 | ||||||
|  | 	CAP_SYS_TTY_CONFIG = Cap(26) | ||||||
|  | 
 | ||||||
|  | 	// Allow the privileged aspects of mknod()
 | ||||||
|  | 	CAP_MKNOD = Cap(27) | ||||||
|  | 
 | ||||||
|  | 	// Allow taking of leases on files
 | ||||||
|  | 	CAP_LEASE = Cap(28) | ||||||
|  | 
 | ||||||
|  | 	CAP_AUDIT_WRITE   = Cap(29) | ||||||
|  | 	CAP_AUDIT_CONTROL = Cap(30) | ||||||
|  | 	CAP_SETFCAP       = Cap(31) | ||||||
|  | 
 | ||||||
|  | 	// Override MAC access.
 | ||||||
|  | 	// The base kernel enforces no MAC policy.
 | ||||||
|  | 	// An LSM may enforce a MAC policy, and if it does and it chooses
 | ||||||
|  | 	// to implement capability based overrides of that policy, this is
 | ||||||
|  | 	// the capability it should use to do so.
 | ||||||
|  | 	CAP_MAC_OVERRIDE = Cap(32) | ||||||
|  | 
 | ||||||
|  | 	// Allow MAC configuration or state changes.
 | ||||||
|  | 	// The base kernel requires no MAC configuration.
 | ||||||
|  | 	// An LSM may enforce a MAC policy, and if it does and it chooses
 | ||||||
|  | 	// to implement capability based checks on modifications to that
 | ||||||
|  | 	// policy or the data required to maintain it, this is the
 | ||||||
|  | 	// capability it should use to do so.
 | ||||||
|  | 	CAP_MAC_ADMIN = Cap(33) | ||||||
|  | 
 | ||||||
|  | 	// Allow configuring the kernel's syslog (printk behaviour)
 | ||||||
|  | 	CAP_SYSLOG = Cap(34) | ||||||
|  | 
 | ||||||
|  | 	// Allow triggering something that will wake the system
 | ||||||
|  | 	CAP_WAKE_ALARM = Cap(35) | ||||||
|  | 
 | ||||||
|  | 	// Allow preventing system suspends
 | ||||||
|  | 	CAP_BLOCK_SUSPEND = Cap(36) | ||||||
|  | 
 | ||||||
|  | 	// Allow reading audit messages from the kernel
 | ||||||
|  | 	CAP_AUDIT_READ = Cap(37) | ||||||
|  | ) | ||||||
|  | 
 | ||||||
|  | var ( | ||||||
|  | 	// Highest valid capability of the running kernel.
 | ||||||
|  | 	CAP_LAST_CAP = Cap(63) | ||||||
|  | 
 | ||||||
|  | 	capUpperMask = ^uint32(0) | ||||||
|  | ) | ||||||
|  | @ -0,0 +1,129 @@ | ||||||
|  | // generated file; DO NOT EDIT - use go generate in directory with source
 | ||||||
|  | 
 | ||||||
|  | package capability | ||||||
|  | 
 | ||||||
|  | func (c Cap) String() string { | ||||||
|  | 	switch c { | ||||||
|  | 	case CAP_CHOWN: | ||||||
|  | 		return "chown" | ||||||
|  | 	case CAP_DAC_OVERRIDE: | ||||||
|  | 		return "dac_override" | ||||||
|  | 	case CAP_DAC_READ_SEARCH: | ||||||
|  | 		return "dac_read_search" | ||||||
|  | 	case CAP_FOWNER: | ||||||
|  | 		return "fowner" | ||||||
|  | 	case CAP_FSETID: | ||||||
|  | 		return "fsetid" | ||||||
|  | 	case CAP_KILL: | ||||||
|  | 		return "kill" | ||||||
|  | 	case CAP_SETGID: | ||||||
|  | 		return "setgid" | ||||||
|  | 	case CAP_SETUID: | ||||||
|  | 		return "setuid" | ||||||
|  | 	case CAP_SETPCAP: | ||||||
|  | 		return "setpcap" | ||||||
|  | 	case CAP_LINUX_IMMUTABLE: | ||||||
|  | 		return "linux_immutable" | ||||||
|  | 	case CAP_NET_BIND_SERVICE: | ||||||
|  | 		return "net_bind_service" | ||||||
|  | 	case CAP_NET_BROADCAST: | ||||||
|  | 		return "net_broadcast" | ||||||
|  | 	case CAP_NET_ADMIN: | ||||||
|  | 		return "net_admin" | ||||||
|  | 	case CAP_NET_RAW: | ||||||
|  | 		return "net_raw" | ||||||
|  | 	case CAP_IPC_LOCK: | ||||||
|  | 		return "ipc_lock" | ||||||
|  | 	case CAP_IPC_OWNER: | ||||||
|  | 		return "ipc_owner" | ||||||
|  | 	case CAP_SYS_MODULE: | ||||||
|  | 		return "sys_module" | ||||||
|  | 	case CAP_SYS_RAWIO: | ||||||
|  | 		return "sys_rawio" | ||||||
|  | 	case CAP_SYS_CHROOT: | ||||||
|  | 		return "sys_chroot" | ||||||
|  | 	case CAP_SYS_PTRACE: | ||||||
|  | 		return "sys_ptrace" | ||||||
|  | 	case CAP_SYS_PACCT: | ||||||
|  | 		return "sys_pacct" | ||||||
|  | 	case CAP_SYS_ADMIN: | ||||||
|  | 		return "sys_admin" | ||||||
|  | 	case CAP_SYS_BOOT: | ||||||
|  | 		return "sys_boot" | ||||||
|  | 	case CAP_SYS_NICE: | ||||||
|  | 		return "sys_nice" | ||||||
|  | 	case CAP_SYS_RESOURCE: | ||||||
|  | 		return "sys_resource" | ||||||
|  | 	case CAP_SYS_TIME: | ||||||
|  | 		return "sys_time" | ||||||
|  | 	case CAP_SYS_TTY_CONFIG: | ||||||
|  | 		return "sys_tty_config" | ||||||
|  | 	case CAP_MKNOD: | ||||||
|  | 		return "mknod" | ||||||
|  | 	case CAP_LEASE: | ||||||
|  | 		return "lease" | ||||||
|  | 	case CAP_AUDIT_WRITE: | ||||||
|  | 		return "audit_write" | ||||||
|  | 	case CAP_AUDIT_CONTROL: | ||||||
|  | 		return "audit_control" | ||||||
|  | 	case CAP_SETFCAP: | ||||||
|  | 		return "setfcap" | ||||||
|  | 	case CAP_MAC_OVERRIDE: | ||||||
|  | 		return "mac_override" | ||||||
|  | 	case CAP_MAC_ADMIN: | ||||||
|  | 		return "mac_admin" | ||||||
|  | 	case CAP_SYSLOG: | ||||||
|  | 		return "syslog" | ||||||
|  | 	case CAP_WAKE_ALARM: | ||||||
|  | 		return "wake_alarm" | ||||||
|  | 	case CAP_BLOCK_SUSPEND: | ||||||
|  | 		return "block_suspend" | ||||||
|  | 	case CAP_AUDIT_READ: | ||||||
|  | 		return "audit_read" | ||||||
|  | 	} | ||||||
|  | 	return "unknown" | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | // List returns list of all supported capabilities
 | ||||||
|  | func List() []Cap { | ||||||
|  | 	return []Cap{ | ||||||
|  | 		CAP_CHOWN, | ||||||
|  | 		CAP_DAC_OVERRIDE, | ||||||
|  | 		CAP_DAC_READ_SEARCH, | ||||||
|  | 		CAP_FOWNER, | ||||||
|  | 		CAP_FSETID, | ||||||
|  | 		CAP_KILL, | ||||||
|  | 		CAP_SETGID, | ||||||
|  | 		CAP_SETUID, | ||||||
|  | 		CAP_SETPCAP, | ||||||
|  | 		CAP_LINUX_IMMUTABLE, | ||||||
|  | 		CAP_NET_BIND_SERVICE, | ||||||
|  | 		CAP_NET_BROADCAST, | ||||||
|  | 		CAP_NET_ADMIN, | ||||||
|  | 		CAP_NET_RAW, | ||||||
|  | 		CAP_IPC_LOCK, | ||||||
|  | 		CAP_IPC_OWNER, | ||||||
|  | 		CAP_SYS_MODULE, | ||||||
|  | 		CAP_SYS_RAWIO, | ||||||
|  | 		CAP_SYS_CHROOT, | ||||||
|  | 		CAP_SYS_PTRACE, | ||||||
|  | 		CAP_SYS_PACCT, | ||||||
|  | 		CAP_SYS_ADMIN, | ||||||
|  | 		CAP_SYS_BOOT, | ||||||
|  | 		CAP_SYS_NICE, | ||||||
|  | 		CAP_SYS_RESOURCE, | ||||||
|  | 		CAP_SYS_TIME, | ||||||
|  | 		CAP_SYS_TTY_CONFIG, | ||||||
|  | 		CAP_MKNOD, | ||||||
|  | 		CAP_LEASE, | ||||||
|  | 		CAP_AUDIT_WRITE, | ||||||
|  | 		CAP_AUDIT_CONTROL, | ||||||
|  | 		CAP_SETFCAP, | ||||||
|  | 		CAP_MAC_OVERRIDE, | ||||||
|  | 		CAP_MAC_ADMIN, | ||||||
|  | 		CAP_SYSLOG, | ||||||
|  | 		CAP_WAKE_ALARM, | ||||||
|  | 		CAP_BLOCK_SUSPEND, | ||||||
|  | 		CAP_AUDIT_READ, | ||||||
|  | 	} | ||||||
|  | } | ||||||
							
								
								
									
										154
									
								
								vendor/github.com/syndtr/gocapability/capability/syscall_linux.go
								
								
									generated
								
								
									vendored
								
								
									Normal file
								
							
							
						
						
									
										154
									
								
								vendor/github.com/syndtr/gocapability/capability/syscall_linux.go
								
								
									generated
								
								
									vendored
								
								
									Normal file
								
							|  | @ -0,0 +1,154 @@ | ||||||
|  | // Copyright (c) 2013, Suryandaru Triandana <syndtr@gmail.com>
 | ||||||
|  | // All rights reserved.
 | ||||||
|  | //
 | ||||||
|  | // Use of this source code is governed by a BSD-style license that can be
 | ||||||
|  | // found in the LICENSE file.
 | ||||||
|  | 
 | ||||||
|  | package capability | ||||||
|  | 
 | ||||||
|  | import ( | ||||||
|  | 	"syscall" | ||||||
|  | 	"unsafe" | ||||||
|  | ) | ||||||
|  | 
 | ||||||
|  | type capHeader struct { | ||||||
|  | 	version uint32 | ||||||
|  | 	pid     int | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | type capData struct { | ||||||
|  | 	effective   uint32 | ||||||
|  | 	permitted   uint32 | ||||||
|  | 	inheritable uint32 | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | func capget(hdr *capHeader, data *capData) (err error) { | ||||||
|  | 	_, _, e1 := syscall.Syscall(syscall.SYS_CAPGET, uintptr(unsafe.Pointer(hdr)), uintptr(unsafe.Pointer(data)), 0) | ||||||
|  | 	if e1 != 0 { | ||||||
|  | 		err = e1 | ||||||
|  | 	} | ||||||
|  | 	return | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | func capset(hdr *capHeader, data *capData) (err error) { | ||||||
|  | 	_, _, e1 := syscall.Syscall(syscall.SYS_CAPSET, uintptr(unsafe.Pointer(hdr)), uintptr(unsafe.Pointer(data)), 0) | ||||||
|  | 	if e1 != 0 { | ||||||
|  | 		err = e1 | ||||||
|  | 	} | ||||||
|  | 	return | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | // not yet in syscall
 | ||||||
|  | const ( | ||||||
|  | 	pr_CAP_AMBIENT           = 47 | ||||||
|  | 	pr_CAP_AMBIENT_IS_SET    = uintptr(1) | ||||||
|  | 	pr_CAP_AMBIENT_RAISE     = uintptr(2) | ||||||
|  | 	pr_CAP_AMBIENT_LOWER     = uintptr(3) | ||||||
|  | 	pr_CAP_AMBIENT_CLEAR_ALL = uintptr(4) | ||||||
|  | ) | ||||||
|  | 
 | ||||||
|  | func prctl(option int, arg2, arg3, arg4, arg5 uintptr) (err error) { | ||||||
|  | 	_, _, e1 := syscall.Syscall6(syscall.SYS_PRCTL, uintptr(option), arg2, arg3, arg4, arg5, 0) | ||||||
|  | 	if e1 != 0 { | ||||||
|  | 		err = e1 | ||||||
|  | 	} | ||||||
|  | 	return | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | const ( | ||||||
|  | 	vfsXattrName = "security.capability" | ||||||
|  | 
 | ||||||
|  | 	vfsCapVerMask = 0xff000000 | ||||||
|  | 	vfsCapVer1    = 0x01000000 | ||||||
|  | 	vfsCapVer2    = 0x02000000 | ||||||
|  | 
 | ||||||
|  | 	vfsCapFlagMask      = ^vfsCapVerMask | ||||||
|  | 	vfsCapFlageffective = 0x000001 | ||||||
|  | 
 | ||||||
|  | 	vfscapDataSizeV1 = 4 * (1 + 2*1) | ||||||
|  | 	vfscapDataSizeV2 = 4 * (1 + 2*2) | ||||||
|  | ) | ||||||
|  | 
 | ||||||
|  | type vfscapData struct { | ||||||
|  | 	magic uint32 | ||||||
|  | 	data  [2]struct { | ||||||
|  | 		permitted   uint32 | ||||||
|  | 		inheritable uint32 | ||||||
|  | 	} | ||||||
|  | 	effective [2]uint32 | ||||||
|  | 	version   int8 | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | var ( | ||||||
|  | 	_vfsXattrName *byte | ||||||
|  | ) | ||||||
|  | 
 | ||||||
|  | func init() { | ||||||
|  | 	_vfsXattrName, _ = syscall.BytePtrFromString(vfsXattrName) | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | func getVfsCap(path string, dest *vfscapData) (err error) { | ||||||
|  | 	var _p0 *byte | ||||||
|  | 	_p0, err = syscall.BytePtrFromString(path) | ||||||
|  | 	if err != nil { | ||||||
|  | 		return | ||||||
|  | 	} | ||||||
|  | 	r0, _, e1 := syscall.Syscall6(syscall.SYS_GETXATTR, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(_vfsXattrName)), uintptr(unsafe.Pointer(dest)), vfscapDataSizeV2, 0, 0) | ||||||
|  | 	if e1 != 0 { | ||||||
|  | 		if e1 == syscall.ENODATA { | ||||||
|  | 			dest.version = 2 | ||||||
|  | 			return | ||||||
|  | 		} | ||||||
|  | 		err = e1 | ||||||
|  | 	} | ||||||
|  | 	switch dest.magic & vfsCapVerMask { | ||||||
|  | 	case vfsCapVer1: | ||||||
|  | 		dest.version = 1 | ||||||
|  | 		if r0 != vfscapDataSizeV1 { | ||||||
|  | 			return syscall.EINVAL | ||||||
|  | 		} | ||||||
|  | 		dest.data[1].permitted = 0 | ||||||
|  | 		dest.data[1].inheritable = 0 | ||||||
|  | 	case vfsCapVer2: | ||||||
|  | 		dest.version = 2 | ||||||
|  | 		if r0 != vfscapDataSizeV2 { | ||||||
|  | 			return syscall.EINVAL | ||||||
|  | 		} | ||||||
|  | 	default: | ||||||
|  | 		return syscall.EINVAL | ||||||
|  | 	} | ||||||
|  | 	if dest.magic&vfsCapFlageffective != 0 { | ||||||
|  | 		dest.effective[0] = dest.data[0].permitted | dest.data[0].inheritable | ||||||
|  | 		dest.effective[1] = dest.data[1].permitted | dest.data[1].inheritable | ||||||
|  | 	} else { | ||||||
|  | 		dest.effective[0] = 0 | ||||||
|  | 		dest.effective[1] = 0 | ||||||
|  | 	} | ||||||
|  | 	return | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | func setVfsCap(path string, data *vfscapData) (err error) { | ||||||
|  | 	var _p0 *byte | ||||||
|  | 	_p0, err = syscall.BytePtrFromString(path) | ||||||
|  | 	if err != nil { | ||||||
|  | 		return | ||||||
|  | 	} | ||||||
|  | 	var size uintptr | ||||||
|  | 	if data.version == 1 { | ||||||
|  | 		data.magic = vfsCapVer1 | ||||||
|  | 		size = vfscapDataSizeV1 | ||||||
|  | 	} else if data.version == 2 { | ||||||
|  | 		data.magic = vfsCapVer2 | ||||||
|  | 		if data.effective[0] != 0 || data.effective[1] != 0 { | ||||||
|  | 			data.magic |= vfsCapFlageffective | ||||||
|  | 		} | ||||||
|  | 		size = vfscapDataSizeV2 | ||||||
|  | 	} else { | ||||||
|  | 		return syscall.EINVAL | ||||||
|  | 	} | ||||||
|  | 	_, _, e1 := syscall.Syscall6(syscall.SYS_SETXATTR, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(_vfsXattrName)), uintptr(unsafe.Pointer(data)), size, 0, 0) | ||||||
|  | 	if e1 != 0 { | ||||||
|  | 		err = e1 | ||||||
|  | 	} | ||||||
|  | 	return | ||||||
|  | } | ||||||
		Loading…
	
		Reference in New Issue