Skip to content

Commit d5be152

Browse files
albanDongsu Park
authored andcommitted
validation: mounts: fix condition of source & type check
The runtime-spec says that [mount source is optional]( https://github.com/opencontainers/runtime-spec/blob/v1.0.1/config.md#mounts). So let's relax condition of the mount source path check, so that it only checks for an empty mount source. Ditto for the type field. The 'mount' test now tries different mount options: bind and not bind, recursive or not, different mount propagation modes. runc passes the test after opencontainers/runc#1845 Closes: #651 Based on work from: Dongsu Park <[email protected]> Signed-off-by: Alban Crequy <[email protected]>
1 parent 2e13089 commit d5be152

File tree

2 files changed

+96
-15
lines changed

2 files changed

+96
-15
lines changed

cmd/runtimetest/main.go

Lines changed: 22 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1091,14 +1091,32 @@ func mountMatch(configMount rspec.Mount, sysMount *mount.Info) error {
10911091
return fmt.Errorf("mount destination expected: %v, actual: %v", configMount.Destination, sys.Destination)
10921092
}
10931093

1094-
if configMount.Type != sys.Type {
1094+
isBind := false
1095+
for _, opt := range configMount.Options {
1096+
if opt == "bind" || opt == "rbind" {
1097+
isBind = true
1098+
break
1099+
}
1100+
}
1101+
// Type is an optional field in the spec: only check if it is set
1102+
if configMount.Type != "" && configMount.Type != sys.Type {
10951103
return fmt.Errorf("mount %v type expected: %v, actual: %v", configMount.Destination, configMount.Type, sys.Type)
10961104
}
10971105

1098-
if filepath.Clean(configMount.Source) != sys.Source {
1099-
return fmt.Errorf("mount %v source expected: %v, actual: %v", configMount.Destination, configMount.Source, sys.Source)
1106+
// For bind mounts, the source is not the block device but the path on the host that is being bind mounted.
1107+
// sysMount.Root is that path.
1108+
if isBind {
1109+
// Source is an optional field in the spec: only check if it is set
1110+
// We only test the base name here, in case the tests are being run in a chroot environment
1111+
if configMount.Source != "" && filepath.Base(configMount.Source) != filepath.Base(sysMount.Root) {
1112+
return fmt.Errorf("mount %v source expected: %v, actual: %v", configMount.Destination, filepath.Base(configMount.Source), filepath.Base(sysMount.Root))
1113+
}
1114+
} else {
1115+
// Source is an optional field in the spec: only check if it is set
1116+
if configMount.Source != "" && filepath.Clean(configMount.Source) != sys.Source {
1117+
return fmt.Errorf("mount %v source expected: %v, actual: %v", configMount.Destination, configMount.Source, sys.Source)
1118+
}
11001119
}
1101-
11021120
return nil
11031121
}
11041122

validation/mounts/mounts.go

Lines changed: 74 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -6,22 +6,85 @@ import (
66
)
77

88
func main() {
9+
defaultOptions := []string{
10+
"nosuid",
11+
"strictatime",
12+
"mode=755",
13+
"size=1k",
14+
}
15+
16+
// Different combinations of mount types, mount options, mount propagation modes
17+
mounts := []rspec.Mount{
18+
rspec.Mount{
19+
Destination: "/tmp/test-shared",
20+
Type: "tmpfs",
21+
Source: "tmpfs",
22+
Options: []string{"shared"},
23+
},
24+
rspec.Mount{
25+
Destination: "/tmp/test-slave",
26+
Type: "tmpfs",
27+
Source: "tmpfs",
28+
Options: []string{"slave"},
29+
},
30+
rspec.Mount{
31+
Destination: "/tmp/test-private",
32+
Type: "tmpfs",
33+
Source: "tmpfs",
34+
Options: []string{"private"},
35+
},
36+
rspec.Mount{
37+
Destination: "/mnt/etc-shared",
38+
Source: "/etc",
39+
Options: []string{"bind", "shared"},
40+
},
41+
rspec.Mount{
42+
Destination: "/mnt/etc-rshared",
43+
Source: "/etc",
44+
Options: []string{"rbind", "rshared"},
45+
},
46+
rspec.Mount{
47+
Destination: "/mnt/etc-slave",
48+
Source: "/etc",
49+
Options: []string{"bind", "slave"},
50+
},
51+
rspec.Mount{
52+
Destination: "/mnt/etc-rslave",
53+
Source: "/etc",
54+
Options: []string{"rbind", "rslave"},
55+
},
56+
rspec.Mount{
57+
Destination: "/mnt/etc-private",
58+
Source: "/etc",
59+
Options: []string{"bind", "private"},
60+
},
61+
rspec.Mount{
62+
Destination: "/mnt/etc-rprivate",
63+
Source: "/etc",
64+
Options: []string{"rbind", "rprivate"},
65+
},
66+
rspec.Mount{
67+
Destination: "/mnt/etc-unbindable",
68+
Source: "/etc",
69+
Options: []string{"bind", "unbindable"},
70+
},
71+
rspec.Mount{
72+
Destination: "/mnt/etc-runbindable",
73+
Source: "/etc",
74+
Options: []string{"rbind", "runbindable"},
75+
},
76+
}
77+
978
g, err := util.GetDefaultGenerator()
1079
if err != nil {
1180
util.Fatal(err)
1281
}
13-
mount := rspec.Mount{
14-
Destination: "/tmp",
15-
Type: "tmpfs",
16-
Source: "tmpfs",
17-
Options: []string{
18-
"nosuid",
19-
"strictatime",
20-
"mode=755",
21-
"size=1k",
22-
},
82+
83+
for _, m := range mounts {
84+
m.Options = append(defaultOptions, m.Options...)
85+
86+
g.AddMount(m)
2387
}
24-
g.AddMount(mount)
2588
err = util.RuntimeInsideValidate(g, nil, nil)
2689
if err != nil {
2790
util.Fatal(err)

0 commit comments

Comments
 (0)