pull/1017/merge
Davide Bertola 7 months ago committed by GitHub
commit 32b5d631bc
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194

@ -299,7 +299,7 @@ jobs:
run: |
set -euxo pipefail
find test/.tmp -name '*.deb' -print0 | xargs -t -0 -I {} \
sh -c "dpkg --fsys-tarfile {} | tar -C test/.tmp --wildcards --extract '*vmlinuz*' --file -"
sh -c "dpkg --fsys-tarfile {} | tar -C test/.tmp --wildcards --extract '*vmlinuz*' --wildcards --extract '*config*' --file -"
- name: Run local integration tests
if: runner.os == 'Linux'

@ -18,11 +18,12 @@ use crate::{
info::{FuncSecInfo, LineSecInfo},
relocation::Relocation,
Array, BtfEnum, BtfKind, BtfMember, BtfType, Const, Enum, FuncInfo, FuncLinkage, Int,
IntEncoding, LineInfo, Struct, Typedef, Union, VarLinkage,
IntEncoding, LineInfo, Struct, Typedef, Union, Var, VarLinkage,
},
generated::{btf_ext_header, btf_header},
generated::{bpf_map_type, btf_ext_header, btf_header, BPF_F_RDONLY_PROG},
maps::{bpf_map_def, LegacyMap},
util::{bytes_of, HashMap},
Object,
EbpfSectionKind, Map, Object,
};
pub(crate) const MAX_RESOLVE_DEPTH: u8 = 32;
@ -157,6 +158,20 @@ pub enum BtfError {
/// unable to get symbol name
#[error("Unable to get symbol name")]
InvalidSymbolName,
/// external symbol is invalid
#[error("Invalid extern symbol `{symbol_name}`")]
InvalidExternalSymbol {
/// name of the symbol
symbol_name: String,
},
/// external symbol not found
#[error("Extern symbol not found `{symbol_name}`")]
ExternalSymbolNotFound {
/// name of the symbol
symbol_name: String,
},
}
/// Available BTF features
@ -463,6 +478,57 @@ impl Btf {
})
}
pub(crate) fn type_align(&self, root_type_id: u32) -> Result<usize, BtfError> {
let mut type_id = root_type_id;
for _ in 0..MAX_RESOLVE_DEPTH {
let ty = self.types.type_by_id(type_id)?;
let size = match ty {
BtfType::Array(Array { array, .. }) => {
type_id = array.element_type;
continue;
}
BtfType::Struct(Struct { size, members, .. })
| BtfType::Union(Union { size, members, .. }) => {
let mut max_align = 1;
for m in members {
let align = self.type_align(m.btf_type)?;
max_align = usize::max(align, max_align);
if ty.member_bit_field_size(m).unwrap() == 0
|| m.offset % (8 * align as u32) != 0
{
return Ok(1);
}
}
if size % max_align as u32 != 0 {
return Ok(1);
}
return Ok(max_align);
}
other => {
if let Some(size) = other.size() {
u32::min(BtfType::ptr_size(), size)
} else if let Some(next) = other.btf_type() {
type_id = next;
continue;
} else {
return Err(BtfError::UnexpectedBtfType { type_id });
}
}
};
return Ok(size as usize);
}
Err(BtfError::MaximumTypeDepthReached {
type_id: root_type_id,
})
}
/// Encodes the metadata as BTF format
pub fn to_bytes(&self) -> Vec<u8> {
// Safety: btf_header is POD
@ -473,6 +539,38 @@ impl Btf {
buf
}
pub(crate) fn get_extern_data_sec_entry_info(
&self,
target_var_name: &str,
) -> Result<(String, Var), BtfError> {
for t in &self.types.types {
let BtfType::DataSec(d) = t else {
continue;
};
let sec_name = self.string_at(d.name_offset)?;
for d in &d.entries {
let BtfType::Var(var) = self.types.type_by_id(d.btf_type)? else {
continue;
};
if target_var_name == self.string_at(var.name_offset)? {
if var.linkage == VarLinkage::Extern {
return Ok((sec_name.into(), var.clone()));
} else {
return Err(BtfError::InvalidExternalSymbol {
symbol_name: target_var_name.into(),
});
}
}
}
}
Err(BtfError::ExternalSymbolNotFound {
symbol_name: target_var_name.into(),
})
}
// This follows the same logic as libbpf's bpf_object__sanitize_btf() function.
// https://github.com/libbpf/libbpf/blob/05f94ddbb837f5f4b3161e341eed21be307eaa04/src/libbpf.c#L2701
//
@ -610,6 +708,14 @@ impl Btf {
}
};
e.offset = *offset as u32;
if var.linkage == VarLinkage::Extern {
let mut var = var.clone();
var.linkage = VarLinkage::Global;
types.types[e.btf_type as usize] = BtfType::Var(var);
}
debug!(
"{} {}: VAR {}: fixup offset {}",
kind, name, var_name, offset
@ -730,6 +836,107 @@ impl Default for Btf {
}
impl Object {
fn patch_extern_data_internal(
&mut self,
externs: &HashMap<String, Vec<u8>>,
) -> Result<Option<(SectionIndex, Vec<u8>)>, BtfError> {
if let Some(ref mut obj_btf) = &mut self.btf {
if obj_btf.is_empty() {
return Ok(None);
}
let mut kconfig_map_index = 0;
for map in self.maps.values() {
if map.section_index() >= kconfig_map_index {
kconfig_map_index = map.section_index() + 1;
}
}
let kconfig_map_index = self.maps.len();
let symbols = self
.symbol_table
.iter_mut()
.filter(|(_, s)| s.name.is_some() && s.section_index.is_none() && s.is_external)
.map(|(_, s)| (s.name.as_ref().unwrap().clone(), s));
let mut section_data = Vec::<u8>::new();
let mut offset = 0u64;
let mut has_extern_data = false;
for (name, symbol) in symbols {
let (datasec_name, var) = obj_btf.get_extern_data_sec_entry_info(&name)?;
if datasec_name == ".kconfig" {
has_extern_data = true;
let type_size = obj_btf.type_size(var.btf_type)?;
let type_align = obj_btf.type_align(var.btf_type)? as u64;
let mut external_value_opt = externs.get(&name);
let empty_data = vec![0; type_size];
if external_value_opt.is_none() && symbol.is_weak {
external_value_opt = Some(&empty_data);
}
if let Some(data) = external_value_opt {
symbol.address = (offset + (type_align - 1)) & !(type_align - 1);
symbol.size = type_size as u64;
symbol.section_index = Some(kconfig_map_index);
section_data.resize((symbol.address - offset) as usize, 0);
self.symbol_offset_by_name.insert(name, symbol.address);
offset = symbol.address + section_data.len() as u64;
section_data.extend(data);
} else {
return Err(BtfError::ExternalSymbolNotFound { symbol_name: name });
}
}
}
if has_extern_data {
self.section_infos.insert(
".kconfig".into(),
(SectionIndex(kconfig_map_index), section_data.len() as u64),
);
return Ok(Some((SectionIndex(kconfig_map_index), section_data)));
}
}
Ok(None)
}
/// Patches extern data
pub fn patch_extern_data(
&mut self,
externs: &HashMap<String, Vec<u8>>,
) -> Result<(), BtfError> {
if let Some((section_index, data)) = self.patch_extern_data_internal(externs)? {
self.maps.insert(
".kconfig".into(),
Map::Legacy(LegacyMap {
def: bpf_map_def {
map_type: bpf_map_type::BPF_MAP_TYPE_ARRAY as u32,
key_size: mem::size_of::<u32>() as u32,
value_size: data.len() as u32,
max_entries: 1,
map_flags: BPF_F_RDONLY_PROG,
..Default::default()
},
section_index: section_index.0,
section_kind: EbpfSectionKind::Rodata,
symbol_index: None,
data,
}),
);
}
Ok(())
}
/// Fixes up and sanitizes BTF data.
///
/// Mostly, it removes unsupported types and works around LLVM behaviours.

@ -1292,11 +1292,15 @@ impl BtfType {
BtfType::Struct(t) => Some(t.size),
BtfType::Union(t) => Some(t.size),
BtfType::DataSec(t) => Some(t.size),
BtfType::Ptr(_) => Some(mem::size_of::<&()>() as u32),
BtfType::Ptr(_) => Some(Self::ptr_size()),
_ => None,
}
}
pub(crate) fn ptr_size() -> u32 {
mem::size_of::<&()>() as u32
}
pub(crate) fn btf_type(&self) -> Option<u32> {
match self {
BtfType::Const(t) => Some(t.btf_type),

@ -49,6 +49,7 @@ pub struct Features {
devmap_prog_id: bool,
prog_info_map_ids: bool,
prog_info_gpl_compatible: bool,
bpf_syscall_wrapper: bool,
btf: Option<BtfFeatures>,
}
@ -65,6 +66,7 @@ impl Features {
devmap_prog_id: bool,
prog_info_map_ids: bool,
prog_info_gpl_compatible: bool,
bpf_syscall_wrapper: bool,
btf: Option<BtfFeatures>,
) -> Self {
Self {
@ -77,6 +79,7 @@ impl Features {
devmap_prog_id,
prog_info_map_ids,
prog_info_gpl_compatible,
bpf_syscall_wrapper,
btf,
}
}
@ -118,6 +121,10 @@ impl Features {
pub fn devmap_prog_id(&self) -> bool {
self.devmap_prog_id
}
/// Returns whether BPF syscall wrapper hooking is supported.
pub fn bpf_syscall_wrapper(&self) -> bool {
self.bpf_syscall_wrapper
}
/// Returns whether `bpf_prog_info` supports `nr_map_ids` & `map_ids` fields.
pub fn prog_info_map_ids(&self) -> bool {
@ -483,6 +490,8 @@ impl Object {
address: symbol.address(),
size: symbol.size(),
is_definition: symbol.is_definition(),
is_external: symbol.is_undefined() && (symbol.is_global() || symbol.is_weak()),
is_weak: symbol.is_weak(),
kind: symbol.kind(),
};
bpf_obj.symbol_table.insert(symbol.index().0, sym);
@ -1465,6 +1474,8 @@ mod tests {
size,
is_definition: false,
kind: SymbolKind::Text,
is_external: false,
is_weak: false,
},
);
obj.symbols_by_section
@ -2601,6 +2612,8 @@ mod tests {
address: 0,
size: 3,
is_definition: true,
is_external: false,
is_weak: false,
kind: SymbolKind::Data,
},
);

@ -99,6 +99,8 @@ pub(crate) struct Symbol {
pub(crate) address: u64,
pub(crate) size: u64,
pub(crate) is_definition: bool,
pub(crate) is_external: bool,
pub(crate) is_weak: bool,
pub(crate) kind: SymbolKind,
}
@ -218,7 +220,9 @@ fn relocate_maps<'a, I: Iterator<Item = &'a Relocation>>(
};
// calls and relocation to .text symbols are handled in a separate step
if insn_is_call(&instructions[ins_index]) || text_sections.contains(&section_index) {
if insn_is_call(&instructions[ins_index])
|| (text_sections.contains(&section_index) && !sym.is_external)
{
continue;
}
@ -367,10 +371,11 @@ impl<'a> FunctionLinker<'a> {
// only consider text relocations, data relocations are
// relocated in relocate_maps()
sym.kind == SymbolKind::Text
|| sym
|| (!sym.is_external
&& sym
.section_index
.map(|section_index| self.text_sections.contains(&section_index))
.unwrap_or(false)
.unwrap_or(false))
});
// not a call and not a text relocation, we don't need to do anything
@ -510,6 +515,8 @@ mod test {
address,
size,
is_definition: false,
is_external: false,
is_weak: false,
kind: SymbolKind::Data,
}
}

@ -23,7 +23,13 @@ libc = { workspace = true }
log = { workspace = true }
object = { workspace = true, features = ["elf", "read_core", "std", "write"] }
thiserror = { workspace = true }
tokio = { workspace = true, features = ["rt"], optional = true }
tokio = { workspace = true, features = [
"rt",
"macros",
"rt-multi-thread",
"net",
], optional = true }
flate2 = "1.0"
[dev-dependencies]
tempfile = { workspace = true }

@ -1,7 +1,8 @@
use std::{
borrow::Cow,
collections::{HashMap, HashSet},
fs, io,
fs::{self, File},
io::{self, Read},
os::{
fd::{AsFd as _, AsRawFd as _},
raw::c_int,
@ -16,6 +17,8 @@ use aya_obj::{
relocation::EbpfRelocationError,
EbpfSectionKind, Features,
};
use flate2::read::GzDecoder;
use lazy_static::lazy_static;
use log::{debug, warn};
use thiserror::Error;
@ -36,14 +39,15 @@ use crate::{
SkMsg, SkSkb, SkSkbKind, SockOps, SocketFilter, TracePoint, UProbe, Xdp,
},
sys::{
bpf_load_btf, is_bpf_cookie_supported, is_bpf_global_data_supported,
is_btf_datasec_supported, is_btf_decl_tag_supported, is_btf_enum64_supported,
is_btf_float_supported, is_btf_func_global_supported, is_btf_func_supported,
is_btf_supported, is_btf_type_tag_supported, is_info_gpl_compatible_supported,
is_info_map_ids_supported, is_perf_link_supported, is_probe_read_kernel_supported,
is_prog_id_supported, is_prog_name_supported, retry_with_verifier_logs,
self, bpf_load_btf, is_bpf_cookie_supported, is_bpf_global_data_supported,
is_bpf_syscall_wrapper_supported, is_btf_datasec_supported, is_btf_decl_tag_supported,
is_btf_enum64_supported, is_btf_float_supported, is_btf_func_global_supported,
is_btf_func_supported, is_btf_supported, is_btf_type_tag_supported,
is_info_gpl_compatible_supported, is_info_map_ids_supported, is_perf_link_supported,
is_probe_read_kernel_supported, is_prog_id_supported, is_prog_name_supported,
retry_with_verifier_logs,
},
util::{bytes_of, bytes_of_slice, page_size, possible_cpus, POSSIBLE_CPUS},
util::{bytes_of, bytes_of_slice, page_size, possible_cpus, KernelVersion, POSSIBLE_CPUS},
};
pub(crate) const BPF_OBJ_NAME_LEN: usize = 16;
@ -98,6 +102,7 @@ fn detect_features() -> Features {
is_prog_id_supported(BPF_MAP_TYPE_DEVMAP),
is_info_map_ids_supported(),
is_info_gpl_compatible_supported(),
is_bpf_syscall_wrapper_supported(),
btf,
);
debug!("BPF Feature Detection: {:#?}", f);
@ -109,6 +114,133 @@ pub fn features() -> &'static Features {
&FEATURES
}
lazy_static! {
static ref KCONFIG_DEFINITION: HashMap<String, Vec<u8>> = compute_kconfig_definition(&FEATURES);
}
fn to_bytes(value: u64) -> [u8; 8] {
if cfg!(target_endian = "big") {
value.to_be_bytes()
} else {
value.to_le_bytes()
}
}
fn compute_kconfig_definition(features: &Features) -> HashMap<String, Vec<u8>> {
let mut result = HashMap::new();
if let Ok(KernelVersion {
major,
minor,
patch,
}) = KernelVersion::current()
{
result.insert(
"LINUX_KERNEL_VERSION".to_string(),
to_bytes((u64::from(major) << 16) + (u64::from(minor) << 8) + u64::from(patch))
.to_vec(),
);
}
let bpf_cookie = if features.bpf_cookie() { 1u64 } else { 0u64 };
let bpf_syscall_wrapper = if features.bpf_syscall_wrapper() {
1u64
} else {
0u64
};
result.insert(
"LINUX_HAS_BPF_COOKIE".to_string(),
to_bytes(bpf_cookie).to_vec(),
);
result.insert(
"LINUX_HAS_SYSCALL_WRAPPER".to_string(),
to_bytes(bpf_syscall_wrapper).to_vec(),
);
if let Some(raw_config) = read_kconfig() {
for line in raw_config.lines() {
if !line.starts_with("CONFIG_") {
continue;
}
let mut parts = line.split('=');
let (key, raw_value) = match (parts.next(), parts.next(), parts.count()) {
(Some(key), Some(value), 0) => (key, value),
_ => continue,
};
let value = match raw_value.chars().next() {
Some('n') => to_bytes(0).to_vec(),
Some('y') => to_bytes(1).to_vec(),
Some('m') => to_bytes(2).to_vec(),
Some('"') => {
let raw_value = &raw_value[1..raw_value.len() - 1];
raw_value.as_bytes().to_vec()
}
Some(_) => {
if let Ok(value) = raw_value.parse::<u64>() {
to_bytes(value).to_vec()
} else {
continue;
}
}
None => continue,
};
result.insert(key.to_string(), value);
}
}
result
}
fn read_kconfig() -> Option<String> {
let config_path = PathBuf::from("/proc/config.gz");
if config_path.exists() {
debug!("Found kernel config at {}", config_path.to_string_lossy());
return read_kconfig_file(&config_path, true);
}
let Ok(release) = sys::kernel_release() else {
return None;
};
let config_path = PathBuf::from("/boot").join(format!("config-{}", release));
if config_path.exists() {
debug!("Found kernel config at {}", config_path.to_string_lossy());
return read_kconfig_file(&config_path, false);
}
None
}
fn read_kconfig_file(path: &PathBuf, gzip: bool) -> Option<String> {
let mut output = String::new();
let res = if gzip {
File::open(path)
.map(GzDecoder::new)
.and_then(|mut file| file.read_to_string(&mut output))
} else {
File::open(path).and_then(|mut file| file.read_to_string(&mut output))
};
match res {
Ok(_) => Some(output),
Err(e) => {
warn!(
"Unable to read kernel config {}: {:?}",
path.to_string_lossy(),
e
);
None
}
}
}
/// Builder style API for advanced loading of eBPF programs.
///
/// Loading eBPF code involves a few steps, including loading maps and applying
@ -399,6 +531,7 @@ impl<'a> EbpfLoader<'a> {
} = self;
let mut obj = Object::parse(data)?;
obj.patch_map_data(globals.clone())?;
obj.patch_extern_data(&KCONFIG_DEFINITION)?;
let btf_fd = if let Some(features) = &FEATURES.btf() {
if let Some(btf) = obj.fixup_and_sanitize_btf(features)? {

@ -38,7 +38,7 @@
// modules we don't export
mod info;
mod probe;
pub(crate) mod probe;
mod utils;
// modules we explicitly export so their pub items (Links etc) get exported too

@ -145,7 +145,7 @@ pub(crate) fn detach_debug_fs(event: ProbeEvent) -> Result<(), ProgramError> {
})
}
fn create_as_probe(
pub(crate) fn create_as_probe(
kind: ProbeKind,
fn_name: &OsStr,
offset: u64,

@ -1,6 +1,6 @@
use std::{
cmp,
ffi::{c_char, CStr, CString},
ffi::{c_char, CStr, CString, OsStr},
io, iter,
mem::{self, MaybeUninit},
os::fd::{AsFd as _, AsRawFd as _, BorrowedFd, FromRawFd as _, RawFd},
@ -30,6 +30,7 @@ use crate::{
},
copy_instructions,
},
programs::probe::create_as_probe,
sys::{syscall, SysResult, Syscall, SyscallError},
util::KernelVersion,
Btf, Pod, VerifierLogLevel, BPF_OBJ_NAME_LEN, FEATURES,
@ -950,6 +951,43 @@ pub(crate) fn is_prog_id_supported(map_type: bpf_map_type) -> bool {
fd.is_ok()
}
fn arch_specific_syscall_prefix() -> Option<&'static str> {
if cfg!(target_arch = "aarch64") {
Some("arm64")
} else if cfg!(target_arch = "arm") {
Some("arm")
} else if cfg!(target_arch = "powerpc") {
Some("powerpc")
} else if cfg!(target_arch = "powerpc64") {
Some("powerpc64")
} else if cfg!(target_arch = "riscv32") || cfg!(target_arch = "riscv64") {
Some("riscv")
} else if cfg!(target_arch = "x86") {
Some("ia32")
} else if cfg!(target_arch = "x86_64") {
Some("x64")
} else if cfg!(target_arch = "s390x") {
Some("s390x")
} else if cfg!(target_arch = "mips") || cfg!(target_arch = "mips64") {
Some("mips")
} else {
None
}
}
pub(crate) fn is_bpf_syscall_wrapper_supported() -> bool {
let syscall_prefix_opt = arch_specific_syscall_prefix();
if let Some(syscall_prefix) = syscall_prefix_opt {
let syscall_name = format!("__{}_sys_bpf", syscall_prefix);
let syscall_name = OsStr::new(syscall_name.as_str());
return create_as_probe(crate::programs::ProbeKind::KProbe, syscall_name, 0, None).is_ok();
}
false
}
pub(crate) fn is_btf_supported() -> bool {
let mut btf = Btf::new();
let name_offset = btf.add_string("int");

@ -191,3 +191,26 @@ impl From<Stats> for crate::generated::bpf_stats_type {
pub fn enable_stats(stats_type: Stats) -> Result<OwnedFd, SyscallError> {
bpf_enable_stats(stats_type.into()).map(|fd| fd.into_inner())
}
#[cfg(test)]
pub(crate) fn kernel_release() -> Result<String, ()> {
Ok("unknown".to_string())
}
#[cfg(not(test))]
pub(crate) fn kernel_release() -> Result<String, ()> {
use std::ffi::CStr;
use libc::utsname;
unsafe {
let mut v = mem::zeroed::<utsname>();
if libc::uname(&mut v as *mut _) != 0 {
return Err(());
}
let release = CStr::from_ptr(v.release.as_ptr());
Ok(release.to_string_lossy().into_owned())
}
}

@ -0,0 +1,38 @@
// clang-format off
#include <vmlinux.h>
#include <bpf/bpf_helpers.h>
// clang-format on
// CONFIG_BPF=y => 1
extern unsigned int CONFIG_BPF __kconfig;
// CONFIG_PANIC_TIMEOUT=0 => 0
extern unsigned int CONFIG_PANIC_TIMEOUT __kconfig;
// CONFIG_DEFAULT_HUNG_TASK_TIMEOUT=120
extern unsigned int CONFIG_DEFAULT_HUNG_TASK_TIMEOUT __kconfig;
// CONFIG_DEFAULT_HOSTNAME
extern char CONFIG_DEFAULT_HOSTNAME[] __kconfig;
SEC("xdp")
int kconfig(struct xdp_md *ctx) {
if (CONFIG_BPF != 1) {
return XDP_DROP;
}
if (CONFIG_PANIC_TIMEOUT != 0) {
return XDP_DROP;
}
if (CONFIG_DEFAULT_HUNG_TASK_TIMEOUT != 120) {
return XDP_DROP;
}
for (int i = 0; i < 7; i++) {
if ("(none)"[i] != CONFIG_DEFAULT_HOSTNAME[i]) {
return XDP_DROP;
}
}
return XDP_PASS;
}
char _license[] SEC("license") = "GPL";

@ -71,6 +71,7 @@ fn main() {
("multimap-btf.bpf.c", false),
("reloc.bpf.c", true),
("text_64_64_reloc.c", false),
("kconfig.bpf.c", false),
];
if build_integration_bpf {

@ -9,6 +9,7 @@ pub const RELOC_BTF: &[u8] =
include_bytes_aligned!(concat!(env!("OUT_DIR"), "/reloc.bpf.target.o"));
pub const TEXT_64_64_RELOC: &[u8] =
include_bytes_aligned!(concat!(env!("OUT_DIR"), "/text_64_64_reloc.o"));
pub const KCONFIG: &[u8] = include_bytes_aligned!(concat!(env!("OUT_DIR"), "/kconfig.bpf.o"));
pub const LOG: &[u8] = include_bytes_aligned!(concat!(env!("OUT_DIR"), "/log"));
pub const MAP_TEST: &[u8] = include_bytes_aligned!(concat!(env!("OUT_DIR"), "/map_test"));

@ -69,3 +69,16 @@ fn extension() {
.load(pass.fd().unwrap().try_clone().unwrap(), "xdp_pass")
.unwrap();
}
#[test]
fn kconfig() {
let kernel_version = KernelVersion::current().unwrap();
if kernel_version < KernelVersion::new(5, 9, 0) {
eprintln!("skipping test on kernel {kernel_version:?}, XDP uses netlink");
return;
}
let mut bpf = Ebpf::load(crate::KCONFIG).unwrap();
let pass: &mut Xdp = bpf.program_mut("kconfig").unwrap().try_into().unwrap();
pass.load().unwrap();
pass.attach("lo", XdpFlags::default()).unwrap();
}

@ -1,10 +1,14 @@
pub mod aya_obj
pub mod aya_obj::btf
pub enum aya_obj::btf::BtfError
pub aya_obj::btf::BtfError::ExternalSymbolNotFound
pub aya_obj::btf::BtfError::ExternalSymbolNotFound::symbol_name: alloc::string::String
pub aya_obj::btf::BtfError::FileError
pub aya_obj::btf::BtfError::FileError::error: std::io::error::Error
pub aya_obj::btf::BtfError::FileError::path: std::path::PathBuf
pub aya_obj::btf::BtfError::InvalidDatasec
pub aya_obj::btf::BtfError::InvalidExternalSymbol
pub aya_obj::btf::BtfError::InvalidExternalSymbol::symbol_name: alloc::string::String
pub aya_obj::btf::BtfError::InvalidHeader
pub aya_obj::btf::BtfError::InvalidInfo
pub aya_obj::btf::BtfError::InvalidInfo::len: usize
@ -7106,6 +7110,7 @@ pub fn aya_obj::Features::bpf_global_data(&self) -> bool
pub fn aya_obj::Features::bpf_name(&self) -> bool
pub fn aya_obj::Features::bpf_perf_link(&self) -> bool
pub fn aya_obj::Features::bpf_probe_read_kernel(&self) -> bool
pub fn aya_obj::Features::bpf_syscall_wrapper(&self) -> bool
pub fn aya_obj::Features::btf(&self) -> core::option::Option<&aya_obj::btf::BtfFeatures>
pub fn aya_obj::Features::cpumap_prog_id(&self) -> bool
pub fn aya_obj::Features::devmap_prog_id(&self) -> bool
@ -7214,6 +7219,7 @@ pub aya_obj::obj::Object::maps: std::collections::hash::map::HashMap<alloc::stri
pub aya_obj::obj::Object::programs: std::collections::hash::map::HashMap<alloc::string::String, aya_obj::Program>
impl aya_obj::Object
pub fn aya_obj::Object::fixup_and_sanitize_btf(&mut self, features: &aya_obj::btf::BtfFeatures) -> core::result::Result<core::option::Option<&aya_obj::btf::Btf>, aya_obj::btf::BtfError>
pub fn aya_obj::Object::patch_extern_data(&mut self, externs: &std::collections::hash::map::HashMap<alloc::string::String, alloc::vec::Vec<u8>>) -> core::result::Result<(), aya_obj::btf::BtfError>
impl aya_obj::Object
pub fn aya_obj::Object::parse(data: &[u8]) -> core::result::Result<aya_obj::Object, aya_obj::ParseError>
pub fn aya_obj::Object::patch_map_data(&mut self, globals: std::collections::hash::map::HashMap<&str, (&[u8], bool)>) -> core::result::Result<(), aya_obj::ParseError>
@ -7966,6 +7972,7 @@ pub fn aya_obj::Features::bpf_global_data(&self) -> bool
pub fn aya_obj::Features::bpf_name(&self) -> bool
pub fn aya_obj::Features::bpf_perf_link(&self) -> bool
pub fn aya_obj::Features::bpf_probe_read_kernel(&self) -> bool
pub fn aya_obj::Features::bpf_syscall_wrapper(&self) -> bool
pub fn aya_obj::Features::btf(&self) -> core::option::Option<&aya_obj::btf::BtfFeatures>
pub fn aya_obj::Features::cpumap_prog_id(&self) -> bool
pub fn aya_obj::Features::devmap_prog_id(&self) -> bool
@ -8074,6 +8081,7 @@ pub aya_obj::Object::maps: std::collections::hash::map::HashMap<alloc::string::S
pub aya_obj::Object::programs: std::collections::hash::map::HashMap<alloc::string::String, aya_obj::Program>
impl aya_obj::Object
pub fn aya_obj::Object::fixup_and_sanitize_btf(&mut self, features: &aya_obj::btf::BtfFeatures) -> core::result::Result<core::option::Option<&aya_obj::btf::Btf>, aya_obj::btf::BtfError>
pub fn aya_obj::Object::patch_extern_data(&mut self, externs: &std::collections::hash::map::HashMap<alloc::string::String, alloc::vec::Vec<u8>>) -> core::result::Result<(), aya_obj::btf::BtfError>
impl aya_obj::Object
pub fn aya_obj::Object::parse(data: &[u8]) -> core::result::Result<aya_obj::Object, aya_obj::ParseError>
pub fn aya_obj::Object::patch_map_data(&mut self, globals: std::collections::hash::map::HashMap<&str, (&[u8], bool)>) -> core::result::Result<(), aya_obj::ParseError>

@ -340,6 +340,28 @@ pub fn run(opts: Options) -> Result<()> {
}
}
}
// Copy kernel configs as well (based on Debian path conventions)
let config_path = PathBuf::from(
kernel_image
.to_string_lossy()
.replace("vmlinuz-", "config-"),
);
if config_path.exists() {
let mut destination = PathBuf::from("/boot");
destination.push(config_path.file_name().expect("filename"));
for bytes in [
"dir /boot 0755 0 0\n".as_bytes(),
"file ".as_bytes(),
destination.as_os_str().as_bytes(),
" ".as_bytes(),
config_path.as_os_str().as_bytes(),
" 0755 0 0\n".as_bytes(),
] {
stdin.write_all(bytes).expect("write");
}
}
// Must explicitly close to signal EOF.
drop(stdin);

Loading…
Cancel
Save