@@ -37,6 +37,10 @@ pub enum Error {
37
37
MmioSize ,
38
38
/// Operation would have made the command line too large.
39
39
TooLarge ,
40
+ /// Double-quotes can be used to protect spaces in values
41
+ NoQuoteSpace ,
42
+ /// A double quote that is in the middle of the value
43
+ InvalidQuote ,
40
44
}
41
45
42
46
impl fmt:: Display for Error {
@@ -56,6 +60,11 @@ impl fmt::Display for Error {
56
60
"0-sized virtio MMIO device passed to the kernel command line builder."
57
61
) ,
58
62
Error :: TooLarge => write ! ( f, "Inserting string would make command line too long." ) ,
63
+ Error :: NoQuoteSpace => write ! (
64
+ f,
65
+ "Value that contains spaces need to be surrounded by quotes"
66
+ ) ,
67
+ Error :: InvalidQuote => write ! ( f, "Double quote can not be in the middle of the value" ) ,
59
68
}
60
69
}
61
70
}
@@ -79,7 +88,26 @@ fn valid_str(s: &str) -> Result<()> {
79
88
}
80
89
}
81
90
82
- fn valid_element ( s : & str ) -> Result < ( ) > {
91
+ fn is_quoted ( s : & str ) -> bool {
92
+ if s. len ( ) < 2 {
93
+ return false ;
94
+ }
95
+ if let Some ( first_char) = s. chars ( ) . next ( ) {
96
+ if let Some ( last_char) = s. chars ( ) . last ( ) {
97
+ return first_char == '"' && last_char == '"' ;
98
+ }
99
+ }
100
+ false
101
+ }
102
+
103
+ fn contains_double_quotes ( s : & str ) -> bool {
104
+ if s. len ( ) < 3 {
105
+ return false ;
106
+ }
107
+ return s. chars ( ) . skip ( 1 ) . take ( s. len ( ) - 2 ) . any ( |c| c == '"' ) ;
108
+ }
109
+
110
+ fn valid_key ( s : & str ) -> Result < ( ) > {
83
111
if !s. chars ( ) . all ( valid_char) {
84
112
Err ( Error :: InvalidAscii )
85
113
} else if s. contains ( ' ' ) {
@@ -91,6 +119,18 @@ fn valid_element(s: &str) -> Result<()> {
91
119
}
92
120
}
93
121
122
+ fn valid_value ( s : & str ) -> Result < ( ) > {
123
+ if !s. chars ( ) . all ( valid_char) {
124
+ Err ( Error :: InvalidAscii )
125
+ } else if contains_double_quotes ( s) {
126
+ Err ( Error :: InvalidQuote )
127
+ } else if s. contains ( ' ' ) && !is_quoted ( s) {
128
+ Err ( Error :: NoQuoteSpace )
129
+ } else {
130
+ Ok ( ( ) )
131
+ }
132
+ }
133
+
94
134
/// A builder for a kernel command line string that validates the string as it's being built.
95
135
///
96
136
/// # Examples
@@ -155,8 +195,8 @@ impl Cmdline {
155
195
let k = key. as_ref ( ) ;
156
196
let v = val. as_ref ( ) ;
157
197
158
- valid_element ( k) ?;
159
- valid_element ( v) ?;
198
+ valid_key ( k) ?;
199
+ valid_value ( v) ?;
160
200
161
201
let kv_str = format ! ( "{}={}" , k, v) ;
162
202
@@ -186,7 +226,7 @@ impl Cmdline {
186
226
pub fn insert_multiple < T : AsRef < str > > ( & mut self , key : T , vals : & [ T ] ) -> Result < ( ) > {
187
227
let k = key. as_ref ( ) ;
188
228
189
- valid_element ( k) ?;
229
+ valid_key ( k) ?;
190
230
if vals. is_empty ( ) {
191
231
return Err ( Error :: MissingVal ( k. to_string ( ) ) ) ;
192
232
}
@@ -196,7 +236,7 @@ impl Cmdline {
196
236
k,
197
237
vals. iter( )
198
238
. map( |v| -> Result <& str > {
199
- valid_element ( v. as_ref( ) ) ?;
239
+ valid_value ( v. as_ref( ) ) ?;
200
240
Ok ( v. as_ref( ) )
201
241
} )
202
242
. collect:: <Result <Vec <& str >>>( ) ?
@@ -567,20 +607,29 @@ mod tests {
567
607
fn test_insert_space ( ) {
568
608
let mut cl = Cmdline :: new ( 100 ) . unwrap ( ) ;
569
609
assert_eq ! ( cl. insert( "a " , "b" ) , Err ( Error :: HasSpace ) ) ;
570
- assert_eq ! ( cl. insert( "a" , "b " ) , Err ( Error :: HasSpace ) ) ;
610
+ assert_eq ! ( cl. insert( "a" , "b " ) , Err ( Error :: NoQuoteSpace ) ) ;
571
611
assert_eq ! ( cl. insert( "a " , "b " ) , Err ( Error :: HasSpace ) ) ;
572
612
assert_eq ! ( cl. insert( " a" , "b" ) , Err ( Error :: HasSpace ) ) ;
613
+ assert_eq ! ( cl. insert( "a" , "hello \" world" ) , Err ( Error :: InvalidQuote ) ) ;
614
+ assert_eq ! (
615
+ cl. insert( "a" , "\" foor bar\" \" foor bar\" " ) ,
616
+ Err ( Error :: InvalidQuote )
617
+ ) ;
573
618
assert_eq ! ( cl. as_cstring( ) . unwrap( ) . as_bytes_with_nul( ) , b"\0 " ) ;
619
+ assert ! ( cl. insert( "a" , "\" b b\" " ) . is_ok( ) ) ;
620
+ assert ! ( cl. insert( "c" , "\" d\" " ) . is_ok( ) ) ;
621
+ assert_eq ! (
622
+ cl. as_cstring( ) . unwrap( ) . as_bytes_with_nul( ) ,
623
+ b"a=\" b b\" c=\" d\" \0 "
624
+ ) ;
574
625
}
575
626
576
627
#[ test]
577
628
fn test_insert_equals ( ) {
578
629
let mut cl = Cmdline :: new ( 100 ) . unwrap ( ) ;
579
630
assert_eq ! ( cl. insert( "a=" , "b" ) , Err ( Error :: HasEquals ) ) ;
580
- assert_eq ! ( cl. insert( "a" , "b=" ) , Err ( Error :: HasEquals ) ) ;
581
631
assert_eq ! ( cl. insert( "a=" , "b " ) , Err ( Error :: HasEquals ) ) ;
582
632
assert_eq ! ( cl. insert( "=a" , "b" ) , Err ( Error :: HasEquals ) ) ;
583
- assert_eq ! ( cl. insert( "a" , "=b" ) , Err ( Error :: HasEquals ) ) ;
584
633
assert_eq ! ( cl. as_cstring( ) . unwrap( ) . as_bytes_with_nul( ) , b"\0 " ) ;
585
634
}
586
635
@@ -702,7 +751,10 @@ mod tests {
702
751
cl. insert_multiple( "foo" , & no_vals) ,
703
752
Err ( Error :: MissingVal ( "foo" . to_string( ) ) )
704
753
) ;
705
- assert_eq ! ( cl. insert_multiple( "foo" , & [ "bar " ] ) , Err ( Error :: HasSpace ) ) ;
754
+ assert_eq ! (
755
+ cl. insert_multiple( "foo" , & [ "bar " ] ) ,
756
+ Err ( Error :: NoQuoteSpace )
757
+ ) ;
706
758
assert_eq ! (
707
759
cl. insert_multiple( "foo" , & [ "bar" , "baz" ] ) ,
708
760
Err ( Error :: TooLarge )
0 commit comments