Fix: trigger: leak of trigger on failure to set name
[lttng-tools.git] / src / common / trigger.c
1 /*
2 * Copyright (C) 2017 Jérémie Galarneau <jeremie.galarneau@efficios.com>
3 *
4 * SPDX-License-Identifier: LGPL-2.1-only
5 *
6 */
7
8 #include <lttng/trigger/trigger-internal.h>
9 #include <lttng/condition/condition-internal.h>
10 #include <lttng/action/action-internal.h>
11 #include <common/credentials.h>
12 #include <common/payload.h>
13 #include <common/payload-view.h>
14 #include <common/error.h>
15 #include <common/dynamic-array.h>
16 #include <common/optional.h>
17 #include <assert.h>
18 #include <inttypes.h>
19
20 LTTNG_HIDDEN
21 bool lttng_trigger_validate(struct lttng_trigger *trigger)
22 {
23 bool valid;
24
25 if (!trigger) {
26 valid = false;
27 goto end;
28 }
29
30 if (!trigger->creds.uid.is_set) {
31 valid = false;
32 goto end;
33 }
34
35 valid = lttng_condition_validate(trigger->condition) &&
36 lttng_action_validate(trigger->action);
37 end:
38 return valid;
39 }
40
41 struct lttng_trigger *lttng_trigger_create(
42 struct lttng_condition *condition,
43 struct lttng_action *action)
44 {
45 struct lttng_trigger *trigger = NULL;
46
47 if (!condition || !action) {
48 goto end;
49 }
50
51 trigger = zmalloc(sizeof(struct lttng_trigger));
52 if (!trigger) {
53 goto end;
54 }
55
56 urcu_ref_init(&trigger->ref);
57
58 lttng_condition_get(condition);
59 trigger->condition = condition;
60
61 lttng_action_get(action);
62 trigger->action = action;
63
64 end:
65 return trigger;
66 }
67
68 /*
69 * Note: the lack of reference counting 'get' on the condition object is normal.
70 * This API was exposed as such in 2.11. The client is not expected to call
71 * lttng_condition_destroy on the returned object.
72 */
73 struct lttng_condition *lttng_trigger_get_condition(
74 struct lttng_trigger *trigger)
75 {
76 return trigger ? trigger->condition : NULL;
77 }
78
79 LTTNG_HIDDEN
80 const struct lttng_condition *lttng_trigger_get_const_condition(
81 const struct lttng_trigger *trigger)
82 {
83 return trigger->condition;
84 }
85
86
87 /*
88 * Note: the lack of reference counting 'get' on the action object is normal.
89 * This API was exposed as such in 2.11. The client is not expected to call
90 * lttng_action_destroy on the returned object.
91 */
92 struct lttng_action *lttng_trigger_get_action(
93 struct lttng_trigger *trigger)
94 {
95 return trigger ? trigger->action : NULL;
96 }
97
98 LTTNG_HIDDEN
99 const struct lttng_action *lttng_trigger_get_const_action(
100 const struct lttng_trigger *trigger)
101 {
102 return trigger->action;
103 }
104
105 static void trigger_destroy_ref(struct urcu_ref *ref)
106 {
107 struct lttng_trigger *trigger =
108 container_of(ref, struct lttng_trigger, ref);
109 struct lttng_action *action = lttng_trigger_get_action(trigger);
110 struct lttng_condition *condition =
111 lttng_trigger_get_condition(trigger);
112
113 assert(action);
114 assert(condition);
115
116 /* Release ownership. */
117 lttng_action_put(action);
118 lttng_condition_put(condition);
119
120 free(trigger->name);
121 free(trigger);
122 }
123
124 void lttng_trigger_destroy(struct lttng_trigger *trigger)
125 {
126 lttng_trigger_put(trigger);
127 }
128
129 LTTNG_HIDDEN
130 ssize_t lttng_trigger_create_from_payload(
131 struct lttng_payload_view *src_view,
132 struct lttng_trigger **_trigger)
133 {
134 ssize_t ret, offset = 0, condition_size, action_size, name_size = 0;
135 struct lttng_condition *condition = NULL;
136 struct lttng_action *action = NULL;
137 const struct lttng_trigger_comm *trigger_comm;
138 const char *name = NULL;
139 struct lttng_credentials creds = {
140 .uid = LTTNG_OPTIONAL_INIT_UNSET,
141 .gid = LTTNG_OPTIONAL_INIT_UNSET,
142 };
143 struct lttng_trigger *trigger = NULL;
144 const struct lttng_payload_view trigger_comm_view =
145 lttng_payload_view_from_view(
146 src_view, 0, sizeof(*trigger_comm));
147
148 if (!src_view || !_trigger) {
149 ret = -1;
150 goto end;
151 }
152
153 if (!lttng_payload_view_is_valid(&trigger_comm_view)) {
154 /* Payload not large enough to contain the header. */
155 ret = -1;
156 goto end;
157 }
158
159 /* lttng_trigger_comm header */
160 trigger_comm = (typeof(trigger_comm)) trigger_comm_view.buffer.data;
161
162 /* Set the trigger's creds. */
163 if (trigger_comm->uid > (uint64_t) ((uid_t) -1)) {
164 /* UID out of range for this platform. */
165 ret = -1;
166 goto end;
167 }
168
169 LTTNG_OPTIONAL_SET(&creds.uid, trigger_comm->uid);
170
171 offset += sizeof(*trigger_comm);
172
173 if (trigger_comm->name_length != 0) {
174 /* Name. */
175 const struct lttng_payload_view name_view =
176 lttng_payload_view_from_view(
177 src_view, offset,
178 trigger_comm->name_length);
179
180 if (!lttng_payload_view_is_valid(&name_view)) {
181 ret = -1;
182 goto end;
183 }
184
185 name = name_view.buffer.data;
186 if (!lttng_buffer_view_contains_string(&name_view.buffer, name,
187 trigger_comm->name_length)) {
188 ret = -1;
189 goto end;
190 }
191
192 offset += trigger_comm->name_length;
193 name_size = trigger_comm->name_length;
194 }
195
196 {
197 /* struct lttng_condition */
198 struct lttng_payload_view condition_view =
199 lttng_payload_view_from_view(
200 src_view, offset, -1);
201
202 condition_size = lttng_condition_create_from_payload(&condition_view,
203 &condition);
204 }
205
206 if (condition_size < 0) {
207 ret = condition_size;
208 goto end;
209 }
210
211 offset += condition_size;
212 {
213 /* struct lttng_action */
214 struct lttng_payload_view action_view =
215 lttng_payload_view_from_view(
216 src_view, offset, -1);
217
218 action_size = lttng_action_create_from_payload(&action_view, &action);
219 }
220
221 if (action_size < 0) {
222 ret = action_size;
223 goto end;
224 }
225 offset += action_size;
226
227 /* Unexpected size of inner-elements; the buffer is corrupted. */
228 if ((ssize_t) trigger_comm->length != condition_size + action_size + name_size) {
229 ret = -1;
230 goto error;
231 }
232
233 trigger = lttng_trigger_create(condition, action);
234 if (!trigger) {
235 ret = -1;
236 goto error;
237 }
238
239 lttng_trigger_set_credentials(trigger, &creds);
240
241 /*
242 * The trigger object owns references to the action and condition
243 * objects.
244 */
245 lttng_condition_put(condition);
246 condition = NULL;
247
248 lttng_action_put(action);
249 action = NULL;
250
251 if (name) {
252 const enum lttng_trigger_status status =
253 lttng_trigger_set_name(trigger, name);
254
255 if (status != LTTNG_TRIGGER_STATUS_OK) {
256 ret = -1;
257 goto end;
258 }
259 }
260
261 ret = offset;
262
263 error:
264 lttng_condition_put(condition);
265 lttng_action_put(action);
266 end:
267 if (ret == 0) {
268 *_trigger = trigger;
269 } else {
270 lttng_trigger_put(trigger);
271 }
272
273 return ret;
274 }
275
276 /*
277 * Both elements are stored contiguously, see their "*_comm" structure
278 * for the detailed format.
279 */
280 LTTNG_HIDDEN
281 int lttng_trigger_serialize(const struct lttng_trigger *trigger,
282 struct lttng_payload *payload)
283 {
284 int ret;
285 size_t header_offset, size_before_payload, size_name;
286 struct lttng_trigger_comm trigger_comm = {};
287 struct lttng_trigger_comm *header;
288 const struct lttng_credentials *creds = NULL;
289
290 creds = lttng_trigger_get_credentials(trigger);
291 assert(creds);
292
293 trigger_comm.uid = LTTNG_OPTIONAL_GET(creds->uid);
294
295 if (trigger->name != NULL) {
296 size_name = strlen(trigger->name) + 1;
297 } else {
298 size_name = 0;
299 }
300
301 trigger_comm.name_length = size_name;
302
303 header_offset = payload->buffer.size;
304 ret = lttng_dynamic_buffer_append(&payload->buffer, &trigger_comm,
305 sizeof(trigger_comm));
306 if (ret) {
307 goto end;
308 }
309
310 size_before_payload = payload->buffer.size;
311
312 /* Trigger name. */
313 ret = lttng_dynamic_buffer_append(
314 &payload->buffer, trigger->name, size_name);
315 if (ret) {
316 goto end;
317 }
318
319 ret = lttng_condition_serialize(trigger->condition, payload);
320 if (ret) {
321 goto end;
322 }
323
324 ret = lttng_action_serialize(trigger->action, payload);
325 if (ret) {
326 goto end;
327 }
328
329 /* Update payload size. */
330 header = (typeof(header)) (payload->buffer.data + header_offset);
331 header->length = payload->buffer.size - size_before_payload;
332 end:
333 return ret;
334 }
335
336 LTTNG_HIDDEN
337 bool lttng_trigger_is_equal(
338 const struct lttng_trigger *a, const struct lttng_trigger *b)
339 {
340 /*
341 * Name is not taken into account since it is cosmetic only.
342 */
343 if (!lttng_condition_is_equal(a->condition, b->condition)) {
344 return false;
345 }
346
347 if (!lttng_action_is_equal(a->action, b->action)) {
348 return false;
349 }
350
351 if (!lttng_credentials_is_equal(lttng_trigger_get_credentials(a),
352 lttng_trigger_get_credentials(b))) {
353 return false;
354 }
355
356 return true;
357 }
358
359 enum lttng_trigger_status lttng_trigger_set_name(struct lttng_trigger *trigger,
360 const char* name)
361 {
362 char *name_copy = NULL;
363 enum lttng_trigger_status status = LTTNG_TRIGGER_STATUS_OK;
364
365 if (!trigger || !name ||
366 strlen(name) == 0) {
367 status = LTTNG_TRIGGER_STATUS_INVALID;
368 goto end;
369 }
370
371 name_copy = strdup(name);
372 if (!name_copy) {
373 status = LTTNG_TRIGGER_STATUS_ERROR;
374 goto end;
375 }
376
377 free(trigger->name);
378
379 trigger->name = name_copy;
380 name_copy = NULL;
381 end:
382 return status;
383 }
384
385 enum lttng_trigger_status lttng_trigger_get_name(
386 const struct lttng_trigger *trigger, const char **name)
387 {
388 enum lttng_trigger_status status = LTTNG_TRIGGER_STATUS_OK;
389
390 if (!trigger || !name) {
391 status = LTTNG_TRIGGER_STATUS_INVALID;
392 goto end;
393 }
394
395 if (!trigger->name) {
396 status = LTTNG_TRIGGER_STATUS_UNSET;
397 }
398
399 *name = trigger->name;
400 end:
401 return status;
402 }
403
404 LTTNG_HIDDEN
405 int lttng_trigger_assign_name(struct lttng_trigger *dst,
406 const struct lttng_trigger *src)
407 {
408 int ret = 0;
409 enum lttng_trigger_status status;
410
411 status = lttng_trigger_set_name(dst, src->name);
412 if (status != LTTNG_TRIGGER_STATUS_OK) {
413 ret = -1;
414 ERR("Failed to set name for trigger");
415 goto end;
416 }
417 end:
418 return ret;
419 }
420
421 LTTNG_HIDDEN
422 void lttng_trigger_set_tracer_token(struct lttng_trigger *trigger,
423 uint64_t token)
424 {
425 assert(trigger);
426 LTTNG_OPTIONAL_SET(&trigger->tracer_token, token);
427 }
428
429 LTTNG_HIDDEN
430 uint64_t lttng_trigger_get_tracer_token(const struct lttng_trigger *trigger)
431 {
432 assert(trigger);
433
434 return LTTNG_OPTIONAL_GET(trigger->tracer_token);
435 }
436
437 LTTNG_HIDDEN
438 int lttng_trigger_generate_name(struct lttng_trigger *trigger,
439 uint64_t unique_id)
440 {
441 int ret = 0;
442 char *generated_name = NULL;
443
444 ret = asprintf(&generated_name, "T%" PRIu64 "", unique_id);
445 if (ret < 0) {
446 ERR("Failed to generate trigger name");
447 ret = -1;
448 goto end;
449 }
450
451 ret = 0;
452 free(trigger->name);
453 trigger->name = generated_name;
454 end:
455 return ret;
456 }
457
458 LTTNG_HIDDEN
459 void lttng_trigger_get(struct lttng_trigger *trigger)
460 {
461 urcu_ref_get(&trigger->ref);
462 }
463
464 LTTNG_HIDDEN
465 void lttng_trigger_put(struct lttng_trigger *trigger)
466 {
467 if (!trigger) {
468 return;
469 }
470
471 urcu_ref_put(&trigger->ref , trigger_destroy_ref);
472 }
473
474 static void delete_trigger_array_element(void *ptr)
475 {
476 struct lttng_trigger *trigger = ptr;
477
478 lttng_trigger_put(trigger);
479 }
480
481 LTTNG_HIDDEN
482 struct lttng_triggers *lttng_triggers_create(void)
483 {
484 struct lttng_triggers *triggers = NULL;
485
486 triggers = zmalloc(sizeof(*triggers));
487 if (!triggers) {
488 goto end;
489 }
490
491 lttng_dynamic_pointer_array_init(&triggers->array, delete_trigger_array_element);
492
493 end:
494 return triggers;
495 }
496
497 LTTNG_HIDDEN
498 struct lttng_trigger *lttng_triggers_borrow_mutable_at_index(
499 const struct lttng_triggers *triggers, unsigned int index)
500 {
501 struct lttng_trigger *trigger = NULL;
502
503 assert(triggers);
504 if (index >= lttng_dynamic_pointer_array_get_count(&triggers->array)) {
505 goto end;
506 }
507
508 trigger = (struct lttng_trigger *)
509 lttng_dynamic_pointer_array_get_pointer(
510 &triggers->array, index);
511 end:
512 return trigger;
513 }
514
515 LTTNG_HIDDEN
516 int lttng_triggers_add(
517 struct lttng_triggers *triggers, struct lttng_trigger *trigger)
518 {
519 int ret;
520
521 assert(triggers);
522 assert(trigger);
523
524 lttng_trigger_get(trigger);
525
526 ret = lttng_dynamic_pointer_array_add_pointer(&triggers->array, trigger);
527 if (ret) {
528 lttng_trigger_put(trigger);
529 }
530
531 return ret;
532 }
533
534 const struct lttng_trigger *lttng_triggers_get_at_index(
535 const struct lttng_triggers *triggers, unsigned int index)
536 {
537 return lttng_triggers_borrow_mutable_at_index(triggers, index);
538 }
539
540 enum lttng_trigger_status lttng_triggers_get_count(const struct lttng_triggers *triggers, unsigned int *count)
541 {
542 enum lttng_trigger_status status = LTTNG_TRIGGER_STATUS_OK;
543
544 if (!triggers || !count) {
545 status = LTTNG_TRIGGER_STATUS_INVALID;
546 goto end;
547 }
548
549 *count = lttng_dynamic_pointer_array_get_count(&triggers->array);
550 end:
551 return status;
552 }
553
554 void lttng_triggers_destroy(struct lttng_triggers *triggers)
555 {
556 if (!triggers) {
557 return;
558 }
559
560 lttng_dynamic_pointer_array_reset(&triggers->array);
561 free(triggers);
562 }
563
564 int lttng_triggers_serialize(const struct lttng_triggers *triggers,
565 struct lttng_payload *payload)
566 {
567 int ret;
568 unsigned int i, count;
569 size_t size_before_payload;
570 struct lttng_triggers_comm triggers_comm = {};
571 struct lttng_triggers_comm *header;
572 enum lttng_trigger_status status;
573 const size_t header_offset = payload->buffer.size;
574
575 status = lttng_triggers_get_count(triggers, &count);
576 if (status != LTTNG_TRIGGER_STATUS_OK) {
577 ret = LTTNG_ERR_INVALID;
578 goto end;
579 }
580
581 triggers_comm.count = count;
582
583 /* Placeholder header; updated at the end. */
584 ret = lttng_dynamic_buffer_append(&payload->buffer, &triggers_comm,
585 sizeof(triggers_comm));
586 if (ret) {
587 goto end;
588 }
589
590 size_before_payload = payload->buffer.size;
591
592 for (i = 0; i < count; i++) {
593 const struct lttng_trigger *trigger =
594 lttng_triggers_get_at_index(triggers, i);
595
596 assert(trigger);
597
598 ret = lttng_trigger_serialize(trigger, payload);
599 if (ret) {
600 goto end;
601 }
602 }
603
604 /* Update payload size. */
605 header = (struct lttng_triggers_comm *) ((char *) payload->buffer.data + header_offset);
606 header->length = payload->buffer.size - size_before_payload;
607 end:
608 return ret;
609 }
610
611 LTTNG_HIDDEN
612 ssize_t lttng_triggers_create_from_payload(
613 struct lttng_payload_view *src_view,
614 struct lttng_triggers **triggers)
615 {
616 ssize_t ret, offset = 0, triggers_size = 0;
617 unsigned int i;
618 const struct lttng_triggers_comm *triggers_comm;
619 struct lttng_triggers *local_triggers = NULL;
620
621 if (!src_view || !triggers) {
622 ret = -1;
623 goto error;
624 }
625
626 /* lttng_trigger_comms header */
627 triggers_comm = (const struct lttng_triggers_comm *) src_view->buffer.data;
628 offset += sizeof(*triggers_comm);
629
630 local_triggers = lttng_triggers_create();
631 if (!local_triggers) {
632 ret = -1;
633 goto error;
634 }
635
636 for (i = 0; i < triggers_comm->count; i++) {
637 struct lttng_trigger *trigger = NULL;
638 struct lttng_payload_view trigger_view =
639 lttng_payload_view_from_view(src_view, offset, -1);
640 ssize_t trigger_size;
641
642 trigger_size = lttng_trigger_create_from_payload(
643 &trigger_view, &trigger);
644 if (trigger_size < 0) {
645 ret = trigger_size;
646 goto error;
647 }
648
649 /* Transfer ownership of the trigger to the collection. */
650 ret = lttng_triggers_add(local_triggers, trigger);
651 lttng_trigger_put(trigger);
652 if (ret < 0) {
653 ret = -1;
654 goto error;
655 }
656
657 offset += trigger_size;
658 triggers_size += trigger_size;
659 }
660
661 /* Unexpected size of inner-elements; the buffer is corrupted. */
662 if ((ssize_t) triggers_comm->length != triggers_size) {
663 ret = -1;
664 goto error;
665 }
666
667 /* Pass ownership to caller. */
668 *triggers = local_triggers;
669 local_triggers = NULL;
670
671 ret = offset;
672 error:
673
674 lttng_triggers_destroy(local_triggers);
675 return ret;
676 }
677
678 LTTNG_HIDDEN
679 const struct lttng_credentials *lttng_trigger_get_credentials(
680 const struct lttng_trigger *trigger)
681 {
682 return &trigger->creds;
683 }
684
685 LTTNG_HIDDEN
686 void lttng_trigger_set_credentials(struct lttng_trigger *trigger,
687 const struct lttng_credentials *creds)
688 {
689 assert(creds);
690 trigger->creds = *creds;
691 }
692
693 enum lttng_trigger_status lttng_trigger_set_owner_uid(
694 struct lttng_trigger *trigger, uid_t uid)
695 {
696 enum lttng_trigger_status ret = LTTNG_TRIGGER_STATUS_OK;
697 const struct lttng_credentials creds = {
698 .uid = LTTNG_OPTIONAL_INIT_VALUE(uid),
699 .gid = LTTNG_OPTIONAL_INIT_UNSET,
700 };
701
702 if (!trigger) {
703 ret = LTTNG_TRIGGER_STATUS_INVALID;
704 goto end;
705 }
706
707 /* Client-side validation only to report a clearer error. */
708 if (geteuid() != 0) {
709 ret = LTTNG_TRIGGER_STATUS_PERMISSION_DENIED;
710 goto end;
711 }
712
713 lttng_trigger_set_credentials(trigger, &creds);
714
715 end:
716 return ret;
717 }
718
719 enum lttng_trigger_status lttng_trigger_get_owner_uid(
720 const struct lttng_trigger *trigger, uid_t *uid)
721 {
722 enum lttng_trigger_status ret = LTTNG_TRIGGER_STATUS_OK;
723 const struct lttng_credentials *creds = NULL;
724
725 if (!trigger || !uid ) {
726 ret = LTTNG_TRIGGER_STATUS_INVALID;
727 goto end;
728 }
729
730 if (!trigger->creds.uid.is_set ) {
731 ret = LTTNG_TRIGGER_STATUS_UNSET;
732 goto end;
733 }
734
735 creds = lttng_trigger_get_credentials(trigger);
736 *uid = lttng_credentials_get_uid(creds);
737
738 end:
739 return ret;
740 }
This page took 0.068627 seconds and 4 git commands to generate.