Skip to content

Commit c186165

Browse files
d-e-s-odanielocfb
authored andcommitted
libbpf-cargo: Fix leakage of bpf_object
With the switch over to using uninitialized memory that has been provided to the skeleton at open time we ended up leaking the object. The reason is simple: on paper we no longer own it and neither does the MaybeUninit that was passed in. As a result, nobody runs its destructor. This change fixes the problem by treating the object reference as owned while the skeleton is around. Signed-off-by: Daniel Müller <[email protected]>
1 parent a5e17e3 commit c186165

File tree

2 files changed

+70
-18
lines changed

2 files changed

+70
-18
lines changed

libbpf-cargo/CHANGELOG.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,8 @@
1+
Unreleased
2+
----------
3+
- Fixed missing BPF object cleanup after skeleton destruction
4+
5+
16
0.24.0
27
------
38
- Reworked generated skeletons to contain publicly accessible maps and

libbpf-cargo/src/gen/mod.rs

Lines changed: 65 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -951,6 +951,44 @@ fn gen_skel_contents(_debug: bool, raw_obj_name: &str, obj_file_path: &Path) ->
951951
write!(
952952
skel,
953953
"\
954+
struct OwnedRef<'obj, O> {{
955+
object: Option<&'obj mut std::mem::MaybeUninit<O>>,
956+
}}
957+
958+
impl<'obj, O> OwnedRef<'obj, O> {{
959+
/// # Safety
960+
/// The object has to be initialized.
961+
unsafe fn new(object: &'obj mut std::mem::MaybeUninit<O>) -> Self {{
962+
Self {{
963+
object: Some(object),
964+
}}
965+
}}
966+
967+
fn as_ref(&self) -> &O {{
968+
// SAFETY: As per the contract during construction, the
969+
// object has to be initialized.
970+
unsafe {{ self.object.as_ref().unwrap().assume_init_ref() }}
971+
}}
972+
973+
fn as_mut(&mut self) -> &mut O {{
974+
// SAFETY: As per the contract during construction, the
975+
// object has to be initialized.
976+
unsafe {{ self.object.as_mut().unwrap().assume_init_mut() }}
977+
}}
978+
979+
fn take(mut self) -> &'obj mut std::mem::MaybeUninit<O> {{
980+
self.object.take().unwrap()
981+
}}
982+
}}
983+
984+
impl<O> Drop for OwnedRef<'_, O> {{
985+
fn drop(&mut self) {{
986+
if let Some(object) = &mut self.object {{
987+
unsafe {{ object.assume_init_drop() }}
988+
}}
989+
}}
990+
}}
991+
954992
#[derive(Default)]
955993
pub struct {name}SkelBuilder {{
956994
pub obj_builder: libbpf_rs::ObjectBuilder,
@@ -980,17 +1018,23 @@ fn gen_skel_contents(_debug: bool, raw_obj_name: &str, obj_file_path: &Path) ->
9801018
return Err(libbpf_rs::Error::from_raw_os_error(-ret));
9811019
}}
9821020
1021+
// SAFETY: `skel_ptr` points to a valid object after the
1022+
// open call.
9831023
let obj_ptr = unsafe {{ *skel_ptr.as_ref().obj }};
9841024
// SANITY: `bpf_object__open_skeleton` should have
9851025
// allocated the object.
9861026
let obj_ptr = std::ptr::NonNull::new(obj_ptr).unwrap();
1027+
// SAFETY: `obj_ptr` points to an opened object after
1028+
// skeleton open.
9871029
let obj = unsafe {{ libbpf_rs::OpenObject::from_ptr(obj_ptr) }};
988-
let obj_ref = object.write(obj);
1030+
let _obj = object.write(obj);
1031+
// SAFETY: We just wrote initialized data to `object`.
1032+
let mut obj_ref = unsafe {{ OwnedRef::new(object) }};
9891033
9901034
#[allow(unused_mut)]
9911035
let mut skel = Open{name}Skel {{
992-
maps: unsafe {{ Open{name}Maps::new(&skel_config, obj_ref)? }},
993-
progs: unsafe {{ Open{name}Progs::new(obj_ref)? }},
1036+
maps: unsafe {{ Open{name}Maps::new(&skel_config, obj_ref.as_mut())? }},
1037+
progs: unsafe {{ Open{name}Progs::new(obj_ref.as_mut())? }},
9941038
obj: obj_ref,
9951039
// SAFETY: Our `struct_ops` type contains only pointers,
9961040
// which are allowed to be NULL.
@@ -1057,7 +1101,7 @@ pub struct StructOps {{}}
10571101
skel,
10581102
"\
10591103
pub struct Open{name}Skel<'obj> {{
1060-
obj: &'obj mut libbpf_rs::OpenObject,
1104+
obj: OwnedRef<'obj, libbpf_rs::OpenObject>,
10611105
pub maps: Open{name}Maps<'obj>,
10621106
pub progs: Open{name}Progs<'obj>,
10631107
pub struct_ops: StructOps,
@@ -1074,22 +1118,25 @@ pub struct StructOps {{}}
10741118
return Err(libbpf_rs::Error::from_raw_os_error(-ret));
10751119
}}
10761120
1077-
let obj_ref = unsafe {{
1078-
std::mem::transmute::<
1079-
&'obj mut libbpf_rs::OpenObject,
1080-
&'obj mut std::mem::MaybeUninit<libbpf_rs::OpenObject>,
1081-
>(self.obj)
1082-
}};
1121+
let obj_ref = self.obj.take();
10831122
let open_obj = std::mem::replace(obj_ref, std::mem::MaybeUninit::uninit());
1084-
let obj = unsafe {{ libbpf_rs::Object::from_ptr(open_obj.assume_init().take_ptr()) }};
1085-
1123+
// SAFETY: `open_obj` is guaranteed to be properly
1124+
// initialized as it came from an `OwnedRef`.
1125+
let obj_ptr = unsafe {{ open_obj.assume_init().take_ptr() }};
1126+
// SAFETY: `obj_ptr` points to a loaded object after
1127+
// skeleton load.
1128+
let obj = unsafe {{ libbpf_rs::Object::from_ptr(obj_ptr) }};
1129+
// SAFETY: `OpenObject` and `Object` are guaranteed to
1130+
// have the same memory layout.
10861131
let obj_ref = unsafe {{
10871132
std::mem::transmute::<
10881133
&'obj mut std::mem::MaybeUninit<libbpf_rs::OpenObject>,
10891134
&'obj mut std::mem::MaybeUninit<libbpf_rs::Object>,
10901135
>(obj_ref)
10911136
}};
1092-
let obj_ref = obj_ref.write(obj);
1137+
let _obj = obj_ref.write(obj);
1138+
// SAFETY: We just wrote initialized data to `obj_ref`.
1139+
let obj_ref = unsafe {{ OwnedRef::new(obj_ref) }};
10931140
10941141
Ok({name}Skel {{
10951142
obj: obj_ref,
@@ -1102,11 +1149,11 @@ pub struct StructOps {{}}
11021149
}}
11031150
11041151
fn open_object(&self) -> &libbpf_rs::OpenObject {{
1105-
self.obj
1152+
self.obj.as_ref()
11061153
}}
11071154
11081155
fn open_object_mut(&mut self) -> &mut libbpf_rs::OpenObject {{
1109-
self.obj
1156+
self.obj.as_mut()
11101157
}}
11111158
",
11121159
name = &obj_name,
@@ -1124,7 +1171,7 @@ pub struct StructOps {{}}
11241171
skel,
11251172
"\
11261173
pub struct {name}Skel<'obj> {{
1127-
obj: &'obj mut libbpf_rs::Object,
1174+
obj: OwnedRef<'obj, libbpf_rs::Object>,
11281175
pub maps: {name}Maps<'obj>,
11291176
pub progs: {name}Progs<'obj>,
11301177
struct_ops: StructOps,
@@ -1143,11 +1190,11 @@ pub struct StructOps {{}}
11431190
11441191
impl<'obj> Skel<'obj> for {name}Skel<'obj> {{
11451192
fn object(&self) -> &libbpf_rs::Object {{
1146-
self.obj
1193+
self.obj.as_ref()
11471194
}}
11481195
11491196
fn object_mut(&mut self) -> &mut libbpf_rs::Object {{
1150-
self.obj
1197+
self.obj.as_mut()
11511198
}}
11521199
",
11531200
name = &obj_name,

0 commit comments

Comments
 (0)