Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Appearance settings

Commit f426348

Browse filesBrowse files
authored
Merge pull request #5558 from coolreader18/openssl-probe-no-env
Use non-env-var methods from openssl_probe
2 parents ff9947f + 085ac88 commit f426348
Copy full SHA for f426348

File tree

Expand file treeCollapse file tree

6 files changed

+108
-64
lines changed
Filter options
Expand file treeCollapse file tree

6 files changed

+108
-64
lines changed

‎Cargo.toml

Copy file name to clipboardExpand all lines: Cargo.toml
+1Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -192,6 +192,7 @@ unsafe_code = "allow"
192192
unsafe_op_in_unsafe_fn = "deny"
193193
missing_unsafe_on_extern = "deny"
194194
unsafe_attr_outside_unsafe = "deny"
195+
deprecated_safe_2024 = "deny"
195196

196197
[workspace.lints.clippy]
197198
perf = "warn"

‎stdlib/Cargo.toml

Copy file name to clipboardExpand all lines: stdlib/Cargo.toml
+2-2Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,8 +17,8 @@ threading = ["rustpython-common/threading", "rustpython-vm/threading"]
1717
zlib = ["libz-sys", "flate2/zlib"]
1818
bz2 = ["bzip2"]
1919
sqlite = ["dep:libsqlite3-sys"]
20-
ssl = ["openssl", "openssl-sys", "foreign-types-shared"]
21-
ssl-vendor = ["ssl", "openssl/vendored", "openssl-probe"]
20+
ssl = ["openssl", "openssl-sys", "foreign-types-shared", "openssl-probe"]
21+
ssl-vendor = ["ssl", "openssl/vendored"]
2222

2323
[dependencies]
2424
# rustpython crates

‎stdlib/build.rs

Copy file name to clipboardExpand all lines: stdlib/build.rs
+6Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
fn main() {
22
println!(r#"cargo::rustc-check-cfg=cfg(osslconf, values("OPENSSL_NO_COMP"))"#);
3+
println!(r#"cargo::rustc-check-cfg=cfg(openssl_vendored)"#);
34

45
#[allow(clippy::unusual_byte_groupings)]
56
let ossl_vers = [
@@ -36,4 +37,9 @@ fn main() {
3637
println!("cargo:rustc-cfg=osslconf=\"{conf}\"");
3738
}
3839
}
40+
// it's possible for openssl-sys to link against the system openssl under certain conditions,
41+
// so let the ssl module know to only perform a probe if we're actually vendored
42+
if std::env::var("DEP_OPENSSL_VENDORED").is_ok_and(|s| s == "1") {
43+
println!("cargo::rustc-cfg=openssl_vendored")
44+
}
3945
}

‎stdlib/src/ssl.rs

Copy file name to clipboardExpand all lines: stdlib/src/ssl.rs
+83-49Lines changed: 83 additions & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,32 @@
11
use crate::vm::{builtins::PyModule, PyRef, VirtualMachine};
2+
use openssl_probe::ProbeResult;
23

34
pub(crate) fn make_module(vm: &VirtualMachine) -> PyRef<PyModule> {
4-
// if openssl is vendored, it doesn't know the locations of system certificates
5-
#[cfg(feature = "ssl-vendor")]
6-
if let None | Some("0") = option_env!("OPENSSL_NO_VENDOR") {
7-
// TODO: use openssl_probe::probe() instead
8-
unsafe { openssl_probe::init_openssl_env_vars() };
9-
}
10-
openssl::init();
5+
// if openssl is vendored, it doesn't know the locations
6+
// of system certificates - cache the probe result now.
7+
#[cfg(openssl_vendored)]
8+
LazyLock::force(&PROBE);
119
_ssl::make_module(vm)
1210
}
1311

12+
// define our own copy of ProbeResult so we can handle the vendor case
13+
// easily, without having to have a bunch of cfgs
14+
cfg_if::cfg_if! {
15+
if #[cfg(openssl_vendored)] {
16+
use std::sync::LazyLock;
17+
static PROBE: LazyLock<ProbeResult> = LazyLock::new(openssl_probe::probe);
18+
fn probe() -> &'static ProbeResult { &PROBE }
19+
} else {
20+
fn probe() -> &'static ProbeResult {
21+
&ProbeResult { cert_file: None, cert_dir: None }
22+
}
23+
}
24+
}
25+
1426
#[allow(non_upper_case_globals)]
1527
#[pymodule(with(ossl101, windows))]
1628
mod _ssl {
17-
use super::bio;
29+
use super::{bio, probe};
1830
use crate::{
1931
common::{
2032
ascii,
@@ -46,10 +58,12 @@ mod _ssl {
4658
x509::{self, X509Ref, X509},
4759
};
4860
use openssl_sys as sys;
61+
use rustpython_vm::ospath::OsPath;
4962
use std::{
5063
ffi::CStr,
5164
fmt,
5265
io::{Read, Write},
66+
path::Path,
5367
time::Instant,
5468
};
5569

@@ -355,21 +369,43 @@ mod _ssl {
355369
.ok_or_else(|| vm.new_value_error(format!("unknown NID {nid}")))
356370
}
357371

358-
#[pyfunction]
359-
fn get_default_verify_paths() -> (String, String, String, String) {
360-
macro_rules! convert {
361-
($f:ident) => {
362-
CStr::from_ptr(sys::$f()).to_string_lossy().into_owned()
363-
};
364-
}
365-
unsafe {
366-
(
367-
convert!(X509_get_default_cert_file_env),
368-
convert!(X509_get_default_cert_file),
369-
convert!(X509_get_default_cert_dir_env),
370-
convert!(X509_get_default_cert_dir),
371-
)
372+
fn get_cert_file_dir() -> (&'static Path, &'static Path) {
373+
let probe = probe();
374+
// on windows, these should be utf8 strings
375+
fn path_from_bytes(c: &CStr) -> &Path {
376+
#[cfg(unix)]
377+
{
378+
use std::os::unix::ffi::OsStrExt;
379+
std::ffi::OsStr::from_bytes(c.to_bytes()).as_ref()
380+
}
381+
#[cfg(windows)]
382+
{
383+
c.to_str().unwrap().as_ref()
384+
}
372385
}
386+
let cert_file = probe.cert_file.as_deref().unwrap_or_else(|| {
387+
path_from_bytes(unsafe { CStr::from_ptr(sys::X509_get_default_cert_file()) })
388+
});
389+
let cert_dir = probe.cert_dir.as_deref().unwrap_or_else(|| {
390+
path_from_bytes(unsafe { CStr::from_ptr(sys::X509_get_default_cert_dir()) })
391+
});
392+
(cert_file, cert_dir)
393+
}
394+
395+
#[pyfunction]
396+
fn get_default_verify_paths(
397+
vm: &VirtualMachine,
398+
) -> PyResult<(&'static str, PyObjectRef, &'static str, PyObjectRef)> {
399+
let cert_file_env = unsafe { CStr::from_ptr(sys::X509_get_default_cert_file_env()) }
400+
.to_str()
401+
.unwrap();
402+
let cert_dir_env = unsafe { CStr::from_ptr(sys::X509_get_default_cert_dir_env()) }
403+
.to_str()
404+
.unwrap();
405+
let (cert_file, cert_dir) = get_cert_file_dir();
406+
let cert_file = OsPath::new_str(cert_file).filename(vm)?;
407+
let cert_dir = OsPath::new_str(cert_dir).filename(vm)?;
408+
Ok((cert_file_env, cert_file, cert_dir_env, cert_dir))
373409
}
374410

375411
#[pyfunction(name = "RAND_status")]
@@ -591,9 +627,18 @@ mod _ssl {
591627

592628
#[pymethod]
593629
fn set_default_verify_paths(&self, vm: &VirtualMachine) -> PyResult<()> {
594-
self.builder()
595-
.set_default_verify_paths()
596-
.map_err(|e| convert_openssl_error(vm, e))
630+
cfg_if::cfg_if! {
631+
if #[cfg(openssl_vendored)] {
632+
let (cert_file, cert_dir) = get_cert_file_dir();
633+
self.builder()
634+
.load_verify_locations(Some(cert_file), Some(cert_dir))
635+
.map_err(|e| convert_openssl_error(vm, e))
636+
} else {
637+
self.builder()
638+
.set_default_verify_paths()
639+
.map_err(|e| convert_openssl_error(vm, e))
640+
}
641+
}
597642
}
598643

599644
#[pymethod]
@@ -640,6 +685,12 @@ mod _ssl {
640685
vm.new_type_error("cafile, capath and cadata cannot be all omitted".to_owned())
641686
);
642687
}
688+
if let Some(cafile) = &args.cafile {
689+
cafile.ensure_no_nul(vm)?
690+
}
691+
if let Some(capath) = &args.capath {
692+
capath.ensure_no_nul(vm)?
693+
}
643694

644695
#[cold]
645696
fn invalid_cadata(vm: &VirtualMachine) -> PyBaseExceptionRef {
@@ -648,6 +699,8 @@ mod _ssl {
648699
)
649700
}
650701

702+
let mut ctx = self.builder();
703+
651704
// validate cadata type and load cadata
652705
if let Some(cadata) = args.cadata {
653706
let certs = match cadata {
@@ -660,7 +713,6 @@ mod _ssl {
660713
Either::B(b) => b.with_ref(x509_stack_from_der),
661714
};
662715
let certs = certs.map_err(|e| convert_openssl_error(vm, e))?;
663-
let mut ctx = self.builder();
664716
let store = ctx.cert_store_mut();
665717
for cert in certs {
666718
store
@@ -670,29 +722,11 @@ mod _ssl {
670722
}
671723

672724
if args.cafile.is_some() || args.capath.is_some() {
673-
let cafile = args.cafile.map(|s| s.to_cstring(vm)).transpose()?;
674-
let capath = args.capath.map(|s| s.to_cstring(vm)).transpose()?;
675-
let ret = unsafe {
676-
let ctx = self.ctx.write();
677-
sys::SSL_CTX_load_verify_locations(
678-
ctx.as_ptr(),
679-
cafile
680-
.as_ref()
681-
.map_or_else(std::ptr::null, |cs| cs.as_ptr()),
682-
capath
683-
.as_ref()
684-
.map_or_else(std::ptr::null, |cs| cs.as_ptr()),
685-
)
686-
};
687-
if ret != 1 {
688-
let errno = crate::common::os::last_posix_errno();
689-
let err = if errno != 0 {
690-
crate::vm::stdlib::os::errno_err(vm)
691-
} else {
692-
convert_openssl_error(vm, ErrorStack::get())
693-
};
694-
return Err(err);
695-
}
725+
ctx.load_verify_locations(
726+
args.cafile.as_ref().map(|s| s.as_str().as_ref()),
727+
args.capath.as_ref().map(|s| s.as_str().as_ref()),
728+
)
729+
.map_err(|e| convert_openssl_error(vm, e))?;
696730
}
697731

698732
Ok(())

‎vm/src/stdlib/os.rs

Copy file name to clipboardExpand all lines: vm/src/stdlib/os.rs
+4-2Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -401,7 +401,8 @@ pub(super) mod _os {
401401
}
402402
let key = super::bytes_as_osstr(key, vm)?;
403403
let value = super::bytes_as_osstr(value, vm)?;
404-
env::set_var(key, value);
404+
// SAFETY: requirements forwarded from the caller
405+
unsafe { env::set_var(key, value) };
405406
Ok(())
406407
}
407408

@@ -421,7 +422,8 @@ pub(super) mod _os {
421422
));
422423
}
423424
let key = super::bytes_as_osstr(key, vm)?;
424-
env::remove_var(key);
425+
// SAFETY: requirements forwarded from the caller
426+
unsafe { env::remove_var(key) };
425427
Ok(())
426428
}
427429

‎vm/src/utils.rs

Copy file name to clipboardExpand all lines: vm/src/utils.rs
+12-11Lines changed: 12 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
use crate::{
22
builtins::PyStr,
33
convert::{ToPyException, ToPyObject},
4+
exceptions::cstring_error,
45
PyObjectRef, PyResult, VirtualMachine,
56
};
67

@@ -17,22 +18,22 @@ impl ToPyObject for std::convert::Infallible {
1718
}
1819
}
1920

20-
pub trait ToCString {
21-
fn to_cstring(&self, vm: &VirtualMachine) -> PyResult<std::ffi::CString>;
22-
}
23-
24-
impl ToCString for &str {
25-
fn to_cstring(&self, vm: &VirtualMachine) -> PyResult<std::ffi::CString> {
26-
std::ffi::CString::new(*self).map_err(|err| err.to_pyexception(vm))
27-
}
28-
}
29-
30-
impl ToCString for PyStr {
21+
pub trait ToCString: AsRef<str> {
3122
fn to_cstring(&self, vm: &VirtualMachine) -> PyResult<std::ffi::CString> {
3223
std::ffi::CString::new(self.as_ref()).map_err(|err| err.to_pyexception(vm))
3324
}
25+
fn ensure_no_nul(&self, vm: &VirtualMachine) -> PyResult<()> {
26+
if self.as_ref().as_bytes().contains(&b'\0') {
27+
Err(cstring_error(vm))
28+
} else {
29+
Ok(())
30+
}
31+
}
3432
}
3533

34+
impl ToCString for &str {}
35+
impl ToCString for PyStr {}
36+
3637
pub(crate) fn collection_repr<'a, I>(
3738
class_name: Option<&str>,
3839
prefix: &str,

0 commit comments

Comments
0 (0)
Morty Proxy This is a proxified and sanitized view of the page, visit original site.