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.
Files changed (49) hide show
  1. checksums.yaml +7 -0
  2. data/.rubocop.yml +44 -0
  3. data/LICENSE.txt +21 -0
  4. data/README.md +114 -0
  5. data/Rakefile +170 -0
  6. data/codegen/ast.rb +67 -0
  7. data/codegen/emit_c.rb +68 -0
  8. data/codegen/emit_ruby.rb +128 -0
  9. data/codegen/ir.rb +193 -0
  10. data/codegen/overlay/availability.yml +158 -0
  11. data/codegen/overlay/version_map.yml +92 -0
  12. data/codegen/run.rb +80 -0
  13. data/codegen/snapshots/26.5.json +5828 -0
  14. data/examples/eslogger_clone.rb +5 -0
  15. data/examples/execblock.rb +16 -0
  16. data/examples/filemon.rb +10 -0
  17. data/examples/procmon.rb +13 -0
  18. data/ext/endpoint_security/client.c +795 -0
  19. data/ext/endpoint_security/client.h +88 -0
  20. data/ext/endpoint_security/endpoint_security.c +17 -0
  21. data/ext/endpoint_security/extconf.rb +37 -0
  22. data/ext/endpoint_security/field.c +719 -0
  23. data/ext/endpoint_security/field.h +42 -0
  24. data/ext/endpoint_security/generated/es_schema.c +1233 -0
  25. data/ext/endpoint_security/message.c +426 -0
  26. data/ext/endpoint_security/message.h +13 -0
  27. data/ext/endpoint_security/mute.c +291 -0
  28. data/ext/endpoint_security/mute.h +8 -0
  29. data/ext/endpoint_security/queue.c +124 -0
  30. data/ext/endpoint_security/queue.h +46 -0
  31. data/ext/endpoint_security/watchdog.c +243 -0
  32. data/lib/endpoint_security/availability.rb +30 -0
  33. data/lib/endpoint_security/client.rb +280 -0
  34. data/lib/endpoint_security/diagnostics.rb +26 -0
  35. data/lib/endpoint_security/doctor.rb +35 -0
  36. data/lib/endpoint_security/errors.rb +42 -0
  37. data/lib/endpoint_security/generated/availability.rb +169 -0
  38. data/lib/endpoint_security/generated/enums.rb +409 -0
  39. data/lib/endpoint_security/generated/event_types.rb +520 -0
  40. data/lib/endpoint_security/message.rb +29 -0
  41. data/lib/endpoint_security/object_model.rb +170 -0
  42. data/lib/endpoint_security/recorder.rb +26 -0
  43. data/lib/endpoint_security/version.rb +6 -0
  44. data/lib/endpoint_security.rb +38 -0
  45. data/support/entitlements.plist +8 -0
  46. data/support/esmock/esmock.c +482 -0
  47. data/support/esmock/esmock.h +21 -0
  48. data/support/sign_ruby.sh +13 -0
  49. metadata +90 -0
@@ -0,0 +1,426 @@
1
+ /* message.c
2
+ * Calling thread: Ruby dispatcher with the GVL.
3
+ */
4
+ #include "message.h"
5
+
6
+ #include <mach/mach_time.h>
7
+ #include <unistd.h>
8
+
9
+ #include "field.h"
10
+
11
+ typedef struct {
12
+ VALUE owner;
13
+ esrb_client_t *client;
14
+ esrb_slot_t *slot;
15
+ bool valid;
16
+ bool held;
17
+ } esrb_message_t;
18
+
19
+ static VALUE c_message;
20
+
21
+ static bool
22
+ message_owned_here(const esrb_message_t *message)
23
+ {
24
+ return message->client->owner_pid == getpid();
25
+ }
26
+
27
+ static void
28
+ message_mark(void *pointer)
29
+ {
30
+ esrb_message_t *message = pointer;
31
+ rb_gc_mark(message->owner);
32
+ }
33
+
34
+ static void
35
+ message_release(esrb_message_t *message)
36
+ {
37
+ if (!message->valid) {
38
+ return;
39
+ }
40
+ if (!message_owned_here(message)) {
41
+ message->valid = false;
42
+ return;
43
+ }
44
+ uint32_t flags = message->client->default_auth == ES_AUTH_RESULT_ALLOW ? UINT32_MAX : 0;
45
+ esrb_respond_slot(
46
+ message->client, message->slot, message->client->default_auth, flags, message->client->default_cache, NULL);
47
+ esrb_queue_disarm(message->slot);
48
+ es_release_message(message->slot->message);
49
+ esrb_queue_release(&message->client->queue, message->slot);
50
+ message->valid = false;
51
+ }
52
+
53
+ static void
54
+ message_free(void *pointer)
55
+ {
56
+ esrb_message_t *message = pointer;
57
+ if (message->valid && message->held && message_owned_here(message)) {
58
+ atomic_fetch_add_explicit(&message->client->leaked_messages, 1, memory_order_relaxed);
59
+ }
60
+ message_release(message);
61
+ xfree(message);
62
+ }
63
+
64
+ static size_t
65
+ message_size(const void *pointer)
66
+ {
67
+ return pointer == NULL ? 0 : sizeof(esrb_message_t);
68
+ }
69
+
70
+ static const rb_data_type_t message_type = {
71
+ .wrap_struct_name = "EndpointSecurity::Message",
72
+ .function = {.dmark = message_mark, .dfree = message_free, .dsize = message_size},
73
+ .flags = RUBY_TYPED_FREE_IMMEDIATELY
74
+ };
75
+
76
+ static esrb_message_t *
77
+ get_message(VALUE self)
78
+ {
79
+ esrb_message_t *message;
80
+ TypedData_Get_Struct(self, esrb_message_t, &message_type, message);
81
+ if (!message_owned_here(message)) {
82
+ rb_raise(rb_path2class("EndpointSecurity::ForkedClientError"), "Endpoint Security messages cannot be used after fork");
83
+ }
84
+ if (!message->valid) {
85
+ rb_raise(rb_path2class("EndpointSecurity::MessageInvalidatedError"), "message has been released");
86
+ }
87
+ return message;
88
+ }
89
+
90
+ static VALUE
91
+ message_version(VALUE self)
92
+ {
93
+ return UINT2NUM(get_message(self)->slot->message->version);
94
+ }
95
+
96
+ static VALUE
97
+ message_event_type(VALUE self)
98
+ {
99
+ es_event_type_t event = get_message(self)->slot->message->event_type;
100
+ VALUE event_type = rb_path2class("EndpointSecurity::EventType");
101
+ return rb_funcall(event_type, rb_intern("symbol"), 1, INT2NUM(event));
102
+ }
103
+
104
+ static VALUE
105
+ message_action_type(VALUE self)
106
+ {
107
+ es_action_type_t action = get_message(self)->slot->message->action_type;
108
+ if (action == ES_ACTION_TYPE_AUTH) {
109
+ return ID2SYM(rb_intern("auth"));
110
+ }
111
+ if (action == ES_ACTION_TYPE_NOTIFY) {
112
+ return ID2SYM(rb_intern("notify"));
113
+ }
114
+ return INT2NUM(action);
115
+ }
116
+
117
+ static VALUE
118
+ message_auth_p(VALUE self)
119
+ {
120
+ return get_message(self)->slot->message->action_type == ES_ACTION_TYPE_AUTH ? Qtrue : Qfalse;
121
+ }
122
+
123
+ static VALUE
124
+ message_deadline(VALUE self)
125
+ {
126
+ return ULL2NUM(get_message(self)->slot->message->deadline);
127
+ }
128
+
129
+ static VALUE
130
+ message_mach_time(VALUE self)
131
+ {
132
+ return ULL2NUM(get_message(self)->slot->message->mach_time);
133
+ }
134
+
135
+ static VALUE
136
+ message_seq_num(VALUE self)
137
+ {
138
+ const es_message_t *message = get_message(self)->slot->message;
139
+ return message->version >= 2 ? ULL2NUM(message->seq_num) : Qnil;
140
+ }
141
+
142
+ static VALUE
143
+ message_global_seq_num(VALUE self)
144
+ {
145
+ const es_message_t *message = get_message(self)->slot->message;
146
+ return message->version >= 4 ? ULL2NUM(message->global_seq_num) : Qnil;
147
+ }
148
+
149
+ static VALUE
150
+ message_time(VALUE self)
151
+ {
152
+ const es_message_t *message = get_message(self)->slot->message;
153
+ return rb_time_nano_new(message->time.tv_sec, message->time.tv_nsec);
154
+ }
155
+
156
+ static VALUE
157
+ message_process(VALUE self)
158
+ {
159
+ esrb_message_t *wrapper = get_message(self);
160
+ const es_message_t *message = wrapper->slot->message;
161
+ return esrb_view_wrap(self, message->process, "es_process_t", message->version, wrapper->client->strict_version);
162
+ }
163
+
164
+ static VALUE
165
+ message_thread(VALUE self)
166
+ {
167
+ esrb_message_t *wrapper = get_message(self);
168
+ const es_message_t *message = wrapper->slot->message;
169
+ return message->version >= 4
170
+ ? esrb_view_wrap(self, message->thread, "es_thread_t", message->version, wrapper->client->strict_version)
171
+ : Qnil;
172
+ }
173
+
174
+ static VALUE
175
+ message_event(VALUE self)
176
+ {
177
+ esrb_message_t *wrapper = get_message(self);
178
+ return esrb_event_wrap(self, wrapper->slot->message, wrapper->client->strict_version);
179
+ }
180
+
181
+ static VALUE
182
+ message_result(VALUE self)
183
+ {
184
+ const es_message_t *message = get_message(self)->slot->message;
185
+ if (message->action_type == ES_ACTION_TYPE_AUTH) {
186
+ return Qnil;
187
+ }
188
+ if (message->action_type != ES_ACTION_TYPE_NOTIFY) {
189
+ return Qnil;
190
+ }
191
+ switch (message->action.notify.result_type) {
192
+ case ES_RESULT_TYPE_FLAGS:
193
+ return UINT2NUM(message->action.notify.result.flags);
194
+ case ES_RESULT_TYPE_AUTH:
195
+ if (message->action.notify.result.auth == ES_AUTH_RESULT_ALLOW) {
196
+ return ID2SYM(rb_intern("allow"));
197
+ }
198
+ if (message->action.notify.result.auth == ES_AUTH_RESULT_DENY) {
199
+ return ID2SYM(rb_intern("deny"));
200
+ }
201
+ return INT2NUM(message->action.notify.result.auth);
202
+ default:
203
+ return INT2NUM(message->action.notify.result_type);
204
+ }
205
+ }
206
+
207
+ static VALUE
208
+ message_raw_pointer(VALUE self)
209
+ {
210
+ return ULL2NUM((uintptr_t)get_message(self)->slot->message);
211
+ }
212
+
213
+ static VALUE
214
+ message_raw_event_bytes(VALUE self)
215
+ {
216
+ const es_message_t *message = get_message(self)->slot->message;
217
+ return rb_str_new((const char *)&message->event, sizeof(message->event));
218
+ }
219
+
220
+ static VALUE
221
+ message_time_left(VALUE self)
222
+ {
223
+ esrb_message_t *message = get_message(self);
224
+ uint64_t now = mach_absolute_time();
225
+ uint64_t deadline = message->slot->message->deadline;
226
+ if (deadline <= now) {
227
+ return DBL2NUM(0.0);
228
+ }
229
+ mach_timebase_info_data_t info;
230
+ mach_timebase_info(&info);
231
+ double seconds = (double)(deadline - now) * (double)info.numer / (double)info.denom / 1000000000.0;
232
+ return DBL2NUM(seconds);
233
+ }
234
+
235
+ static VALUE
236
+ message_answered_p(VALUE self)
237
+ {
238
+ esrb_message_t *message = get_message(self);
239
+ return atomic_load_explicit(&message->slot->answer_state, memory_order_acquire) == ESRB_ANSWER_ANSWERED ? Qtrue : Qfalse;
240
+ }
241
+
242
+ static VALUE
243
+ respond_slot(esrb_message_t *message, es_auth_result_t result, uint32_t flags, bool cache)
244
+ {
245
+ es_respond_result_t response = ES_RESPOND_RESULT_SUCCESS;
246
+ bool sent = esrb_respond_slot(message->client, message->slot, result, flags, cache, &response);
247
+ if (response != ES_RESPOND_RESULT_SUCCESS) {
248
+ rb_raise(rb_path2class("EndpointSecurity::MessageError"), "Endpoint Security response failed (%d)", response);
249
+ }
250
+ return sent ? Qtrue : Qfalse;
251
+ }
252
+
253
+ static VALUE
254
+ respond_auth(int argc, VALUE *argv, VALUE self, es_auth_result_t result)
255
+ {
256
+ VALUE options;
257
+ rb_scan_args(argc, argv, "0:", &options);
258
+ bool cache = true;
259
+ if (!NIL_P(options)) {
260
+ VALUE cache_value = rb_hash_aref(options, ID2SYM(rb_intern("cache")));
261
+ cache = NIL_P(cache_value) || RTEST(cache_value);
262
+ }
263
+ esrb_message_t *message = get_message(self);
264
+ if (message->slot->message->action_type != ES_ACTION_TYPE_AUTH) {
265
+ rb_raise(rb_path2class("EndpointSecurity::MessageError"), "authorization responses require an AUTH event");
266
+ }
267
+ if (cache) {
268
+ VALUE event_type = rb_path2class("EndpointSecurity::EventType");
269
+ VALUE event = rb_funcall(event_type, rb_intern("symbol"), 1, INT2NUM(message->slot->message->event_type));
270
+ if (!RTEST(rb_funcall(event_type, rb_intern("cacheable?"), 1, event))) {
271
+ if (message->client->strict_cache) {
272
+ rb_raise(rb_path2class("EndpointSecurity::NonCacheableEventError"), "event cannot be cached");
273
+ }
274
+ rb_warn("Endpoint Security event cannot be cached; using cache: false");
275
+ cache = false;
276
+ }
277
+ }
278
+ uint32_t flags = result == ES_AUTH_RESULT_ALLOW ? UINT32_MAX : 0;
279
+ return respond_slot(message, result, flags, cache);
280
+ }
281
+
282
+ static VALUE
283
+ message_allow(int argc, VALUE *argv, VALUE self)
284
+ {
285
+ return respond_auth(argc, argv, self, ES_AUTH_RESULT_ALLOW);
286
+ }
287
+
288
+ static VALUE
289
+ message_deny(int argc, VALUE *argv, VALUE self)
290
+ {
291
+ return respond_auth(argc, argv, self, ES_AUTH_RESULT_DENY);
292
+ }
293
+
294
+ static VALUE
295
+ message_respond(int argc, VALUE *argv, VALUE self)
296
+ {
297
+ VALUE options;
298
+ rb_scan_args(argc, argv, "0:", &options);
299
+ VALUE flags = rb_hash_fetch(options, ID2SYM(rb_intern("flags")));
300
+ VALUE cache_value = rb_hash_aref(options, ID2SYM(rb_intern("cache")));
301
+ bool cache = NIL_P(cache_value) || RTEST(cache_value);
302
+ esrb_message_t *message = get_message(self);
303
+ if (message->slot->message->action_type != ES_ACTION_TYPE_AUTH ||
304
+ message->slot->message->event_type != ES_EVENT_TYPE_AUTH_OPEN) {
305
+ rb_raise(rb_path2class("EndpointSecurity::MessageError"), "flags responses are only valid for AUTH_OPEN");
306
+ }
307
+ return respond_slot(message, ES_AUTH_RESULT_ALLOW, NUM2UINT(flags), cache);
308
+ }
309
+
310
+ static VALUE
311
+ message_respond_default(VALUE self)
312
+ {
313
+ esrb_message_t *message = get_message(self);
314
+ uint32_t flags = message->client->default_auth == ES_AUTH_RESULT_ALLOW ? UINT32_MAX : 0;
315
+ return esrb_respond_slot(
316
+ message->client, message->slot, message->client->default_auth, flags, message->client->default_cache, NULL)
317
+ ? Qtrue
318
+ : Qfalse;
319
+ }
320
+
321
+ static VALUE
322
+ message_retain(VALUE self)
323
+ {
324
+ get_message(self)->held = true;
325
+ return self;
326
+ }
327
+
328
+ static VALUE
329
+ message_release_bang(VALUE self)
330
+ {
331
+ esrb_message_t *message;
332
+ TypedData_Get_Struct(self, esrb_message_t, &message_type, message);
333
+ if (!message_owned_here(message)) {
334
+ rb_raise(rb_path2class("EndpointSecurity::ForkedClientError"), "Endpoint Security messages cannot be used after fork");
335
+ }
336
+ message_release(message);
337
+ return Qnil;
338
+ }
339
+
340
+ static VALUE
341
+ message_auto_release(VALUE self)
342
+ {
343
+ esrb_message_t *message;
344
+ TypedData_Get_Struct(self, esrb_message_t, &message_type, message);
345
+ if (!message->held) {
346
+ message_release(message);
347
+ }
348
+ return Qnil;
349
+ }
350
+
351
+ static VALUE
352
+ message_valid_p(VALUE self)
353
+ {
354
+ esrb_message_t *message;
355
+ TypedData_Get_Struct(self, esrb_message_t, &message_type, message);
356
+ if (!message_owned_here(message)) {
357
+ rb_raise(rb_path2class("EndpointSecurity::ForkedClientError"), "Endpoint Security messages cannot be used after fork");
358
+ }
359
+ return message->valid ? Qtrue : Qfalse;
360
+ }
361
+
362
+ static VALUE
363
+ message_warn_on_truncated_path(VALUE self)
364
+ {
365
+ return get_message(self)->client->warn_on_truncated_path ? Qtrue : Qfalse;
366
+ }
367
+
368
+ VALUE
369
+ esrb_message_wrap(VALUE owner, esrb_client_t *client, esrb_slot_t *slot)
370
+ {
371
+ esrb_message_t *message;
372
+ VALUE object = TypedData_Make_Struct(c_message, esrb_message_t, &message_type, message);
373
+ message->owner = owner;
374
+ message->client = client;
375
+ message->slot = slot;
376
+ message->valid = true;
377
+ message->held = false;
378
+ return object;
379
+ }
380
+
381
+ bool
382
+ esrb_message_valid_object(VALUE object)
383
+ {
384
+ esrb_message_t *message;
385
+ if (!rb_typeddata_is_kind_of(object, &message_type)) {
386
+ return false;
387
+ }
388
+ TypedData_Get_Struct(object, esrb_message_t, &message_type, message);
389
+ if (!message_owned_here(message)) {
390
+ rb_raise(rb_path2class("EndpointSecurity::ForkedClientError"), "Endpoint Security messages cannot be used after fork");
391
+ }
392
+ return message->valid;
393
+ }
394
+
395
+ void
396
+ esrb_init_message(VALUE endpoint_security)
397
+ {
398
+ c_message = rb_define_class_under(endpoint_security, "Message", rb_cObject);
399
+ rb_undef_alloc_func(c_message);
400
+ rb_define_method(c_message, "version", message_version, 0);
401
+ rb_define_method(c_message, "event_type", message_event_type, 0);
402
+ rb_define_method(c_message, "action_type", message_action_type, 0);
403
+ rb_define_method(c_message, "auth?", message_auth_p, 0);
404
+ rb_define_method(c_message, "deadline", message_deadline, 0);
405
+ rb_define_method(c_message, "mach_time", message_mach_time, 0);
406
+ rb_define_method(c_message, "seq_num", message_seq_num, 0);
407
+ rb_define_method(c_message, "global_seq_num", message_global_seq_num, 0);
408
+ rb_define_method(c_message, "time", message_time, 0);
409
+ rb_define_method(c_message, "process", message_process, 0);
410
+ rb_define_method(c_message, "thread", message_thread, 0);
411
+ rb_define_method(c_message, "event", message_event, 0);
412
+ rb_define_method(c_message, "result", message_result, 0);
413
+ rb_define_method(c_message, "raw_event_bytes", message_raw_event_bytes, 0);
414
+ rb_define_method(c_message, "raw_pointer", message_raw_pointer, 0);
415
+ rb_define_method(c_message, "time_left", message_time_left, 0);
416
+ rb_define_method(c_message, "answered?", message_answered_p, 0);
417
+ rb_define_method(c_message, "allow!", message_allow, -1);
418
+ rb_define_method(c_message, "deny!", message_deny, -1);
419
+ rb_define_method(c_message, "respond", message_respond, -1);
420
+ rb_define_method(c_message, "retain!", message_retain, 0);
421
+ rb_define_method(c_message, "release!", message_release_bang, 0);
422
+ rb_define_method(c_message, "valid?", message_valid_p, 0);
423
+ rb_define_method(c_message, "__warn_on_truncated_path?", message_warn_on_truncated_path, 0);
424
+ rb_define_method(c_message, "__respond_default!", message_respond_default, 0);
425
+ rb_define_method(c_message, "__auto_release!", message_auto_release, 0);
426
+ }
@@ -0,0 +1,13 @@
1
+ #ifndef ESRB_MESSAGE_H
2
+ #define ESRB_MESSAGE_H
3
+
4
+ #include <ruby.h>
5
+ #include <stdbool.h>
6
+
7
+ #include "client.h"
8
+
9
+ void esrb_init_message(VALUE endpoint_security);
10
+ VALUE esrb_message_wrap(VALUE owner, esrb_client_t *client, esrb_slot_t *slot);
11
+ bool esrb_message_valid_object(VALUE object);
12
+
13
+ #endif