#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub(crate) struct PerfCredentialIds {
uid: u32,
gid: u32,
euid: u32,
egid: u32,
suid: u32,
sgid: u32,
}
impl PerfCredentialIds {
pub(crate) const fn new(
uid: u32,
gid: u32,
euid: u32,
egid: u32,
suid: u32,
sgid: u32,
) -> Self {
Self {
uid,
gid,
euid,
egid,
suid,
sgid,
}
}
}
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub(crate) struct PerfAccessCapabilities {
perfmon_capable: bool,
ptrace_capable: bool,
kill_capable: bool,
}
impl PerfAccessCapabilities {
pub(crate) const fn new(
perfmon_capable: bool,
ptrace_capable: bool,
kill_capable: bool,
) -> Self {
Self {
perfmon_capable,
ptrace_capable,
kill_capable,
}
}
}
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub(crate) struct PerfCredentialSnapshot {
ids: PerfCredentialIds,
capabilities: PerfAccessCapabilities,
}
impl PerfCredentialSnapshot {
pub(crate) const fn new(ids: PerfCredentialIds, capabilities: PerfAccessCapabilities) -> Self {
Self { ids, capabilities }
}
}
pub(crate) const fn perf_task_access_allowed(
caller: PerfCredentialSnapshot,
target: PerfCredentialSnapshot,
same_thread_group: bool,
target_dumpable: bool,
signal_delivery: bool,
) -> bool {
let perfmon_bypass = caller.capabilities.perfmon_capable
&& (!signal_delivery || caller.capabilities.kill_capable);
if same_thread_group || perfmon_bypass || caller.capabilities.ptrace_capable {
return true;
}
target_dumpable
&& caller.ids.uid == target.ids.uid
&& caller.ids.uid == target.ids.euid
&& caller.ids.uid == target.ids.suid
&& caller.ids.gid == target.ids.gid
&& caller.ids.gid == target.ids.egid
&& caller.ids.gid == target.ids.sgid
}