summaryrefslogtreecommitdiff
path: root/src/session.rs
diff options
context:
space:
mode:
authorWez Furlong <wez@wezfurlong.org>2019-08-01 12:42:33 -0700
committerWez Furlong <wez@wezfurlong.org>2019-08-01 12:42:33 -0700
commit672893d6f8ff3fec22f7f509247adeb477aa5f4a (patch)
tree53547c1c5f3e234394c229bc9d482d8b9181263e /src/session.rs
parent8f580e16d9bce9c6cf7ad529f0b8fa444f6de505 (diff)
downloadssh2-rs-672893d6f8ff3fec22f7f509247adeb477aa5f4a.zip
don't allow panics to escape the prompt callback
This avoids the potential for UB if the callback panics; Rust doesn't specify what happens if a panic unwinds back into C code.
Diffstat (limited to 'src/session.rs')
-rw-r--r--src/session.rs118
1 files changed, 61 insertions, 57 deletions
diff --git a/src/session.rs b/src/session.rs
index acf9522..cd33327 100644
--- a/src/session.rs
+++ b/src/session.rs
@@ -310,67 +310,71 @@ impl Session {
responses: *mut raw::LIBSSH2_USERAUTH_KBDINT_RESPONSE,
abstrakt: *mut *mut c_void,
) {
- let prompter = unsafe { &mut **(abstrakt as *mut *mut P) };
-
- let username =
- unsafe { slice::from_raw_parts(username as *const u8, username_len as usize) };
- let username = String::from_utf8_lossy(username);
-
- let instruction = unsafe {
- slice::from_raw_parts(instruction as *const u8, instruction_len as usize)
- };
- let instruction = String::from_utf8_lossy(instruction);
-
- let prompts = unsafe { slice::from_raw_parts(prompts, num_prompts as usize) };
- let responses = unsafe { slice::from_raw_parts_mut(responses, num_prompts as usize) };
-
- let prompts: Vec<Prompt> = prompts
- .iter()
- .map(|item| {
- let data = unsafe {
- slice::from_raw_parts(item.text as *const u8, item.length as usize)
- };
- Prompt {
- text: String::from_utf8_lossy(data),
- echo: item.echo != 0,
- }
- })
- .collect();
-
- // libssh2 wants to be able to free(3) the response strings, so allocate
- // storage and copy the responses into appropriately owned memory.
- // We can't simply call strdup(3) here because the rust string types
- // are not NUL terminated.
- fn strdup_string(s: &str) -> *mut c_char {
- let len = s.len();
- let ptr = unsafe { libc::malloc(len + 1) as *mut c_char };
- if !ptr.is_null() {
- unsafe {
- ::std::ptr::copy_nonoverlapping(
- s.as_bytes().as_ptr() as *const c_char,
- ptr,
- len,
- );
- *ptr.offset(len as isize) = 0;
+ use std::panic::{catch_unwind, AssertUnwindSafe};
+ catch_unwind(AssertUnwindSafe(|| {
+ let prompter = unsafe { &mut **(abstrakt as *mut *mut P) };
+
+ let username =
+ unsafe { slice::from_raw_parts(username as *const u8, username_len as usize) };
+ let username = String::from_utf8_lossy(username);
+
+ let instruction = unsafe {
+ slice::from_raw_parts(instruction as *const u8, instruction_len as usize)
+ };
+ let instruction = String::from_utf8_lossy(instruction);
+
+ let prompts = unsafe { slice::from_raw_parts(prompts, num_prompts as usize) };
+ let responses =
+ unsafe { slice::from_raw_parts_mut(responses, num_prompts as usize) };
+
+ let prompts: Vec<Prompt> = prompts
+ .iter()
+ .map(|item| {
+ let data = unsafe {
+ slice::from_raw_parts(item.text as *const u8, item.length as usize)
+ };
+ Prompt {
+ text: String::from_utf8_lossy(data),
+ echo: item.echo != 0,
+ }
+ })
+ .collect();
+
+ // libssh2 wants to be able to free(3) the response strings, so allocate
+ // storage and copy the responses into appropriately owned memory.
+ // We can't simply call strdup(3) here because the rust string types
+ // are not NUL terminated.
+ fn strdup_string(s: &str) -> *mut c_char {
+ let len = s.len();
+ let ptr = unsafe { libc::malloc(len + 1) as *mut c_char };
+ if !ptr.is_null() {
+ unsafe {
+ ::std::ptr::copy_nonoverlapping(
+ s.as_bytes().as_ptr() as *const c_char,
+ ptr,
+ len,
+ );
+ *ptr.offset(len as isize) = 0;
+ }
}
+ ptr
}
- ptr
- }
- for (i, response) in (*prompter)
- .prompt(&username, &instruction, &prompts)
- .into_iter()
- .take(prompts.len())
- .enumerate()
- {
- let ptr = strdup_string(&response);
- if !ptr.is_null() {
- responses[i].length = response.len() as c_uint;
- } else {
- responses[i].length = 0;
+ for (i, response) in (*prompter)
+ .prompt(&username, &instruction, &prompts)
+ .into_iter()
+ .take(prompts.len())
+ .enumerate()
+ {
+ let ptr = strdup_string(&response);
+ if !ptr.is_null() {
+ responses[i].length = response.len() as c_uint;
+ } else {
+ responses[i].length = 0;
+ }
+ responses[i].text = ptr;
}
- responses[i].text = ptr;
- }
+ }));
}
unsafe {