mirror of
https://github.com/opencontainers/runc.git
synced 2026-07-11 06:03:57 +08:00
Merge pull request #3257 from mengjiao-liu/sysctl-allow-slash
Fix the conversion of sysctl variable dots and slashes
This commit is contained in:
@@ -128,6 +128,36 @@ func (v *ConfigValidator) cgroupnamespace(config *configs.Config) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// convertSysctlVariableToDotsSeparator can return sysctl variables in dots separator format.
|
||||
// The '/' separator is also accepted in place of a '.'.
|
||||
// Convert the sysctl variables to dots separator format for validation.
|
||||
// More info:
|
||||
// https://man7.org/linux/man-pages/man8/sysctl.8.html
|
||||
// https://man7.org/linux/man-pages/man5/sysctl.d.5.html
|
||||
// For example:
|
||||
// Input sysctl variable "net/ipv4/conf/eno2.100.rp_filter"
|
||||
// will return the converted value "net.ipv4.conf.eno2/100.rp_filter"
|
||||
func convertSysctlVariableToDotsSeparator(val string) string {
|
||||
if val == "" {
|
||||
return val
|
||||
}
|
||||
firstSepIndex := strings.IndexAny(val, "./")
|
||||
if firstSepIndex == -1 || val[firstSepIndex] == '.' {
|
||||
return val
|
||||
}
|
||||
|
||||
f := func(r rune) rune {
|
||||
switch r {
|
||||
case '.':
|
||||
return '/'
|
||||
case '/':
|
||||
return '.'
|
||||
}
|
||||
return r
|
||||
}
|
||||
return strings.Map(f, val)
|
||||
}
|
||||
|
||||
// sysctl validates that the specified sysctl keys are valid or not.
|
||||
// /proc/sys isn't completely namespaced and depending on which namespaces
|
||||
// are specified, a subset of sysctls are permitted.
|
||||
@@ -150,7 +180,7 @@ func (v *ConfigValidator) sysctl(config *configs.Config) error {
|
||||
)
|
||||
|
||||
for s := range config.Sysctl {
|
||||
s := strings.Replace(s, "/", ".", -1)
|
||||
s := convertSysctlVariableToDotsSeparator(s)
|
||||
if validSysctlMap[s] || strings.HasPrefix(s, "fs.mqueue.") {
|
||||
if config.Namespaces.Contains(configs.NEWIPC) {
|
||||
continue
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
package validate_test
|
||||
package validate
|
||||
|
||||
import (
|
||||
"os"
|
||||
@@ -6,7 +6,6 @@ import (
|
||||
"testing"
|
||||
|
||||
"github.com/opencontainers/runc/libcontainer/configs"
|
||||
"github.com/opencontainers/runc/libcontainer/configs/validate"
|
||||
"golang.org/x/sys/unix"
|
||||
)
|
||||
|
||||
@@ -15,7 +14,7 @@ func TestValidate(t *testing.T) {
|
||||
Rootfs: "/var",
|
||||
}
|
||||
|
||||
validator := validate.New()
|
||||
validator := New()
|
||||
err := validator.Validate(config)
|
||||
if err != nil {
|
||||
t.Errorf("Expected error to not occur: %+v", err)
|
||||
@@ -33,7 +32,7 @@ func TestValidateWithInvalidRootfs(t *testing.T) {
|
||||
Rootfs: dir,
|
||||
}
|
||||
|
||||
validator := validate.New()
|
||||
validator := New()
|
||||
err := validator.Validate(config)
|
||||
if err == nil {
|
||||
t.Error("Expected error to occur but it was nil")
|
||||
@@ -48,7 +47,7 @@ func TestValidateNetworkWithoutNETNamespace(t *testing.T) {
|
||||
Networks: []*configs.Network{network},
|
||||
}
|
||||
|
||||
validator := validate.New()
|
||||
validator := New()
|
||||
err := validator.Validate(config)
|
||||
if err == nil {
|
||||
t.Error("Expected error to occur but it was nil")
|
||||
@@ -63,7 +62,7 @@ func TestValidateNetworkRoutesWithoutNETNamespace(t *testing.T) {
|
||||
Routes: []*configs.Route{route},
|
||||
}
|
||||
|
||||
validator := validate.New()
|
||||
validator := New()
|
||||
err := validator.Validate(config)
|
||||
if err == nil {
|
||||
t.Error("Expected error to occur but it was nil")
|
||||
@@ -81,7 +80,7 @@ func TestValidateHostname(t *testing.T) {
|
||||
),
|
||||
}
|
||||
|
||||
validator := validate.New()
|
||||
validator := New()
|
||||
err := validator.Validate(config)
|
||||
if err != nil {
|
||||
t.Errorf("Expected error to not occur: %+v", err)
|
||||
@@ -94,7 +93,7 @@ func TestValidateHostnameWithoutUTSNamespace(t *testing.T) {
|
||||
Hostname: "runc",
|
||||
}
|
||||
|
||||
validator := validate.New()
|
||||
validator := New()
|
||||
err := validator.Validate(config)
|
||||
if err == nil {
|
||||
t.Error("Expected error to occur but it was nil")
|
||||
@@ -112,7 +111,7 @@ func TestValidateSecurityWithMaskPaths(t *testing.T) {
|
||||
),
|
||||
}
|
||||
|
||||
validator := validate.New()
|
||||
validator := New()
|
||||
err := validator.Validate(config)
|
||||
if err != nil {
|
||||
t.Errorf("Expected error to not occur: %+v", err)
|
||||
@@ -130,7 +129,7 @@ func TestValidateSecurityWithROPaths(t *testing.T) {
|
||||
),
|
||||
}
|
||||
|
||||
validator := validate.New()
|
||||
validator := New()
|
||||
err := validator.Validate(config)
|
||||
if err != nil {
|
||||
t.Errorf("Expected error to not occur: %+v", err)
|
||||
@@ -144,7 +143,7 @@ func TestValidateSecurityWithoutNEWNS(t *testing.T) {
|
||||
ReadonlyPaths: []string{"/proc/sys"},
|
||||
}
|
||||
|
||||
validator := validate.New()
|
||||
validator := New()
|
||||
err := validator.Validate(config)
|
||||
if err == nil {
|
||||
t.Error("Expected error to occur but it was nil")
|
||||
@@ -164,7 +163,7 @@ func TestValidateUsernamespace(t *testing.T) {
|
||||
),
|
||||
}
|
||||
|
||||
validator := validate.New()
|
||||
validator := New()
|
||||
err := validator.Validate(config)
|
||||
if err != nil {
|
||||
t.Errorf("expected error to not occur %+v", err)
|
||||
@@ -178,21 +177,47 @@ func TestValidateUsernamespaceWithoutUserNS(t *testing.T) {
|
||||
UidMappings: []configs.IDMap{uidMap},
|
||||
}
|
||||
|
||||
validator := validate.New()
|
||||
validator := New()
|
||||
err := validator.Validate(config)
|
||||
if err == nil {
|
||||
t.Error("Expected error to occur but it was nil")
|
||||
}
|
||||
}
|
||||
|
||||
// TestConvertSysctlVariableToDotsSeparator tests whether the sysctl variable
|
||||
// can be correctly converted to a dot as a separator.
|
||||
func TestConvertSysctlVariableToDotsSeparator(t *testing.T) {
|
||||
type testCase struct {
|
||||
in string
|
||||
out string
|
||||
}
|
||||
valid := []testCase{
|
||||
{in: "kernel.shm_rmid_forced", out: "kernel.shm_rmid_forced"},
|
||||
{in: "kernel/shm_rmid_forced", out: "kernel.shm_rmid_forced"},
|
||||
{in: "net.ipv4.conf.eno2/100.rp_filter", out: "net.ipv4.conf.eno2/100.rp_filter"},
|
||||
{in: "net/ipv4/conf/eno2.100/rp_filter", out: "net.ipv4.conf.eno2/100.rp_filter"},
|
||||
{in: "net/ipv4/ip_local_port_range", out: "net.ipv4.ip_local_port_range"},
|
||||
{in: "kernel/msgmax", out: "kernel.msgmax"},
|
||||
{in: "kernel/sem", out: "kernel.sem"},
|
||||
}
|
||||
|
||||
for _, test := range valid {
|
||||
convertSysctlVal := convertSysctlVariableToDotsSeparator(test.in)
|
||||
if convertSysctlVal != test.out {
|
||||
t.Errorf("The sysctl variable was not converted correctly. got: %s, want: %s", convertSysctlVal, test.out)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestValidateSysctl(t *testing.T) {
|
||||
sysctl := map[string]string{
|
||||
"fs.mqueue.ctl": "ctl",
|
||||
"fs/mqueue/ctl": "ctl",
|
||||
"net.ctl": "ctl",
|
||||
"net/ctl": "ctl",
|
||||
"kernel.ctl": "ctl",
|
||||
"kernel/ctl": "ctl",
|
||||
"fs.mqueue.ctl": "ctl",
|
||||
"fs/mqueue/ctl": "ctl",
|
||||
"net.ctl": "ctl",
|
||||
"net/ctl": "ctl",
|
||||
"net.ipv4.conf.eno2/100.rp_filter": "ctl",
|
||||
"kernel.ctl": "ctl",
|
||||
"kernel/ctl": "ctl",
|
||||
}
|
||||
|
||||
for k, v := range sysctl {
|
||||
@@ -201,7 +226,7 @@ func TestValidateSysctl(t *testing.T) {
|
||||
Sysctl: map[string]string{k: v},
|
||||
}
|
||||
|
||||
validator := validate.New()
|
||||
validator := New()
|
||||
err := validator.Validate(config)
|
||||
if err == nil {
|
||||
t.Error("Expected error to occur but it was nil")
|
||||
@@ -211,12 +236,13 @@ func TestValidateSysctl(t *testing.T) {
|
||||
|
||||
func TestValidateValidSysctl(t *testing.T) {
|
||||
sysctl := map[string]string{
|
||||
"fs.mqueue.ctl": "ctl",
|
||||
"fs/mqueue/ctl": "ctl",
|
||||
"net.ctl": "ctl",
|
||||
"net/ctl": "ctl",
|
||||
"kernel.msgmax": "ctl",
|
||||
"kernel/msgmax": "ctl",
|
||||
"fs.mqueue.ctl": "ctl",
|
||||
"fs/mqueue/ctl": "ctl",
|
||||
"net.ctl": "ctl",
|
||||
"net/ctl": "ctl",
|
||||
"net.ipv4.conf.eno2/100.rp_filter": "ctl",
|
||||
"kernel.msgmax": "ctl",
|
||||
"kernel/msgmax": "ctl",
|
||||
}
|
||||
|
||||
for k, v := range sysctl {
|
||||
@@ -233,7 +259,7 @@ func TestValidateValidSysctl(t *testing.T) {
|
||||
},
|
||||
}
|
||||
|
||||
validator := validate.New()
|
||||
validator := New()
|
||||
err := validator.Validate(config)
|
||||
if err != nil {
|
||||
t.Errorf("Expected error to not occur with {%s=%s} but got: %q", k, v, err)
|
||||
@@ -255,7 +281,7 @@ func TestValidateSysctlWithSameNs(t *testing.T) {
|
||||
),
|
||||
}
|
||||
|
||||
validator := validate.New()
|
||||
validator := New()
|
||||
err := validator.Validate(config)
|
||||
if err == nil {
|
||||
t.Error("Expected error to occur but it was nil")
|
||||
@@ -297,7 +323,7 @@ func TestValidateSysctlWithBindHostNetNS(t *testing.T) {
|
||||
),
|
||||
}
|
||||
|
||||
validator := validate.New()
|
||||
validator := New()
|
||||
if err := validator.Validate(config); err == nil {
|
||||
t.Error("Expected error to occur but it was nil")
|
||||
}
|
||||
@@ -310,7 +336,7 @@ func TestValidateSysctlWithoutNETNamespace(t *testing.T) {
|
||||
Namespaces: []configs.Namespace{},
|
||||
}
|
||||
|
||||
validator := validate.New()
|
||||
validator := New()
|
||||
err := validator.Validate(config)
|
||||
if err == nil {
|
||||
t.Error("Expected error to occur but it was nil")
|
||||
@@ -332,7 +358,7 @@ func TestValidateMounts(t *testing.T) {
|
||||
{isErr: false, dest: "/abs/but/../unclean"},
|
||||
}
|
||||
|
||||
validator := validate.New()
|
||||
validator := New()
|
||||
|
||||
for _, tc := range testCases {
|
||||
config := &configs.Config{
|
||||
|
||||
Reference in New Issue
Block a user