Skip to content

Commit

Permalink
move helper to a private module
Browse files Browse the repository at this point in the history
  • Loading branch information
vankoven committed Aug 24, 2024
1 parent 3af5a0b commit 831a81e
Show file tree
Hide file tree
Showing 5 changed files with 59 additions and 57 deletions.
2 changes: 0 additions & 2 deletions libbpf-rs/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,6 @@ Unreleased
----------
- Added `Program::fd_from_pinned_path` method for restoring program descriptor
from a pinned path
- Added `query::object_type_from_fd` function to get BPF object type by file
descriptor


0.24.0
Expand Down
5 changes: 2 additions & 3 deletions libbpf-rs/src/program.rs
Original file line number Diff line number Diff line change
Expand Up @@ -24,10 +24,9 @@ use std::slice;

use libbpf_sys::bpf_func_id;

use crate::query;
use crate::query::BpfObjectType;
use crate::util;
use crate::util::validate_bpf_ret;
use crate::util::BpfObjectType;
use crate::AsRawLibbpf;
use crate::Error;
use crate::ErrorExt as _;
Expand Down Expand Up @@ -645,7 +644,7 @@ impl<'obj> Program<'obj> {
// A pinned path may represent an object of any kind, including map
// and link. This may cause unexpected behaviour for following functions,
// like bpf_*_get_info_by_fd(), which allow objects of any type.
let fd_type = query::object_type_from_fd(fd.as_fd())?;
let fd_type = util::object_type_from_fd(fd.as_fd())?;
match fd_type {
BpfObjectType::Program => Ok(fd),
other => Err(Error::with_invalid_data(format!(
Expand Down
38 changes: 0 additions & 38 deletions libbpf-rs/src/query.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,6 @@

use std::ffi::c_void;
use std::ffi::CString;
use std::fs;
use std::io;
use std::mem::size_of_val;
use std::os::fd::AsFd;
Expand All @@ -24,9 +23,7 @@ use std::os::raw::c_char;
use std::ptr;
use std::time::Duration;

use crate::error::IntoError;
use crate::util;
use crate::Error;
use crate::MapType;
use crate::ProgramAttachType;
use crate::ProgramType;
Expand Down Expand Up @@ -706,38 +703,3 @@ gen_info_impl!(
libbpf_sys::bpf_link_get_next_id,
libbpf_sys::bpf_link_get_fd_by_id
);

/// An enum describing type of eBPF object.
#[derive(Copy, Clone, PartialEq, Eq, Debug)]
pub enum BpfObjectType {
/// The object is a map.
Map,
/// The object is a program.
Program,
/// The object is a BPF link.
Link,
}

/// Get type of BPF object by fd.
///
/// This information is not exported directly by bpf_*_get_info_by_fd() functions,
/// as kernel relies on the userspace code to know what kind of object it
/// queries. The type of object can be recovered by fd only from the proc
/// filesystem. The same approach is used in bpftool.
pub fn object_type_from_fd(fd: BorrowedFd<'_>) -> Result<BpfObjectType> {
let fd_link = format!("/proc/self/fd/{}", fd.as_raw_fd());
let link_type = fs::read_link(fd_link)
.map_err(|e| Error::with_invalid_data(format!("can't read fd link: {}", e)))?;
let link_type = link_type
.to_str()
.ok_or_invalid_data(|| "can't convert PathBuf to str")?;

match link_type {
"anon_inode:bpf-link" => Ok(BpfObjectType::Link),
"anon_inode:bpf-map" => Ok(BpfObjectType::Map),
"anon_inode:bpf-prog" => Ok(BpfObjectType::Program),
other => Err(Error::with_invalid_data(format!(
"unknown type of BPF fd: {other}"
))),
}
}
57 changes: 57 additions & 0 deletions libbpf-rs/src/util.rs
Original file line number Diff line number Diff line change
@@ -1,12 +1,16 @@
use std::ffi::CStr;
use std::ffi::CString;
use std::fs;
use std::mem::transmute;
use std::ops::Deref;
use std::os::fd::AsRawFd;
use std::os::fd::BorrowedFd;
use std::os::raw::c_char;
use std::path::Path;
use std::ptr::NonNull;
use std::sync::OnceLock;

use crate::error::IntoError;
use crate::Error;
use crate::Result;

Expand Down Expand Up @@ -92,6 +96,40 @@ pub fn validate_bpf_ret<T>(ptr: *mut T) -> Result<NonNull<T>> {
}
}

/// An enum describing type of eBPF object.
#[derive(Copy, Clone, PartialEq, Eq, Debug)]
pub enum BpfObjectType {
/// The object is a map.
Map,
/// The object is a program.
Program,
/// The object is a BPF link.
Link,
}

/// Get type of BPF object by fd.
///
/// This information is not exported directly by bpf_*_get_info_by_fd() functions,
/// as kernel relies on the userspace code to know what kind of object it
/// queries. The type of object can be recovered by fd only from the proc
/// filesystem. The same approach is used in bpftool.
pub fn object_type_from_fd(fd: BorrowedFd<'_>) -> Result<BpfObjectType> {
let fd_link = format!("/proc/self/fd/{}", fd.as_raw_fd());
let link_type = fs::read_link(fd_link)
.map_err(|e| Error::with_invalid_data(format!("can't read fd link: {}", e)))?;
let link_type = link_type
.to_str()
.ok_or_invalid_data(|| "can't convert PathBuf to str")?;

match link_type {
"anon_inode:bpf-link" => Ok(BpfObjectType::Link),
"anon_inode:bpf-map" => Ok(BpfObjectType::Map),
"anon_inode:bpf-prog" => Ok(BpfObjectType::Program),
other => Err(Error::with_invalid_data(format!(
"unknown type of BPF fd: {other}"
))),
}
}

// Fix me, If std::sync::LazyLock is stable(https://github.com/rust-lang/rust/issues/109736).
pub(crate) struct LazyLock<T> {
Expand Down Expand Up @@ -120,6 +158,9 @@ impl<T> Deref for LazyLock<T> {
mod tests {
use super::*;

use std::io;
use std::os::fd::AsFd;

#[test]
fn test_roundup() {
for i in 1..=256 {
Expand Down Expand Up @@ -165,4 +206,20 @@ mod tests {
let slice = ['a' as _, 'b' as _, 'c' as _];
assert_eq!(c_char_slice_to_cstr(&slice), None);
}

/// Check that object_type_from_fd() doesn't allow descriptors of usual
/// files to be used. Testing with BPF objects requires BPF to be
/// loaded.
#[test]
fn test_object_type_from_fd_with_unexpected_fds() {
let path = "/tmp/libbpf-rs_not_a_bpf_object";
let not_object = fs::File::create(path).expect("failed to create a plain file");

let _ = object_type_from_fd(not_object.as_fd())
.expect_err("a common file was treated as a BPF object");
let _ = object_type_from_fd(io::stdout().as_fd())
.expect_err("the stdout fd was treated as a BPF object");

fs::remove_file(path).expect("failed to remove temporary file");
}
}
14 changes: 0 additions & 14 deletions libbpf-rs/tests/test.rs
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,6 @@ use std::sync::mpsc::channel;
use std::time::Duration;

use libbpf_rs::num_possible_cpus;
use libbpf_rs::query;
use libbpf_rs::AsRawLibbpf;
use libbpf_rs::Iter;
use libbpf_rs::Linker;
Expand Down Expand Up @@ -790,19 +789,6 @@ fn test_program_loading_fd_from_pinned_path_with_wrong_pin_type() {
map.unpin(path).expect("unpinning program failed");
}

#[test]
fn test_program_loading_fd_from_pinned_path_with_not_bfp_object() {
let path = "/tmp/libbpf-rs_not_a_bpf_object";
let not_object = fs::File::create(path).expect("failed to create a plain file");

// Must fail, as the pinned path points to a usual file, not a bpf object.
let _ = Program::fd_from_pinned_path(path).expect_err("program fd obtained from plain file");
let _ = query::object_type_from_fd(not_object.as_fd())
.expect_err("a common file was treated as a BPF object");

fs::remove_file(path).expect("failed to remove temporary file");
}

#[tag(root)]
#[test]
fn test_object_loading_loaded_map_from_id() {
Expand Down

0 comments on commit 831a81e

Please sign in to comment.