Skip to content

Commit 2cc9413

Browse files
committed
Conditionally disable file fallback for Android and Linux
1 parent 5f0701f commit 2cc9413

File tree

7 files changed

+103
-41
lines changed

7 files changed

+103
-41
lines changed

.github/workflows/tests.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,7 @@ jobs:
6161
- uses: Swatinem/rust-cache@v2
6262
- run: cargo test
6363
- run: cargo test --features=std
64+
- run: cargo test --features=disable_urandom_fallback
6465
- run: cargo test --features=custom # custom should do nothing here
6566
- if: ${{ matrix.toolchain == 'nightly' }}
6667
run: cargo test --benches

CHANGELOG.md

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,18 @@ All notable changes to this project will be documented in this file.
44
The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/)
55
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
66

7+
## Unreleased
8+
### Added
9+
- `disable_urandom_fallback` crate feature to disable `/dev/urandom`-based fallback on Linux and
10+
Android targets. Enabling this feature bumps minimum supported Linux kernel version to 4.17 and
11+
Android API level to 23 (Marshmallow). [#396]
12+
13+
### Changed
14+
- Disable `/dev/urandom`-based fallback for Linux targets outside of the following
15+
`target_arch`es: `arm`, `powerpc`, `powerpc64`, `s390x`, `x86`, `x86_64`. [#396]
16+
17+
[#396]: https://github.com/rust-random/getrandom/pull/396
18+
719
## [0.2.12] - 2024-01-09
820
### Fixed
921
- Custom backend for targets without atomics [#385]

Cargo.toml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,9 @@ wasm-bindgen-test = "0.3.18"
3232
[features]
3333
# Implement std-only traits for getrandom::Error
3434
std = []
35+
# Disable `/dev/urandom` fallback for Linux and Android targets.
36+
# Bumps minimum supported Linux kernel version to 3.17 and Android API level to 23 (Marshmallow).
37+
disable_urandom_fallback = []
3538
# Feature to enable fallback RDRAND-based implementation on x86/x86_64
3639
rdrand = []
3740
# Feature to enable JavaScript bindings on wasm*-unknown-unknown

src/lib.rs

Lines changed: 33 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -99,11 +99,14 @@
9999
//! This crate will then use the provided `webcrypto` implementation.
100100
//!
101101
//! ### Platform Support
102-
//! This crate generally supports the same operating system and platform versions that the Rust standard library does.
103-
//! Additional targets may be supported using pluggable custom implementations.
102+
//! This crate generally supports the same operating system and platform versions
103+
//! that the Rust standard library does. Additional targets may be supported using
104+
//! pluggable custom implementations.
104105
//!
105-
//! This means that as Rust drops support for old versions of operating systems (such as old Linux kernel versions, Android API levels, etc)
106-
//! in stable releases, `getrandom` may create new patch releases (`0.N.x`) that remove support for outdated platform versions.
106+
//! This means that as Rust drops support for old versions of operating systems
107+
//! (such as old Linux kernel versions, Android API levels, etc) in stable releases,
108+
//! `getrandom` may create new patch releases (`0.N.x`) that remove support for
109+
//! outdated platform versions.
107110
//!
108111
//! ### Custom implementations
109112
//!
@@ -220,10 +223,35 @@ cfg_if! {
220223
if #[cfg(any(target_os = "haiku", target_os = "redox", target_os = "nto", target_os = "aix"))] {
221224
mod util_libc;
222225
#[path = "use_file.rs"] mod imp;
223-
} else if #[cfg(any(target_os = "android", target_os = "linux"))] {
226+
} else if #[cfg(all(
227+
not(feature = "disable_urandom_fallback"),
228+
any(
229+
// Rust supports Android API level 19 (KitKat) [0], while `getrandom(2)`
230+
// was added only in level 23 (Marshmallow).
231+
// [0]: https://blog.rust-lang.org/2023/01/09/android-ndk-update-r25.html
232+
target_os = "android",
233+
all(
234+
target_os = "linux",
235+
// Only on these `target_arch`es Rust supports Linux kernel versions (3.2+)
236+
// that precede the version (3.17) in which `getrandom(2)` was added:
237+
// https://doc.rust-lang.org/stable/rustc/platform-support.html
238+
any(
239+
target_arch = "arm",
240+
target_arch = "powerpc",
241+
target_arch = "powerpc64",
242+
target_arch = "s390x",
243+
target_arch = "x86",
244+
target_arch = "x86_64",
245+
),
246+
)
247+
),
248+
))] {
224249
mod util_libc;
225250
mod use_file;
226251
mod lazy;
252+
#[path = "linux_with_fallback.rs"] mod imp;
253+
} else if #[cfg(any(target_os = "android", target_os = "linux"))] {
254+
mod util_libc;
227255
#[path = "linux_android.rs"] mod imp;
228256
} else if #[cfg(any(target_os = "illumos", target_os = "solaris"))] {
229257
mod util_libc;

src/linux_android.rs

Lines changed: 3 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -1,40 +1,7 @@
1-
//! Implementation for Linux / Android
2-
use crate::{
3-
lazy::LazyBool,
4-
util_libc::{last_os_error, sys_fill_exact},
5-
{use_file, Error},
6-
};
1+
//! Implementation for Linux / Android without `/dev/urandom` fallback
2+
use crate::{util_libc, Error};
73
use core::mem::MaybeUninit;
84

95
pub fn getrandom_inner(dest: &mut [MaybeUninit<u8>]) -> Result<(), Error> {
10-
// getrandom(2) was introduced in Linux 3.17
11-
static HAS_GETRANDOM: LazyBool = LazyBool::new();
12-
if HAS_GETRANDOM.unsync_init(is_getrandom_available) {
13-
sys_fill_exact(dest, |buf| unsafe {
14-
getrandom(buf.as_mut_ptr() as *mut libc::c_void, buf.len(), 0)
15-
})
16-
} else {
17-
use_file::getrandom_inner(dest)
18-
}
19-
}
20-
21-
fn is_getrandom_available() -> bool {
22-
let res = unsafe { getrandom(core::ptr::null_mut(), 0, libc::GRND_NONBLOCK) };
23-
if res < 0 {
24-
match last_os_error().raw_os_error() {
25-
Some(libc::ENOSYS) => false, // No kernel support
26-
Some(libc::EPERM) => false, // Blocked by seccomp
27-
_ => true,
28-
}
29-
} else {
30-
true
31-
}
32-
}
33-
34-
unsafe fn getrandom(
35-
buf: *mut libc::c_void,
36-
buflen: libc::size_t,
37-
flags: libc::c_uint,
38-
) -> libc::ssize_t {
39-
libc::syscall(libc::SYS_getrandom, buf, buflen, flags) as libc::ssize_t
6+
util_libc::sys_fill_exact(dest, util_libc::getrandom_syscall)
407
}

src/linux_with_fallback.rs

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
//! Implementation for Linux / Android with `/dev/urandom` fallback
2+
use crate::{
3+
lazy::LazyBool,
4+
util_libc::{getrandom_syscall, last_os_error, sys_fill_exact},
5+
{use_file, Error},
6+
};
7+
use core::mem::MaybeUninit;
8+
9+
pub fn getrandom_inner(dest: &mut [MaybeUninit<u8>]) -> Result<(), Error> {
10+
// getrandom(2) was introduced in Linux 3.17
11+
static HAS_GETRANDOM: LazyBool = LazyBool::new();
12+
if HAS_GETRANDOM.unsync_init(is_getrandom_available) {
13+
sys_fill_exact(dest, getrandom_syscall)
14+
} else {
15+
use_file::getrandom_inner(dest)
16+
}
17+
}
18+
19+
fn is_getrandom_available() -> bool {
20+
let res = unsafe { getrandom(core::ptr::null_mut(), 0, libc::GRND_NONBLOCK) };
21+
if res < 0 {
22+
match last_os_error().raw_os_error() {
23+
Some(libc::ENOSYS) => false, // No kernel support
24+
Some(libc::EPERM) => false, // Blocked by seccomp
25+
_ => true,
26+
}
27+
} else {
28+
true
29+
}
30+
}
31+
32+
unsafe fn getrandom(
33+
buf: *mut libc::c_void,
34+
buflen: libc::size_t,
35+
flags: libc::c_uint,
36+
) -> libc::ssize_t {
37+
libc::syscall(libc::SYS_getrandom, buf, buflen, flags) as libc::ssize_t
38+
}

src/util_libc.rs

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -151,3 +151,16 @@ pub unsafe fn open_readonly(path: &str) -> Result<libc::c_int, Error> {
151151
}
152152
}
153153
}
154+
155+
/// Thin wrapper around the `getrandom()` Linux system call
156+
#[cfg(any(target_os = "android", target_os = "linux"))]
157+
pub fn getrandom_syscall(buf: &mut [MaybeUninit<u8>]) -> libc::ssize_t {
158+
unsafe {
159+
libc::syscall(
160+
libc::SYS_getrandom,
161+
buf.as_mut_ptr() as *mut libc::c_void,
162+
buf.len(),
163+
0,
164+
) as libc::ssize_t
165+
}
166+
}

0 commit comments

Comments
 (0)