Skip to content

Commit

Permalink
Add support of ES_EVENT_TYPE_NOTIFY_GATEKEEPER_USER_OVERRIDE
Browse files Browse the repository at this point in the history
  • Loading branch information
Alkenso committed Sep 17, 2024
1 parent 94421e3 commit ade1f45
Show file tree
Hide file tree
Showing 3 changed files with 85 additions and 4 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -328,6 +328,8 @@ extension es_event_type_t: SpellbookEndpointSecurity.ESNativeType {
return "ES_EVENT_TYPE_NOTIFY_OD_DELETE_GROUP"
case ES_EVENT_TYPE_NOTIFY_XPC_CONNECT:
return "ES_EVENT_TYPE_NOTIFY_XPC_CONNECT"
case ES_EVENT_TYPE_NOTIFY_GATEKEEPER_USER_OVERRIDE:
return "ES_EVENT_TYPE_NOTIFY_GATEKEEPER_USER_OVERRIDE"
default:
return nil
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -118,10 +118,18 @@ public extension ESConverter {
ESThread(threadID: es.thread_id)
}

func esThreadState(_ es: es_thread_state_t) throws -> ESThreadState {
func esThreadState(_ es: es_thread_state_t) -> ESThreadState {
ESThreadState(flavor: es.flavor, state: esToken(es.state))
}

func esSignedFileInfo(_ es: es_signed_file_info_t) -> ESSignedFileInfo {
.init(
cdHash: withUnsafeBytes(of: es.cdhash) { Data($0) },
teamID: esString(es.team_id),
signingID: esString(es.signing_id)
)
}

func esAuthResult(_ es: es_result_t) throws -> ESAuthResult {
switch es.result_type {
case ES_RESULT_TYPE_AUTH:
Expand Down Expand Up @@ -402,7 +410,7 @@ public extension ESConverter {
case ES_EVENT_TYPE_NOTIFY_TRACE:
return .trace(esEvent(trace: event.trace))
case ES_EVENT_TYPE_NOTIFY_REMOTE_THREAD_CREATE:
return try .remoteThreadCreate(esEvent(remote_thread_create: event.remote_thread_create))
return .remoteThreadCreate(esEvent(remote_thread_create: event.remote_thread_create))
case ES_EVENT_TYPE_AUTH_REMOUNT:
return .remount(esEvent(remount: event.remount))
case ES_EVENT_TYPE_NOTIFY_REMOUNT:
Expand Down Expand Up @@ -499,6 +507,8 @@ public extension ESConverter {
return .odDeleteGroup(esEvent(odDeleteGroup: event.od_delete_group.pointee))
case ES_EVENT_TYPE_NOTIFY_XPC_CONNECT:
return .xpcConnect(esEvent(xpcConnect: event.xpc_connect.pointee))
case ES_EVENT_TYPE_NOTIFY_GATEKEEPER_USER_OVERRIDE:
return try .gatekeeperUserOverride(esEvent(gatekeeperUserOverride: event.gatekeeper_user_override.pointee))
default:
throw CommonError.invalidArgument(arg: "es_event_type_t", invalidValue: type)
}
Expand Down Expand Up @@ -697,8 +707,8 @@ public extension ESConverter {
.init(source: esFile(es.source))
}

func esEvent(remote_thread_create es: es_event_remote_thread_create_t) throws -> ESEvent.RemoteThreadCreate {
try .init(target: esProcess(es.target), threadState: es.thread_state.map(\.pointee).flatMap(esThreadState))
func esEvent(remote_thread_create es: es_event_remote_thread_create_t) -> ESEvent.RemoteThreadCreate {
.init(target: esProcess(es.target), threadState: es.thread_state.map(\.pointee).flatMap(esThreadState))
}

func esEvent(remount es: es_event_remount_t) -> ESEvent.Remount {
Expand Down Expand Up @@ -1215,4 +1225,21 @@ public extension ESConverter {
func esEvent(xpcConnect es: es_event_xpc_connect_t) -> ESEvent.XPCConnect {
.init(serviceName: esString(es.service_name), serviceDomainType: es.service_domain_type)
}

func esEvent(gatekeeperUserOverride es: es_event_gatekeeper_user_override_t) throws -> ESEvent.GatekeeperUserOverride {
let file: ESEvent.GatekeeperUserOverride.File = switch es.file_type {
case ES_GATEKEEPER_USER_OVERRIDE_FILE_TYPE_FILE: .file(esFile(es.file.file))
case ES_GATEKEEPER_USER_OVERRIDE_FILE_TYPE_PATH: .path(esString(es.file.file_path))
default:
throw CommonError.invalidArgument(
arg: "es_gatekeeper_user_override_file_type_t",
invalidValue: es.file_type
)
}
return .init(
file: file,
sha256: es.sha256.flatMap { withUnsafeBytes(of: $0.pointee) { Data($0) } },
signing_info: es.signing_info.flatMap { esSignedFileInfo($0.pointee) }
)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -129,6 +129,26 @@ public struct ESThreadState: Equatable, Codable {
}
}

/// 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.
public struct ESSignedFileInfo: Equatable, Codable {
/// Code Directory Hash
public var cdHash: Data

/// Team Identifier, if available in the signing information.
public var teamID: String

/// Signing Identifier, if available in the signing information.
public var signingID: String

public init(cdHash: Data, teamID: String, signingID: String) {
self.cdHash = cdHash
self.teamID = teamID
self.signingID = signingID
}
}

public struct ESAuthResult: Equatable, Codable, RawRepresentable {
public static func auth(_ auth: Bool) -> ESAuthResult { .init(rawValue: auth ? .max : 0) }
public static func flags(_ flags: UInt32) -> ESAuthResult { .init(rawValue: flags) }
Expand Down Expand Up @@ -287,6 +307,7 @@ public enum ESEvent: Equatable, Codable {
case xpMalwareDetected(XPMalwareDetected)
case xpMalwareRemediated(XPMalwareRemediated)
case xpcConnect(XPCConnect)
case gatekeeperUserOverride(GatekeeperUserOverride)
}

public extension ESEvent {
Expand Down Expand Up @@ -1843,6 +1864,37 @@ public extension ESEvent {
self.serviceDomainType = serviceDomainType
}
}

/// Notification for a gatekeeper_user_override events.
///
/// - Note: This event type does not support caching (notify-only).
/// - Note: 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.
struct GatekeeperUserOverride: Equatable, Codable {
/// Describes the target file that is being overridden by the user
public var file: File

/// SHA256 of the file. Provided if the filesize is less than 100MB.
public var sha256: Data?

/// Signing Information, available if the file has been signed.
public var signing_info: ESSignedFileInfo?

/// The type of the file field.
/// If Endpoint security can't lookup the file at event submission
/// it will emit a path instead of an `es_file_t`.
public enum File: Equatable, Codable {
case path(String)
case file(ESFile)
}

public init(file: File, sha256: Data?, signing_info: ESSignedFileInfo?) {
self.file = file
self.sha256 = sha256
self.signing_info = signing_info
}
}
}

extension ESEvent.Create.Destination {
Expand Down

0 comments on commit ade1f45

Please sign in to comment.