Skip to content

Commit d7fda01

Browse files
committed
Add daemon flag to set no_new_priv as default for unprivileged containers.
Signed-off-by: Daniel Zhang <[email protected]>
1 parent d26cf30 commit d7fda01

9 files changed

Lines changed: 67 additions & 3 deletions

File tree

daemon/config/config_unix.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ type Config struct {
3030
InitPath string `json:"init-path,omitempty"`
3131
SeccompProfile string `json:"seccomp-profile,omitempty"`
3232
ShmSize opts.MemBytes `json:"default-shm-size,omitempty"`
33+
NoNewPrivileges bool `json:"no-new-privileges,omitempty"`
3334
}
3435

3536
// BridgeConfig stores all the bridge driver specific

daemon/container.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -181,7 +181,7 @@ func (daemon *Daemon) generateHostname(id string, config *containertypes.Config)
181181
func (daemon *Daemon) setSecurityOptions(container *container.Container, hostConfig *containertypes.HostConfig) error {
182182
container.Lock()
183183
defer container.Unlock()
184-
return parseSecurityOpt(container, hostConfig)
184+
return daemon.parseSecurityOpt(container, hostConfig)
185185
}
186186

187187
func (daemon *Daemon) setHostConfig(container *container.Container, hostConfig *containertypes.HostConfig) error {

daemon/daemon_solaris.go

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,10 @@ func (daemon *Daemon) cleanupMountsByID(id string) error {
6666
return nil
6767
}
6868

69+
func (daemon *Daemon) parseSecurityOpt(container *container.Container, hostConfig *containertypes.HostConfig) error {
70+
return parseSecurityOpt(container, hostConfig)
71+
}
72+
6973
func parseSecurityOpt(container *container.Container, config *containertypes.HostConfig) error {
7074
//Since config.SecurityOpt is specifically defined as a "List of string values to
7175
//customize labels for MLs systems, such as SELinux"

daemon/daemon_unix.go

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -162,6 +162,11 @@ func getBlkioWeightDevices(config containertypes.Resources) ([]specs.WeightDevic
162162
return blkioWeightDevices, nil
163163
}
164164

165+
func (daemon *Daemon) parseSecurityOpt(container *container.Container, hostConfig *containertypes.HostConfig) error {
166+
container.NoNewPrivileges = daemon.configStore.NoNewPrivileges
167+
return parseSecurityOpt(container, hostConfig)
168+
}
169+
165170
func parseSecurityOpt(container *container.Container, config *containertypes.HostConfig) error {
166171
var (
167172
labelOpts []string
@@ -193,6 +198,12 @@ func parseSecurityOpt(container *container.Container, config *containertypes.Hos
193198
container.AppArmorProfile = con[1]
194199
case "seccomp":
195200
container.SeccompProfile = con[1]
201+
case "no-new-privileges":
202+
noNewPrivileges, err := strconv.ParseBool(con[1])
203+
if err != nil {
204+
return fmt.Errorf("invalid --security-opt 2: %q", opt)
205+
}
206+
container.NoNewPrivileges = noNewPrivileges
196207
default:
197208
return fmt.Errorf("invalid --security-opt 2: %q", opt)
198209
}

daemon/daemon_unix_test.go

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -180,6 +180,35 @@ func TestParseSecurityOpt(t *testing.T) {
180180
}
181181
}
182182

183+
func TestParseNNPSecurityOptions(t *testing.T) {
184+
daemon := &Daemon{
185+
configStore: &config.Config{NoNewPrivileges: true},
186+
}
187+
container := &container.Container{}
188+
config := &containertypes.HostConfig{}
189+
190+
// test NNP when "daemon:true" and "no-new-privileges=false""
191+
config.SecurityOpt = []string{"no-new-privileges=false"}
192+
193+
if err := daemon.parseSecurityOpt(container, config); err != nil {
194+
t.Fatalf("Unexpected daemon.parseSecurityOpt error: %v", err)
195+
}
196+
if container.NoNewPrivileges {
197+
t.Fatalf("container.NoNewPrivileges should be FALSE: %v", container.NoNewPrivileges)
198+
}
199+
200+
// test NNP when "daemon:false" and "no-new-privileges=true""
201+
daemon.configStore.NoNewPrivileges = false
202+
config.SecurityOpt = []string{"no-new-privileges=true"}
203+
204+
if err := daemon.parseSecurityOpt(container, config); err != nil {
205+
t.Fatalf("Unexpected daemon.parseSecurityOpt error: %v", err)
206+
}
207+
if !container.NoNewPrivileges {
208+
t.Fatalf("container.NoNewPrivileges should be TRUE: %v", container.NoNewPrivileges)
209+
}
210+
}
211+
183212
func TestNetworkOptions(t *testing.T) {
184213
daemon := &Daemon{}
185214
dconfigCorrect := &config.Config{

daemon/daemon_windows.go

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,10 @@ func getBlkioWeightDevices(config *containertypes.HostConfig) ([]blkiodev.Weight
4848
return nil, nil
4949
}
5050

51+
func (daemon *Daemon) parseSecurityOpt(container *container.Container, hostConfig *containertypes.HostConfig) error {
52+
return parseSecurityOpt(container, hostConfig)
53+
}
54+
5155
func parseSecurityOpt(container *container.Container, config *containertypes.HostConfig) error {
5256
return nil
5357
}

docs/reference/commandline/dockerd.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,7 @@ Options:
7070
--max-concurrent-uploads int Set the max concurrent uploads for each push (default 5)
7171
--metrics-addr string Set address and port to serve the metrics api (default "")
7272
--mtu int Set the containers network MTU
73+
--no-new-privileges Disable container processes from gaining new privileges
7374
--oom-score-adjust int Set the oom_score_adj for the daemon (default -500)
7475
-p, --pidfile string Path to use for daemon PID file (default "/var/run/docker.pid")
7576
--raw-logs Full timestamps without ANSI coloring
@@ -1190,6 +1191,7 @@ This is a full example of the allowed configuration options on Linux:
11901191
"seccomp-profile": "",
11911192
"insecure-registries": [],
11921193
"disable-legacy-registry": false,
1194+
"no-new-privileges": false,
11931195
"default-runtime": "runc",
11941196
"oom-score-adjust": -500,
11951197
"runtimes": {

docs/reference/run.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -630,7 +630,7 @@ with the same logic -- if the original volume was specified with a name it will
630630
--security-opt="label=level:LEVEL" : Set the label level for the container
631631
--security-opt="label=disable" : Turn off label confinement for the container
632632
--security-opt="apparmor=PROFILE" : Set the apparmor profile to be applied to the container
633-
--security-opt="no-new-privileges" : Disable container processes from gaining new privileges
633+
--security-opt="no-new-privileges:true|false" : Disable/enable container processes from gaining new privileges
634634
--security-opt="seccomp=unconfined" : Turn off seccomp confinement for the container
635635
--security-opt="seccomp=profile.json": White listed syscalls seccomp Json file to be used as a seccomp filter
636636

integration-cli/docker_cli_run_unix_test.go

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1140,12 +1140,25 @@ func (s *DockerSuite) TestRunSeccompDefaultProfileNS(c *check.C) {
11401140
}
11411141
}
11421142

1143-
// TestRunNoNewPrivSetuid checks that --security-opt=no-new-privileges prevents
1143+
// TestRunNoNewPrivSetuid checks that --security-opt='no-new-privileges=true' prevents
11441144
// effective uid transtions on executing setuid binaries.
11451145
func (s *DockerSuite) TestRunNoNewPrivSetuid(c *check.C) {
11461146
testRequires(c, DaemonIsLinux, NotUserNamespace, SameHostDaemon)
11471147
ensureNNPTest(c)
11481148

1149+
// test that running a setuid binary results in no effective uid transition
1150+
icmd.RunCommand(dockerBinary, "run", "--security-opt", "no-new-privileges=true", "--user", "1000",
1151+
"nnp-test", "/usr/bin/nnp-test").Assert(c, icmd.Expected{
1152+
Out: "EUID=1000",
1153+
})
1154+
}
1155+
1156+
// TestLegacyRunNoNewPrivSetuid checks that --security-opt=no-new-privileges prevents
1157+
// effective uid transtions on executing setuid binaries.
1158+
func (s *DockerSuite) TestLegacyRunNoNewPrivSetuid(c *check.C) {
1159+
testRequires(c, DaemonIsLinux, NotUserNamespace, SameHostDaemon)
1160+
ensureNNPTest(c)
1161+
11491162
// test that running a setuid binary results in no effective uid transition
11501163
icmd.RunCommand(dockerBinary, "run", "--security-opt", "no-new-privileges", "--user", "1000",
11511164
"nnp-test", "/usr/bin/nnp-test").Assert(c, icmd.Expected{

0 commit comments

Comments
 (0)