Fix: trigger: leak of trigger on failure to set name
[lttng-tools.git] / src / common / trigger.c
CommitLineData
a58c490f 1/*
ab5be9fa 2 * Copyright (C) 2017 Jérémie Galarneau <jeremie.galarneau@efficios.com>
a58c490f 3 *
ab5be9fa 4 * SPDX-License-Identifier: LGPL-2.1-only
a58c490f 5 *
a58c490f
JG
6 */
7
8#include <lttng/trigger/trigger-internal.h>
9#include <lttng/condition/condition-internal.h>
10#include <lttng/action/action-internal.h>
3da864a9 11#include <common/credentials.h>
9e620ea7
JG
12#include <common/payload.h>
13#include <common/payload-view.h>
a58c490f 14#include <common/error.h>
a02903c0 15#include <common/dynamic-array.h>
3da864a9 16#include <common/optional.h>
a58c490f 17#include <assert.h>
242388e4 18#include <inttypes.h>
a58c490f
JG
19
20LTTNG_HIDDEN
21bool lttng_trigger_validate(struct lttng_trigger *trigger)
22{
23 bool valid;
24
25 if (!trigger) {
26 valid = false;
27 goto end;
28 }
29
64eafdf6
JR
30 if (!trigger->creds.uid.is_set) {
31 valid = false;
32 goto end;
33 }
34
a58c490f
JG
35 valid = lttng_condition_validate(trigger->condition) &&
36 lttng_action_validate(trigger->action);
37end:
38 return valid;
39}
40
41struct 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
f01d28b4
JR
56 urcu_ref_init(&trigger->ref);
57
7ca172c1 58 lttng_condition_get(condition);
a58c490f 59 trigger->condition = condition;
7ca172c1
JR
60
61 lttng_action_get(action);
a58c490f 62 trigger->action = action;
3da864a9 63
a58c490f
JG
64end:
65 return trigger;
66}
67
7ca172c1
JR
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 */
a58c490f
JG
73struct lttng_condition *lttng_trigger_get_condition(
74 struct lttng_trigger *trigger)
75{
76 return trigger ? trigger->condition : NULL;
77}
78
9b63a4aa
JG
79LTTNG_HIDDEN
80const struct lttng_condition *lttng_trigger_get_const_condition(
81 const struct lttng_trigger *trigger)
82{
83 return trigger->condition;
84}
85
7ca172c1
JR
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 */
e2ba1c78 92struct lttng_action *lttng_trigger_get_action(
a58c490f
JG
93 struct lttng_trigger *trigger)
94{
95 return trigger ? trigger->action : NULL;
96}
97
9b63a4aa
JG
98LTTNG_HIDDEN
99const struct lttng_action *lttng_trigger_get_const_action(
100 const struct lttng_trigger *trigger)
101{
102 return trigger->action;
103}
104
f01d28b4 105static void trigger_destroy_ref(struct urcu_ref *ref)
a58c490f 106{
f01d28b4
JR
107 struct lttng_trigger *trigger =
108 container_of(ref, struct lttng_trigger, ref);
7ca172c1
JR
109 struct lttng_action *action = lttng_trigger_get_action(trigger);
110 struct lttng_condition *condition =
111 lttng_trigger_get_condition(trigger);
112
7ca172c1
JR
113 assert(action);
114 assert(condition);
115
116 /* Release ownership. */
117 lttng_action_put(action);
118 lttng_condition_put(condition);
119
242388e4 120 free(trigger->name);
a58c490f
JG
121 free(trigger);
122}
123
f01d28b4
JR
124void lttng_trigger_destroy(struct lttng_trigger *trigger)
125{
126 lttng_trigger_put(trigger);
127}
128
a58c490f 129LTTNG_HIDDEN
c0a66c84
JG
130ssize_t lttng_trigger_create_from_payload(
131 struct lttng_payload_view *src_view,
6808ef55 132 struct lttng_trigger **_trigger)
a58c490f 133{
242388e4 134 ssize_t ret, offset = 0, condition_size, action_size, name_size = 0;
a58c490f
JG
135 struct lttng_condition *condition = NULL;
136 struct lttng_action *action = NULL;
137 const struct lttng_trigger_comm *trigger_comm;
242388e4 138 const char *name = NULL;
64eafdf6
JR
139 struct lttng_credentials creds = {
140 .uid = LTTNG_OPTIONAL_INIT_UNSET,
141 .gid = LTTNG_OPTIONAL_INIT_UNSET,
142 };
6808ef55 143 struct lttng_trigger *trigger = NULL;
3e6e0df2
JG
144 const struct lttng_payload_view trigger_comm_view =
145 lttng_payload_view_from_view(
146 src_view, 0, sizeof(*trigger_comm));
a58c490f 147
6808ef55 148 if (!src_view || !_trigger) {
a58c490f
JG
149 ret = -1;
150 goto end;
151 }
152
3e6e0df2
JG
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
a58c490f 159 /* lttng_trigger_comm header */
3e6e0df2 160 trigger_comm = (typeof(trigger_comm)) trigger_comm_view.buffer.data;
64eafdf6
JR
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
a58c490f 171 offset += sizeof(*trigger_comm);
242388e4
JR
172
173 if (trigger_comm->name_length != 0) {
174 /* Name. */
175 const struct lttng_payload_view name_view =
176 lttng_payload_view_from_view(
3e6e0df2
JG
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 }
242388e4
JR
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
c0a66c84
JG
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 }
a58c490f 205
a58c490f
JG
206 if (condition_size < 0) {
207 ret = condition_size;
208 goto end;
209 }
c0a66c84 210
a58c490f 211 offset += condition_size;
c0a66c84
JG
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 }
a58c490f 220
a58c490f
JG
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. */
242388e4 228 if ((ssize_t) trigger_comm->length != condition_size + action_size + name_size) {
a58c490f
JG
229 ret = -1;
230 goto error;
231 }
232
6808ef55
JG
233 trigger = lttng_trigger_create(condition, action);
234 if (!trigger) {
a58c490f
JG
235 ret = -1;
236 goto error;
237 }
c0a66c84 238
6808ef55 239 lttng_trigger_set_credentials(trigger, &creds);
64eafdf6 240
7ca172c1
JR
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
242388e4
JR
251 if (name) {
252 const enum lttng_trigger_status status =
6808ef55 253 lttng_trigger_set_name(trigger, name);
242388e4
JR
254
255 if (status != LTTNG_TRIGGER_STATUS_OK) {
256 ret = -1;
257 goto end;
258 }
259 }
260
a58c490f 261 ret = offset;
7ca172c1 262
a58c490f 263error:
1065801b
JG
264 lttng_condition_put(condition);
265 lttng_action_put(action);
7ca172c1 266end:
6808ef55
JG
267 if (ret == 0) {
268 *_trigger = trigger;
269 } else {
270 lttng_trigger_put(trigger);
271 }
272
a58c490f
JG
273 return ret;
274}
275
276/*
a58c490f
JG
277 * Both elements are stored contiguously, see their "*_comm" structure
278 * for the detailed format.
279 */
280LTTNG_HIDDEN
a02903c0 281int lttng_trigger_serialize(const struct lttng_trigger *trigger,
c0a66c84 282 struct lttng_payload *payload)
a58c490f 283{
3647288f 284 int ret;
242388e4 285 size_t header_offset, size_before_payload, size_name;
c0a66c84 286 struct lttng_trigger_comm trigger_comm = {};
3647288f 287 struct lttng_trigger_comm *header;
64eafdf6
JR
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);
a58c490f 294
242388e4
JR
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
c0a66c84
JG
303 header_offset = payload->buffer.size;
304 ret = lttng_dynamic_buffer_append(&payload->buffer, &trigger_comm,
3647288f
JG
305 sizeof(trigger_comm));
306 if (ret) {
a58c490f
JG
307 goto end;
308 }
309
c0a66c84 310 size_before_payload = payload->buffer.size;
242388e4
JR
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
c0a66c84 319 ret = lttng_condition_serialize(trigger->condition, payload);
3647288f 320 if (ret) {
a58c490f
JG
321 goto end;
322 }
a58c490f 323
c0a66c84 324 ret = lttng_action_serialize(trigger->action, payload);
3647288f 325 if (ret) {
a58c490f
JG
326 goto end;
327 }
a58c490f 328
3647288f 329 /* Update payload size. */
c0a66c84
JG
330 header = (typeof(header)) (payload->buffer.data + header_offset);
331 header->length = payload->buffer.size - size_before_payload;
a58c490f
JG
332end:
333 return ret;
334}
3da864a9 335
85c06c44
JR
336LTTNG_HIDDEN
337bool 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
242388e4
JR
359enum 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;
381end:
382 return status;
383}
384
385enum 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;
400end:
401 return status;
402}
403
404LTTNG_HIDDEN
405int 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 }
417end:
418 return ret;
419}
420
e6887944
JR
421LTTNG_HIDDEN
422void 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
429LTTNG_HIDDEN
430uint64_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
242388e4
JR
437LTTNG_HIDDEN
438int 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;
454end:
455 return ret;
456}
457
f01d28b4
JR
458LTTNG_HIDDEN
459void lttng_trigger_get(struct lttng_trigger *trigger)
460{
461 urcu_ref_get(&trigger->ref);
462}
463
464LTTNG_HIDDEN
465void 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
a02903c0
JR
474static void delete_trigger_array_element(void *ptr)
475{
476 struct lttng_trigger *trigger = ptr;
477
478 lttng_trigger_put(trigger);
479}
480
481LTTNG_HIDDEN
482struct 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
493end:
494 return triggers;
495}
496
497LTTNG_HIDDEN
498struct 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);
511end:
512 return trigger;
513}
514
515LTTNG_HIDDEN
516int 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
534const 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
540enum 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);
550end:
551 return status;
552}
553
554void 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
564int 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;
607end:
608 return ret;
609}
610
611LTTNG_HIDDEN
612ssize_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;
672error:
673
674 lttng_triggers_destroy(local_triggers);
675 return ret;
676}
677
3da864a9
JR
678LTTNG_HIDDEN
679const struct lttng_credentials *lttng_trigger_get_credentials(
680 const struct lttng_trigger *trigger)
681{
64eafdf6 682 return &trigger->creds;
3da864a9
JR
683}
684
685LTTNG_HIDDEN
64eafdf6 686void lttng_trigger_set_credentials(struct lttng_trigger *trigger,
3da864a9
JR
687 const struct lttng_credentials *creds)
688{
689 assert(creds);
64eafdf6
JR
690 trigger->creds = *creds;
691}
692
693enum 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
715end:
716 return ret;
717}
718
719enum 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
738end:
739 return ret;
3da864a9 740}
This page took 0.065059 seconds and 4 git commands to generate.