Skip to content

Commit bcf89dd

Browse files
author
Zhou Hao
authored
Merge pull request #297 from Mashimiao/validate-enhance-devices-validation
validate: enhance linux devices validation
2 parents c6de221 + 119353e commit bcf89dd

File tree

1 file changed

+89
-2
lines changed

1 file changed

+89
-2
lines changed

validate/validate.go

Lines changed: 89 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ import (
1111
"reflect"
1212
"runtime"
1313
"strings"
14+
"syscall"
1415
"unicode"
1516
"unicode/utf8"
1617

@@ -496,9 +497,95 @@ func (v *Validator) CheckLinux() (msgs []string) {
496497
msgs = append(msgs, fmt.Sprintf("On Linux, hostname requires a new UTS namespace to be specified as well"))
497498
}
498499

500+
// Linux devices validation
501+
devList := make(map[string]bool)
502+
typeList := make(map[string]bool)
499503
for index := 0; index < len(v.spec.Linux.Devices); index++ {
500-
if !deviceValid(v.spec.Linux.Devices[index]) {
501-
msgs = append(msgs, fmt.Sprintf("device %v is invalid.", v.spec.Linux.Devices[index]))
504+
device := v.spec.Linux.Devices[index]
505+
if !deviceValid(device) {
506+
msgs = append(msgs, fmt.Sprintf("device %v is invalid.", device))
507+
}
508+
509+
if _, exists := devList[device.Path]; exists {
510+
msgs = append(msgs, fmt.Sprintf("device %s is duplicated", device.Path))
511+
} else {
512+
var rootfsPath string
513+
if filepath.IsAbs(v.spec.Root.Path) {
514+
rootfsPath = v.spec.Root.Path
515+
} else {
516+
rootfsPath = filepath.Join(v.bundlePath, v.spec.Root.Path)
517+
}
518+
absPath := filepath.Join(rootfsPath, device.Path)
519+
fi, err := os.Stat(absPath)
520+
if os.IsNotExist(err) {
521+
devList[device.Path] = true
522+
} else if err != nil {
523+
msgs = append(msgs, err.Error())
524+
} else {
525+
fStat, ok := fi.Sys().(*syscall.Stat_t)
526+
if !ok {
527+
msgs = append(msgs, fmt.Sprintf("cannot determine state for device %s", device.Path))
528+
continue
529+
}
530+
var devType string
531+
switch fStat.Mode & syscall.S_IFMT {
532+
case syscall.S_IFCHR:
533+
devType = "c"
534+
case syscall.S_IFBLK:
535+
devType = "b"
536+
case syscall.S_IFIFO:
537+
devType = "p"
538+
default:
539+
devType = "unmatched"
540+
}
541+
if devType != device.Type || (devType == "c" && device.Type == "u") {
542+
msgs = append(msgs, fmt.Sprintf("unmatched %s already exists in filesystem", device.Path))
543+
continue
544+
}
545+
if devType != "p" {
546+
dev := fStat.Rdev
547+
major := (dev >> 8) & 0xfff
548+
minor := (dev & 0xff) | ((dev >> 12) & 0xfff00)
549+
if int64(major) != device.Major || int64(minor) != device.Minor {
550+
msgs = append(msgs, fmt.Sprintf("unmatched %s already exists in filesystem", device.Path))
551+
continue
552+
}
553+
}
554+
if device.FileMode != nil {
555+
expectedPerm := *device.FileMode & os.ModePerm
556+
actualPerm := fi.Mode() & os.ModePerm
557+
if expectedPerm != actualPerm {
558+
msgs = append(msgs, fmt.Sprintf("unmatched %s already exists in filesystem", device.Path))
559+
continue
560+
}
561+
}
562+
if device.UID != nil {
563+
if *device.UID != fStat.Uid {
564+
msgs = append(msgs, fmt.Sprintf("unmatched %s already exists in filesystem", device.Path))
565+
continue
566+
}
567+
}
568+
if device.GID != nil {
569+
if *device.GID != fStat.Gid {
570+
msgs = append(msgs, fmt.Sprintf("unmatched %s already exists in filesystem", device.Path))
571+
continue
572+
}
573+
}
574+
}
575+
}
576+
577+
// unify u->c when comparing, they are synonyms
578+
var devID string
579+
if device.Type == "u" {
580+
devID = fmt.Sprintf("%s:%d:%d", "c", device.Major, device.Minor)
581+
} else {
582+
devID = fmt.Sprintf("%s:%d:%d", device.Type, device.Major, device.Minor)
583+
}
584+
585+
if _, exists := typeList[devID]; exists {
586+
logrus.Warnf("type:%s, major:%d and minor:%d for linux devices is duplicated", device.Type, device.Major, device.Minor)
587+
} else {
588+
typeList[devID] = true
502589
}
503590
}
504591

0 commit comments

Comments
 (0)