Skip to content

Commit

Permalink
Merge pull request #24825 from giuseppe/simplify-systemd-parser
Browse files Browse the repository at this point in the history
systemd: simplify parser and fix infinite loop
  • Loading branch information
openshift-merge-bot[bot] authored Dec 13, 2024
2 parents 8030093 + 64e94ef commit 3cffc6b
Show file tree
Hide file tree
Showing 3 changed files with 66 additions and 44 deletions.
64 changes: 24 additions & 40 deletions pkg/systemd/parser/unitfile.go
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,6 @@ type UnitFileParser struct {

currentGroup *unitGroup
pendingComments []*unitLine
lineNr int
}

func newUnitLine(key string, value string, isComment bool) *unitLine {
Expand Down Expand Up @@ -347,7 +346,7 @@ func (p *UnitFileParser) parseKeyValuePair(line string) error {
return nil
}

func (p *UnitFileParser) parseLine(line string) error {
func (p *UnitFileParser) parseLine(line string, lineNr int) error {
switch {
case lineIsComment(line):
return p.parseComment(line)
Expand All @@ -356,7 +355,7 @@ func (p *UnitFileParser) parseLine(line string) error {
case lineIsKeyValuePair(line):
return p.parseKeyValuePair(line)
default:
return fmt.Errorf("file contains line %d: “%s” which is not a key-value pair, group, or comment", p.lineNr, line)
return fmt.Errorf("file contains line %d: “%s” which is not a key-value pair, group, or comment", lineNr, line)
}
}

Expand All @@ -376,53 +375,39 @@ func (p *UnitFileParser) flushPendingComments(toComment bool) {
}
}

func nextLine(data string, afterPos int) (string, string) {
rest := data[afterPos:]
if i := strings.Index(rest, "\n"); i >= 0 {
return strings.TrimSpace(data[:i+afterPos]), data[i+afterPos+1:]
}
return data, ""
}

func trimSpacesFromLines(data string) string {
lines := strings.Split(data, "\n")
for i, line := range lines {
lines[i] = strings.TrimSpace(line)
}
return strings.Join(lines, "\n")
}

// Parse an already loaded unit file (in the form of a string)
func (f *UnitFile) Parse(data string) error {
p := &UnitFileParser{
file: f,
lineNr: 1,
file: f,
}

data = trimSpacesFromLines(data)

for len(data) > 0 {
origdata := data
nLines := 1
var line string
line, data = nextLine(data, 0)
lines := strings.Split(strings.TrimSuffix(data, "\n"), "\n")
remaining := ""

if !lineIsComment(line) {
// Handle multi-line continuations
// Note: This doesn't support comments in the middle of the continuation, which systemd does
if lineIsKeyValuePair(line) {
for len(data) > 0 && line[len(line)-1] == '\\' {
line, data = nextLine(origdata, len(line)+1)
nLines++
for lineNr, line := range lines {
line = strings.TrimSpace(line)
if lineIsComment(line) {
// ignore the comment is inside a continuation line.
if remaining != "" {
continue
}
} else {
if strings.HasSuffix(line, "\\") {
line = line[:len(line)-1]
if lineNr != len(lines)-1 {
remaining += line
continue
}
}
// check whether the line is a continuation of the previous line
if remaining != "" {
line = remaining + line
remaining = ""
}
}

if err := p.parseLine(line); err != nil {
if err := p.parseLine(line, lineNr+1); err != nil {
return err
}

p.lineNr += nLines
}

if p.currentGroup == nil {
Expand Down Expand Up @@ -690,7 +675,6 @@ func (f *UnitFile) LookupInt(groupName string, key string, defaultValue int64) i
}

intVal, err := convertNumber(v)

if err != nil {
return defaultValue
}
Expand Down
42 changes: 38 additions & 4 deletions pkg/systemd/parser/unitfile_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package parser

import (
"reflect"
"strings"
"testing"

"github.com/stretchr/testify/assert"
Expand Down Expand Up @@ -119,7 +120,10 @@ After=dbus.socket
[Service]
BusName=org.freedesktop.login1
CapabilityBoundingSet=CAP_SYS_ADMIN CAP_MAC_ADMIN CAP_AUDIT_CONTROL CAP_CHOWN CAP_DAC_READ_SEARCH CAP_DAC_OVERRIDE CAP_FOWNER CAP_SYS_TTY_CONFIG CAP_LINUX_IMMUTABLE
CapabilityBoundingSet=CAP_SYS_ADMIN CAP_MAC_ADMIN CAP_AUDIT_CONTROL CAP_CHOWN CAP_DAC_READ_SEARCH CAP_DAC_OVERRIDE \
# comment inside a continuation line \
CAP_FOWNER \
CAP_SYS_TTY_CONFIG CAP_LINUX_IMMUTABLE
DeviceAllow=block-* r
DeviceAllow=char-/dev/console rw
DeviceAllow=char-drm rw
Expand Down Expand Up @@ -158,8 +162,8 @@ SystemCallFilter=@system-service
# Increase the default a bit in order to allow many simultaneous logins since
# we keep one fd open per session.
LimitNOFILE=524288
`
LimitNOFILE=524288 \`

const systemdnetworkdService = `# SPDX-License-Identifier: LGPL-2.1-or-later
#
# This file is part of systemd.
Expand Down Expand Up @@ -264,6 +268,23 @@ var sampleDropinPaths = map[string][]string{
sampleDropinTemplateInstance: sampleDropinTemplateInstancePaths,
}

func filterComments(input string) string {
lines := strings.Split(input, "\n")
filtered := make([]string, 0, len(lines))
for _, line := range lines {
line = strings.TrimSpace(line)
if strings.HasPrefix(line, "#") || strings.HasPrefix(line, ";") {
continue
}
filtered = append(filtered, line)
}
// merge continuation lines
joined := strings.ReplaceAll(strings.Join(filtered, "\n"), "\\\n", "")

// and remove any trailing new line, backslash or space
return strings.TrimRight(joined, "\n\\ ")
}

func TestRanges_Roundtrip(t *testing.T) {
for i := range samples {
sample := samples[i]
Expand All @@ -278,7 +299,7 @@ func TestRanges_Roundtrip(t *testing.T) {
panic(e)
}

assert.Equal(t, sample, asStr)
assert.Equal(t, filterComments(sample), filterComments(asStr))
}
}

Expand All @@ -292,3 +313,16 @@ func TestUnitDropinPaths_Search(t *testing.T) {
assert.True(t, reflect.DeepEqual(expectedPaths, generatedPaths))
}
}

func FuzzParser(f *testing.F) {
for _, sample := range samples {
f.Add([]byte(sample))
}

f.Fuzz(func(t *testing.T, orig []byte) {
unitFile := NewUnitFile()
unitFile.Path = "foo/bar"
unitFile.Filename = "bar"
_ = unitFile.Parse(string(orig))
})
}
4 changes: 4 additions & 0 deletions test/e2e/quadlet/emptyline.container
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
[Container]
Exec=true \

# must have a blank line above, but this line can be anything (including another blank line)

0 comments on commit 3cffc6b

Please sign in to comment.