do not leak file descriptors in lirc_mode2

reviewable/pr614/r7
Andrés Medina 2 years ago
parent d3e6d9066f
commit 4452e2f6e2

@ -1,8 +1,8 @@
//! Extension programs. //! Extension programs.
use std::os::fd::{AsRawFd, RawFd}; use std::os::fd::{AsFd, AsRawFd, OwnedFd};
use thiserror::Error;
use object::Endianness; use object::Endianness;
use thiserror::Error;
use crate::{ use crate::{
generated::{bpf_attach_type::BPF_CGROUP_INET_INGRESS, bpf_prog_type::BPF_PROG_TYPE_EXT}, generated::{bpf_attach_type::BPF_CGROUP_INET_INGRESS, bpf_prog_type::BPF_PROG_TYPE_EXT},
@ -71,11 +71,12 @@ impl Extension {
/// There are no restrictions on what functions may be replaced, so you could replace /// There are no restrictions on what functions may be replaced, so you could replace
/// the main entry point of your program with an extension. /// the main entry point of your program with an extension.
pub fn load(&mut self, program: ProgramFd, func_name: &str) -> Result<(), ProgramError> { pub fn load(&mut self, program: ProgramFd, func_name: &str) -> Result<(), ProgramError> {
let target_prog_fd = program.as_raw_fd(); let target_prog_fd = program.as_fd();
let (btf_fd, btf_id) = get_btf_info(target_prog_fd, func_name)?; let (btf_fd, btf_id) = get_btf_info(target_prog_fd, func_name)?;
self.data.attach_btf_obj_fd = Some(btf_fd as u32); self.data.attach_btf_obj_fd = Some(btf_fd);
self.data.attach_prog_fd = Some(target_prog_fd); // TODO (AM)
self.data.attach_prog_fd = Some(target_prog_fd.as_raw_fd());
self.data.attach_btf_id = Some(btf_id); self.data.attach_btf_id = Some(btf_id);
load_program(BPF_PROG_TYPE_EXT, &mut self.data) load_program(BPF_PROG_TYPE_EXT, &mut self.data)
} }
@ -118,15 +119,22 @@ impl Extension {
program: ProgramFd, program: ProgramFd,
func_name: &str, func_name: &str,
) -> Result<ExtensionLinkId, ProgramError> { ) -> Result<ExtensionLinkId, ProgramError> {
let target_fd = program.as_raw_fd(); let target_fd = program.as_fd();
let (_, btf_id) = get_btf_info(target_fd, func_name)?; let (_, btf_id) = get_btf_info(target_fd, func_name)?;
let prog_fd = self.data.fd_or_err()?; let prog_fd = self.data.fd_or_err()?;
// the attach type must be set as 0, which is bpf_attach_type::BPF_CGROUP_INET_INGRESS // the attach type must be set as 0, which is bpf_attach_type::BPF_CGROUP_INET_INGRESS
let link_fd = bpf_link_create(prog_fd, target_fd, BPF_CGROUP_INET_INGRESS, Some(btf_id), 0) // TODO (AM)
.map_err(|(_, io_error)| ProgramError::SyscallError { let link_fd = bpf_link_create(
call: "bpf_link_create".to_owned(), prog_fd,
io_error, target_fd.as_raw_fd(),
})?; BPF_CGROUP_INET_INGRESS,
Some(btf_id),
0,
)
.map_err(|(_, io_error)| ProgramError::SyscallError {
call: "bpf_link_create".to_owned(),
io_error,
})?;
self.data self.data
.links .links
.insert(ExtensionLink::new(FdLink::new(link_fd))) .insert(ExtensionLink::new(FdLink::new(link_fd)))
@ -151,7 +159,10 @@ impl Extension {
/// Retrieves the FD of the BTF object for the provided `prog_fd` and the BTF ID of the function /// Retrieves the FD of the BTF object for the provided `prog_fd` and the BTF ID of the function
/// with the name `func_name` within that BTF object. /// with the name `func_name` within that BTF object.
fn get_btf_info(prog_fd: i32, func_name: &str) -> Result<(RawFd, u32), ProgramError> { fn get_btf_info(
prog_fd: std::os::fd::BorrowedFd<'_>,
func_name: &str,
) -> Result<(OwnedFd, u32), ProgramError> {
// retrieve program information // retrieve program information
let info = let info =
sys::bpf_prog_get_info_by_fd(prog_fd).map_err(|io_error| ProgramError::SyscallError { sys::bpf_prog_get_info_by_fd(prog_fd).map_err(|io_error| ProgramError::SyscallError {
@ -174,12 +185,12 @@ fn get_btf_info(prog_fd: i32, func_name: &str) -> Result<(RawFd, u32), ProgramEr
// we need to read the btf bytes into a buffer but we don't know the size ahead of time. // we need to read the btf bytes into a buffer but we don't know the size ahead of time.
// assume 4kb. if this is too small we can resize based on the size obtained in the response. // assume 4kb. if this is too small we can resize based on the size obtained in the response.
let mut buf = vec![0u8; 4096]; let mut buf = vec![0u8; 4096];
let btf_info = match sys::btf_obj_get_info_by_fd(btf_fd, &mut buf) { let btf_info = match sys::btf_obj_get_info_by_fd(btf_fd.as_fd(), &mut buf) {
Ok(info) => { Ok(info) => {
if info.btf_size > buf.len() as u32 { if info.btf_size > buf.len() as u32 {
buf.resize(info.btf_size as usize, 0u8); buf.resize(info.btf_size as usize, 0u8);
let btf_info = let btf_info =
sys::btf_obj_get_info_by_fd(btf_fd, &mut buf).map_err(|io_error| { sys::btf_obj_get_info_by_fd(btf_fd.as_fd(), &mut buf).map_err(|io_error| {
ProgramError::SyscallError { ProgramError::SyscallError {
call: "bpf_prog_get_info_by_fd".to_owned(), call: "bpf_prog_get_info_by_fd".to_owned(),
io_error, io_error,

@ -71,7 +71,7 @@ impl LircMode2 {
// TODO (AM) // TODO (AM)
self.data.links.insert(LircLink::new( self.data.links.insert(LircLink::new(
prog_fd.as_raw_fd(), prog_fd.try_clone_to_owned()?,
lircdev_fd.try_clone_to_owned()?, lircdev_fd.try_clone_to_owned()?,
)) ))
} }
@ -104,7 +104,7 @@ impl LircMode2 {
io_error, io_error,
})?; })?;
prog_fds.push(fd as RawFd); prog_fds.push(fd);
} }
prog_fds prog_fds
@ -121,18 +121,18 @@ pub struct LircLinkId(RawFd, RawFd);
#[derive(Debug)] #[derive(Debug)]
/// An LircMode2 Link /// An LircMode2 Link
pub struct LircLink { pub struct LircLink {
prog_fd: RawFd, prog_fd: OwnedFd,
target_fd: OwnedFd, target_fd: OwnedFd,
} }
impl LircLink { impl LircLink {
pub(crate) fn new(prog_fd: RawFd, target_fd: OwnedFd) -> LircLink { pub(crate) fn new(prog_fd: OwnedFd, target_fd: OwnedFd) -> LircLink {
LircLink { prog_fd, target_fd } LircLink { prog_fd, target_fd }
} }
/// Get ProgramInfo from this link /// Get ProgramInfo from this link
pub fn info(&self) -> Result<ProgramInfo, ProgramError> { pub fn info(&self) -> Result<ProgramInfo, ProgramError> {
match bpf_prog_get_info_by_fd(self.prog_fd) { match bpf_prog_get_info_by_fd(self.prog_fd.as_fd()) {
Ok(info) => Ok(ProgramInfo(info)), Ok(info) => Ok(ProgramInfo(info)),
Err(io_error) => Err(ProgramError::SyscallError { Err(io_error) => Err(ProgramError::SyscallError {
call: "bpf_prog_get_info_by_fd".to_owned(), call: "bpf_prog_get_info_by_fd".to_owned(),
@ -147,12 +147,16 @@ impl Link for LircLink {
fn id(&self) -> Self::Id { fn id(&self) -> Self::Id {
// TODO (AM) // TODO (AM)
LircLinkId(self.prog_fd, self.target_fd.as_raw_fd()) LircLinkId(self.prog_fd.as_raw_fd(), self.target_fd.as_raw_fd())
} }
fn detach(self) -> Result<(), ProgramError> { fn detach(self) -> Result<(), ProgramError> {
// TODO (AM) // TODO (AM)
let _ = bpf_prog_detach(self.prog_fd, self.target_fd.as_raw_fd(), BPF_LIRC_MODE2); let _ = bpf_prog_detach(
self.prog_fd.as_raw_fd(),
self.target_fd.as_raw_fd(),
BPF_LIRC_MODE2,
);
Ok(()) Ok(())
} }
} }

@ -418,7 +418,7 @@ pub(crate) struct ProgramData<T: Link> {
pub(crate) fd: Option<OwnedFd>, pub(crate) fd: Option<OwnedFd>,
pub(crate) links: LinkMap<T>, pub(crate) links: LinkMap<T>,
pub(crate) expected_attach_type: Option<bpf_attach_type>, pub(crate) expected_attach_type: Option<bpf_attach_type>,
pub(crate) attach_btf_obj_fd: Option<u32>, pub(crate) attach_btf_obj_fd: Option<OwnedFd>,
pub(crate) attach_btf_id: Option<u32>, pub(crate) attach_btf_id: Option<u32>,
pub(crate) attach_prog_fd: Option<RawFd>, pub(crate) attach_prog_fd: Option<RawFd>,
pub(crate) btf_fd: Option<RawFd>, pub(crate) btf_fd: Option<RawFd>,
@ -468,7 +468,7 @@ impl<T: Link> ProgramData<T> {
io_error, io_error,
} }
})?; })?;
Some(fd as u32) Some(fd)
} else { } else {
None None
}; };
@ -500,13 +500,11 @@ impl<T: Link> ProgramData<T> {
io_error, io_error,
})?; })?;
// TODO: AM let info =
let info = bpf_prog_get_info_by_fd(fd.as_raw_fd()).map_err(|io_error| { bpf_prog_get_info_by_fd(fd.as_fd()).map_err(|io_error| ProgramError::SyscallError {
ProgramError::SyscallError {
call: "bpf_prog_get_info_by_fd".to_owned(), call: "bpf_prog_get_info_by_fd".to_owned(),
io_error, io_error,
} })?;
})?;
let info = ProgramInfo(info); let info = ProgramInfo(info);
let name = info.name_as_str().map(|s| s.to_string()); let name = info.name_as_str().map(|s| s.to_string());
@ -615,7 +613,7 @@ fn load_program<T: Link>(
kernel_version: target_kernel_version, kernel_version: target_kernel_version,
expected_attach_type: data.expected_attach_type, expected_attach_type: data.expected_attach_type,
prog_btf_fd: data.btf_fd, prog_btf_fd: data.btf_fd,
attach_btf_obj_fd: data.attach_btf_obj_fd, attach_btf_obj_fd: data.attach_btf_obj_fd.as_ref().map(|f| f.as_fd()),
attach_btf_id: data.attach_btf_id, attach_btf_id: data.attach_btf_id,
attach_prog_fd: data.attach_prog_fd, attach_prog_fd: data.attach_prog_fd,
func_info_rec_size: *func_info_rec_size, func_info_rec_size: *func_info_rec_size,
@ -955,15 +953,13 @@ impl ProgramInfo {
} }
/// Returns the fd associated with the program. /// Returns the fd associated with the program.
/// pub fn fd(&self) -> Result<OwnedFd, ProgramError> {
/// The returned fd must be closed when no longer needed.
pub fn fd(&self) -> Result<RawFd, ProgramError> {
let fd = let fd =
bpf_prog_get_fd_by_id(self.0.id).map_err(|io_error| ProgramError::SyscallError { bpf_prog_get_fd_by_id(self.0.id).map_err(|io_error| ProgramError::SyscallError {
call: "bpf_prog_get_fd_by_id".to_owned(), call: "bpf_prog_get_fd_by_id".to_owned(),
io_error, io_error,
})?; })?;
Ok(fd as RawFd) Ok(fd)
} }
/// Loads a program from a pinned path in bpffs. /// Loads a program from a pinned path in bpffs.
@ -975,13 +971,11 @@ impl ProgramInfo {
io_error, io_error,
})?; })?;
// TODO (AM) let info =
let info = bpf_prog_get_info_by_fd(fd.as_raw_fd()).map_err(|io_error| { bpf_prog_get_info_by_fd(fd.as_fd()).map_err(|io_error| ProgramError::SyscallError {
ProgramError::SyscallError {
call: "bpf_prog_get_info_by_fd".to_owned(), call: "bpf_prog_get_info_by_fd".to_owned(),
io_error, io_error,
} })?;
})?;
Ok(ProgramInfo(info)) Ok(ProgramInfo(info))
} }
@ -1012,14 +1006,12 @@ impl Iterator for ProgramsIter {
io_error, io_error,
}) })
.and_then(|fd| { .and_then(|fd| {
let info = bpf_prog_get_info_by_fd(fd) bpf_prog_get_info_by_fd(fd.as_fd())
.map_err(|io_error| ProgramError::SyscallError { .map_err(|io_error| ProgramError::SyscallError {
call: "bpf_prog_get_info_by_fd".to_owned(), call: "bpf_prog_get_info_by_fd".to_owned(),
io_error, io_error,
}) })
.map(ProgramInfo); .map(ProgramInfo)
unsafe { libc::close(fd) };
info
}), }),
) )
} }

@ -125,7 +125,7 @@ pub(crate) struct BpfLoadProgramAttrs<'a> {
pub(crate) kernel_version: u32, pub(crate) kernel_version: u32,
pub(crate) expected_attach_type: Option<bpf_attach_type>, pub(crate) expected_attach_type: Option<bpf_attach_type>,
pub(crate) prog_btf_fd: Option<RawFd>, pub(crate) prog_btf_fd: Option<RawFd>,
pub(crate) attach_btf_obj_fd: Option<u32>, pub(crate) attach_btf_obj_fd: Option<BorrowedFd<'a>>,
pub(crate) attach_btf_id: Option<u32>, pub(crate) attach_btf_id: Option<u32>,
pub(crate) attach_prog_fd: Option<RawFd>, pub(crate) attach_prog_fd: Option<RawFd>,
pub(crate) func_info_rec_size: usize, pub(crate) func_info_rec_size: usize,
@ -189,7 +189,7 @@ pub(crate) fn bpf_load_program(
u.log_size = log_buf.capacity() as u32; u.log_size = log_buf.capacity() 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.as_raw_fd() as u32;
} }
if let Some(v) = aya_attr.attach_prog_fd { if let Some(v) = aya_attr.attach_prog_fd {
u.__bindgen_anon_1.attach_prog_fd = v as u32; u.__bindgen_anon_1.attach_prog_fd = v as u32;
@ -474,23 +474,24 @@ pub(crate) fn bpf_prog_query(
ret ret
} }
pub(crate) fn bpf_prog_get_fd_by_id(prog_id: u32) -> io::Result<RawFd> { pub(crate) fn bpf_prog_get_fd_by_id(prog_id: u32) -> io::Result<OwnedFd> {
let mut attr = unsafe { mem::zeroed::<bpf_attr>() }; let mut attr = unsafe { mem::zeroed::<bpf_attr>() };
attr.__bindgen_anon_6.__bindgen_anon_1.prog_id = prog_id; attr.__bindgen_anon_6.__bindgen_anon_1.prog_id = prog_id;
match sys_bpf(bpf_cmd::BPF_PROG_GET_FD_BY_ID, &attr) { match sys_bpf(bpf_cmd::BPF_PROG_GET_FD_BY_ID, &attr) {
Ok(v) => Ok(v as RawFd), // SAFETY: BPF_PROG_GET_FD_BY_ID returns new fd
Ok(v) => Ok(unsafe { OwnedFd::from_raw_fd(v as RawFd) }),
Err((_, err)) => Err(err), Err((_, err)) => Err(err),
} }
} }
pub(crate) fn bpf_prog_get_info_by_fd(prog_fd: RawFd) -> io::Result<bpf_prog_info> { pub(crate) fn bpf_prog_get_info_by_fd(prog_fd: BorrowedFd<'_>) -> io::Result<bpf_prog_info> {
let mut attr = unsafe { mem::zeroed::<bpf_attr>() }; let mut attr = unsafe { mem::zeroed::<bpf_attr>() };
// info gets entirely populated by the kernel // info gets entirely populated by the kernel
let info = MaybeUninit::zeroed(); let info = MaybeUninit::zeroed();
attr.info.bpf_fd = prog_fd as u32; attr.info.bpf_fd = prog_fd.as_raw_fd() as u32;
attr.info.info = &info as *const _ as u64; attr.info.info = &info as *const _ as u64;
attr.info.info_len = mem::size_of::<bpf_prog_info>() as u32; attr.info.info_len = mem::size_of::<bpf_prog_info>() as u32;
@ -530,13 +531,16 @@ pub(crate) fn bpf_link_get_info_by_fd(link_fd: BorrowedFd<'_>) -> io::Result<bpf
} }
} }
pub(crate) fn btf_obj_get_info_by_fd(prog_fd: RawFd, buf: &mut [u8]) -> io::Result<bpf_btf_info> { pub(crate) fn btf_obj_get_info_by_fd(
prog_fd: BorrowedFd<'_>,
buf: &mut [u8],
) -> io::Result<bpf_btf_info> {
let mut attr = unsafe { mem::zeroed::<bpf_attr>() }; let mut attr = unsafe { mem::zeroed::<bpf_attr>() };
let mut info = unsafe { mem::zeroed::<bpf_btf_info>() }; let mut info = unsafe { mem::zeroed::<bpf_btf_info>() };
let buf_size = buf.len() as u32; let buf_size = buf.len() as u32;
info.btf = buf.as_ptr() as u64; info.btf = buf.as_ptr() as u64;
info.btf_size = buf_size; info.btf_size = buf_size;
attr.info.bpf_fd = prog_fd as u32; attr.info.bpf_fd = prog_fd.as_raw_fd() as u32;
attr.info.info = &info as *const bpf_btf_info as u64; attr.info.info = &info as *const bpf_btf_info as u64;
attr.info.info_len = mem::size_of::<bpf_btf_info>() as u32; attr.info.info_len = mem::size_of::<bpf_btf_info>() as u32;
@ -579,12 +583,13 @@ pub(crate) fn bpf_load_btf(raw_btf: &[u8], log: &mut VerifierLog) -> Result<Owne
Ok(unsafe { OwnedFd::from_raw_fd(fd) }) Ok(unsafe { OwnedFd::from_raw_fd(fd) })
} }
pub(crate) fn bpf_btf_get_fd_by_id(id: u32) -> io::Result<RawFd> { pub(crate) fn bpf_btf_get_fd_by_id(id: u32) -> io::Result<OwnedFd> {
let mut attr = unsafe { mem::zeroed::<bpf_attr>() }; let mut attr = unsafe { mem::zeroed::<bpf_attr>() };
attr.__bindgen_anon_6.__bindgen_anon_1.btf_id = id; attr.__bindgen_anon_6.__bindgen_anon_1.btf_id = id;
match sys_bpf(bpf_cmd::BPF_BTF_GET_FD_BY_ID, &attr) { match sys_bpf(bpf_cmd::BPF_BTF_GET_FD_BY_ID, &attr) {
Ok(v) => Ok(v as RawFd), // SAFETY: BPF_BTF_GET_FD_BY_ID returns new fd
Ok(v) => Ok(unsafe { OwnedFd::from_raw_fd(v as RawFd) }),
Err((_, err)) => Err(err), Err((_, err)) => Err(err),
} }
} }

@ -14,8 +14,8 @@ macro_rules! read_str_bytes {
($fun:ident, $ptr:expr, $len:expr $(,)?) => { ($fun:ident, $ptr:expr, $len:expr $(,)?) => {
let r = unsafe { let r = unsafe {
let Some(ptr) = RESULT.get_ptr_mut(0) else { let Some(ptr) = RESULT.get_ptr_mut(0) else {
return; return;
}; };
&mut *ptr &mut *ptr
}; };

Loading…
Cancel
Save