endpoint_security 0.1.0-universal-darwin
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/.rubocop.yml +44 -0
- data/LICENSE.txt +21 -0
- data/README.md +114 -0
- data/Rakefile +170 -0
- data/codegen/ast.rb +67 -0
- data/codegen/emit_c.rb +68 -0
- data/codegen/emit_ruby.rb +128 -0
- data/codegen/ir.rb +193 -0
- data/codegen/overlay/availability.yml +158 -0
- data/codegen/overlay/version_map.yml +92 -0
- data/codegen/run.rb +80 -0
- data/codegen/snapshots/26.5.json +5828 -0
- data/examples/eslogger_clone.rb +5 -0
- data/examples/execblock.rb +16 -0
- data/examples/filemon.rb +10 -0
- data/examples/procmon.rb +13 -0
- data/ext/endpoint_security/client.c +795 -0
- data/ext/endpoint_security/client.h +88 -0
- data/ext/endpoint_security/endpoint_security.c +17 -0
- data/ext/endpoint_security/extconf.rb +37 -0
- data/ext/endpoint_security/field.c +719 -0
- data/ext/endpoint_security/field.h +42 -0
- data/ext/endpoint_security/generated/es_schema.c +1233 -0
- data/ext/endpoint_security/message.c +426 -0
- data/ext/endpoint_security/message.h +13 -0
- data/ext/endpoint_security/mute.c +291 -0
- data/ext/endpoint_security/mute.h +8 -0
- data/ext/endpoint_security/queue.c +124 -0
- data/ext/endpoint_security/queue.h +46 -0
- data/ext/endpoint_security/watchdog.c +243 -0
- data/lib/endpoint_security/availability.rb +30 -0
- data/lib/endpoint_security/client.rb +280 -0
- data/lib/endpoint_security/diagnostics.rb +26 -0
- data/lib/endpoint_security/doctor.rb +35 -0
- data/lib/endpoint_security/errors.rb +42 -0
- data/lib/endpoint_security/generated/availability.rb +169 -0
- data/lib/endpoint_security/generated/enums.rb +409 -0
- data/lib/endpoint_security/generated/event_types.rb +520 -0
- data/lib/endpoint_security/message.rb +29 -0
- data/lib/endpoint_security/object_model.rb +170 -0
- data/lib/endpoint_security/recorder.rb +26 -0
- data/lib/endpoint_security/version.rb +6 -0
- data/lib/endpoint_security.rb +38 -0
- data/support/entitlements.plist +8 -0
- data/support/esmock/esmock.c +482 -0
- data/support/esmock/esmock.h +21 -0
- data/support/sign_ruby.sh +13 -0
- metadata +90 -0
data/codegen/ir.rb
ADDED
|
@@ -0,0 +1,193 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module EndpointSecurity
|
|
4
|
+
module Codegen
|
|
5
|
+
Event = Data.define(:name, :symbol, :value, :minimum_os, :reserved)
|
|
6
|
+
EventTypes = Data.define(:events, :last)
|
|
7
|
+
Field = Data.define(:name, :type, :minimum_version)
|
|
8
|
+
Record = Data.define(:name, :fields)
|
|
9
|
+
EnumValue = Data.define(:name, :symbol, :value)
|
|
10
|
+
Enumeration = Data.define(:name, :values)
|
|
11
|
+
|
|
12
|
+
class IR
|
|
13
|
+
AVAILABILITY = /available beginning in macOS ([0-9]+(?:\.[0-9]+){1,2})/i
|
|
14
|
+
EVENT = /\b(ES_EVENT_TYPE_[A-Z0-9_]+)\b/
|
|
15
|
+
SCALAR_TYPES = [
|
|
16
|
+
"bool", "_Bool", "unsigned long long", "uint64_t", "long long", "int64_t", "unsigned long", "long",
|
|
17
|
+
"unsigned int", "uint32_t", "int", "int32_t", "unsigned short", "uint16_t", "short", "int16_t",
|
|
18
|
+
"unsigned char", "uint8_t", "signed char", "int8_t", "char", "es_string_token_t", "es_token_t",
|
|
19
|
+
"audit_token_t", "struct stat", "struct timespec", "struct timeval", "struct attrlist"
|
|
20
|
+
].freeze
|
|
21
|
+
POINTER_TYPES = ["struct statfs *", "struct _acl *", "es_sha256_t *", "audit_token_t *"].freeze
|
|
22
|
+
SPECIAL_FIELDS = %w[
|
|
23
|
+
es_token_t.data es_string_token_t.data es_muted_path_t.events es_muted_process_t.events
|
|
24
|
+
es_muted_paths_t.paths es_muted_processes_t.processes es_event_su_t.argv es_event_su_t.env
|
|
25
|
+
es_event_authorization_petition_t.rights es_event_authorization_judgement_t.results
|
|
26
|
+
es_event_od_attribute_set_t.attribute_values es_message_t.opaque es_message_t.action es_result_t.result
|
|
27
|
+
es_fd_t.pipe es_event_rename_t.destination es_event_create_t.destination es_event_authentication_t.data
|
|
28
|
+
es_event_authentication_touchid_t.uid es_event_openssh_login_t.uid es_event_login_login_t.uid
|
|
29
|
+
es_event_su_t.to_uid es_event_sudo_t.from_uid es_event_sudo_t.to_uid
|
|
30
|
+
es_event_gatekeeper_user_override_t.file es_event_setacl_t.acl es_od_member_id_t.member_value
|
|
31
|
+
es_od_member_id_array_t.member_array
|
|
32
|
+
].freeze
|
|
33
|
+
|
|
34
|
+
def self.event_types(ast:, source:)
|
|
35
|
+
availability = scan_availability(source)
|
|
36
|
+
value = -1
|
|
37
|
+
last = nil
|
|
38
|
+
entries = ast.enum_containing("ES_EVENT_TYPE_AUTH_EXEC").fetch("inner", []).filter_map do |node|
|
|
39
|
+
next unless node["kind"] == "EnumConstantDecl"
|
|
40
|
+
|
|
41
|
+
value = explicit_value(node) || (value + 1)
|
|
42
|
+
if node["name"] == "ES_EVENT_TYPE_LAST"
|
|
43
|
+
last = value
|
|
44
|
+
next
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
symbol = node["name"].delete_prefix("ES_EVENT_TYPE_").downcase.to_sym
|
|
48
|
+
Event.new(node["name"], symbol, value, availability.fetch(node["name"]), symbol.start_with?("reserved_"))
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
unless last == entries.length
|
|
52
|
+
raise CodegenError, "ES_EVENT_TYPE_LAST=#{last}, but #{entries.length} events were parsed"
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
EventTypes.new(entries.freeze, last)
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
def self.scan_availability(source)
|
|
59
|
+
first_event = source.index("ES_EVENT_TYPE_AUTH_EXEC")
|
|
60
|
+
raise CodegenError, "es_event_type_t was not found" unless first_event
|
|
61
|
+
|
|
62
|
+
source = source[source.rindex("typedef enum {", first_event)..]
|
|
63
|
+
current = nil
|
|
64
|
+
|
|
65
|
+
source.each_line.with_object({}) do |line, versions|
|
|
66
|
+
availability_match = line.match(AVAILABILITY)
|
|
67
|
+
current = availability_match[1] if availability_match
|
|
68
|
+
name = line[EVENT, 1]
|
|
69
|
+
versions[name] = current if name && name != "ES_EVENT_TYPE_LAST"
|
|
70
|
+
break versions if line.include?("} es_event_type_t;")
|
|
71
|
+
end
|
|
72
|
+
end
|
|
73
|
+
|
|
74
|
+
def self.explicit_value(node)
|
|
75
|
+
pending = node.fetch("inner", []).dup
|
|
76
|
+
until pending.empty?
|
|
77
|
+
child = pending.shift
|
|
78
|
+
return Integer(child["value"]) if child.key?("value")
|
|
79
|
+
|
|
80
|
+
pending.concat(child.fetch("inner", []))
|
|
81
|
+
end
|
|
82
|
+
nil
|
|
83
|
+
end
|
|
84
|
+
|
|
85
|
+
private_class_method :explicit_value
|
|
86
|
+
|
|
87
|
+
def self.records(ast:, version_sources:)
|
|
88
|
+
versions = scan_field_versions(version_sources)
|
|
89
|
+
ast.typedef_records.filter_map do |name, node|
|
|
90
|
+
direct = node.fetch("inner", []).select { |child| child["kind"] == "FieldDecl" && child["name"] }
|
|
91
|
+
indirect_fields = node.fetch("inner", []).select { |child| child["kind"] == "IndirectFieldDecl" }
|
|
92
|
+
indirect = indirect_fields.filter_map do |child|
|
|
93
|
+
recursive_field(node, child["name"])
|
|
94
|
+
end
|
|
95
|
+
fields = (direct + indirect).uniq { |field| field["name"] }.filter_map do |field|
|
|
96
|
+
next if field["name"].start_with?("reserved")
|
|
97
|
+
|
|
98
|
+
type = normalize_type(field.dig("type", "desugaredQualType") || field.dig("type", "qualType"))
|
|
99
|
+
minimum_version = versions.fetch([name, field["name"]], 1)
|
|
100
|
+
Field.new(field["name"], type, minimum_version)
|
|
101
|
+
end
|
|
102
|
+
Record.new(name, fields.freeze)
|
|
103
|
+
end.freeze
|
|
104
|
+
end
|
|
105
|
+
|
|
106
|
+
def self.enumerations(ast:)
|
|
107
|
+
ast.typedef_enums.map do |name, node|
|
|
108
|
+
value = -1
|
|
109
|
+
prefix = "#{name.delete_suffix("_t").upcase}_"
|
|
110
|
+
values = node.fetch("inner", []).filter_map do |entry|
|
|
111
|
+
next unless entry["kind"] == "EnumConstantDecl"
|
|
112
|
+
|
|
113
|
+
value = explicit_value(entry) || (value + 1)
|
|
114
|
+
symbol = entry.fetch("name").delete_prefix(prefix).delete_prefix("ES_").downcase.to_sym
|
|
115
|
+
EnumValue.new(entry.fetch("name"), symbol, value)
|
|
116
|
+
end
|
|
117
|
+
Enumeration.new(name, values.freeze) unless values.empty?
|
|
118
|
+
end.compact.freeze
|
|
119
|
+
end
|
|
120
|
+
|
|
121
|
+
def self.normalize_type(type)
|
|
122
|
+
type.gsub(/\((?:unnamed|anonymous) at .*?:\d+:\d+\)/, "(anonymous)")
|
|
123
|
+
end
|
|
124
|
+
|
|
125
|
+
def self.validate_field_types!(records:, enumerations:)
|
|
126
|
+
record_names = records.map(&:name)
|
|
127
|
+
enum_names = enumerations.map(&:name)
|
|
128
|
+
records.each do |record|
|
|
129
|
+
record.fields.each do |field|
|
|
130
|
+
next if supported_field_type?(record, field, record_names, enum_names)
|
|
131
|
+
|
|
132
|
+
raise CodegenError, "unsupported field type #{field.type} at #{record.name}.#{field.name}"
|
|
133
|
+
end
|
|
134
|
+
end
|
|
135
|
+
end
|
|
136
|
+
|
|
137
|
+
def self.scan_field_versions(sources)
|
|
138
|
+
sources.each_with_object({}) do |source, versions|
|
|
139
|
+
fields = nil
|
|
140
|
+
source.each_line do |line|
|
|
141
|
+
fields = {} if fields.nil? && line.match?(/\btypedef\s+struct(?:\s+[a-zA-Z_]\w*)?\s*\{/)
|
|
142
|
+
if fields && (match = line.match(
|
|
143
|
+
/\b([a-zA-Z_]\w*)\s*(?:\[[^\]]*\])?\s*;[^\n]*(?:message|msg)\s+versions?\s*>=\s*(\d+)/i
|
|
144
|
+
))
|
|
145
|
+
fields[match[1]] = Integer(match[2])
|
|
146
|
+
end
|
|
147
|
+
next unless fields && (record = line[/^\s*}\s*(es_[a-zA-Z0-9_]+_t)\s*;/, 1])
|
|
148
|
+
|
|
149
|
+
fields.each { |name, version| versions[[record, name]] = version }
|
|
150
|
+
fields = nil
|
|
151
|
+
end
|
|
152
|
+
end
|
|
153
|
+
end
|
|
154
|
+
|
|
155
|
+
def self.recursive_field(node, name)
|
|
156
|
+
pending = node.fetch("inner", []).dup
|
|
157
|
+
until pending.empty?
|
|
158
|
+
child = pending.shift
|
|
159
|
+
return child if child["kind"] == "FieldDecl" && child["name"] == name
|
|
160
|
+
|
|
161
|
+
pending.concat(child.fetch("inner", []))
|
|
162
|
+
end
|
|
163
|
+
nil
|
|
164
|
+
end
|
|
165
|
+
|
|
166
|
+
private_class_method :recursive_field
|
|
167
|
+
|
|
168
|
+
def self.supported_field_type?(record, field, record_names, enum_names)
|
|
169
|
+
type = field.type
|
|
170
|
+
return true if SPECIAL_FIELDS.include?("#{record.name}.#{field.name}")
|
|
171
|
+
return true if SCALAR_TYPES.include?(type) || enum_names.include?(type) || record_names.include?(type)
|
|
172
|
+
return true if type == "uint8_t[20]" || POINTER_TYPES.include?(type)
|
|
173
|
+
|
|
174
|
+
pointee = type.delete_prefix("const ").delete_suffix(" *")
|
|
175
|
+
type.end_with?(" *") && record_names.include?(pointee)
|
|
176
|
+
end
|
|
177
|
+
|
|
178
|
+
private_class_method :supported_field_type?
|
|
179
|
+
|
|
180
|
+
def self.cacheable_events(source, events)
|
|
181
|
+
cacheable_structs = source.to_enum(:scan, /}\s*(es_event_[a-zA-Z0-9_]+_t);/).filter_map do
|
|
182
|
+
match = Regexp.last_match
|
|
183
|
+
comment_start = source.rindex("/**", match.begin(0))
|
|
184
|
+
match[1] if comment_start && source[comment_start...match.begin(0)].include?("Cache key for this event type")
|
|
185
|
+
end
|
|
186
|
+
suffixes = cacheable_structs.map { |name| name.delete_prefix("es_event_").delete_suffix("_t") }
|
|
187
|
+
events.events.select do |event|
|
|
188
|
+
event.symbol.start_with?("auth_") && suffixes.include?(event.symbol.to_s.delete_prefix("auth_"))
|
|
189
|
+
end.map(&:symbol)
|
|
190
|
+
end
|
|
191
|
+
end
|
|
192
|
+
end
|
|
193
|
+
end
|
|
@@ -0,0 +1,158 @@
|
|
|
1
|
+
---
|
|
2
|
+
auth_exec: '10.15'
|
|
3
|
+
auth_open: '10.15'
|
|
4
|
+
auth_kextload: '10.15'
|
|
5
|
+
auth_mmap: '10.15'
|
|
6
|
+
auth_mprotect: '10.15'
|
|
7
|
+
auth_mount: '10.15'
|
|
8
|
+
auth_rename: '10.15'
|
|
9
|
+
auth_signal: '10.15'
|
|
10
|
+
auth_unlink: '10.15'
|
|
11
|
+
notify_exec: '10.15'
|
|
12
|
+
notify_open: '10.15'
|
|
13
|
+
notify_fork: '10.15'
|
|
14
|
+
notify_close: '10.15'
|
|
15
|
+
notify_create: '10.15'
|
|
16
|
+
notify_exchangedata: '10.15'
|
|
17
|
+
notify_exit: '10.15'
|
|
18
|
+
notify_get_task: '10.15'
|
|
19
|
+
notify_kextload: '10.15'
|
|
20
|
+
notify_kextunload: '10.15'
|
|
21
|
+
notify_link: '10.15'
|
|
22
|
+
notify_mmap: '10.15'
|
|
23
|
+
notify_mprotect: '10.15'
|
|
24
|
+
notify_mount: '10.15'
|
|
25
|
+
notify_unmount: '10.15'
|
|
26
|
+
notify_iokit_open: '10.15'
|
|
27
|
+
notify_rename: '10.15'
|
|
28
|
+
notify_setattrlist: '10.15'
|
|
29
|
+
notify_setextattr: '10.15'
|
|
30
|
+
notify_setflags: '10.15'
|
|
31
|
+
notify_setmode: '10.15'
|
|
32
|
+
notify_setowner: '10.15'
|
|
33
|
+
notify_signal: '10.15'
|
|
34
|
+
notify_unlink: '10.15'
|
|
35
|
+
notify_write: '10.15'
|
|
36
|
+
auth_file_provider_materialize: '10.15'
|
|
37
|
+
notify_file_provider_materialize: '10.15'
|
|
38
|
+
auth_file_provider_update: '10.15'
|
|
39
|
+
notify_file_provider_update: '10.15'
|
|
40
|
+
auth_readlink: '10.15'
|
|
41
|
+
notify_readlink: '10.15'
|
|
42
|
+
auth_truncate: '10.15'
|
|
43
|
+
notify_truncate: '10.15'
|
|
44
|
+
auth_link: '10.15'
|
|
45
|
+
notify_lookup: '10.15'
|
|
46
|
+
auth_create: '10.15'
|
|
47
|
+
auth_setattrlist: '10.15'
|
|
48
|
+
auth_setextattr: '10.15'
|
|
49
|
+
auth_setflags: '10.15'
|
|
50
|
+
auth_setmode: '10.15'
|
|
51
|
+
auth_setowner: '10.15'
|
|
52
|
+
auth_chdir: 10.15.1
|
|
53
|
+
notify_chdir: 10.15.1
|
|
54
|
+
auth_getattrlist: 10.15.1
|
|
55
|
+
notify_getattrlist: 10.15.1
|
|
56
|
+
notify_stat: 10.15.1
|
|
57
|
+
notify_access: 10.15.1
|
|
58
|
+
auth_chroot: 10.15.1
|
|
59
|
+
notify_chroot: 10.15.1
|
|
60
|
+
auth_utimes: 10.15.1
|
|
61
|
+
notify_utimes: 10.15.1
|
|
62
|
+
auth_clone: 10.15.1
|
|
63
|
+
notify_clone: 10.15.1
|
|
64
|
+
notify_fcntl: 10.15.1
|
|
65
|
+
auth_getextattr: 10.15.1
|
|
66
|
+
notify_getextattr: 10.15.1
|
|
67
|
+
auth_listextattr: 10.15.1
|
|
68
|
+
notify_listextattr: 10.15.1
|
|
69
|
+
auth_readdir: 10.15.1
|
|
70
|
+
notify_readdir: 10.15.1
|
|
71
|
+
auth_deleteextattr: 10.15.1
|
|
72
|
+
notify_deleteextattr: 10.15.1
|
|
73
|
+
auth_fsgetpath: 10.15.1
|
|
74
|
+
notify_fsgetpath: 10.15.1
|
|
75
|
+
notify_dup: 10.15.1
|
|
76
|
+
auth_settime: 10.15.1
|
|
77
|
+
notify_settime: 10.15.1
|
|
78
|
+
notify_uipc_bind: 10.15.1
|
|
79
|
+
auth_uipc_bind: 10.15.1
|
|
80
|
+
notify_uipc_connect: 10.15.1
|
|
81
|
+
auth_uipc_connect: 10.15.1
|
|
82
|
+
auth_exchangedata: 10.15.1
|
|
83
|
+
auth_setacl: 10.15.1
|
|
84
|
+
notify_setacl: 10.15.1
|
|
85
|
+
notify_pty_grant: 10.15.4
|
|
86
|
+
notify_pty_close: 10.15.4
|
|
87
|
+
auth_proc_check: 10.15.4
|
|
88
|
+
notify_proc_check: 10.15.4
|
|
89
|
+
auth_get_task: 10.15.4
|
|
90
|
+
auth_searchfs: '11.0'
|
|
91
|
+
notify_searchfs: '11.0'
|
|
92
|
+
auth_fcntl: '11.0'
|
|
93
|
+
auth_iokit_open: '11.0'
|
|
94
|
+
auth_proc_suspend_resume: '11.0'
|
|
95
|
+
notify_proc_suspend_resume: '11.0'
|
|
96
|
+
notify_cs_invalidated: '11.0'
|
|
97
|
+
notify_get_task_name: '11.0'
|
|
98
|
+
notify_trace: '11.0'
|
|
99
|
+
notify_remote_thread_create: '11.0'
|
|
100
|
+
auth_remount: '11.0'
|
|
101
|
+
notify_remount: '11.0'
|
|
102
|
+
auth_get_task_read: '11.3'
|
|
103
|
+
notify_get_task_read: '11.3'
|
|
104
|
+
notify_get_task_inspect: '11.3'
|
|
105
|
+
notify_setuid: '12.0'
|
|
106
|
+
notify_setgid: '12.0'
|
|
107
|
+
notify_seteuid: '12.0'
|
|
108
|
+
notify_setegid: '12.0'
|
|
109
|
+
notify_setreuid: '12.0'
|
|
110
|
+
notify_setregid: '12.0'
|
|
111
|
+
auth_copyfile: '12.0'
|
|
112
|
+
notify_copyfile: '12.0'
|
|
113
|
+
notify_authentication: '13.0'
|
|
114
|
+
notify_xp_malware_detected: '13.0'
|
|
115
|
+
notify_xp_malware_remediated: '13.0'
|
|
116
|
+
notify_lw_session_login: '13.0'
|
|
117
|
+
notify_lw_session_logout: '13.0'
|
|
118
|
+
notify_lw_session_lock: '13.0'
|
|
119
|
+
notify_lw_session_unlock: '13.0'
|
|
120
|
+
notify_screensharing_attach: '13.0'
|
|
121
|
+
notify_screensharing_detach: '13.0'
|
|
122
|
+
notify_openssh_login: '13.0'
|
|
123
|
+
notify_openssh_logout: '13.0'
|
|
124
|
+
notify_login_login: '13.0'
|
|
125
|
+
notify_login_logout: '13.0'
|
|
126
|
+
notify_btm_launch_item_add: '13.0'
|
|
127
|
+
notify_btm_launch_item_remove: '13.0'
|
|
128
|
+
notify_profile_add: '14.0'
|
|
129
|
+
notify_profile_remove: '14.0'
|
|
130
|
+
notify_su: '14.0'
|
|
131
|
+
notify_authorization_petition: '14.0'
|
|
132
|
+
notify_authorization_judgement: '14.0'
|
|
133
|
+
notify_sudo: '14.0'
|
|
134
|
+
notify_od_group_add: '14.0'
|
|
135
|
+
notify_od_group_remove: '14.0'
|
|
136
|
+
notify_od_group_set: '14.0'
|
|
137
|
+
notify_od_modify_password: '14.0'
|
|
138
|
+
notify_od_disable_user: '14.0'
|
|
139
|
+
notify_od_enable_user: '14.0'
|
|
140
|
+
notify_od_attribute_value_add: '14.0'
|
|
141
|
+
notify_od_attribute_value_remove: '14.0'
|
|
142
|
+
notify_od_attribute_set: '14.0'
|
|
143
|
+
notify_od_create_user: '14.0'
|
|
144
|
+
notify_od_create_group: '14.0'
|
|
145
|
+
notify_od_delete_user: '14.0'
|
|
146
|
+
notify_od_delete_group: '14.0'
|
|
147
|
+
notify_xpc_connect: '14.0'
|
|
148
|
+
notify_gatekeeper_user_override: '15.0'
|
|
149
|
+
notify_tcc_modify: '15.4'
|
|
150
|
+
reserved_0: '26.3'
|
|
151
|
+
reserved_1: '26.3'
|
|
152
|
+
reserved_2: '26.3'
|
|
153
|
+
reserved_3: 26.4.0
|
|
154
|
+
reserved_4: 26.4.0
|
|
155
|
+
reserved_5: 26.4.0
|
|
156
|
+
reserved_6: 26.4.0
|
|
157
|
+
reserved_7: '26.5'
|
|
158
|
+
reserved_8: '26.5'
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
---
|
|
2
|
+
es_process_t:
|
|
3
|
+
tty: 2
|
|
4
|
+
start_time: 3
|
|
5
|
+
responsible_audit_token: 4
|
|
6
|
+
parent_audit_token: 4
|
|
7
|
+
cs_validation_category: 10
|
|
8
|
+
es_event_exec_t:
|
|
9
|
+
dyld_exec_path: 7
|
|
10
|
+
script: 2
|
|
11
|
+
cwd: 3
|
|
12
|
+
last_fd: 4
|
|
13
|
+
image_cputype: 6
|
|
14
|
+
image_cpusubtype: 6
|
|
15
|
+
es_event_mount_t:
|
|
16
|
+
disposition: 8
|
|
17
|
+
es_event_remount_t:
|
|
18
|
+
remount_flags: 8
|
|
19
|
+
disposition: 8
|
|
20
|
+
es_event_signal_t:
|
|
21
|
+
instigator: 9
|
|
22
|
+
es_event_close_t:
|
|
23
|
+
was_mapped_writable: 6
|
|
24
|
+
es_event_create_t:
|
|
25
|
+
acl: 2
|
|
26
|
+
es_event_iokit_open_t:
|
|
27
|
+
parent_registry_id: 10
|
|
28
|
+
parent_path: 10
|
|
29
|
+
es_event_get_task_t:
|
|
30
|
+
type: 5
|
|
31
|
+
es_event_get_task_read_t:
|
|
32
|
+
type: 5
|
|
33
|
+
es_event_get_task_inspect_t:
|
|
34
|
+
type: 5
|
|
35
|
+
es_event_get_task_name_t:
|
|
36
|
+
type: 5
|
|
37
|
+
es_event_file_provider_materialize_t:
|
|
38
|
+
instigator_token: 8
|
|
39
|
+
es_event_authentication_od_t:
|
|
40
|
+
instigator_token: 8
|
|
41
|
+
es_event_authentication_touchid_t:
|
|
42
|
+
instigator_token: 8
|
|
43
|
+
es_event_authentication_token_t:
|
|
44
|
+
instigator_token: 8
|
|
45
|
+
es_event_xp_malware_detected_t:
|
|
46
|
+
detected_executable: 10
|
|
47
|
+
es_event_btm_launch_item_add_t:
|
|
48
|
+
instigator_token: 8
|
|
49
|
+
app_token: 8
|
|
50
|
+
es_event_btm_launch_item_remove_t:
|
|
51
|
+
instigator_token: 8
|
|
52
|
+
app_token: 8
|
|
53
|
+
es_event_profile_add_t:
|
|
54
|
+
instigator_token: 8
|
|
55
|
+
es_event_profile_remove_t:
|
|
56
|
+
instigator_token: 8
|
|
57
|
+
es_event_authorization_petition_t:
|
|
58
|
+
instigator_token: 8
|
|
59
|
+
petitioner_token: 8
|
|
60
|
+
es_event_authorization_judgement_t:
|
|
61
|
+
instigator_token: 8
|
|
62
|
+
petitioner_token: 8
|
|
63
|
+
es_event_od_group_add_t:
|
|
64
|
+
instigator_token: 8
|
|
65
|
+
es_event_od_group_remove_t:
|
|
66
|
+
instigator_token: 8
|
|
67
|
+
es_event_od_group_set_t:
|
|
68
|
+
instigator_token: 8
|
|
69
|
+
es_event_od_modify_password_t:
|
|
70
|
+
instigator_token: 8
|
|
71
|
+
es_event_od_disable_user_t:
|
|
72
|
+
instigator_token: 8
|
|
73
|
+
es_event_od_enable_user_t:
|
|
74
|
+
instigator_token: 8
|
|
75
|
+
es_event_od_attribute_value_add_t:
|
|
76
|
+
instigator_token: 8
|
|
77
|
+
es_event_od_attribute_value_remove_t:
|
|
78
|
+
instigator_token: 8
|
|
79
|
+
es_event_od_attribute_set_t:
|
|
80
|
+
instigator_token: 8
|
|
81
|
+
es_event_od_create_user_t:
|
|
82
|
+
instigator_token: 8
|
|
83
|
+
es_event_od_create_group_t:
|
|
84
|
+
instigator_token: 8
|
|
85
|
+
es_event_od_delete_user_t:
|
|
86
|
+
instigator_token: 8
|
|
87
|
+
es_event_od_delete_group_t:
|
|
88
|
+
instigator_token: 8
|
|
89
|
+
es_message_t:
|
|
90
|
+
seq_num: 2
|
|
91
|
+
thread: 4
|
|
92
|
+
global_seq_num: 4
|
data/codegen/run.rb
ADDED
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "fileutils"
|
|
4
|
+
require "json"
|
|
5
|
+
require "open3"
|
|
6
|
+
require "yaml"
|
|
7
|
+
require_relative "../lib/endpoint_security/errors"
|
|
8
|
+
require_relative "ast"
|
|
9
|
+
require_relative "ir"
|
|
10
|
+
require_relative "emit_ruby"
|
|
11
|
+
require_relative "emit_c"
|
|
12
|
+
|
|
13
|
+
module EndpointSecurity
|
|
14
|
+
module Codegen
|
|
15
|
+
module Run
|
|
16
|
+
module_function
|
|
17
|
+
|
|
18
|
+
def call
|
|
19
|
+
sdk = capture("xcrun", "--show-sdk-path")
|
|
20
|
+
version = capture("xcrun", "--show-sdk-version")
|
|
21
|
+
header = File.join(sdk, "usr/include/EndpointSecurity/ESTypes.h")
|
|
22
|
+
source = File.read(header)
|
|
23
|
+
ir = IR.event_types(ast: AST.load(header: header, sdk: sdk), source: source)
|
|
24
|
+
umbrella = File.join(sdk, "usr/include/EndpointSecurity/EndpointSecurity.h")
|
|
25
|
+
schema_ast = AST.load(header: umbrella, sdk: sdk)
|
|
26
|
+
message_sources = %w[ESMessage.h ESMessageCore.h].map do |name|
|
|
27
|
+
File.read(File.join(sdk, "usr/include/EndpointSecurity", name))
|
|
28
|
+
end
|
|
29
|
+
records = IR.records(ast: schema_ast, version_sources: message_sources)
|
|
30
|
+
enumerations = IR.enumerations(ast: schema_ast)
|
|
31
|
+
IR.validate_field_types!(records: records, enumerations: enumerations)
|
|
32
|
+
emitter = EmitRuby.new(
|
|
33
|
+
ir, cacheable: IR.cacheable_events(message_sources.first, ir), enumerations: enumerations
|
|
34
|
+
)
|
|
35
|
+
|
|
36
|
+
write("lib/endpoint_security/generated/event_types.rb", emitter.event_types)
|
|
37
|
+
write("lib/endpoint_security/generated/enums.rb", emitter.enums)
|
|
38
|
+
write("lib/endpoint_security/generated/availability.rb", emitter.availability)
|
|
39
|
+
write("ext/endpoint_security/generated/es_schema.c", EmitC.new(records, ir).schema)
|
|
40
|
+
availability = ir.events.to_h { |event| [event.symbol.to_s, event.minimum_os] }
|
|
41
|
+
write("codegen/overlay/availability.yml", YAML.dump(availability))
|
|
42
|
+
write("codegen/overlay/version_map.yml", YAML.dump(version_map(records)))
|
|
43
|
+
snapshot_json = JSON.pretty_generate(snapshot(version, ir, records, enumerations)) << "\n"
|
|
44
|
+
write("codegen/snapshots/#{version}.json", snapshot_json)
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
def capture(*command)
|
|
48
|
+
output, status = Open3.capture2(*command)
|
|
49
|
+
raise CodegenError, "#{command.join(" ")} failed" unless status.success?
|
|
50
|
+
|
|
51
|
+
output.strip
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
def write(path, content)
|
|
55
|
+
FileUtils.mkdir_p(File.dirname(path))
|
|
56
|
+
File.write(path, content) unless File.exist?(path) && File.binread(path) == content
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
def version_map(records)
|
|
60
|
+
versions = records.to_h do |record|
|
|
61
|
+
fields = record.fields.select { |field| field.minimum_version > 1 }
|
|
62
|
+
[record.name, fields.to_h { |field| [field.name, field.minimum_version] }]
|
|
63
|
+
end
|
|
64
|
+
versions.reject { |_record, fields| fields.empty? }
|
|
65
|
+
end
|
|
66
|
+
|
|
67
|
+
def snapshot(version, event_types_ir, records, enumerations)
|
|
68
|
+
{
|
|
69
|
+
sdk_version: version,
|
|
70
|
+
last: event_types_ir.last,
|
|
71
|
+
events: event_types_ir.events.map(&:to_h),
|
|
72
|
+
records: records.to_h { |record| [record.name, record.fields.map(&:to_h)] },
|
|
73
|
+
enumerations: enumerations.to_h { |enumeration| [enumeration.name, enumeration.values.map(&:to_h)] }
|
|
74
|
+
}
|
|
75
|
+
end
|
|
76
|
+
end
|
|
77
|
+
end
|
|
78
|
+
end
|
|
79
|
+
|
|
80
|
+
EndpointSecurity::Codegen::Run.call if $PROGRAM_NAME == __FILE__
|