1
0
mirror of https://github.com/containers/bootc.git synced 2026-02-05 15:45:53 +01:00

kernel_cmdline: Fix parsing/equivalence of "outside" quoted args

Primary motivation here is that these two should be equivalent:

foo="quoted value"
"foo=quoted value"

This also adds tests for a few more oddball cases that weren't covered
before but clarify the expected kernel behavior.

Closes: #1737
Signed-off-by: John Eckersberg <jeckersb@redhat.com>
This commit is contained in:
John Eckersberg
2025-11-06 17:10:41 -05:00
committed by Colin Walters
parent 3181bb58e7
commit 87bcbd9ae9
2 changed files with 58 additions and 14 deletions

View File

@@ -421,27 +421,31 @@ impl<'a> Parameter<'a> {
/// This is an internal method that assumes the input has already been
/// split into a single parameter (e.g., by CmdlineIterBytes).
fn parse_internal(input: &'a [u8]) -> Option<Self> {
let equals = input.iter().position(|b| *b == b'=');
// *Only* the first and last double quotes are stripped
let dequoted_input = input.strip_prefix(b"\"").unwrap_or(input);
let dequoted_input = dequoted_input.strip_suffix(b"\"").unwrap_or(dequoted_input);
let equals = dequoted_input.iter().position(|b| *b == b'=');
match equals {
None => Some(Self {
parameter: input,
key: ParameterKey(input),
key: ParameterKey(dequoted_input),
value: None,
}),
Some(i) => {
let (key, mut value) = input.split_at(i);
let (key, mut value) = dequoted_input.split_at(i);
let key = ParameterKey(key);
// skip `=`, we know it's the first byte because we
// found it above
value = &value[1..];
// *Only* the first and last double quotes are stripped
value = {
let v = value.strip_prefix(b"\"").unwrap_or(value);
v.strip_suffix(b"\"").unwrap_or(v)
};
// If there is a quote after the equals, skip it. If
// there was a closing quote at the end of the value,
// we would have already removed it in
// `dequoted_input` above
value = value.strip_prefix(b"\"").unwrap_or(value);
Some(Self {
parameter: input,
@@ -528,6 +532,10 @@ mod tests {
let p = param("foo=trailing_quotes\"");
assert_eq!(p.value, Some(b"trailing_quotes".as_slice()));
let outside_quoted = param("\"foo=quoted value\"");
let value_quoted = param("foo=\"quoted value\"");
assert_eq!(outside_quoted, value_quoted);
}
#[test]
@@ -549,9 +557,22 @@ mod tests {
fn test_parameter_pathological() {
// valid things that certified insane people would do
// quotes don't get removed from keys
let p = param("\"\"\"");
assert_eq!(p.key.0, b"\"\"\"");
// you can quote just the key part in a key-value param, but
// the end quote is actually part of the key as far as the
// kernel is concerned...
let p = param("\"foo\"=bar");
assert_eq!(p.key.0, b"foo\"");
assert_eq!(p.value, Some(b"bar".as_slice()));
// and it is definitely not equal to an unquoted foo ...
assert_ne!(p, param("foo=bar"));
// ... but if you close the quote immediately after the
// equals sign, it does get removed.
let p = param("\"foo=\"bar");
assert_eq!(p.key.0, b"foo");
assert_eq!(p.value, Some(b"bar".as_slice()));
// ... so of course this makes sense ...
assert_eq!(p, param("foo=bar"));
// quotes only get stripped from the absolute ends of values
let p = param("foo=\"internal\"quotes\"are\"ok\"");

View File

@@ -426,6 +426,16 @@ mod tests {
fn test_parameter_quoted() {
let p = param("foo=\"quoted value\"");
assert_eq!(p.value(), Some("quoted value"));
let p = param("foo=\"unclosed quotes");
assert_eq!(p.value(), Some("unclosed quotes"));
let p = param("foo=trailing_quotes\"");
assert_eq!(p.value(), Some("trailing_quotes"));
let outside_quoted = param("\"foo=quoted value\"");
let value_quoted = param("foo=\"quoted value\"");
assert_eq!(outside_quoted, value_quoted);
}
#[test]
@@ -447,9 +457,22 @@ mod tests {
fn test_parameter_pathological() {
// valid things that certified insane people would do
// quotes don't get removed from keys
let p = param("\"\"\"");
assert_eq!(p.key(), "\"\"\"".into());
// you can quote just the key part in a key-value param, but
// the end quote is actually part of the key as far as the
// kernel is concerned...
let p = param("\"foo\"=bar");
assert_eq!(p.key(), ParameterKey::from("foo\""));
assert_eq!(p.value(), Some("bar"));
// and it is definitely not equal to an unquoted foo ...
assert_ne!(p, param("foo=bar"));
// ... but if you close the quote immediately after the
// equals sign, it does get removed.
let p = param("\"foo=\"bar");
assert_eq!(p.key(), ParameterKey::from("foo"));
assert_eq!(p.value(), Some("bar"));
// ... so of course this makes sense ...
assert_eq!(p, param("foo=bar"));
// quotes only get stripped from the absolute ends of values
let p = param("foo=\"internal\"quotes\"are\"ok\"");