Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add more Rustified version of kernel_check #862

Open
wants to merge 1 commit into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion src/common/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@ impl fmt::Display for Error {
Error::SelfCheck => {
f.write_str("sudo must be owned by uid 0 and have the setuid bit set")
}
Error::KernelCheck => f.write_str("sudo needs a Kernel >= 5.9"),
Error::KernelCheck => f.write_str("sudo-rs needs a Linux kernel newer than v5.9"),
Error::CommandNotFound(p) => write!(f, "'{}': command not found", p.display()),
Error::InvalidCommand(p) => write!(f, "'{}': invalid command", p.display()),
Error::UserNotFound(u) => write!(f, "user '{u}' not found"),
Expand Down
49 changes: 26 additions & 23 deletions src/system/kernel.rs
Original file line number Diff line number Diff line change
@@ -1,37 +1,40 @@
use std::ffi::CStr;

use std::mem::zeroed;
use std::mem::MaybeUninit;

use crate::common::Error;
use crate::{common::Error, cutils::cerr};

pub fn kernel_check(major: u32, minor: u32) -> Result<(), Error> {
let mut utsname: libc::utsname = unsafe { zeroed() };
#[cfg(target_os = "linux")]
pub fn kernel_check(target_major: u32, target_minor: u32) -> Result<(), Error> {
let mut utsname = MaybeUninit::uninit();

if unsafe { libc::uname(&mut utsname) } != 0 {
// Could not get the kernel version. Try to run anyway
return Ok(());
}

let release = unsafe { CStr::from_ptr(utsname.release.as_ptr()) }
.to_string_lossy()
.into_owned();
// SAFETY: uname is passed a correct pointer
cerr(unsafe { libc::uname(utsname.as_mut_ptr()) })?;

let version_parts: Vec<&str> = release.split('.').collect();
// SAFETY: since uname exited normally, the struct is now initialized
let utsname = unsafe { utsname.assume_init() };

if version_parts.len() < 2 {
// Could not get the kernel version. Try to run anyway
return Ok(());
}
// SAFETY: utsname.release will hold a null-terminated C string
let release = unsafe { CStr::from_ptr(utsname.release.as_ptr()) }.to_string_lossy();

// Parse the major and minor version numbers
if let (Ok(major_version), Ok(minor_version)) = (
version_parts[0].parse::<u32>(),
version_parts[1].parse::<u32>(),
) {
if major_version > major || (major_version == major && minor_version >= minor) {
return Ok(());
let mut version_parts = release.split('.').map_while(|x| x.parse::<u32>().ok());

match (version_parts.next(), version_parts.next()) {
(Some(major), Some(minor)) if (major, minor) < (target_major, target_minor) => {
// We have determined that this Linux kernel is too old.
Err(Error::KernelCheck)
}
_ => {
// We have not been able to prove that sudo-rs is incompatible with this kernel
// and are giving the benefit of the doubt.
Ok(())
}
}
}

#[cfg(not(target_os = "linux"))]
pub fn kernel_check(target_major: u32, target_minor: u32) -> Result<(), Error> {
// if someone managed to compile this on anything else than Linux: your luck runs out here
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe have a compile_error!() inside the non-linux version of kernel_check?

Err(Error::KernelCheck)
}
Loading