mirror of
https://github.com/containers/podman.git
synced 2025-10-12 08:45:37 +08:00
Merge pull request #24825 from giuseppe/simplify-systemd-parser
systemd: simplify parser and fix infinite loop
This commit is contained in:
@ -48,7 +48,6 @@ type UnitFileParser struct {
|
||||
|
||||
currentGroup *unitGroup
|
||||
pendingComments []*unitLine
|
||||
lineNr int
|
||||
}
|
||||
|
||||
func newUnitLine(key string, value string, isComment bool) *unitLine {
|
||||
@ -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)
|
||||
@ -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)
|
||||
}
|
||||
}
|
||||
|
||||
@ -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)
|
||||
lines := strings.Split(strings.TrimSuffix(data, "\n"), "\n")
|
||||
remaining := ""
|
||||
|
||||
for len(data) > 0 {
|
||||
origdata := data
|
||||
nLines := 1
|
||||
var line string
|
||||
line, data = nextLine(data, 0)
|
||||
|
||||
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 {
|
||||
@ -690,7 +675,6 @@ func (f *UnitFile) LookupInt(groupName string, key string, defaultValue int64) i
|
||||
}
|
||||
|
||||
intVal, err := convertNumber(v)
|
||||
|
||||
if err != nil {
|
||||
return defaultValue
|
||||
}
|
||||
|
@ -2,6 +2,7 @@ package parser
|
||||
|
||||
import (
|
||||
"reflect"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
@ -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
|
||||
@ -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.
|
||||
@ -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]
|
||||
@ -278,7 +299,7 @@ func TestRanges_Roundtrip(t *testing.T) {
|
||||
panic(e)
|
||||
}
|
||||
|
||||
assert.Equal(t, sample, asStr)
|
||||
assert.Equal(t, filterComments(sample), filterComments(asStr))
|
||||
}
|
||||
}
|
||||
|
||||
@ -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))
|
||||
})
|
||||
}
|
||||
|
Reference in New Issue
Block a user