Skip to content

Commit

Permalink
daemon: add a flag to override the default seccomp profile
Browse files Browse the repository at this point in the history
Signed-off-by: Antonio Murdaca <[email protected]>
  • Loading branch information
runcom committed Nov 2, 2016
1 parent ecd806c commit b237189
Show file tree
Hide file tree
Showing 15 changed files with 149 additions and 22 deletions.
14 changes: 12 additions & 2 deletions api/server/router/system/system_routes.go
Original file line number Diff line number Diff line change
Expand Up @@ -42,10 +42,20 @@ func (s *systemRouter) getInfo(ctx context.Context, w http.ResponseWriter, r *ht
if versions.LessThan(httputils.VersionFromContext(ctx), "1.25") {
// TODO: handle this conversion in engine-api
type oldInfo struct {
*types.Info
*types.InfoBase
ExecutionDriver string
SecurityOptions []string
}
return httputils.WriteJSON(w, http.StatusOK, &oldInfo{Info: info, ExecutionDriver: "<not supported>"})
old := &oldInfo{
InfoBase: info.InfoBase,
ExecutionDriver: "<not supported>",
}
for _, s := range info.SecurityOptions {
if s.Key == "Name" {
old.SecurityOptions = append(old.SecurityOptions, s.Value)
}
}
return httputils.WriteJSON(w, http.StatusOK, old)
}
return httputils.WriteJSON(w, http.StatusOK, info)
}
Expand Down
17 changes: 14 additions & 3 deletions api/types/types.go
Original file line number Diff line number Diff line change
Expand Up @@ -142,9 +142,9 @@ type Version struct {
BuildTime string `json:",omitempty"`
}

// Info contains response of Remote API:
// InfoBase contains the base response of Remote API:
// GET "/info"
type Info struct {
type InfoBase struct {
ID string
Containers int
ContainersRunning int
Expand Down Expand Up @@ -191,7 +191,6 @@ type Info struct {
ServerVersion string
ClusterStore string
ClusterAdvertise string
SecurityOptions []string
Runtimes map[string]Runtime
DefaultRuntime string
Swarm swarm.Info
Expand All @@ -202,6 +201,18 @@ type Info struct {
Isolation container.Isolation
}

// SecurityOpt holds key/value pair about a security option
type SecurityOpt struct {
Key, Value string
}

// Info contains response of Remote API:
// GET "/info"
type Info struct {
*InfoBase
SecurityOptions []SecurityOpt
}

// PluginsInfo is a temp struct holding Plugins name
// registered with docker daemon. It is used by Info struct
type PluginsInfo struct {
Expand Down
17 changes: 14 additions & 3 deletions cli/command/system/info.go
Original file line number Diff line number Diff line change
Expand Up @@ -140,9 +140,20 @@ func prettyPrintInfo(dockerCli *command.DockerCli, info types.Info) error {
}

if info.OSType == "linux" {
fmt.Fprintf(dockerCli.Out(), "Security Options:")
ioutils.FprintfIfNotEmpty(dockerCli.Out(), " %s", strings.Join(info.SecurityOptions, " "))
fmt.Fprintf(dockerCli.Out(), "\n")
if len(info.SecurityOptions) != 0 {
fmt.Fprintf(dockerCli.Out(), "Security Options:\n")
for _, o := range info.SecurityOptions {
switch o.Key {
case "Name":
fmt.Fprintf(dockerCli.Out(), " %s\n", o.Value)
case "Profile":
if o.Key != "default" {
fmt.Fprintf(dockerCli.Err(), " WARNING: You're not using the Docker's default seccomp profile\n")
}
fmt.Fprintf(dockerCli.Out(), " %s: %s\n", o.Key, o.Value)
}
}
}
}

// Isolation only has meaning on a Windows daemon.
Expand Down
6 changes: 4 additions & 2 deletions client/info_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -46,8 +46,10 @@ func TestInfo(t *testing.T) {
return nil, fmt.Errorf("Expected URL '%s', got '%s'", expectedURL, req.URL)
}
info := &types.Info{
ID: "daemonID",
Containers: 3,
InfoBase: &types.InfoBase{
ID: "daemonID",
Containers: 3,
},
}
b, err := json.Marshal(info)
if err != nil {
Expand Down
2 changes: 2 additions & 0 deletions daemon/config_unix.go
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ type Config struct {
OOMScoreAdjust int `json:"oom-score-adjust,omitempty"`
Init bool `json:"init,omitempty"`
InitPath string `json:"init-path,omitempty"`
SeccompProfile string `json:"seccomp-profile,omitempty"`
}

// bridgeConfig stores all the bridge driver specific
Expand Down Expand Up @@ -101,6 +102,7 @@ func (config *Config) InstallFlags(flags *pflag.FlagSet) {
flags.StringVar(&config.InitPath, "init-path", "", "Path to the docker-init binary")
flags.Int64Var(&config.CPURealtimePeriod, "cpu-rt-period", 0, "Limit the CPU real-time period in microseconds")
flags.Int64Var(&config.CPURealtimeRuntime, "cpu-rt-runtime", 0, "Limit the CPU real-time runtime in microseconds")
flags.StringVar(&config.SeccompProfile, "seccomp-profile", "", "Path to seccomp profile")

config.attachExperimentalFlags(flags)
}
Expand Down
7 changes: 7 additions & 0 deletions daemon/daemon.go
Original file line number Diff line number Diff line change
Expand Up @@ -104,6 +104,9 @@ type Daemon struct {
defaultIsolation containertypes.Isolation // Default isolation mode on Windows
clusterProvider cluster.Provider
cluster Cluster

seccompProfile []byte
seccompProfilePath string
}

// HasExperimental returns whether the experimental features of the daemon are enabled or not
Expand Down Expand Up @@ -530,6 +533,10 @@ func NewDaemon(config *Config, registryService registry.Service, containerdRemot
}
}()

if err := d.setupSeccompProfile(); err != nil {
return nil, err
}

// Set the default isolation mode (only applicable on Windows)
if err := d.setDefaultIsolation(); err != nil {
return nil, fmt.Errorf("error setting default isolation mode: %v", err)
Expand Down
4 changes: 4 additions & 0 deletions daemon/daemon_solaris.go
Original file line number Diff line number Diff line change
Expand Up @@ -177,3 +177,7 @@ func setupDaemonProcess(config *Config) error {
func (daemon *Daemon) verifyVolumesInfo(container *container.Container) error {
return nil
}

func (daemon *Daemon) setupSeccompProfile() error {
return nil
}
18 changes: 18 additions & 0 deletions daemon/daemon_unix.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ package daemon

import (
"bytes"
"encoding/json"
"fmt"
"io/ioutil"
"net"
Expand Down Expand Up @@ -1242,6 +1243,23 @@ func (daemon *Daemon) initCgroupsPath(path string) error {
return err
}
}
return nil
}

func (daemon *Daemon) setupSeccompProfile() error {
if daemon.configStore.SeccompProfile != "" {
daemon.seccompProfilePath = daemon.configStore.SeccompProfile
b, err := ioutil.ReadFile(daemon.configStore.SeccompProfile)
if err != nil {
return fmt.Errorf("opening seccomp profile (%s) failed: %v", daemon.configStore.SeccompProfile, err)
}
daemon.seccompProfile = b
p := struct {
DefaultAction string `json:"defaultAction"`
}{}
if err := json.Unmarshal(daemon.seccompProfile, &p); err != nil {
return err
}
}
return nil
}
4 changes: 4 additions & 0 deletions daemon/daemon_windows.go
Original file line number Diff line number Diff line change
Expand Up @@ -532,3 +532,7 @@ func setupDaemonProcess(config *Config) error {
func (daemon *Daemon) verifyVolumesInfo(container *container.Container) error {
return nil
}

func (daemon *Daemon) setupSeccompProfile() error {
return nil
}
27 changes: 19 additions & 8 deletions daemon/info.go
Original file line number Diff line number Diff line change
Expand Up @@ -68,22 +68,29 @@ func (daemon *Daemon) SystemInfo() (*types.Info, error) {
}
})

var securityOptions []string
securityOptions := []types.SecurityOpt{}
if sysInfo.AppArmor {
securityOptions = append(securityOptions, "apparmor")
securityOptions = append(securityOptions, types.SecurityOpt{Key: "Name", Value: "apparmor"})
}
if sysInfo.Seccomp && supportsSeccomp {
securityOptions = append(securityOptions, "seccomp")
profile := daemon.seccompProfilePath
if profile == "" {
profile = "default"
}
securityOptions = append(securityOptions,
types.SecurityOpt{Key: "Name", Value: "seccomp"},
types.SecurityOpt{Key: "Profile", Value: profile},
)
}
if selinuxEnabled() {
securityOptions = append(securityOptions, "selinux")
securityOptions = append(securityOptions, types.SecurityOpt{Key: "Name", Value: "selinux"})
}
uid, gid := daemon.GetRemappedUIDGID()
if uid != 0 || gid != 0 {
securityOptions = append(securityOptions, "userns")
securityOptions = append(securityOptions, types.SecurityOpt{Key: "Name", Value: "userns"})
}

v := &types.Info{
v := &types.InfoBase{
ID: daemon.ID,
Containers: int(cRunning + cPaused + cStopped),
ContainersRunning: int(cRunning),
Expand Down Expand Up @@ -120,7 +127,6 @@ func (daemon *Daemon) SystemInfo() (*types.Info, error) {
HTTPProxy: sockets.GetProxyEnv("http_proxy"),
HTTPSProxy: sockets.GetProxyEnv("https_proxy"),
NoProxy: sockets.GetProxyEnv("no_proxy"),
SecurityOptions: securityOptions,
LiveRestoreEnabled: daemon.configStore.LiveRestoreEnabled,
Isolation: daemon.defaultIsolation,
}
Expand Down Expand Up @@ -150,7 +156,12 @@ func (daemon *Daemon) SystemInfo() (*types.Info, error) {
}
v.Name = hostname

return v, nil
i := &types.Info{
InfoBase: v,
SecurityOptions: securityOptions,
}

return i, nil
}

// SystemVersion returns version information about the daemon.
Expand Down
13 changes: 10 additions & 3 deletions daemon/seccomp_linux.go
Original file line number Diff line number Diff line change
Expand Up @@ -37,9 +37,16 @@ func setSeccomp(daemon *Daemon, rs *specs.Spec, c *container.Container) error {
return err
}
} else {
profile, err = seccomp.GetDefaultProfile(rs)
if err != nil {
return err
if daemon.seccompProfile != nil {
profile, err = seccomp.LoadProfile(string(daemon.seccompProfile), rs)
if err != nil {
return err
}
} else {
profile, err = seccomp.GetDefaultProfile(rs)
if err != nil {
return err
}
}
}

Expand Down
2 changes: 2 additions & 0 deletions docs/reference/commandline/dockerd.md
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,7 @@ Options:
-p, --pidfile string Path to use for daemon PID file (default "/var/run/docker.pid")
--raw-logs Full timestamps without ANSI coloring
--registry-mirror value Preferred Docker registry mirror (default [])
--seccomp-profile value Path to seccomp profile
--selinux-enabled Enable selinux support
--shutdown-timeout=15 Set the shutdown timeout value in seconds
-s, --storage-driver string Storage driver to use
Expand Down Expand Up @@ -1195,6 +1196,7 @@ This is a full example of the allowed configuration options on Linux:
"icc": false,
"raw-logs": false,
"registry-mirrors": [],
"seccomp-profile": "",
"insecure-registries": [],
"disable-legacy-registry": false,
"default-runtime": "runc",
Expand Down
2 changes: 1 addition & 1 deletion integration-cli/docker_cli_info_unix_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,5 +11,5 @@ func (s *DockerSuite) TestInfoSecurityOptions(c *check.C) {
testRequires(c, SameHostDaemon, seccompEnabled, Apparmor, DaemonIsLinux)

out, _ := dockerCmd(c, "info")
c.Assert(out, checker.Contains, "Security Options: apparmor seccomp")
c.Assert(out, checker.Contains, "Security Options:\n apparmor\n seccomp\n Profile: default\n")
}
34 changes: 34 additions & 0 deletions integration-cli/docker_cli_run_unix_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -1375,3 +1375,37 @@ func (s *DockerDaemonSuite) TestRunSeccompJSONNoArchAndArchMap(c *check.C) {
c.Assert(err, check.NotNil)
c.Assert(out, checker.Contains, "'architectures' and 'archMap' were specified in the seccomp profile, use either 'architectures' or 'archMap'")
}

func (s *DockerDaemonSuite) TestRunWithDaemonDefaultSeccompProfile(c *check.C) {
testRequires(c, SameHostDaemon, seccompEnabled)

err := s.d.StartWithBusybox()
c.Assert(err, check.IsNil)

// 1) verify I can run containers with the Docker default shipped profile which allows chmod
_, err = s.d.Cmd("run", "busybox", "chmod", "777", ".")
c.Assert(err, check.IsNil)

jsonData := `{
"defaultAction": "SCMP_ACT_ALLOW",
"syscalls": [
{
"name": "chmod",
"action": "SCMP_ACT_ERRNO"
}
]
}`
tmpFile, err := ioutil.TempFile("", "profile.json")
c.Assert(err, check.IsNil)
defer tmpFile.Close()
_, err = tmpFile.Write([]byte(jsonData))
c.Assert(err, check.IsNil)

// 2) restart the daemon and add a custom seccomp profile in which we deny chmod
err = s.d.Restart("--seccomp-profile=" + tmpFile.Name())
c.Assert(err, check.IsNil)

out, err := s.d.Cmd("run", "busybox", "chmod", "777", ".")
c.Assert(err, check.NotNil)
c.Assert(out, checker.Contains, "Operation not permitted")
}
4 changes: 4 additions & 0 deletions man/dockerd.8.md
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,7 @@ dockerd - Enable daemon mode
[**--raw-logs**]
[**--registry-mirror**[=*[]*]]
[**-s**|**--storage-driver**[=*STORAGE-DRIVER*]]
[**--seccomp-profile**[=*SECCOMP-PROFILE-PATH*]]
[**--selinux-enabled**]
[**--shutdown-timeout**[=*15*]]
[**--storage-opt**[=*[]*]]
Expand Down Expand Up @@ -248,6 +249,9 @@ output otherwise.
**-s**, **--storage-driver**=""
Force the Docker runtime to use a specific storage driver.

**--seccomp-profile**=""
Path to seccomp profile.

**--selinux-enabled**=*true*|*false*
Enable selinux support. Default is false.

Expand Down

0 comments on commit b237189

Please sign in to comment.