Skip to content

Commit 669f4db

Browse files
committed
configs: validate: add validation for bind-mount fsflags
Bind-mounts cannot have any filesystem-specific "data" arguments, because the kernel ignores the data argument for MS_BIND and MS_BIND|MS_REMOUNT and we cannot safely try to override the flags because those would affect mounts on the host (these flags affect the superblock). It should be noted that there are cases where the filesystem-specified flags will also be ignored for non-bind-mounts but those are kernel quirks and there's no real way for us to work around them. And users wouldn't get any real benefit from us adding guardrails to existing kernel behaviour. Signed-off-by: Aleksa Sarai <[email protected]>
1 parent da44f69 commit 669f4db

File tree

2 files changed

+66
-0
lines changed

2 files changed

+66
-0
lines changed

libcontainer/configs/validate/validator.go

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -275,6 +275,26 @@ func cgroupsCheck(config *configs.Config) error {
275275
return nil
276276
}
277277

278+
func checkBindOptions(m *configs.Mount) error {
279+
if !m.IsBind() {
280+
return nil
281+
}
282+
// We must reject bind-mounts that also have filesystem-specific mount
283+
// options, because the kernel will completely ignore these flags and we
284+
// cannot set them per-mountpoint.
285+
//
286+
// It should be noted that (due to how the kernel caches superblocks), data
287+
// options could also silently ignored for other filesystems even when
288+
// doing a fresh mount, but there is no real way to avoid this (and it
289+
// matches how everything else works). There have been proposals to make it
290+
// possible for userspace to detect this caching, but this wouldn't help
291+
// runc because the behaviour wouldn't even be desirable for most users.
292+
if m.Data != "" {
293+
return errors.New("bind mounts cannot have any filesystem-specific options applied")
294+
}
295+
return nil
296+
}
297+
278298
func checkIDMapMounts(config *configs.Config, m *configs.Mount) error {
279299
if !m.IsIDMapped() {
280300
return nil
@@ -313,6 +333,9 @@ func mountsWarn(config *configs.Config) error {
313333

314334
func mountsStrict(config *configs.Config) error {
315335
for _, m := range config.Mounts {
336+
if err := checkBindOptions(m); err != nil {
337+
return fmt.Errorf("invalid mount %+v: %w", m, err)
338+
}
316339
if err := checkIDMapMounts(config, m); err != nil {
317340
return fmt.Errorf("invalid mount %+v: %w", m, err)
318341
}

libcontainer/configs/validate/validator_test.go

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -421,6 +421,49 @@ func TestValidateMounts(t *testing.T) {
421421
}
422422
}
423423

424+
func TestValidateBindMounts(t *testing.T) {
425+
testCases := []struct {
426+
isErr bool
427+
flags int
428+
data string
429+
}{
430+
{isErr: false, flags: 0, data: ""},
431+
{isErr: false, flags: unix.MS_RDONLY | unix.MS_NOSYMFOLLOW, data: ""},
432+
433+
{isErr: true, flags: 0, data: "idmap"},
434+
{isErr: true, flags: unix.MS_RDONLY, data: "custom_ext4_flag"},
435+
{isErr: true, flags: unix.MS_NOATIME, data: "rw=foobar"},
436+
}
437+
438+
for _, tc := range testCases {
439+
for _, bind := range []string{"bind", "rbind"} {
440+
bindFlag := map[string]int{
441+
"bind": unix.MS_BIND,
442+
"rbind": unix.MS_BIND | unix.MS_REC,
443+
}[bind]
444+
445+
config := &configs.Config{
446+
Rootfs: "/var",
447+
Mounts: []*configs.Mount{
448+
{
449+
Destination: "/",
450+
Flags: tc.flags | bindFlag,
451+
Data: tc.data,
452+
},
453+
},
454+
}
455+
456+
err := Validate(config)
457+
if tc.isErr && err == nil {
458+
t.Errorf("%s mount flags:0x%x data:%v, expected error, got nil", bind, tc.flags, tc.data)
459+
}
460+
if !tc.isErr && err != nil {
461+
t.Errorf("%s mount flags:0x%x data:%v, expected nil, got error %v", bind, tc.flags, tc.data, err)
462+
}
463+
}
464+
}
465+
}
466+
424467
func TestValidateIDMapMounts(t *testing.T) {
425468
mapping := []configs.IDMap{
426469
{

0 commit comments

Comments
 (0)