1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
//! [`EventGatekeeperUserOverride`]
use std::ffi::OsStr;
use endpoint_sec_sys::{es_event_gatekeeper_user_override_t, es_gatekeeper_user_override_file_type_t, es_signed_file_info_t};
use crate::File;
/// Notification for a gatekeeper_user_override event.
///
/// This event type does not support caching (notify-only).
///
/// Hashes are calculated in usermode by Gatekeeper. There is no guarantee that
/// any other program including the kernel will observe the same file at the
/// reported path. Furthermore, there is no guarantee that the CDHash is valid
/// or that it matches the containing binary.
#[doc(alias = "es_event_gatekeeper_user_override_t")]
pub struct EventGatekeeperUserOverride<'a> {
/// Raw event
pub(super) raw: &'a es_event_gatekeeper_user_override_t,
}
impl<'a> EventGatekeeperUserOverride<'a> {
/// Describes the target file that is being overridden by the user.
///
/// If Endpoint security can't lookup the file at event submission it will
/// emit a path instead of a [`File`].
pub fn file(&self) -> Option<GatekeeperFile<'a>> {
match self.raw.file_type {
es_gatekeeper_user_override_file_type_t::ES_GATEKEEPER_USER_OVERRIDE_FILE_TYPE_PATH => {
// Safety: Union access (file_path) is allowed as file_type
// indicates this field was used to construct this event.
//
// 'a tied to self, object obtained through ES
let file_path = unsafe { self.raw.file.file_path.as_os_str() };
Some(GatekeeperFile::Path(file_path))
},
es_gatekeeper_user_override_file_type_t::ES_GATEKEEPER_USER_OVERRIDE_FILE_TYPE_FILE => {
// Safety: Union access (file) is allowed as file_type indicates
// this field was used to construct this event.
//
// 'a tied to self, object obtained through ES
let file = unsafe { self.raw.file.file.as_ref() };
Some(GatekeeperFile::File(File::new(file)))
},
_ => None,
}
}
/// SHA256 of the file.
///
/// Provided if the filesize is less than 100MB.
#[inline(always)]
pub fn sha256(&self) -> &[u8; 32] {
// Safety: 'a tied to self, object obtained through ES
unsafe {
&*self.raw.sha256
}
}
/// Signing Information, available if the file has been signed.
#[inline(always)]
pub fn signing_info(&self) -> Option<SignedFileInfo<'_>> {
// Safety: 'a tied to self, object obtained through ES
let signing_info = unsafe { self.raw.signing_info()? };
Some(SignedFileInfo::new(signing_info))
}
}
// Safety: safe to send across threads: does not contain any interior mutability nor depend on current thread state
unsafe impl Send for EventGatekeeperUserOverride<'_> {}
// Safety: safe to share across threads: does not contain any interior mutability nor depend on current thread state
unsafe impl Sync for EventGatekeeperUserOverride<'_> {}
impl_debug_eq_hash_with_functions!(EventGatekeeperUserOverride<'a>; file, sha256, signing_info);
/// The file being overridden by a user.
#[derive(Debug, PartialEq, Hash)]
pub enum GatekeeperFile<'a> {
/// Endpoint Security couldn't lookup the file, and emitted a path.
Path(&'a OsStr),
/// The full information of the file being overridden.
File(File<'a>),
}
/// Information from a signed file.
///
/// If the file is a multiarchitecture binary, only the signing information for
/// the native host architecture is reported. I.e. the CDHash from the AArch64
/// slice if the host is AArch64.
pub struct SignedFileInfo<'a> {
/// Raw event
raw: &'a es_signed_file_info_t,
}
impl<'a> SignedFileInfo<'a> {
/// Create a new [`SignedFileInfo`] instance.
fn new(raw: &es_signed_file_info_t) -> SignedFileInfo<'_> {
SignedFileInfo { raw }
}
/// Code Directory Hash
#[inline(always)]
pub fn cdhash(&self) -> &'a [u8; 20] {
&self.raw.cdhash
}
/// Signing Identifier, if available in the signing information.
#[inline(always)]
pub fn signing_id(&self) -> &'a OsStr {
// Safety: 'a tied to self, object obtained through ES
unsafe {
self.raw.signing_id.as_os_str()
}
}
/// Team Identifier, if available in the signing information.
#[inline(always)]
pub fn team_id(&self) -> &'a OsStr {
// Safety: 'a tied to self, object obtained through ES
unsafe {
self.raw.team_id.as_os_str()
}
}
}
impl_debug_eq_hash_with_functions!(SignedFileInfo<'a>; cdhash, signing_id, team_id);