Skip to content

Commit 3290636

Browse files
committed
Fixes from PR
- rename to image_handle_protocol - verify that cli args are valid UTF-16 Signed-off-by: Ayush Singh <ayushdevel1325@gmail.com>
1 parent 9f26c8b commit 3290636

File tree

2 files changed

+35
-42
lines changed

2 files changed

+35
-42
lines changed

Diff for: library/std/src/sys/uefi/args.rs

+34-41
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,6 @@ use crate::ffi::OsString;
55
use crate::fmt;
66
use crate::iter::Iterator;
77
use crate::mem::size_of;
8-
use crate::os::uefi::ffi::OsStringExt;
98
use crate::sys::uefi::helpers;
109
use crate::vec;
1110

@@ -16,31 +15,27 @@ pub struct Args {
1615
pub fn args() -> Args {
1716
// SAFETY: Each loaded image has an image handle that supports EFI_LOADED_IMAGE_PROTOCOL
1817
let protocol =
19-
helpers::current_handle_protocol::<loaded_image::Protocol>(loaded_image::PROTOCOL_GUID)
18+
helpers::image_handle_protocol::<loaded_image::Protocol>(loaded_image::PROTOCOL_GUID)
2019
.unwrap();
2120

2221
let lp_size = unsafe { (*protocol.as_ptr()).load_options_size } as usize;
23-
let lp_size: usize = lp_size / size_of::<u16>();
2422

25-
if lp_size <= 0 {
23+
// Break if we are sure that it cannot be UTF-16
24+
if lp_size < size_of::<u16>() || lp_size % size_of::<u16>() != 0 {
2625
return Args {
2726
parsed_args_list: Vec::from([current_exe().map(Into::into).unwrap_or_default()])
2827
.into_iter(),
2928
};
3029
}
3130

3231
let lp_cmd_line = unsafe {
32+
let lp_size = lp_size / size_of::<u16>();
3333
let temp = (*protocol.as_ptr()).load_options as *const u16;
3434
crate::slice::from_raw_parts(temp, lp_size)
3535
};
3636

37-
let vec_args = parse_lp_cmd_line(lp_cmd_line);
38-
let vec_args = if vec_args.is_empty() {
39-
Vec::from([current_exe().map(Into::into).unwrap_or_default()])
40-
} else {
41-
vec_args
42-
};
43-
37+
let vec_args = parse_lp_cmd_line(lp_cmd_line)
38+
.unwrap_or(Vec::from([current_exe().map(Into::into).unwrap_or_default()]));
4439
Args { parsed_args_list: vec_args.into_iter() }
4540
}
4641

@@ -78,20 +73,25 @@ impl DoubleEndedIterator for Args {
7873
///
7974
/// This implementation is based on what is defined in Section 3.4 of
8075
/// [UEFI Shell Specification](https://uefi.org/sites/default/files/resources/UEFI_Shell_Spec_2_0.pdf)
81-
fn parse_lp_cmd_line(code_units: &[u16]) -> Vec<OsString> {
82-
const QUOTE: u16 = b'"' as u16;
83-
const SPACE: u16 = b' ' as u16;
84-
const CARET: u16 = b'^' as u16;
85-
const NULL: u16 = 0;
76+
///
77+
/// Return None in the following cases:
78+
/// - Invalid UTF-16 (unpaired surrogate)
79+
/// - Empty/improper arguments
80+
fn parse_lp_cmd_line(code_units: &[u16]) -> Option<Vec<OsString>> {
81+
const QUOTE: char = '"';
82+
const SPACE: char = ' ';
83+
const CARET: char = '^';
84+
const NULL: char = '\0';
8685

8786
let mut ret_val = Vec::new();
88-
let mut code_units_iter = code_units.iter().peekable();
87+
let mut code_units_iter = char::decode_utf16(code_units.iter().cloned()).peekable();
8988

9089
// The executable name at the beginning is special.
9190
let mut in_quotes = false;
92-
let mut cur = Vec::new();
91+
let mut cur = String::new();
9392
while let Some(w) = code_units_iter.next() {
94-
match *w {
93+
let w = w.ok()?;
94+
match w {
9595
// break on NULL
9696
NULL => break,
9797
// A quote mark always toggles `in_quotes` no matter what because
@@ -100,13 +100,13 @@ fn parse_lp_cmd_line(code_units: &[u16]) -> Vec<OsString> {
100100
// If not `in_quotes` then whitespace ends argv[0].
101101
SPACE if !in_quotes => break,
102102
// In all other cases the code unit is taken literally.
103-
_ => cur.push(*w),
103+
_ => cur.push(w),
104104
}
105105
}
106106

107107
// Skip whitespace.
108-
while code_units_iter.next_if_eq(&&SPACE).is_some() {}
109-
ret_val.push(OsString::from_wide(&cur));
108+
while code_units_iter.next_if_eq(&Ok(SPACE)).is_some() {}
109+
ret_val.push(OsString::from(cur));
110110

111111
// Parse the arguments according to these rules:
112112
// * All code units are taken literally except space, quote and caret.
@@ -116,44 +116,37 @@ fn parse_lp_cmd_line(code_units: &[u16]) -> Vec<OsString> {
116116
// * A quote toggles `in_quotes` mode unless it's escaped. An escaped quote is taken literally.
117117
// * A quote can be escaped if preceded by caret.
118118
// * A caret can be escaped if preceded by caret.
119-
let mut cur = Vec::new();
119+
let mut cur = String::new();
120120
let mut in_quotes = false;
121121
while let Some(w) = code_units_iter.next() {
122-
match *w {
122+
let w = w.ok()?;
123+
match w {
123124
// break on NULL
124125
NULL => break,
125126
// If not `in_quotes`, a space or tab ends the argument.
126127
SPACE if !in_quotes => {
127-
ret_val.push(OsString::from_wide(&cur[..]));
128+
ret_val.push(OsString::from(&cur[..]));
128129
cur.truncate(0);
129130

130131
// Skip whitespace.
131-
while code_units_iter.next_if_eq(&&SPACE).is_some() {}
132+
while code_units_iter.next_if_eq(&Ok(SPACE)).is_some() {}
132133
}
133134
// Caret can escape quotes or carets
134135
CARET if in_quotes => {
135136
if let Some(x) = code_units_iter.next() {
136-
cur.push(*x)
137+
cur.push(x.ok()?);
137138
}
138139
}
139-
// If `in_quotes` and not caret escaped (see above) then a quote either
140-
// unsets `in_quote` or is escaped by another quote.
141-
QUOTE if in_quotes => match code_units_iter.peek() {
142-
// Otherwise set `in_quotes`.
143-
Some(_) => in_quotes = false,
144-
// The end of the command line.
145-
// Push `cur` even if empty, which we do by breaking while `in_quotes` is still set.
146-
None => break,
147-
},
148-
// If not `in_quotes` and not BACKSLASH escaped (see above) then a quote sets `in_quote`.
149-
QUOTE => in_quotes = true,
140+
// If quote then flip `in_quotes`
141+
QUOTE => in_quotes = !in_quotes,
150142
// Everything else is always taken literally.
151-
_ => cur.push(*w),
143+
_ => cur.push(w),
152144
}
153145
}
154146
// Push the final argument, if any.
155147
if !cur.is_empty() || in_quotes {
156-
ret_val.push(OsString::from_wide(&cur[..]));
148+
ret_val.push(OsString::from(cur));
157149
}
158-
ret_val
150+
151+
if ret_val.is_empty() { None } else { Some(ret_val) }
159152
}

Diff for: library/std/src/sys/uefi/helpers.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -142,7 +142,7 @@ pub(crate) unsafe fn close_event(evt: NonNull<crate::ffi::c_void>) -> io::Result
142142

143143
/// Get the Protocol for current system handle.
144144
/// Note: Some protocols need to be manually freed. It is the callers responsibility to do so.
145-
pub(crate) fn current_handle_protocol<T>(protocol_guid: Guid) -> Option<NonNull<T>> {
145+
pub(crate) fn image_handle_protocol<T>(protocol_guid: Guid) -> Option<NonNull<T>> {
146146
let system_handle = uefi::env::try_image_handle()?;
147147
open_protocol(system_handle, protocol_guid).ok()
148148
}

0 commit comments

Comments
 (0)