Skip to content

Commit

Permalink
config/types/config: prevent files/links/dirs from conflicting with s…
Browse files Browse the repository at this point in the history
…ystemd units and dropins
  • Loading branch information
marmijo committed Oct 5, 2022
1 parent 58bf6aa commit 66ed4ce
Show file tree
Hide file tree
Showing 12 changed files with 1,519 additions and 0 deletions.
1 change: 1 addition & 0 deletions config/shared/errors/errors.go
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,7 @@ var (
ErrDuplicateLabels = errors.New("cannot use the same partition label twice")
ErrInvalidProxy = errors.New("proxies must be http(s)")
ErrInsecureProxy = errors.New("insecure plaintext HTTP proxy specified for HTTPS resources")
ErrPathConflictsSystemd = errors.New("path conflicts with systemd unit or dropin")

// Systemd section errors
ErrInvalidSystemdExt = errors.New("invalid systemd unit extension")
Expand Down
52 changes: 52 additions & 0 deletions config/v3_0/types/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,13 @@
package types

import (
"strings"

"github.com/coreos/go-semver/semver"
"github.com/coreos/ignition/v2/config/shared/errors"

"github.com/coreos/vcontext/path"
"github.com/coreos/vcontext/report"
)

var (
Expand All @@ -24,3 +30,49 @@ var (
Minor: 0,
}
)

func (cfg Config) Validate(c path.ContextPath) (r report.Report) {
systemdPath := "/etc/systemd/system/"
unit_paths := make([]string, 0)
for _, unit := range cfg.Systemd.Units {
if unit.Contents != nil {
path_string := systemdPath + unit.Name
unit_paths = append(unit_paths, path_string)
} else {
for _, dropin := range unit.Dropins {
if dropin.Contents != nil {
path_string := systemdPath + unit.Name + ".d/" + dropin.Name
unit_paths = append(unit_paths, path_string)
}
}
}
}
for i, f := range cfg.Storage.Files {
if validateSystemdConflict(f.Path, unit_paths) {
r.AddOnError(c.Append("storage", "files", i, "path"), errors.ErrPathConflictsSystemd)
}
}
for i, d := range cfg.Storage.Directories {
if validateSystemdConflict(d.Path, unit_paths) {
r.AddOnError(c.Append("storage", "directories", i, "path"), errors.ErrPathConflictsSystemd)
}
}
for i, l := range cfg.Storage.Links {
if validateSystemdConflict(l.Path, unit_paths) {
r.AddOnError(c.Append("storage", "links", i, "path"), errors.ErrPathConflictsSystemd)
}
}
return
}

func validateSystemdConflict(p string, unit_paths []string) bool {
systemdPath := "/etc/systemd/system/"
if strings.HasPrefix(p, systemdPath) {
for _, u := range unit_paths {
if strings.Compare(p, u) == 0 {
return true
}
}
}
return false
}
249 changes: 249 additions & 0 deletions config/v3_0/types/config_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,249 @@
// Copyright 2020 Red Hat, Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package types

import (
"reflect"
"testing"

"github.com/coreos/ignition/v2/config/shared/errors"
"github.com/coreos/ignition/v2/config/util"

"github.com/coreos/vcontext/path"
"github.com/coreos/vcontext/report"
)

func TestConfigValidation(t *testing.T) {
tests := []struct {
in Config
out error
at path.ContextPath
}{
// test 0: file conflicts with systemd dropin file, error
{
in: Config{
Ignition{},
Passwd{},
Storage{
Files: []File{
{
Node: Node{Path: "/etc/systemd/system/foo.service.d/bar.conf"},
},
},
},
Systemd{
Units: []Unit{
{
Name: "foo.service",
Dropins: []Dropin{
{
Name: "bar.conf",
Contents: util.StrToPtr("[Foo]\nQux=Bar"),
},
},
},
},
},
},
out: errors.ErrPathConflictsSystemd,
at: path.New("json", "storage", "files", 0, "path"),
},
// test 1: file conflicts with systemd unit, error
{
in: Config{
Ignition{},
Passwd{},
Storage{
Files: []File{
{
Node: Node{Path: "/etc/systemd/system/foo.service"},
},
},
},
Systemd{
Units: []Unit{
{
Name: "foo.service",
Contents: util.StrToPtr("[Foo]\nQux=Bar"),
Enabled: util.BoolToPtr(true),
},
},
},
},
out: errors.ErrPathConflictsSystemd,
at: path.New("json", "storage", "files", 0, "path"),
},
// test 2: directory conflicts with systemd dropin file, error
{
in: Config{
Ignition{},
Passwd{},
Storage{
Directories: []Directory{
{
Node: Node{Path: "/etc/systemd/system/foo.service.d/bar.conf"},
},
},
},
Systemd{
[]Unit{
{
Name: "foo.service",
Dropins: []Dropin{
{
Name: "bar.conf",
Contents: util.StrToPtr("[Foo]\nQux=Bar"),
},
},
},
},
},
},
out: errors.ErrPathConflictsSystemd,
at: path.New("json", "storage", "directories", 0, "path"),
},
// test 3: directory conflicts with systemd unit, error
{
in: Config{
Ignition{},
Passwd{},
Storage{
Directories: []Directory{
{
Node: Node{Path: "/etc/systemd/system/foo.service"},
},
},
},
Systemd{
[]Unit{
{
Name: "foo.service",
Contents: util.StrToPtr("[foo]\nQux=Baz"),
Enabled: util.BoolToPtr(true),
},
},
},
},
out: errors.ErrPathConflictsSystemd,
at: path.New("json", "storage", "directories", 0, "path"),
},
// test 4: link conflicts with systemd dropin file, error
{
in: Config{
Ignition{},
Passwd{},
Storage{
Links: []Link{
{
Node: Node{Path: "/etc/systemd/system/foo.service.d/bar.conf"},
LinkEmbedded1: LinkEmbedded1{Target: "/qux.conf"},
},
},
},
Systemd{
[]Unit{
{
Name: "foo.service",
Dropins: []Dropin{
{
Name: "bar.conf",
Contents: util.StrToPtr("[Foo]\nQux=Bar"),
},
},
},
},
},
},
out: errors.ErrPathConflictsSystemd,
at: path.New("json", "storage", "links", 0, "path"),
},
// test 5: non-conflicting scenarios
{
in: Config{
Ignition{},
Passwd{},
Storage{
Files: []File{
{
Node: Node{Path: "/etc/systemd/system/bar.service.d/baz.conf"},
},
{
Node: Node{Path: "/etc/systemd/system/bar.service"},
},
{
Node: Node{Path: "/etc/systemd/system/foo.service.d/qux.conf"},
},
},
Links: []Link{
{
Node: Node{Path: "/etc/systemd/system/qux.service"},
LinkEmbedded1: LinkEmbedded1{Target: "/qux.conf"},
},
{
Node: Node{Path: "/etc/systemd/system/quux.service.d/foo.conf"},
LinkEmbedded1: LinkEmbedded1{Target: "/foo.conf"},
},
},
Directories: []Directory{
{
Node: Node{Path: "/etc/systemd/system/quux.service.d"},
},
},
},
Systemd{
Units: []Unit{
{
Name: "foo.service",
Contents: util.StrToPtr("[Foo]\nQux=Baz"),
Enabled: util.BoolToPtr(true),
},
{
Name: "bar.service",
Dropins: []Dropin{
{
Name: "baz.conf",
},
},
Enabled: util.BoolToPtr(true),
},
{
Name: "qux.service",
Dropins: []Dropin{
{
Name: "bar.conf",
Contents: util.StrToPtr("[Foo]\nQux=Baz"),
},
},
},
{
Name: "quux.service",
Contents: util.StrToPtr("[Foo]\nQux=Baz"),
Enabled: util.BoolToPtr(true),
},
},
},
},
at: path.New("json", "storage", "files", 0, "path"),
},
}
for i, test := range tests {
r := test.in.Validate(path.New("json"))
expected := report.Report{}
expected.AddOnError(test.at, test.out)
if !reflect.DeepEqual(expected, r) {
t.Errorf("#%d: bad error: expected : %v, got %v", i, expected, r)
}
}
}
52 changes: 52 additions & 0 deletions config/v3_1/types/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,13 @@
package types

import (
"strings"

"github.com/coreos/go-semver/semver"
"github.com/coreos/ignition/v2/config/shared/errors"

"github.com/coreos/vcontext/path"
"github.com/coreos/vcontext/report"
)

var (
Expand All @@ -24,3 +30,49 @@ var (
Minor: 1,
}
)

func (cfg Config) Validate(c path.ContextPath) (r report.Report) {
systemdPath := "/etc/systemd/system/"
unit_paths := make([]string, 0)
for _, unit := range cfg.Systemd.Units {
if unit.Contents != nil {
path_string := systemdPath + unit.Name
unit_paths = append(unit_paths, path_string)
} else {
for _, dropin := range unit.Dropins {
if dropin.Contents != nil {
path_string := systemdPath + unit.Name + ".d/" + dropin.Name
unit_paths = append(unit_paths, path_string)
}
}
}
}
for i, f := range cfg.Storage.Files {
if validateSystemdConflict(f.Path, unit_paths) {
r.AddOnError(c.Append("storage", "files", i, "path"), errors.ErrPathConflictsSystemd)
}
}
for i, d := range cfg.Storage.Directories {
if validateSystemdConflict(d.Path, unit_paths) {
r.AddOnError(c.Append("storage", "directories", i, "path"), errors.ErrPathConflictsSystemd)
}
}
for i, l := range cfg.Storage.Links {
if validateSystemdConflict(l.Path, unit_paths) {
r.AddOnError(c.Append("storage", "links", i, "path"), errors.ErrPathConflictsSystemd)
}
}
return
}

func validateSystemdConflict(p string, unit_paths []string) bool {
systemdPath := "/etc/systemd/system/"
if strings.HasPrefix(p, systemdPath) {
for _, u := range unit_paths {
if strings.Compare(p, u) == 0 {
return true
}
}
}
return false
}
Loading

0 comments on commit 66ed4ce

Please sign in to comment.