commit
7e713ff336
1
go.mod
1
go.mod
|
@ -77,6 +77,7 @@ require (
|
|||
google.golang.org/appengine v1.6.1 // indirect
|
||||
google.golang.org/genproto v0.0.0-20190620144150-6af8c5fc6601 // indirect
|
||||
gopkg.in/yaml.v2 v2.2.8
|
||||
gotest.tools/v3 v3.0.2 // indirect
|
||||
k8s.io/api v0.17.3
|
||||
k8s.io/apimachinery v0.17.3
|
||||
k8s.io/client-go v0.0.0-20190620085101-78d2af792bab
|
||||
|
|
4
go.sum
4
go.sum
|
@ -574,6 +574,7 @@ golang.org/x/tools v0.0.0-20190312151545-0bb0c0a6e846/go.mod h1:LCzVGOaR6xXOjkQ3
|
|||
golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
|
||||
golang.org/x/tools v0.0.0-20190606124116-d0a3d012864b/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
|
||||
golang.org/x/tools v0.0.0-20190614205625-5aca471b1d59/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
|
||||
golang.org/x/tools v0.0.0-20190624222133-a101b041ded4/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
|
||||
golang.org/x/tools v0.0.0-20190920225731-5eefd052ad72/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7 h1:9zdDQZ7Thm29KFXgAX/+yaf3eVbP7djjWp/dXAppNCc=
|
||||
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
|
@ -616,7 +617,10 @@ gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
|||
gopkg.in/yaml.v2 v2.2.8 h1:obN1ZagJSUGI0Ek/LBmuj4SNLPfIny3KsKFopxRdj10=
|
||||
gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
gotest.tools v0.0.0-20190624233834-05ebafbffc79/go.mod h1:R//lfYlUuTOTfblYI3lGoAAAebUdzjvbmQsuB7Ykd90=
|
||||
gotest.tools v2.2.0+incompatible h1:VsBPFP1AI068pPrMxtb/S8Zkgf9xEmTLJjfM+P5UIEo=
|
||||
gotest.tools v2.2.0+incompatible/go.mod h1:DsYFclhRJ6vuDpmuTbkuFWG+y2sxOXAzmJt81HFBacw=
|
||||
gotest.tools/v3 v3.0.2 h1:kG1BFyqVHuQoVQiR1bWGnfz/fmHvvuiSPIV7rvl360E=
|
||||
gotest.tools/v3 v3.0.2/go.mod h1:3SzNCllyD9/Y+b5r9JIKQ474KzkZyqLqEfYqMsX94Bk=
|
||||
honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
||||
honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
||||
k8s.io/api v0.0.0-20190620084959-7cf5895f2711/go.mod h1:TBhBqb1AWbBQbW3XRusr7n7E4v2+5ZY8r8sAMnyFC5A=
|
||||
|
|
|
@ -11,8 +11,8 @@ import (
|
|||
|
||||
"github.com/containers/libpod/libpod/define"
|
||||
"github.com/containers/libpod/libpod/events"
|
||||
"github.com/containers/libpod/pkg/capabilities"
|
||||
"github.com/containers/storage/pkg/stringid"
|
||||
"github.com/docker/docker/oci/caps"
|
||||
"github.com/opentracing/opentracing-go"
|
||||
"github.com/pkg/errors"
|
||||
"github.com/sirupsen/logrus"
|
||||
|
@ -237,7 +237,7 @@ func (c *Container) Exec(tty, privileged bool, env map[string]string, cmd []stri
|
|||
}
|
||||
|
||||
if privileged || c.config.Privileged {
|
||||
capList = caps.GetAllCapabilities()
|
||||
capList = capabilities.AllCapabilities()
|
||||
}
|
||||
|
||||
// Generate exec session ID
|
||||
|
|
|
@ -5,7 +5,7 @@ import (
|
|||
"syscall"
|
||||
|
||||
"github.com/containers/libpod/libpod"
|
||||
"github.com/docker/docker/pkg/signal"
|
||||
"github.com/containers/libpod/pkg/signal"
|
||||
"github.com/sirupsen/logrus"
|
||||
)
|
||||
|
||||
|
@ -20,7 +20,7 @@ func ProxySignals(ctr *libpod.Container) {
|
|||
for s := range sigBuffer {
|
||||
// Ignore SIGCHLD and SIGPIPE - these are mostly likely
|
||||
// intended for the podman command itself.
|
||||
if s == signal.SIGCHLD || s == signal.SIGPIPE {
|
||||
if s == syscall.SIGCHLD || s == syscall.SIGPIPE {
|
||||
continue
|
||||
}
|
||||
|
||||
|
|
|
@ -3,9 +3,9 @@ package adapter
|
|||
import (
|
||||
"context"
|
||||
"os"
|
||||
gosignal "os/signal"
|
||||
"os/signal"
|
||||
|
||||
"github.com/docker/docker/pkg/signal"
|
||||
lsignal "github.com/containers/libpod/pkg/signal"
|
||||
"github.com/docker/docker/pkg/term"
|
||||
"github.com/pkg/errors"
|
||||
"github.com/sirupsen/logrus"
|
||||
|
@ -33,7 +33,7 @@ func getResize() *remotecommand.TerminalSize {
|
|||
// Helper for prepareAttach - set up a goroutine to generate terminal resize events
|
||||
func resizeTty(ctx context.Context, resize chan remotecommand.TerminalSize) {
|
||||
sigchan := make(chan os.Signal, 1)
|
||||
gosignal.Notify(sigchan, signal.SIGWINCH)
|
||||
signal.Notify(sigchan, lsignal.SIGWINCH)
|
||||
go func() {
|
||||
defer close(resize)
|
||||
// Update the terminal size immediately without waiting
|
||||
|
|
|
@ -12,9 +12,9 @@ import (
|
|||
image2 "github.com/containers/libpod/libpod/image"
|
||||
"github.com/containers/libpod/pkg/api/handlers/utils"
|
||||
"github.com/containers/libpod/pkg/namespaces"
|
||||
"github.com/containers/libpod/pkg/signal"
|
||||
createconfig "github.com/containers/libpod/pkg/spec"
|
||||
"github.com/containers/storage"
|
||||
"github.com/docker/docker/pkg/signal"
|
||||
"github.com/gorilla/schema"
|
||||
"github.com/pkg/errors"
|
||||
log "github.com/sirupsen/logrus"
|
||||
|
|
|
@ -0,0 +1,129 @@
|
|||
package capabilities
|
||||
|
||||
// Copyright 2013-2018 Docker, Inc.
|
||||
|
||||
// NOTE: this package has been copied from github.com/docker/docker but been
|
||||
// changed significantly to fit the needs of libpod.
|
||||
|
||||
import (
|
||||
"strings"
|
||||
|
||||
"github.com/containers/libpod/pkg/util"
|
||||
"github.com/pkg/errors"
|
||||
"github.com/syndtr/gocapability/capability"
|
||||
)
|
||||
|
||||
var (
|
||||
// Used internally and populated during init().
|
||||
capabilityList []string
|
||||
|
||||
// ErrUnknownCapability is thrown when an unknown capability is processed.
|
||||
ErrUnknownCapability = errors.New("unknown capability")
|
||||
)
|
||||
|
||||
// All is a special value used to add/drop all known capababilities.
|
||||
// Useful on the CLI for `--cap-add=all` etc.
|
||||
const All = "ALL"
|
||||
|
||||
func init() {
|
||||
last := capability.CAP_LAST_CAP
|
||||
// hack for RHEL6 which has no /proc/sys/kernel/cap_last_cap
|
||||
if last == capability.Cap(63) {
|
||||
last = capability.CAP_BLOCK_SUSPEND
|
||||
}
|
||||
for _, cap := range capability.List() {
|
||||
if cap > last {
|
||||
continue
|
||||
}
|
||||
capabilityList = append(capabilityList, "CAP_"+strings.ToUpper(cap.String()))
|
||||
}
|
||||
}
|
||||
|
||||
// AllCapabilities returns all known capabilities.
|
||||
func AllCapabilities() []string {
|
||||
return capabilityList
|
||||
}
|
||||
|
||||
// normalizeCapabilities normalizes caps by adding a "CAP_" prefix (if not yet
|
||||
// present).
|
||||
func normalizeCapabilities(caps []string) ([]string, error) {
|
||||
normalized := make([]string, len(caps))
|
||||
for i, c := range caps {
|
||||
c = strings.ToUpper(c)
|
||||
if c == All {
|
||||
normalized = append(normalized, c)
|
||||
continue
|
||||
}
|
||||
if !strings.HasPrefix(c, "CAP_") {
|
||||
c = "CAP_" + c
|
||||
}
|
||||
if !util.StringInSlice(c, capabilityList) {
|
||||
return nil, errors.Wrapf(ErrUnknownCapability, "%q", c)
|
||||
}
|
||||
normalized[i] = c
|
||||
}
|
||||
return normalized, nil
|
||||
}
|
||||
|
||||
// ValidateCapabilities validates if caps only contains valid capabilities.
|
||||
func ValidateCapabilities(caps []string) error {
|
||||
for _, c := range caps {
|
||||
if !util.StringInSlice(c, capabilityList) {
|
||||
return errors.Wrapf(ErrUnknownCapability, "%q", c)
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// MergeCapabilities computes a set of capabilities by adding capapbitilities
|
||||
// to or dropping them from base.
|
||||
//
|
||||
// Note that "ALL" will cause all known capabilities to be added/dropped but
|
||||
// the ones specified to be dropped/added.
|
||||
func MergeCapabilities(base, adds, drops []string) ([]string, error) {
|
||||
if len(adds) == 0 && len(drops) == 0 {
|
||||
// Nothing to tweak; we're done
|
||||
return base, nil
|
||||
}
|
||||
|
||||
capDrop, err := normalizeCapabilities(drops)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
capAdd, err := normalizeCapabilities(adds)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// Make sure that capDrop and capAdd are distinct sets.
|
||||
for _, drop := range capDrop {
|
||||
if util.StringInSlice(drop, capAdd) {
|
||||
return nil, errors.Errorf("capability %q cannot be dropped and added", drop)
|
||||
}
|
||||
}
|
||||
|
||||
var caps []string
|
||||
|
||||
switch {
|
||||
case util.StringInSlice(All, capAdd):
|
||||
// Add all capabilities except ones on capDrop
|
||||
for _, c := range capabilityList {
|
||||
if !util.StringInSlice(c, capDrop) {
|
||||
caps = append(caps, c)
|
||||
}
|
||||
}
|
||||
case util.StringInSlice(All, capDrop):
|
||||
// "Drop" all capabilities; use what's in capAdd instead
|
||||
caps = capAdd
|
||||
default:
|
||||
// First drop some capabilities
|
||||
for _, c := range base {
|
||||
if !util.StringInSlice(c, capDrop) {
|
||||
caps = append(caps, c)
|
||||
}
|
||||
}
|
||||
// Then add the list of capabilities from capAdd
|
||||
caps = append(caps, capAdd...)
|
||||
}
|
||||
return caps, nil
|
||||
}
|
|
@ -1,8 +1,18 @@
|
|||
// +build !mips,!mipsle,!mips64,!mips64le
|
||||
// +build linux
|
||||
|
||||
package signal // import "github.com/docker/docker/pkg/signal"
|
||||
// Signal handling for Linux only.
|
||||
package signal
|
||||
|
||||
// Copyright 2013-2018 Docker, Inc.
|
||||
|
||||
// NOTE: this package has originally been copied from github.com/docker/docker.
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"os/signal"
|
||||
"strconv"
|
||||
"strings"
|
||||
"syscall"
|
||||
|
||||
"golang.org/x/sys/unix"
|
||||
|
@ -11,10 +21,12 @@ import (
|
|||
const (
|
||||
sigrtmin = 34
|
||||
sigrtmax = 64
|
||||
|
||||
SIGWINCH = syscall.SIGWINCH // For cross-compilation with Windows
|
||||
)
|
||||
|
||||
// SignalMap is a map of Linux signals.
|
||||
var SignalMap = map[string]syscall.Signal{
|
||||
// signalMap is a map of Linux signals.
|
||||
var signalMap = map[string]syscall.Signal{
|
||||
"ABRT": unix.SIGABRT,
|
||||
"ALRM": unix.SIGALRM,
|
||||
"BUS": unix.SIGBUS,
|
||||
|
@ -81,3 +93,35 @@ var SignalMap = map[string]syscall.Signal{
|
|||
"RTMAX-1": sigrtmax - 1,
|
||||
"RTMAX": sigrtmax,
|
||||
}
|
||||
|
||||
// ParseSignal translates a string to a valid syscall signal.
|
||||
// It returns an error if the signal map doesn't include the given signal.
|
||||
func ParseSignal(rawSignal string) (syscall.Signal, error) {
|
||||
s, err := strconv.Atoi(rawSignal)
|
||||
if err == nil {
|
||||
if s == 0 {
|
||||
return -1, fmt.Errorf("invalid signal: %s", rawSignal)
|
||||
}
|
||||
return syscall.Signal(s), nil
|
||||
}
|
||||
signal, ok := signalMap[strings.TrimPrefix(strings.ToUpper(rawSignal), "SIG")]
|
||||
if !ok {
|
||||
return -1, fmt.Errorf("invalid signal: %s", rawSignal)
|
||||
}
|
||||
return signal, nil
|
||||
}
|
||||
|
||||
// CatchAll catches all signals and relays them to the specified channel.
|
||||
func CatchAll(sigc chan os.Signal) {
|
||||
var handledSigs []os.Signal
|
||||
for _, s := range signalMap {
|
||||
handledSigs = append(handledSigs, s)
|
||||
}
|
||||
signal.Notify(sigc, handledSigs...)
|
||||
}
|
||||
|
||||
// StopCatch stops catching the signals and closes the specified channel.
|
||||
func StopCatch(sigc chan os.Signal) {
|
||||
signal.Stop(sigc)
|
||||
close(sigc)
|
||||
}
|
|
@ -0,0 +1,28 @@
|
|||
// +build !linux
|
||||
|
||||
// Signal handling for Linux only.
|
||||
package signal
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"syscall"
|
||||
)
|
||||
|
||||
const SIGWINCH = syscall.Signal(0xff)
|
||||
|
||||
// ParseSignal translates a string to a valid syscall signal.
|
||||
// It returns an error if the signal map doesn't include the given signal.
|
||||
func ParseSignal(rawSignal string) (syscall.Signal, error) {
|
||||
return 0, fmt.Errorf("unsupported on non-linux platforms")
|
||||
}
|
||||
|
||||
// CatchAll catches all signals and relays them to the specified channel.
|
||||
func CatchAll(sigc chan os.Signal) {
|
||||
panic("Unsupported on non-linux platforms")
|
||||
}
|
||||
|
||||
// StopCatch stops catching the signals and closes the specified channel.
|
||||
func StopCatch(sigc chan os.Signal) {
|
||||
panic("Unsupported on non-linux platforms")
|
||||
}
|
|
@ -5,7 +5,7 @@ import (
|
|||
"strings"
|
||||
|
||||
"github.com/containers/libpod/libpod"
|
||||
"github.com/docker/docker/oci/caps"
|
||||
"github.com/containers/libpod/pkg/capabilities"
|
||||
"github.com/opencontainers/runtime-tools/generate"
|
||||
"github.com/opencontainers/selinux/go-selinux/label"
|
||||
"github.com/pkg/errors"
|
||||
|
@ -118,7 +118,7 @@ func (c *SecurityConfig) ConfigureGenerator(g *generate.Generator, user *UserCon
|
|||
if useNotRoot(user.User) {
|
||||
configSpec.Process.Capabilities.Bounding = caplist
|
||||
}
|
||||
caplist, err = caps.TweakCapabilities(configSpec.Process.Capabilities.Bounding, c.CapAdd, c.CapDrop, nil, false)
|
||||
caplist, err = capabilities.MergeCapabilities(configSpec.Process.Capabilities.Bounding, c.CapAdd, c.CapDrop)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
@ -129,7 +129,7 @@ func (c *SecurityConfig) ConfigureGenerator(g *generate.Generator, user *UserCon
|
|||
configSpec.Process.Capabilities.Effective = caplist
|
||||
configSpec.Process.Capabilities.Ambient = caplist
|
||||
if useNotRoot(user.User) {
|
||||
caplist, err = caps.TweakCapabilities(bounding, c.CapAdd, c.CapDrop, nil, false)
|
||||
caplist, err = capabilities.MergeCapabilities(bounding, c.CapAdd, c.CapDrop)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
|
|
@ -18,9 +18,9 @@ import (
|
|||
"github.com/containers/libpod/pkg/errorhandling"
|
||||
"github.com/containers/libpod/pkg/namespaces"
|
||||
"github.com/containers/libpod/pkg/rootless"
|
||||
"github.com/containers/libpod/pkg/signal"
|
||||
"github.com/containers/storage"
|
||||
"github.com/containers/storage/pkg/idtools"
|
||||
"github.com/docker/docker/pkg/signal"
|
||||
v1 "github.com/opencontainers/image-spec/specs-go/v1"
|
||||
"github.com/pkg/errors"
|
||||
"github.com/sirupsen/logrus"
|
||||
|
|
|
@ -70,10 +70,10 @@ load helpers
|
|||
for s in ${bad_signal_names[@]}; do
|
||||
# 'nosuchcontainer' is fine: podman should bail before it gets there
|
||||
run_podman 125 kill -s $s nosuchcontainer
|
||||
is "$output" "Error: Invalid signal: $s" "Error from kill -s $s"
|
||||
is "$output" "Error: invalid signal: $s" "Error from kill -s $s"
|
||||
|
||||
run_podman 125 pod kill -s $s nosuchpod
|
||||
is "$output" "Error: Invalid signal: $s" "Error from pod kill -s $s"
|
||||
is "$output" "Error: invalid signal: $s" "Error from pod kill -s $s"
|
||||
done
|
||||
|
||||
# Special case: these too are thrown by docker/signal.ParseSignal(),
|
||||
|
@ -82,7 +82,7 @@ load helpers
|
|||
local -a bad_dash_signals=(-0 -SIGBADSIG -SIG -BADSIG -)
|
||||
for s in ${bad_dash_signals[@]}; do
|
||||
run_podman 125 kill -s $s nosuchcontainer
|
||||
is "$output" "Error: Invalid signal: ${s##-}" "Error from kill -s $s"
|
||||
is "$output" "Error: invalid signal: ${s##-}" "Error from kill -s $s"
|
||||
done
|
||||
|
||||
# This error (signal out of range) is thrown by our wrapper
|
||||
|
|
|
@ -1,21 +0,0 @@
|
|||
package caps // import "github.com/docker/docker/oci/caps"
|
||||
|
||||
// DefaultCapabilities returns a Linux kernel default capabilities
|
||||
func DefaultCapabilities() []string {
|
||||
return []string{
|
||||
"CAP_CHOWN",
|
||||
"CAP_DAC_OVERRIDE",
|
||||
"CAP_FSETID",
|
||||
"CAP_FOWNER",
|
||||
"CAP_MKNOD",
|
||||
"CAP_NET_RAW",
|
||||
"CAP_SETGID",
|
||||
"CAP_SETUID",
|
||||
"CAP_SETFCAP",
|
||||
"CAP_SETPCAP",
|
||||
"CAP_NET_BIND_SERVICE",
|
||||
"CAP_SYS_CHROOT",
|
||||
"CAP_KILL",
|
||||
"CAP_AUDIT_WRITE",
|
||||
}
|
||||
}
|
|
@ -1,169 +0,0 @@
|
|||
package caps // import "github.com/docker/docker/oci/caps"
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
"github.com/docker/docker/errdefs"
|
||||
"github.com/syndtr/gocapability/capability"
|
||||
)
|
||||
|
||||
var capabilityList Capabilities
|
||||
|
||||
func init() {
|
||||
last := capability.CAP_LAST_CAP
|
||||
// hack for RHEL6 which has no /proc/sys/kernel/cap_last_cap
|
||||
if last == capability.Cap(63) {
|
||||
last = capability.CAP_BLOCK_SUSPEND
|
||||
}
|
||||
for _, cap := range capability.List() {
|
||||
if cap > last {
|
||||
continue
|
||||
}
|
||||
capabilityList = append(capabilityList,
|
||||
&CapabilityMapping{
|
||||
Key: "CAP_" + strings.ToUpper(cap.String()),
|
||||
Value: cap,
|
||||
},
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
type (
|
||||
// CapabilityMapping maps linux capability name to its value of capability.Cap type
|
||||
// Capabilities is one of the security systems in Linux Security Module (LSM)
|
||||
// framework provided by the kernel.
|
||||
// For more details on capabilities, see http://man7.org/linux/man-pages/man7/capabilities.7.html
|
||||
CapabilityMapping struct {
|
||||
Key string `json:"key,omitempty"`
|
||||
Value capability.Cap `json:"value,omitempty"`
|
||||
}
|
||||
// Capabilities contains all CapabilityMapping
|
||||
Capabilities []*CapabilityMapping
|
||||
)
|
||||
|
||||
// String returns <key> of CapabilityMapping
|
||||
func (c *CapabilityMapping) String() string {
|
||||
return c.Key
|
||||
}
|
||||
|
||||
// GetCapability returns CapabilityMapping which contains specific key
|
||||
func GetCapability(key string) *CapabilityMapping {
|
||||
for _, capp := range capabilityList {
|
||||
if capp.Key == key {
|
||||
cpy := *capp
|
||||
return &cpy
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// GetAllCapabilities returns all of the capabilities
|
||||
func GetAllCapabilities() []string {
|
||||
output := make([]string, len(capabilityList))
|
||||
for i, capability := range capabilityList {
|
||||
output[i] = capability.String()
|
||||
}
|
||||
return output
|
||||
}
|
||||
|
||||
// inSlice tests whether a string is contained in a slice of strings or not.
|
||||
func inSlice(slice []string, s string) bool {
|
||||
for _, ss := range slice {
|
||||
if s == ss {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
const allCapabilities = "ALL"
|
||||
|
||||
// NormalizeLegacyCapabilities normalizes, and validates CapAdd/CapDrop capabilities
|
||||
// by upper-casing them, and adding a CAP_ prefix (if not yet present).
|
||||
//
|
||||
// This function also accepts the "ALL" magic-value, that's used by CapAdd/CapDrop.
|
||||
func NormalizeLegacyCapabilities(caps []string) ([]string, error) {
|
||||
var normalized []string
|
||||
|
||||
valids := GetAllCapabilities()
|
||||
for _, c := range caps {
|
||||
c = strings.ToUpper(c)
|
||||
if c == allCapabilities {
|
||||
normalized = append(normalized, c)
|
||||
continue
|
||||
}
|
||||
if !strings.HasPrefix(c, "CAP_") {
|
||||
c = "CAP_" + c
|
||||
}
|
||||
if !inSlice(valids, c) {
|
||||
return nil, errdefs.InvalidParameter(fmt.Errorf("unknown capability: %q", c))
|
||||
}
|
||||
normalized = append(normalized, c)
|
||||
}
|
||||
return normalized, nil
|
||||
}
|
||||
|
||||
// ValidateCapabilities validates if caps only contains valid capabilities
|
||||
func ValidateCapabilities(caps []string) error {
|
||||
valids := GetAllCapabilities()
|
||||
for _, c := range caps {
|
||||
if !inSlice(valids, c) {
|
||||
return errdefs.InvalidParameter(fmt.Errorf("unknown capability: %q", c))
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// TweakCapabilities tweaks capabilities by adding, dropping, or overriding
|
||||
// capabilities in the basics capabilities list.
|
||||
func TweakCapabilities(basics, adds, drops, capabilities []string, privileged bool) ([]string, error) {
|
||||
switch {
|
||||
case privileged:
|
||||
// Privileged containers get all capabilities
|
||||
return GetAllCapabilities(), nil
|
||||
case capabilities != nil:
|
||||
// Use custom set of capabilities
|
||||
if err := ValidateCapabilities(capabilities); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return capabilities, nil
|
||||
case len(adds) == 0 && len(drops) == 0:
|
||||
// Nothing to tweak; we're done
|
||||
return basics, nil
|
||||
}
|
||||
|
||||
capDrop, err := NormalizeLegacyCapabilities(drops)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
capAdd, err := NormalizeLegacyCapabilities(adds)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var caps []string
|
||||
|
||||
switch {
|
||||
case inSlice(capAdd, allCapabilities):
|
||||
// Add all capabilities except ones on capDrop
|
||||
for _, c := range GetAllCapabilities() {
|
||||
if !inSlice(capDrop, c) {
|
||||
caps = append(caps, c)
|
||||
}
|
||||
}
|
||||
case inSlice(capDrop, allCapabilities):
|
||||
// "Drop" all capabilities; use what's in capAdd instead
|
||||
caps = capAdd
|
||||
default:
|
||||
// First drop some capabilities
|
||||
for _, c := range basics {
|
||||
if !inSlice(capDrop, c) {
|
||||
caps = append(caps, c)
|
||||
}
|
||||
}
|
||||
// Then add the list of capabilities from capAdd
|
||||
caps = append(caps, capAdd...)
|
||||
}
|
||||
return caps, nil
|
||||
}
|
|
@ -1 +0,0 @@
|
|||
This package provides helper functions for dealing with signals across various operating systems
|
|
@ -1,54 +0,0 @@
|
|||
// Package signal provides helper functions for dealing with signals across
|
||||
// various operating systems.
|
||||
package signal // import "github.com/docker/docker/pkg/signal"
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"os/signal"
|
||||
"strconv"
|
||||
"strings"
|
||||
"syscall"
|
||||
)
|
||||
|
||||
// CatchAll catches all signals and relays them to the specified channel.
|
||||
func CatchAll(sigc chan os.Signal) {
|
||||
var handledSigs []os.Signal
|
||||
for _, s := range SignalMap {
|
||||
handledSigs = append(handledSigs, s)
|
||||
}
|
||||
signal.Notify(sigc, handledSigs...)
|
||||
}
|
||||
|
||||
// StopCatch stops catching the signals and closes the specified channel.
|
||||
func StopCatch(sigc chan os.Signal) {
|
||||
signal.Stop(sigc)
|
||||
close(sigc)
|
||||
}
|
||||
|
||||
// ParseSignal translates a string to a valid syscall signal.
|
||||
// It returns an error if the signal map doesn't include the given signal.
|
||||
func ParseSignal(rawSignal string) (syscall.Signal, error) {
|
||||
s, err := strconv.Atoi(rawSignal)
|
||||
if err == nil {
|
||||
if s == 0 {
|
||||
return -1, fmt.Errorf("Invalid signal: %s", rawSignal)
|
||||
}
|
||||
return syscall.Signal(s), nil
|
||||
}
|
||||
signal, ok := SignalMap[strings.TrimPrefix(strings.ToUpper(rawSignal), "SIG")]
|
||||
if !ok {
|
||||
return -1, fmt.Errorf("Invalid signal: %s", rawSignal)
|
||||
}
|
||||
return signal, nil
|
||||
}
|
||||
|
||||
// ValidSignalForPlatform returns true if a signal is valid on the platform
|
||||
func ValidSignalForPlatform(sig syscall.Signal) bool {
|
||||
for _, v := range SignalMap {
|
||||
if v == sig {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
|
@ -1,41 +0,0 @@
|
|||
package signal // import "github.com/docker/docker/pkg/signal"
|
||||
|
||||
import (
|
||||
"syscall"
|
||||
)
|
||||
|
||||
// SignalMap is a map of Darwin signals.
|
||||
var SignalMap = map[string]syscall.Signal{
|
||||
"ABRT": syscall.SIGABRT,
|
||||
"ALRM": syscall.SIGALRM,
|
||||
"BUG": syscall.SIGBUS,
|
||||
"CHLD": syscall.SIGCHLD,
|
||||
"CONT": syscall.SIGCONT,
|
||||
"EMT": syscall.SIGEMT,
|
||||
"FPE": syscall.SIGFPE,
|
||||
"HUP": syscall.SIGHUP,
|
||||
"ILL": syscall.SIGILL,
|
||||
"INFO": syscall.SIGINFO,
|
||||
"INT": syscall.SIGINT,
|
||||
"IO": syscall.SIGIO,
|
||||
"IOT": syscall.SIGIOT,
|
||||
"KILL": syscall.SIGKILL,
|
||||
"PIPE": syscall.SIGPIPE,
|
||||
"PROF": syscall.SIGPROF,
|
||||
"QUIT": syscall.SIGQUIT,
|
||||
"SEGV": syscall.SIGSEGV,
|
||||
"STOP": syscall.SIGSTOP,
|
||||
"SYS": syscall.SIGSYS,
|
||||
"TERM": syscall.SIGTERM,
|
||||
"TRAP": syscall.SIGTRAP,
|
||||
"TSTP": syscall.SIGTSTP,
|
||||
"TTIN": syscall.SIGTTIN,
|
||||
"TTOU": syscall.SIGTTOU,
|
||||
"URG": syscall.SIGURG,
|
||||
"USR1": syscall.SIGUSR1,
|
||||
"USR2": syscall.SIGUSR2,
|
||||
"VTALRM": syscall.SIGVTALRM,
|
||||
"WINCH": syscall.SIGWINCH,
|
||||
"XCPU": syscall.SIGXCPU,
|
||||
"XFSZ": syscall.SIGXFSZ,
|
||||
}
|
|
@ -1,43 +0,0 @@
|
|||
package signal // import "github.com/docker/docker/pkg/signal"
|
||||
|
||||
import (
|
||||
"syscall"
|
||||
)
|
||||
|
||||
// SignalMap is a map of FreeBSD signals.
|
||||
var SignalMap = map[string]syscall.Signal{
|
||||
"ABRT": syscall.SIGABRT,
|
||||
"ALRM": syscall.SIGALRM,
|
||||
"BUF": syscall.SIGBUS,
|
||||
"CHLD": syscall.SIGCHLD,
|
||||
"CONT": syscall.SIGCONT,
|
||||
"EMT": syscall.SIGEMT,
|
||||
"FPE": syscall.SIGFPE,
|
||||
"HUP": syscall.SIGHUP,
|
||||
"ILL": syscall.SIGILL,
|
||||
"INFO": syscall.SIGINFO,
|
||||
"INT": syscall.SIGINT,
|
||||
"IO": syscall.SIGIO,
|
||||
"IOT": syscall.SIGIOT,
|
||||
"KILL": syscall.SIGKILL,
|
||||
"LWP": syscall.SIGLWP,
|
||||
"PIPE": syscall.SIGPIPE,
|
||||
"PROF": syscall.SIGPROF,
|
||||
"QUIT": syscall.SIGQUIT,
|
||||
"SEGV": syscall.SIGSEGV,
|
||||
"STOP": syscall.SIGSTOP,
|
||||
"SYS": syscall.SIGSYS,
|
||||
"TERM": syscall.SIGTERM,
|
||||
"THR": syscall.SIGTHR,
|
||||
"TRAP": syscall.SIGTRAP,
|
||||
"TSTP": syscall.SIGTSTP,
|
||||
"TTIN": syscall.SIGTTIN,
|
||||
"TTOU": syscall.SIGTTOU,
|
||||
"URG": syscall.SIGURG,
|
||||
"USR1": syscall.SIGUSR1,
|
||||
"USR2": syscall.SIGUSR2,
|
||||
"VTALRM": syscall.SIGVTALRM,
|
||||
"WINCH": syscall.SIGWINCH,
|
||||
"XCPU": syscall.SIGXCPU,
|
||||
"XFSZ": syscall.SIGXFSZ,
|
||||
}
|
|
@ -1,84 +0,0 @@
|
|||
// +build linux
|
||||
// +build mips mipsle mips64 mips64le
|
||||
|
||||
package signal // import "github.com/docker/docker/pkg/signal"
|
||||
|
||||
import (
|
||||
"syscall"
|
||||
|
||||
"golang.org/x/sys/unix"
|
||||
)
|
||||
|
||||
const (
|
||||
sigrtmin = 34
|
||||
sigrtmax = 127
|
||||
)
|
||||
|
||||
// SignalMap is a map of Linux signals.
|
||||
var SignalMap = map[string]syscall.Signal{
|
||||
"ABRT": unix.SIGABRT,
|
||||
"ALRM": unix.SIGALRM,
|
||||
"BUS": unix.SIGBUS,
|
||||
"CHLD": unix.SIGCHLD,
|
||||
"CLD": unix.SIGCLD,
|
||||
"CONT": unix.SIGCONT,
|
||||
"FPE": unix.SIGFPE,
|
||||
"HUP": unix.SIGHUP,
|
||||
"ILL": unix.SIGILL,
|
||||
"INT": unix.SIGINT,
|
||||
"IO": unix.SIGIO,
|
||||
"IOT": unix.SIGIOT,
|
||||
"KILL": unix.SIGKILL,
|
||||
"PIPE": unix.SIGPIPE,
|
||||
"POLL": unix.SIGPOLL,
|
||||
"PROF": unix.SIGPROF,
|
||||
"PWR": unix.SIGPWR,
|
||||
"QUIT": unix.SIGQUIT,
|
||||
"SEGV": unix.SIGSEGV,
|
||||
"SIGEMT": unix.SIGEMT,
|
||||
"STOP": unix.SIGSTOP,
|
||||
"SYS": unix.SIGSYS,
|
||||
"TERM": unix.SIGTERM,
|
||||
"TRAP": unix.SIGTRAP,
|
||||
"TSTP": unix.SIGTSTP,
|
||||
"TTIN": unix.SIGTTIN,
|
||||
"TTOU": unix.SIGTTOU,
|
||||
"URG": unix.SIGURG,
|
||||
"USR1": unix.SIGUSR1,
|
||||
"USR2": unix.SIGUSR2,
|
||||
"VTALRM": unix.SIGVTALRM,
|
||||
"WINCH": unix.SIGWINCH,
|
||||
"XCPU": unix.SIGXCPU,
|
||||
"XFSZ": unix.SIGXFSZ,
|
||||
"RTMIN": sigrtmin,
|
||||
"RTMIN+1": sigrtmin + 1,
|
||||
"RTMIN+2": sigrtmin + 2,
|
||||
"RTMIN+3": sigrtmin + 3,
|
||||
"RTMIN+4": sigrtmin + 4,
|
||||
"RTMIN+5": sigrtmin + 5,
|
||||
"RTMIN+6": sigrtmin + 6,
|
||||
"RTMIN+7": sigrtmin + 7,
|
||||
"RTMIN+8": sigrtmin + 8,
|
||||
"RTMIN+9": sigrtmin + 9,
|
||||
"RTMIN+10": sigrtmin + 10,
|
||||
"RTMIN+11": sigrtmin + 11,
|
||||
"RTMIN+12": sigrtmin + 12,
|
||||
"RTMIN+13": sigrtmin + 13,
|
||||
"RTMIN+14": sigrtmin + 14,
|
||||
"RTMIN+15": sigrtmin + 15,
|
||||
"RTMAX-14": sigrtmax - 14,
|
||||
"RTMAX-13": sigrtmax - 13,
|
||||
"RTMAX-12": sigrtmax - 12,
|
||||
"RTMAX-11": sigrtmax - 11,
|
||||
"RTMAX-10": sigrtmax - 10,
|
||||
"RTMAX-9": sigrtmax - 9,
|
||||
"RTMAX-8": sigrtmax - 8,
|
||||
"RTMAX-7": sigrtmax - 7,
|
||||
"RTMAX-6": sigrtmax - 6,
|
||||
"RTMAX-5": sigrtmax - 5,
|
||||
"RTMAX-4": sigrtmax - 4,
|
||||
"RTMAX-3": sigrtmax - 3,
|
||||
"RTMAX-2": sigrtmax - 2,
|
||||
"RTMAX-1": sigrtmax - 1,
|
||||
"RTMAX": sigrtmax,
|
||||
}
|
|
@ -1,21 +0,0 @@
|
|||
// +build !windows
|
||||
|
||||
package signal // import "github.com/docker/docker/pkg/signal"
|
||||
|
||||
import (
|
||||
"syscall"
|
||||
)
|
||||
|
||||
// Signals used in cli/command (no windows equivalent, use
|
||||
// invalid signals so they don't get handled)
|
||||
|
||||
const (
|
||||
// SIGCHLD is a signal sent to a process when a child process terminates, is interrupted, or resumes after being interrupted.
|
||||
SIGCHLD = syscall.SIGCHLD
|
||||
// SIGWINCH is a signal sent to a process when its controlling terminal changes its size
|
||||
SIGWINCH = syscall.SIGWINCH
|
||||
// SIGPIPE is a signal sent to a process when a pipe is written to before the other end is open for reading
|
||||
SIGPIPE = syscall.SIGPIPE
|
||||
// DefaultStopSignal is the syscall signal used to stop a container in unix systems.
|
||||
DefaultStopSignal = "SIGTERM"
|
||||
)
|
|
@ -1,10 +0,0 @@
|
|||
// +build !linux,!darwin,!freebsd,!windows
|
||||
|
||||
package signal // import "github.com/docker/docker/pkg/signal"
|
||||
|
||||
import (
|
||||
"syscall"
|
||||
)
|
||||
|
||||
// SignalMap is an empty map of signals for unsupported platform.
|
||||
var SignalMap = map[string]syscall.Signal{}
|
|
@ -1,26 +0,0 @@
|
|||
package signal // import "github.com/docker/docker/pkg/signal"
|
||||
|
||||
import (
|
||||
"syscall"
|
||||
)
|
||||
|
||||
// Signals used in cli/command (no windows equivalent, use
|
||||
// invalid signals so they don't get handled)
|
||||
const (
|
||||
SIGCHLD = syscall.Signal(0xff)
|
||||
SIGWINCH = syscall.Signal(0xff)
|
||||
SIGPIPE = syscall.Signal(0xff)
|
||||
// DefaultStopSignal is the syscall signal used to stop a container in windows systems.
|
||||
DefaultStopSignal = "15"
|
||||
)
|
||||
|
||||
// SignalMap is a map of "supported" signals. As per the comment in GOLang's
|
||||
// ztypes_windows.go: "More invented values for signals". Windows doesn't
|
||||
// really support signals in any way, shape or form that Unix does.
|
||||
//
|
||||
// We have these so that docker kill can be used to gracefully (TERM) and
|
||||
// forcibly (KILL) terminate a container on Windows.
|
||||
var SignalMap = map[string]syscall.Signal{
|
||||
"KILL": syscall.SIGKILL,
|
||||
"TERM": syscall.SIGTERM,
|
||||
}
|
|
@ -1,104 +0,0 @@
|
|||
package signal // import "github.com/docker/docker/pkg/signal"
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
gosignal "os/signal"
|
||||
"path/filepath"
|
||||
"runtime"
|
||||
"strings"
|
||||
"sync/atomic"
|
||||
"syscall"
|
||||
"time"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
)
|
||||
|
||||
// Trap sets up a simplified signal "trap", appropriate for common
|
||||
// behavior expected from a vanilla unix command-line tool in general
|
||||
// (and the Docker engine in particular).
|
||||
//
|
||||
// * If SIGINT or SIGTERM are received, `cleanup` is called, then the process is terminated.
|
||||
// * If SIGINT or SIGTERM are received 3 times before cleanup is complete, then cleanup is
|
||||
// skipped and the process is terminated immediately (allows force quit of stuck daemon)
|
||||
// * A SIGQUIT always causes an exit without cleanup, with a goroutine dump preceding exit.
|
||||
// * Ignore SIGPIPE events. These are generated by systemd when journald is restarted while
|
||||
// the docker daemon is not restarted and also running under systemd.
|
||||
// Fixes https://github.com/docker/docker/issues/19728
|
||||
//
|
||||
func Trap(cleanup func(), logger interface {
|
||||
Info(args ...interface{})
|
||||
}) {
|
||||
c := make(chan os.Signal, 1)
|
||||
// we will handle INT, TERM, QUIT, SIGPIPE here
|
||||
signals := []os.Signal{os.Interrupt, syscall.SIGTERM, syscall.SIGQUIT, syscall.SIGPIPE}
|
||||
gosignal.Notify(c, signals...)
|
||||
go func() {
|
||||
interruptCount := uint32(0)
|
||||
for sig := range c {
|
||||
if sig == syscall.SIGPIPE {
|
||||
continue
|
||||
}
|
||||
|
||||
go func(sig os.Signal) {
|
||||
logger.Info(fmt.Sprintf("Processing signal '%v'", sig))
|
||||
switch sig {
|
||||
case os.Interrupt, syscall.SIGTERM:
|
||||
if atomic.LoadUint32(&interruptCount) < 3 {
|
||||
// Initiate the cleanup only once
|
||||
if atomic.AddUint32(&interruptCount, 1) == 1 {
|
||||
// Call the provided cleanup handler
|
||||
cleanup()
|
||||
os.Exit(0)
|
||||
} else {
|
||||
return
|
||||
}
|
||||
} else {
|
||||
// 3 SIGTERM/INT signals received; force exit without cleanup
|
||||
logger.Info("Forcing docker daemon shutdown without cleanup; 3 interrupts received")
|
||||
}
|
||||
case syscall.SIGQUIT:
|
||||
DumpStacks("")
|
||||
logger.Info("Forcing docker daemon shutdown without cleanup on SIGQUIT")
|
||||
}
|
||||
// for the SIGINT/TERM, and SIGQUIT non-clean shutdown case, exit with 128 + signal #
|
||||
os.Exit(128 + int(sig.(syscall.Signal)))
|
||||
}(sig)
|
||||
}
|
||||
}()
|
||||
}
|
||||
|
||||
const stacksLogNameTemplate = "goroutine-stacks-%s.log"
|
||||
|
||||
// DumpStacks appends the runtime stack into file in dir and returns full path
|
||||
// to that file.
|
||||
func DumpStacks(dir string) (string, error) {
|
||||
var (
|
||||
buf []byte
|
||||
stackSize int
|
||||
)
|
||||
bufferLen := 16384
|
||||
for stackSize == len(buf) {
|
||||
buf = make([]byte, bufferLen)
|
||||
stackSize = runtime.Stack(buf, true)
|
||||
bufferLen *= 2
|
||||
}
|
||||
buf = buf[:stackSize]
|
||||
var f *os.File
|
||||
if dir != "" {
|
||||
path := filepath.Join(dir, fmt.Sprintf(stacksLogNameTemplate, strings.Replace(time.Now().Format(time.RFC3339), ":", "", -1)))
|
||||
var err error
|
||||
f, err = os.OpenFile(path, os.O_CREATE|os.O_WRONLY, 0666)
|
||||
if err != nil {
|
||||
return "", errors.Wrap(err, "failed to open file to write the goroutine stacks")
|
||||
}
|
||||
defer f.Close()
|
||||
defer f.Sync()
|
||||
} else {
|
||||
f = os.Stderr
|
||||
}
|
||||
if _, err := f.Write(buf); err != nil {
|
||||
return "", errors.Wrap(err, "failed to write goroutine stacks")
|
||||
}
|
||||
return f.Name(), nil
|
||||
}
|
|
@ -227,7 +227,6 @@ github.com/docker/docker/api/types/versions
|
|||
github.com/docker/docker/api/types/volume
|
||||
github.com/docker/docker/client
|
||||
github.com/docker/docker/errdefs
|
||||
github.com/docker/docker/oci/caps
|
||||
github.com/docker/docker/pkg/archive
|
||||
github.com/docker/docker/pkg/fileutils
|
||||
github.com/docker/docker/pkg/homedir
|
||||
|
@ -239,7 +238,6 @@ github.com/docker/docker/pkg/mount
|
|||
github.com/docker/docker/pkg/namesgenerator
|
||||
github.com/docker/docker/pkg/parsers
|
||||
github.com/docker/docker/pkg/pools
|
||||
github.com/docker/docker/pkg/signal
|
||||
github.com/docker/docker/pkg/stdcopy
|
||||
github.com/docker/docker/pkg/system
|
||||
github.com/docker/docker/pkg/term
|
||||
|
|
Loading…
Reference in New Issue