Skip to content

Commit 8417a35

Browse files
committed
fix: escape control characters in IfcfgUtil.ValueEscape
The ANSI-C quoting branch tested `ord(c) < ord(c)`, which is always False, so the escaping path was dead and control characters were written raw into the $'...' string. ifcfg_to_content() emits one KEY=VALUE per line, so a value containing a newline broke that structure in the generated file. The escape also emitted a decimal code point, but ANSI-C quoting reads \nnn as octal, so the sequence would have decoded to the wrong character once the branch became reachable. Both are corrected by comparing against ord(" ") and emitting %03o. Adds unit tests covering the ANSI-C path, the double-quoting path and the unquoted path. The two control-character tests fail without the fix. Documents the escaping rules in the ValueEscape docstring, citing Bash Reference Manual 3.1.2.3 and 3.1.2.4. Signed-off-by: Suraj Patil <surajpatil522@gmail.com>
1 parent 88fd7be commit 8417a35

2 files changed

Lines changed: 33 additions & 3 deletions

File tree

library/network_connections.py

Lines changed: 19 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -301,7 +301,23 @@ def KeyValid(cls, name):
301301

302302
@classmethod
303303
def ValueEscape(cls, value):
304-
304+
"""Quote a value for an ifcfg file, which is shell syntax.
305+
306+
Two quoting styles are produced, matching the Bash Reference
307+
Manual:
308+
309+
ANSI-C quoting, $'...', used when the value contains control
310+
characters (Bash Reference Manual 3.1.2.4). Backslash escapes
311+
are decoded per the ANSI C standard, so \\nnn is the eight-bit
312+
character whose value is the *octal* value nnn, one to three
313+
octal digits. Backslash and single quote are escaped with a
314+
preceding backslash.
315+
316+
Double quoting, "...", used otherwise (Bash Reference Manual
317+
3.1.2.3). Within double quotes the characters $, `, \\ and "
318+
retain their special meaning and are escaped with a preceding
319+
backslash.
320+
"""
305321
r = getattr(cls, "_re_ValueEscape", None)
306322
if r is None:
307323
r = re.compile("^[a-zA-Z_0-9-.]*$")
@@ -314,8 +330,8 @@ def ValueEscape(cls, value):
314330
# needs ansic escaping due to ANSI control characters (newline)
315331
s = "$'"
316332
for c in value:
317-
if ord(c) < ord(c):
318-
s += "\\" + str(ord(c))
333+
if ord(c) < ord(" "):
334+
s += "\\%03o" % ord(c)
319335
elif c == "\\" or c == "'":
320336
s += "\\" + c
321337
else:

tests/unit/test_network_connections.py

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5657,5 +5657,19 @@ def unstable_fetch():
56575657
self.assertEqual(fetch_mock.call_count, 51)
56585658

56595659

5660+
class TestIfcfgUtilValueEscape(unittest.TestCase):
5661+
def test_plain_value_is_not_quoted(self):
5662+
self.assertEqual(IfcfgUtil.ValueEscape("eth0"), "eth0")
5663+
5664+
def test_control_char_escaped_as_octal(self):
5665+
self.assertEqual(IfcfgUtil.ValueEscape("line1\nline2"), "$'line1\\012line2'")
5666+
5667+
def test_control_char_with_quote_and_backslash(self):
5668+
self.assertEqual(IfcfgUtil.ValueEscape("a\n'b\\c"), "$'a\\012\\'b\\\\c'")
5669+
5670+
def test_double_quoting_path_is_unchanged(self):
5671+
self.assertEqual(IfcfgUtil.ValueEscape('a "b" $c'), '"a \\"b\\" \\$c"')
5672+
5673+
56605674
if __name__ == "__main__":
56615675
unittest.main()

0 commit comments

Comments
 (0)