Hide details of VerifierLog

This type is really only used by one function.
pull/641/head
Tamir Duberstein 1 year ago
parent b0a4ab5f20
commit 6b94b2080d
No known key found for this signature in database

@ -135,7 +135,7 @@ pub enum BtfError {
#[source] #[source]
io_error: std::io::Error, io_error: std::io::Error,
/// The error log produced by the kernel verifier. /// The error log produced by the kernel verifier.
verifier_log: String, verifier_log: Cow<'static, str>,
}, },
/// offset not found for symbol /// offset not found for symbol

@ -39,7 +39,7 @@ use crate::{
is_btf_supported, is_btf_type_tag_supported, is_perf_link_supported, is_btf_supported, is_btf_type_tag_supported, is_perf_link_supported,
is_probe_read_kernel_supported, is_prog_name_supported, retry_with_verifier_logs, is_probe_read_kernel_supported, is_prog_name_supported, retry_with_verifier_logs,
}, },
util::{bytes_of, bytes_of_slice, possible_cpus, VerifierLog, POSSIBLE_CPUS}, util::{bytes_of, bytes_of_slice, possible_cpus, POSSIBLE_CPUS},
}; };
pub(crate) const BPF_OBJ_NAME_LEN: usize = 16; pub(crate) const BPF_OBJ_NAME_LEN: usize = 16;
@ -907,22 +907,14 @@ pub enum BpfError {
} }
fn load_btf(raw_btf: Vec<u8>) -> Result<RawFd, BtfError> { fn load_btf(raw_btf: Vec<u8>) -> Result<RawFd, BtfError> {
let mut logger = VerifierLog::new(); let (ret, verifier_log) =
let ret = retry_with_verifier_logs(10, &mut logger, |logger| { retry_with_verifier_logs(10, |logger| bpf_load_btf(raw_btf.as_slice(), logger));
bpf_load_btf(raw_btf.as_slice(), logger)
});
match ret { match ret {
Ok(fd) => Ok(fd as RawFd), Ok(fd) => Ok(fd as RawFd),
Err((_, io_error)) => { Err((_, io_error)) => Err(BtfError::LoadError {
logger.truncate(); io_error,
Err(BtfError::LoadError { verifier_log,
io_error, }),
verifier_log: logger
.as_c_str()
.map(|s| s.to_string_lossy().to_string())
.unwrap_or_else(|| "[none]".to_owned()),
})
}
} }
} }

@ -67,6 +67,7 @@ pub mod xdp;
use libc::ENOSPC; use libc::ENOSPC;
use procfs::KernelVersion; use procfs::KernelVersion;
use std::{ use std::{
borrow::Cow,
ffi::CString, ffi::CString,
io, io,
os::unix::io::{AsRawFd, RawFd}, os::unix::io::{AsRawFd, RawFd},
@ -113,7 +114,6 @@ use crate::{
bpf_prog_get_fd_by_id, bpf_prog_get_info_by_fd, bpf_prog_get_next_id, bpf_prog_query, bpf_prog_get_fd_by_id, bpf_prog_get_info_by_fd, bpf_prog_get_next_id, bpf_prog_query,
retry_with_verifier_logs, BpfLoadProgramAttrs, retry_with_verifier_logs, BpfLoadProgramAttrs,
}, },
util::VerifierLog,
}; };
/// Error type returned when working with programs. /// Error type returned when working with programs.
@ -142,7 +142,7 @@ pub enum ProgramError {
#[source] #[source]
io_error: io::Error, io_error: io::Error,
/// The error log produced by the kernel verifier. /// The error log produced by the kernel verifier.
verifier_log: String, verifier_log: Cow<'static, str>,
}, },
/// A syscall failed. /// A syscall failed.
@ -583,8 +583,6 @@ fn load_program<T: Link>(
(u32::from(major) << 16) + (u32::from(minor) << 8) + u32::from(patch) (u32::from(major) << 16) + (u32::from(minor) << 8) + u32::from(patch)
}); });
let mut logger = VerifierLog::new();
let prog_name = if let Some(name) = &data.name { let prog_name = if let Some(name) = &data.name {
let mut name = name.clone(); let mut name = name.clone();
if name.len() > 15 { if name.len() > 15 {
@ -616,7 +614,7 @@ fn load_program<T: Link>(
}; };
let verifier_log_level = data.verifier_log_level; let verifier_log_level = data.verifier_log_level;
let ret = retry_with_verifier_logs(10, &mut logger, |logger| { let (ret, verifier_log) = retry_with_verifier_logs(10, |logger| {
bpf_load_program(&attr, logger, verifier_log_level) bpf_load_program(&attr, logger, verifier_log_level)
}); });
@ -625,16 +623,10 @@ fn load_program<T: Link>(
*fd = Some(prog_fd as RawFd); *fd = Some(prog_fd as RawFd);
Ok(()) Ok(())
} }
Err((_, io_error)) => { Err((_, io_error)) => Err(ProgramError::LoadError {
logger.truncate(); io_error,
return Err(ProgramError::LoadError { verifier_log,
io_error, }),
verifier_log: logger
.as_c_str()
.map(|s| s.to_string_lossy().to_string())
.unwrap_or_else(|| "[none]".to_owned()),
});
}
} }
} }

@ -1,4 +1,5 @@
use std::{ use std::{
borrow::Cow,
cmp::{self, min}, cmp::{self, min},
ffi::{CStr, CString}, ffi::{CStr, CString},
io, io,
@ -29,7 +30,6 @@ use crate::{
copy_instructions, copy_instructions,
}, },
sys::{syscall, SysResult, Syscall}, sys::{syscall, SysResult, Syscall},
util::VerifierLog,
Btf, Pod, BPF_OBJ_NAME_LEN, Btf, Pod, BPF_OBJ_NAME_LEN,
}; };
@ -129,7 +129,7 @@ pub(crate) struct BpfLoadProgramAttrs<'a> {
pub(crate) fn bpf_load_program( pub(crate) fn bpf_load_program(
aya_attr: &BpfLoadProgramAttrs, aya_attr: &BpfLoadProgramAttrs,
logger: &mut VerifierLog, log_buf: &mut [u8],
verifier_log_level: u32, verifier_log_level: u32,
) -> SysResult { ) -> SysResult {
let mut attr = unsafe { mem::zeroed::<bpf_attr>() }; let mut attr = unsafe { mem::zeroed::<bpf_attr>() };
@ -174,11 +174,10 @@ pub(crate) fn bpf_load_program(
u.func_info_rec_size = aya_attr.func_info_rec_size as u32; u.func_info_rec_size = aya_attr.func_info_rec_size as u32;
} }
} }
let log_buf = logger.buf(); if !log_buf.is_empty() {
if log_buf.capacity() > 0 {
u.log_level = verifier_log_level; u.log_level = verifier_log_level;
u.log_buf = log_buf.as_mut_ptr() as u64; u.log_buf = log_buf.as_mut_ptr() as u64;
u.log_size = log_buf.capacity() as u32; u.log_size = log_buf.len() as u32;
} }
if let Some(v) = aya_attr.attach_btf_obj_fd { if let Some(v) = aya_attr.attach_btf_obj_fd {
u.__bindgen_anon_1.attach_btf_obj_fd = v; u.__bindgen_anon_1.attach_btf_obj_fd = v;
@ -549,16 +548,15 @@ pub(crate) fn bpf_raw_tracepoint_open(name: Option<&CStr>, prog_fd: RawFd) -> Sy
sys_bpf(bpf_cmd::BPF_RAW_TRACEPOINT_OPEN, &attr) sys_bpf(bpf_cmd::BPF_RAW_TRACEPOINT_OPEN, &attr)
} }
pub(crate) fn bpf_load_btf(raw_btf: &[u8], log: &mut VerifierLog) -> SysResult { pub(crate) fn bpf_load_btf(raw_btf: &[u8], log_buf: &mut [u8]) -> SysResult {
let mut attr = unsafe { mem::zeroed::<bpf_attr>() }; let mut attr = unsafe { mem::zeroed::<bpf_attr>() };
let u = unsafe { &mut attr.__bindgen_anon_7 }; let u = unsafe { &mut attr.__bindgen_anon_7 };
u.btf = raw_btf.as_ptr() as *const _ as u64; u.btf = raw_btf.as_ptr() as *const _ as u64;
u.btf_size = mem::size_of_val(raw_btf) as u32; u.btf_size = mem::size_of_val(raw_btf) as u32;
let log_buf = log.buf(); if !log_buf.is_empty() {
if log_buf.capacity() > 0 {
u.btf_log_level = 1; u.btf_log_level = 1;
u.btf_log_buf = log_buf.as_mut_ptr() as u64; u.btf_log_buf = log_buf.as_mut_ptr() as u64;
u.btf_log_size = log_buf.capacity() as u32; u.btf_log_size = log_buf.len() as u32;
} }
sys_bpf(bpf_cmd::BPF_BTF_LOAD, &attr) sys_bpf(bpf_cmd::BPF_BTF_LOAD, &attr)
} }
@ -993,35 +991,41 @@ pub(crate) fn bpf_prog_get_next_id(id: u32) -> Result<Option<u32>, (c_long, io::
pub(crate) fn retry_with_verifier_logs<F>( pub(crate) fn retry_with_verifier_logs<F>(
max_retries: usize, max_retries: usize,
log: &mut VerifierLog,
f: F, f: F,
) -> SysResult ) -> (SysResult, Cow<'static, str>)
where where
F: Fn(&mut VerifierLog) -> SysResult, F: Fn(&mut [u8]) -> SysResult,
{ {
// 1. Try the syscall const MIN_LOG_BUF_SIZE: usize = 1024 * 10;
let ret = f(log); const MAX_LOG_BUF_SIZE: usize = (std::u32::MAX >> 8) as usize;
if ret.is_ok() {
return ret;
}
// 2. Grow the log buffer so we can capture verifier output let mut log_buf = Vec::new();
// Retry this up to max_retries times
log.grow();
let mut retries = 0; let mut retries = 0;
loop { loop {
let ret = f(log); let ret = f(log_buf.as_mut_slice());
match ret { if retries != max_retries {
Err((v, io_error)) if retries == 0 || io_error.raw_os_error() == Some(ENOSPC) => { if let Err((_, io_error)) = &ret {
if retries == max_retries { if retries == 0 || io_error.raw_os_error() == Some(ENOSPC) {
return Err((v, io_error)); let len = (log_buf.capacity() * 10).clamp(MIN_LOG_BUF_SIZE, MAX_LOG_BUF_SIZE);
log_buf.resize(len, 0);
if let Some(first) = log_buf.first_mut() {
*first = 0;
}
retries += 1;
continue;
} }
retries += 1;
log.grow();
} }
r => return r,
} }
if let Some(pos) = log_buf.iter().position(|b| *b == 0) {
log_buf.truncate(pos);
}
let log_buf = if log_buf.is_empty() {
"none".into()
} else {
String::from_utf8(log_buf).unwrap().into()
};
break (ret, log_buf);
} }
} }

@ -1,7 +1,7 @@
//! Utility functions. //! Utility functions.
use std::{ use std::{
collections::BTreeMap, collections::BTreeMap,
ffi::{CStr, CString}, ffi::CString,
fs::{self, File}, fs::{self, File},
io::{self, BufReader}, io::{self, BufReader},
mem, slice, mem, slice,
@ -200,57 +200,6 @@ pub(crate) fn bytes_of_slice<T: Pod>(val: &[T]) -> &[u8] {
unsafe { slice::from_raw_parts(val.as_ptr().cast(), size) } unsafe { slice::from_raw_parts(val.as_ptr().cast(), size) }
} }
const MIN_LOG_BUF_SIZE: usize = 1024 * 10;
const MAX_LOG_BUF_SIZE: usize = (std::u32::MAX >> 8) as usize;
pub(crate) struct VerifierLog {
buf: Vec<u8>,
}
impl VerifierLog {
pub(crate) fn new() -> VerifierLog {
VerifierLog { buf: Vec::new() }
}
pub(crate) fn buf(&mut self) -> &mut Vec<u8> {
&mut self.buf
}
pub(crate) fn grow(&mut self) {
let len = (self.buf.capacity() * 10).clamp(MIN_LOG_BUF_SIZE, MAX_LOG_BUF_SIZE);
self.buf.resize(len, 0);
self.reset();
}
pub(crate) fn reset(&mut self) {
if !self.buf.is_empty() {
self.buf[0] = 0;
}
}
pub(crate) fn truncate(&mut self) {
if self.buf.is_empty() {
return;
}
let pos = self
.buf
.iter()
.position(|b| *b == 0)
.unwrap_or(self.buf.len() - 1);
self.buf[pos] = 0;
self.buf.truncate(pos + 1);
}
pub(crate) fn as_c_str(&self) -> Option<&CStr> {
if self.buf.is_empty() {
None
} else {
Some(CStr::from_bytes_with_nul(&self.buf).unwrap())
}
}
}
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use super::*; use super::*;

Loading…
Cancel
Save