Skip to content

Commit 9539bef

Browse files
author
Ma Shimiao
authored
Merge pull request #220 from Mashimiao/validate-optimize-cap-check
validate: optimize capabilites check
2 parents 03cd3fd + 73680b2 commit 9539bef

File tree

3 files changed

+79
-73
lines changed

3 files changed

+79
-73
lines changed

cmd/oci-runtime-tool/validate.go

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,9 +4,8 @@ import (
44
"fmt"
55
"strings"
66

7-
"github.com/urfave/cli"
8-
97
"github.com/opencontainers/runtime-tools/validate"
8+
"github.com/urfave/cli"
109
)
1110

1211
var bundleValidateFlags = []cli.Flag{

generate/generate.go

Lines changed: 7 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ import (
1111

1212
rspec "github.com/opencontainers/runtime-spec/specs-go"
1313
"github.com/opencontainers/runtime-tools/generate/seccomp"
14+
"github.com/opencontainers/runtime-tools/validate"
1415
"github.com/syndtr/gocapability/capability"
1516
)
1617

@@ -754,11 +755,10 @@ func (g *Generator) AddBindMount(source, dest string, options []string) {
754755

755756
// SetupPrivileged sets up the privilege-related fields inside g.spec.
756757
func (g *Generator) SetupPrivileged(privileged bool) {
757-
if privileged {
758-
// Add all capabilities in privileged mode.
758+
if privileged { // Add all capabilities in privileged mode.
759759
var finalCapList []string
760760
for _, cap := range capability.List() {
761-
if g.HostSpecific && cap > lastCap() {
761+
if g.HostSpecific && cap > validate.LastCap() {
762762
continue
763763
}
764764
finalCapList = append(finalCapList, fmt.Sprintf("CAP_%s", strings.ToUpper(cap.String())))
@@ -771,36 +771,6 @@ func (g *Generator) SetupPrivileged(privileged bool) {
771771
}
772772
}
773773

774-
func lastCap() capability.Cap {
775-
last := capability.CAP_LAST_CAP
776-
// hack for RHEL6 which has no /proc/sys/kernel/cap_last_cap
777-
if last == capability.Cap(63) {
778-
last = capability.CAP_BLOCK_SUSPEND
779-
}
780-
781-
return last
782-
}
783-
784-
func checkCap(c string, hostSpecific bool) error {
785-
isValid := false
786-
cp := strings.ToUpper(c)
787-
788-
for _, cap := range capability.List() {
789-
if cp == strings.ToUpper(cap.String()) {
790-
if hostSpecific && cap > lastCap() {
791-
return fmt.Errorf("CAP_%s is not supported on the current host", cp)
792-
}
793-
isValid = true
794-
break
795-
}
796-
}
797-
798-
if !isValid {
799-
return fmt.Errorf("Invalid value passed for adding capability")
800-
}
801-
return nil
802-
}
803-
804774
// ClearProcessCapabilities clear g.spec.Process.Capabilities.
805775
func (g *Generator) ClearProcessCapabilities() {
806776
if g.spec == nil {
@@ -811,12 +781,11 @@ func (g *Generator) ClearProcessCapabilities() {
811781

812782
// AddProcessCapability adds a process capability into g.spec.Process.Capabilities.
813783
func (g *Generator) AddProcessCapability(c string) error {
814-
if err := checkCap(c, g.HostSpecific); err != nil {
784+
cp := strings.ToUpper(c)
785+
if err := validate.CapValid(cp, g.HostSpecific); err != nil {
815786
return err
816787
}
817788

818-
cp := fmt.Sprintf("CAP_%s", strings.ToUpper(c))
819-
820789
g.initSpec()
821790
for _, cap := range g.spec.Process.Capabilities {
822791
if strings.ToUpper(cap) == cp {
@@ -830,12 +799,11 @@ func (g *Generator) AddProcessCapability(c string) error {
830799

831800
// DropProcessCapability drops a process capability from g.spec.Process.Capabilities.
832801
func (g *Generator) DropProcessCapability(c string) error {
833-
if err := checkCap(c, g.HostSpecific); err != nil {
802+
cp := strings.ToUpper(c)
803+
if err := validate.CapValid(cp, g.HostSpecific); err != nil {
834804
return err
835805
}
836806

837-
cp := fmt.Sprintf("CAP_%s", strings.ToUpper(c))
838-
839807
g.initSpec()
840808
for i, cap := range g.spec.Process.Capabilities {
841809
if strings.ToUpper(cap) == cp {

validate/validate.go

Lines changed: 71 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -15,28 +15,29 @@ import (
1515
"github.com/Sirupsen/logrus"
1616
"github.com/blang/semver"
1717
rspec "github.com/opencontainers/runtime-spec/specs-go"
18+
"github.com/syndtr/gocapability/capability"
1819
)
1920

2021
const specConfig = "config.json"
2122

2223
var (
2324
defaultRlimits = []string{
25+
"RLIMIT_AS",
26+
"RLIMIT_CORE",
2427
"RLIMIT_CPU",
25-
"RLIMIT_FSIZE",
2628
"RLIMIT_DATA",
27-
"RLIMIT_STACK",
28-
"RLIMIT_CORE",
29-
"RLIMIT_RSS",
30-
"RLIMIT_NPROC",
31-
"RLIMIT_NOFILE",
32-
"RLIMIT_MEMLOCK",
33-
"RLIMIT_AS",
29+
"RLIMIT_FSIZE",
3430
"RLIMIT_LOCKS",
35-
"RLIMIT_SIGPENDING",
31+
"RLIMIT_MEMLOCK",
3632
"RLIMIT_MSGQUEUE",
3733
"RLIMIT_NICE",
34+
"RLIMIT_NOFILE",
35+
"RLIMIT_NPROC",
36+
"RLIMIT_RSS",
3837
"RLIMIT_RTPRIO",
3938
"RLIMIT_RTTIME",
39+
"RLIMIT_SIGPENDING",
40+
"RLIMIT_STACK",
4041
}
4142
defaultCaps = []string{
4243
"CAP_CHOWN",
@@ -56,16 +57,19 @@ var (
5657
}
5758
)
5859

60+
// Validator represents a validator for runtime bundle
5961
type Validator struct {
6062
spec *rspec.Spec
6163
bundlePath string
6264
HostSpecific bool
6365
}
6466

67+
// NewValidator creates a Validator
6568
func NewValidator(spec *rspec.Spec, bundlePath string, hostSpecific bool) Validator {
6669
return Validator{spec: spec, bundlePath: bundlePath, HostSpecific: hostSpecific}
6770
}
6871

72+
// NewValidatorFromPath creates a Validator with specified bundle path
6973
func NewValidatorFromPath(bundlePath string, hostSpecific bool) (Validator, error) {
7074
if bundlePath == "" {
7175
return Validator{}, fmt.Errorf("Bundle path shouldn't be empty")
@@ -91,6 +95,7 @@ func NewValidatorFromPath(bundlePath string, hostSpecific bool) (Validator, erro
9195
return NewValidator(&spec, bundlePath, hostSpecific), nil
9296
}
9397

98+
// CheckAll checks all parts of runtime bundle
9499
func (v *Validator) CheckAll() (msgs []string) {
95100
msgs = append(msgs, v.CheckRootfsPath()...)
96101
msgs = append(msgs, v.CheckMandatoryFields()...)
@@ -104,6 +109,7 @@ func (v *Validator) CheckAll() (msgs []string) {
104109
return
105110
}
106111

112+
// CheckRootfsPath checks status of v.spec.Root.Path
107113
func (v *Validator) CheckRootfsPath() (msgs []string) {
108114
logrus.Debugf("check rootfs path")
109115

@@ -123,6 +129,8 @@ func (v *Validator) CheckRootfsPath() (msgs []string) {
123129
return
124130

125131
}
132+
133+
// CheckSemVer checks v.spec.Version
126134
func (v *Validator) CheckSemVer() (msgs []string) {
127135
logrus.Debugf("check semver")
128136

@@ -138,6 +146,7 @@ func (v *Validator) CheckSemVer() (msgs []string) {
138146
return
139147
}
140148

149+
// CheckPlatform checks v.spec.Platform
141150
func (v *Validator) CheckPlatform() (msgs []string) {
142151
logrus.Debugf("check platform")
143152

@@ -168,6 +177,7 @@ func (v *Validator) CheckPlatform() (msgs []string) {
168177
return
169178
}
170179

180+
// CheckHooks check v.spec.Hooks
171181
func (v *Validator) CheckHooks() (msgs []string) {
172182
logrus.Debugf("check hooks")
173183

@@ -204,6 +214,7 @@ func checkEventHooks(hookType string, hooks []rspec.Hook, hostSpecific bool) (ms
204214
return
205215
}
206216

217+
// CheckProcess checks v.spec.Process
207218
func (v *Validator) CheckProcess() (msgs []string) {
208219
logrus.Debugf("check process")
209220

@@ -243,19 +254,15 @@ func (v *Validator) CheckProcess() (msgs []string) {
243254
}
244255
}
245256

246-
for index := 0; index < len(process.Capabilities); index++ {
247-
capability := process.Capabilities[index]
248-
if !capValid(capability) {
249-
msgs = append(msgs, fmt.Sprintf("capability %q is not valid, man capabilities(7)", process.Capabilities[index]))
257+
for _, capability := range process.Capabilities {
258+
if err := CapValid(capability, v.HostSpecific); err != nil {
259+
msgs = append(msgs, fmt.Sprintf("capability %q is not valid, man capabilities(7)", capability))
250260
}
251261
}
252262

253-
for index := 0; index < len(process.Rlimits); index++ {
254-
if !rlimitValid(process.Rlimits[index].Type) {
255-
msgs = append(msgs, fmt.Sprintf("rlimit type %q is invalid.", process.Rlimits[index].Type))
256-
}
257-
if process.Rlimits[index].Hard < process.Rlimits[index].Soft {
258-
msgs = append(msgs, fmt.Sprintf("hard limit of rlimit %s should not be less than soft limit.", process.Rlimits[index].Type))
263+
for _, rlimit := range process.Rlimits {
264+
if err := rlimitValid(rlimit); err != nil {
265+
msgs = append(msgs, err.Error())
259266
}
260267
}
261268

@@ -311,6 +318,7 @@ func supportedMountTypes(OS string, hostSpecific bool) (map[string]bool, error)
311318
return nil, nil
312319
}
313320

321+
// CheckMounts checks v.spec.Mounts
314322
func (v *Validator) CheckMounts() (msgs []string) {
315323
logrus.Debugf("check mounts")
316324

@@ -335,7 +343,7 @@ func (v *Validator) CheckMounts() (msgs []string) {
335343
return
336344
}
337345

338-
//Linux only
346+
// CheckLinux checks v.spec.Linux
339347
func (v *Validator) CheckLinux() (msgs []string) {
340348
logrus.Debugf("check linux")
341349

@@ -429,6 +437,7 @@ func (v *Validator) CheckLinux() (msgs []string) {
429437
return
430438
}
431439

440+
// CheckLinuxResources checks v.spec.Linux.Resources
432441
func (v *Validator) CheckLinuxResources() (msgs []string) {
433442
logrus.Debugf("check linux resources")
434443

@@ -445,6 +454,7 @@ func (v *Validator) CheckLinuxResources() (msgs []string) {
445454
return
446455
}
447456

457+
// CheckSeccomp checkc v.spec.Linux.Seccomp
448458
func (v *Validator) CheckSeccomp() (msgs []string) {
449459
logrus.Debugf("check linux seccomp")
450460

@@ -483,6 +493,40 @@ func (v *Validator) CheckSeccomp() (msgs []string) {
483493
return
484494
}
485495

496+
// CapValid checks whether a capability is valid
497+
func CapValid(c string, hostSpecific bool) error {
498+
isValid := false
499+
500+
if !strings.HasPrefix(c, "CAP_") {
501+
return fmt.Errorf("capability %s must start with CAP_", c)
502+
}
503+
for _, cap := range capability.List() {
504+
if c == fmt.Sprintf("CAP_%s", strings.ToUpper(cap.String())) {
505+
if hostSpecific && cap > LastCap() {
506+
return fmt.Errorf("CAP_%s is not supported on the current host", c)
507+
}
508+
isValid = true
509+
break
510+
}
511+
}
512+
513+
if !isValid {
514+
return fmt.Errorf("Invalid capability: %s", c)
515+
}
516+
return nil
517+
}
518+
519+
// LastCap return last cap of system
520+
func LastCap() capability.Cap {
521+
last := capability.CAP_LAST_CAP
522+
// hack for RHEL6 which has no /proc/sys/kernel/cap_last_cap
523+
if last == capability.Cap(63) {
524+
last = capability.CAP_BLOCK_SUSPEND
525+
}
526+
527+
return last
528+
}
529+
486530
func envValid(env string) bool {
487531
items := strings.Split(env, "=")
488532
if len(items) < 2 {
@@ -499,22 +543,16 @@ func envValid(env string) bool {
499543
return true
500544
}
501545

502-
func capValid(capability string) bool {
503-
for _, val := range defaultCaps {
504-
if val == capability {
505-
return true
506-
}
546+
func rlimitValid(rlimit rspec.Rlimit) error {
547+
if rlimit.Hard < rlimit.Soft {
548+
return fmt.Errorf("hard limit of rlimit %s should not be less than soft limit", rlimit.Type)
507549
}
508-
return false
509-
}
510-
511-
func rlimitValid(rlimit string) bool {
512550
for _, val := range defaultRlimits {
513-
if val == rlimit {
514-
return true
551+
if val == rlimit.Type {
552+
return nil
515553
}
516554
}
517-
return false
555+
return fmt.Errorf("rlimit type %q is invalid", rlimit.Type)
518556
}
519557

520558
func namespaceValid(ns rspec.Namespace) bool {
@@ -662,6 +700,7 @@ func checkMandatory(obj interface{}) (msgs []string) {
662700
return
663701
}
664702

703+
// CheckMandatoryFields checks mandatory field of container's config file
665704
func (v *Validator) CheckMandatoryFields() []string {
666705
logrus.Debugf("check mandatory fields")
667706

0 commit comments

Comments
 (0)