Fix: lttng_trace_archive_location_serialize is called on freed memory
[lttng-tools.git] / src / common / conditions / session-rotation.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 <assert.h>
9 #include <common/error.h>
10 #include <common/macros.h>
11 #include <common/mi-lttng.h>
12 #include <lttng/condition/condition-internal.h>
13 #include <lttng/condition/session-rotation-internal.h>
14 #include <lttng/location-internal.h>
15 #include <stdbool.h>
16
17 static
18 bool lttng_condition_session_rotation_validate(
19 const struct lttng_condition *condition);
20 static
21 int lttng_condition_session_rotation_serialize(
22 const struct lttng_condition *condition,
23 struct lttng_payload *payload);
24 static
25 bool lttng_condition_session_rotation_is_equal(const struct lttng_condition *_a,
26 const struct lttng_condition *_b);
27 static
28 void lttng_condition_session_rotation_destroy(
29 struct lttng_condition *condition);
30
31 static
32 enum lttng_error_code lttng_condition_session_rotation_mi_serialize(
33 const struct lttng_condition *condition,
34 struct mi_writer *writer);
35
36 static const
37 struct lttng_condition rotation_condition_template = {
38 /* .type omitted; shall be set on creation. */
39 .validate = lttng_condition_session_rotation_validate,
40 .serialize = lttng_condition_session_rotation_serialize,
41 .equal = lttng_condition_session_rotation_is_equal,
42 .destroy = lttng_condition_session_rotation_destroy,
43 .mi_serialize = lttng_condition_session_rotation_mi_serialize,
44 };
45
46 static
47 int lttng_evaluation_session_rotation_serialize(
48 const struct lttng_evaluation *evaluation,
49 struct lttng_payload *payload);
50 static
51 void lttng_evaluation_session_rotation_destroy(
52 struct lttng_evaluation *evaluation);
53
54 static const
55 struct lttng_evaluation rotation_evaluation_template = {
56 /* .type omitted; shall be set on creation. */
57 .serialize = lttng_evaluation_session_rotation_serialize,
58 .destroy = lttng_evaluation_session_rotation_destroy,
59 };
60
61 static
62 bool is_rotation_condition(const struct lttng_condition *condition)
63 {
64 enum lttng_condition_type type = lttng_condition_get_type(condition);
65
66 return type == LTTNG_CONDITION_TYPE_SESSION_ROTATION_ONGOING ||
67 type == LTTNG_CONDITION_TYPE_SESSION_ROTATION_COMPLETED;
68 }
69
70 static
71 bool is_rotation_evaluation(const struct lttng_evaluation *evaluation)
72 {
73 enum lttng_condition_type type = lttng_evaluation_get_type(evaluation);
74
75 return type == LTTNG_CONDITION_TYPE_SESSION_ROTATION_ONGOING ||
76 type == LTTNG_CONDITION_TYPE_SESSION_ROTATION_COMPLETED;
77 }
78
79 static
80 bool lttng_condition_session_rotation_validate(
81 const struct lttng_condition *condition)
82 {
83 bool valid = false;
84 struct lttng_condition_session_rotation *rotation;
85
86 if (!condition) {
87 goto end;
88 }
89
90 rotation = container_of(condition,
91 struct lttng_condition_session_rotation, parent);
92 if (!rotation->session_name) {
93 ERR("Invalid session rotation condition: a target session name must be set.");
94 goto end;
95 }
96
97 valid = true;
98 end:
99 return valid;
100 }
101
102 static
103 int lttng_condition_session_rotation_serialize(
104 const struct lttng_condition *condition,
105 struct lttng_payload *payload)
106 {
107 int ret;
108 size_t session_name_len;
109 struct lttng_condition_session_rotation *rotation;
110 struct lttng_condition_session_rotation_comm rotation_comm;
111
112 if (!condition || !is_rotation_condition(condition)) {
113 ret = -1;
114 goto end;
115 }
116
117 DBG("Serializing session rotation condition");
118 rotation = container_of(condition, struct lttng_condition_session_rotation,
119 parent);
120
121 session_name_len = strlen(rotation->session_name) + 1;
122 if (session_name_len > LTTNG_NAME_MAX) {
123 ret = -1;
124 goto end;
125 }
126
127 rotation_comm.session_name_len = session_name_len;
128 ret = lttng_dynamic_buffer_append(&payload->buffer, &rotation_comm,
129 sizeof(rotation_comm));
130 if (ret) {
131 goto end;
132 }
133 ret = lttng_dynamic_buffer_append(&payload->buffer,
134 rotation->session_name, session_name_len);
135 if (ret) {
136 goto end;
137 }
138 end:
139 return ret;
140 }
141
142 static
143 bool lttng_condition_session_rotation_is_equal(const struct lttng_condition *_a,
144 const struct lttng_condition *_b)
145 {
146 bool is_equal = false;
147 struct lttng_condition_session_rotation *a, *b;
148
149 a = container_of(_a, struct lttng_condition_session_rotation, parent);
150 b = container_of(_b, struct lttng_condition_session_rotation, parent);
151
152 /* Both session names must be set or both must be unset. */
153 if ((a->session_name && !b->session_name) ||
154 (!a->session_name && b->session_name)) {
155 WARN("Comparing session rotation conditions with uninitialized session names.");
156 goto end;
157 }
158
159 if (a->session_name && b->session_name &&
160 strcmp(a->session_name, b->session_name)) {
161 goto end;
162 }
163
164 is_equal = true;
165 end:
166 return is_equal;
167 }
168
169 static
170 void lttng_condition_session_rotation_destroy(
171 struct lttng_condition *condition)
172 {
173 struct lttng_condition_session_rotation *rotation;
174
175 rotation = container_of(condition,
176 struct lttng_condition_session_rotation, parent);
177
178 free(rotation->session_name);
179 free(rotation);
180 }
181
182 static
183 struct lttng_condition *lttng_condition_session_rotation_create(
184 enum lttng_condition_type type)
185 {
186 struct lttng_condition_session_rotation *condition;
187
188 condition = zmalloc(sizeof(struct lttng_condition_session_rotation));
189 if (!condition) {
190 return NULL;
191 }
192
193 memcpy(&condition->parent, &rotation_condition_template,
194 sizeof(condition->parent));
195 lttng_condition_init(&condition->parent, type);
196 return &condition->parent;
197 }
198
199 struct lttng_condition *lttng_condition_session_rotation_ongoing_create(void)
200 {
201 return lttng_condition_session_rotation_create(
202 LTTNG_CONDITION_TYPE_SESSION_ROTATION_ONGOING);
203 }
204
205 struct lttng_condition *lttng_condition_session_rotation_completed_create(void)
206 {
207 return lttng_condition_session_rotation_create(
208 LTTNG_CONDITION_TYPE_SESSION_ROTATION_COMPLETED);
209 }
210
211 static
212 ssize_t init_condition_from_payload(struct lttng_condition *condition,
213 struct lttng_payload_view *src_view)
214 {
215 ssize_t ret, condition_size;
216 enum lttng_condition_status status;
217 const char *session_name;
218 struct lttng_buffer_view name_view;
219 const struct lttng_condition_session_rotation_comm *condition_comm;
220 struct lttng_payload_view condition_comm_view =
221 lttng_payload_view_from_view(
222 src_view, 0, sizeof(*condition_comm));
223
224 if (!lttng_payload_view_is_valid(&condition_comm_view)) {
225 ERR("Failed to initialize from malformed condition buffer: buffer too short to contain header");
226 ret = -1;
227 goto end;
228 }
229
230 condition_comm = (typeof(condition_comm)) src_view->buffer.data;
231 name_view = lttng_buffer_view_from_view(&src_view->buffer,
232 sizeof(*condition_comm), condition_comm->session_name_len);
233
234 if (!lttng_buffer_view_is_valid(&name_view)) {
235 ERR("Failed to initialize from malformed condition buffer: buffer too short to contain session name");
236 ret = -1;
237 goto end;
238 }
239
240 if (condition_comm->session_name_len > LTTNG_NAME_MAX) {
241 ERR("Failed to initialize from malformed condition buffer: name exceeds LTTNG_MAX_NAME");
242 ret = -1;
243 goto end;
244 }
245
246 session_name = name_view.data;
247 if (*(session_name + condition_comm->session_name_len - 1) != '\0') {
248 ERR("Malformed session name encountered in condition buffer");
249 ret = -1;
250 goto end;
251 }
252
253 status = lttng_condition_session_rotation_set_session_name(condition,
254 session_name);
255 if (status != LTTNG_CONDITION_STATUS_OK) {
256 ERR("Failed to set buffer consumed session name");
257 ret = -1;
258 goto end;
259 }
260
261 if (!lttng_condition_validate(condition)) {
262 ret = -1;
263 goto end;
264 }
265
266 condition_size = sizeof(*condition_comm) +
267 (ssize_t) condition_comm->session_name_len;
268 ret = condition_size;
269 end:
270 return ret;
271 }
272
273 static
274 ssize_t lttng_condition_session_rotation_create_from_payload(
275 struct lttng_payload_view *view,
276 struct lttng_condition **_condition,
277 enum lttng_condition_type type)
278 {
279 ssize_t ret;
280 struct lttng_condition *condition = NULL;
281
282 switch (type) {
283 case LTTNG_CONDITION_TYPE_SESSION_ROTATION_ONGOING:
284 condition = lttng_condition_session_rotation_ongoing_create();
285 break;
286 case LTTNG_CONDITION_TYPE_SESSION_ROTATION_COMPLETED:
287 condition = lttng_condition_session_rotation_completed_create();
288 break;
289 default:
290 ret = -1;
291 goto error;
292 }
293
294 if (!_condition || !condition) {
295 ret = -1;
296 goto error;
297 }
298
299 ret = init_condition_from_payload(condition, view);
300 if (ret < 0) {
301 goto error;
302 }
303
304 *_condition = condition;
305 return ret;
306 error:
307 lttng_condition_destroy(condition);
308 return ret;
309 }
310
311 LTTNG_HIDDEN
312 ssize_t lttng_condition_session_rotation_ongoing_create_from_payload(
313 struct lttng_payload_view *view,
314 struct lttng_condition **condition)
315 {
316 return lttng_condition_session_rotation_create_from_payload(view,
317 condition,
318 LTTNG_CONDITION_TYPE_SESSION_ROTATION_ONGOING);
319 }
320
321 LTTNG_HIDDEN
322 ssize_t lttng_condition_session_rotation_completed_create_from_payload(
323 struct lttng_payload_view *view,
324 struct lttng_condition **condition)
325 {
326 return lttng_condition_session_rotation_create_from_payload(view,
327 condition,
328 LTTNG_CONDITION_TYPE_SESSION_ROTATION_COMPLETED);
329 }
330
331 static
332 struct lttng_evaluation *lttng_evaluation_session_rotation_create(
333 enum lttng_condition_type type, uint64_t id,
334 struct lttng_trace_archive_location *location)
335 {
336 struct lttng_evaluation_session_rotation *evaluation;
337
338 evaluation = zmalloc(sizeof(struct lttng_evaluation_session_rotation));
339 if (!evaluation) {
340 return NULL;
341 }
342
343 memcpy(&evaluation->parent, &rotation_evaluation_template,
344 sizeof(evaluation->parent));
345 lttng_evaluation_init(&evaluation->parent, type);
346 evaluation->id = id;
347 if (location) {
348 lttng_trace_archive_location_get(location);
349 }
350 evaluation->location = location;
351 return &evaluation->parent;
352 }
353
354 static
355 ssize_t create_evaluation_from_payload(
356 enum lttng_condition_type type,
357 struct lttng_payload_view *view,
358 struct lttng_evaluation **_evaluation)
359 {
360 ssize_t ret, size;
361 struct lttng_evaluation *evaluation = NULL;
362 struct lttng_trace_archive_location *location = NULL;
363 const struct lttng_evaluation_session_rotation_comm *comm;
364 struct lttng_payload_view comm_view = lttng_payload_view_from_view(
365 view, 0, sizeof(*comm));
366
367 if (!lttng_payload_view_is_valid(&comm_view)) {
368 goto error;
369 }
370
371 comm = (typeof(comm)) comm_view.buffer.data;
372 size = sizeof(*comm);
373 if (comm->has_location) {
374 const struct lttng_buffer_view location_view =
375 lttng_buffer_view_from_view(
376 &view->buffer, sizeof(*comm), -1);
377
378 if (!lttng_buffer_view_is_valid(&location_view)) {
379 goto error;
380 }
381
382 ret = lttng_trace_archive_location_create_from_buffer(
383 &location_view, &location);
384 if (ret < 0) {
385 goto error;
386 }
387 size += ret;
388 }
389
390 evaluation = lttng_evaluation_session_rotation_create(type, comm->id,
391 location);
392 if (!evaluation) {
393 goto error;
394 }
395
396 lttng_trace_archive_location_put(location);
397 ret = size;
398 *_evaluation = evaluation;
399 return ret;
400 error:
401 lttng_trace_archive_location_put(location);
402 evaluation = NULL;
403 return -1;
404 }
405
406 static
407 ssize_t lttng_evaluation_session_rotation_create_from_payload(
408 enum lttng_condition_type type,
409 struct lttng_payload_view *view,
410 struct lttng_evaluation **_evaluation)
411 {
412 ssize_t ret;
413 struct lttng_evaluation *evaluation = NULL;
414
415 if (!_evaluation) {
416 ret = -1;
417 goto error;
418 }
419
420 ret = create_evaluation_from_payload(type, view, &evaluation);
421 if (ret < 0) {
422 goto error;
423 }
424
425 *_evaluation = evaluation;
426 return ret;
427 error:
428 lttng_evaluation_destroy(evaluation);
429 return ret;
430 }
431
432 LTTNG_HIDDEN
433 ssize_t lttng_evaluation_session_rotation_ongoing_create_from_payload(
434 struct lttng_payload_view *view,
435 struct lttng_evaluation **evaluation)
436 {
437 return lttng_evaluation_session_rotation_create_from_payload(
438 LTTNG_CONDITION_TYPE_SESSION_ROTATION_ONGOING,
439 view, evaluation);
440 }
441
442 LTTNG_HIDDEN
443 ssize_t lttng_evaluation_session_rotation_completed_create_from_payload(
444 struct lttng_payload_view *view,
445 struct lttng_evaluation **evaluation)
446 {
447 return lttng_evaluation_session_rotation_create_from_payload(
448 LTTNG_CONDITION_TYPE_SESSION_ROTATION_COMPLETED,
449 view, evaluation);
450 }
451
452 LTTNG_HIDDEN
453 struct lttng_evaluation *lttng_evaluation_session_rotation_ongoing_create(
454 uint64_t id)
455 {
456 return lttng_evaluation_session_rotation_create(
457 LTTNG_CONDITION_TYPE_SESSION_ROTATION_ONGOING, id,
458 NULL);
459 }
460
461 LTTNG_HIDDEN
462 struct lttng_evaluation *lttng_evaluation_session_rotation_completed_create(
463 uint64_t id, struct lttng_trace_archive_location *location)
464 {
465 return lttng_evaluation_session_rotation_create(
466 LTTNG_CONDITION_TYPE_SESSION_ROTATION_COMPLETED, id,
467 location);
468 }
469
470 enum lttng_condition_status
471 lttng_condition_session_rotation_get_session_name(
472 const struct lttng_condition *condition,
473 const char **session_name)
474 {
475 struct lttng_condition_session_rotation *rotation;
476 enum lttng_condition_status status = LTTNG_CONDITION_STATUS_OK;
477
478 if (!condition || !is_rotation_condition(condition) || !session_name) {
479 status = LTTNG_CONDITION_STATUS_INVALID;
480 goto end;
481 }
482
483 rotation = container_of(condition, struct lttng_condition_session_rotation,
484 parent);
485 if (!rotation->session_name) {
486 status = LTTNG_CONDITION_STATUS_UNSET;
487 goto end;
488 }
489 *session_name = rotation->session_name;
490 end:
491 return status;
492 }
493
494 enum lttng_condition_status
495 lttng_condition_session_rotation_set_session_name(
496 struct lttng_condition *condition, const char *session_name)
497 {
498 char *session_name_copy;
499 struct lttng_condition_session_rotation *rotation;
500 enum lttng_condition_status status = LTTNG_CONDITION_STATUS_OK;
501
502 if (!condition || !is_rotation_condition(condition) ||
503 !session_name || strlen(session_name) == 0) {
504 status = LTTNG_CONDITION_STATUS_INVALID;
505 goto end;
506 }
507
508 rotation = container_of(condition,
509 struct lttng_condition_session_rotation, parent);
510 session_name_copy = strdup(session_name);
511 if (!session_name_copy) {
512 status = LTTNG_CONDITION_STATUS_ERROR;
513 goto end;
514 }
515
516 free(rotation->session_name);
517 rotation->session_name = session_name_copy;
518 end:
519 return status;
520 }
521
522 static
523 int lttng_evaluation_session_rotation_serialize(
524 const struct lttng_evaluation *evaluation,
525 struct lttng_payload *payload)
526 {
527 int ret;
528 struct lttng_evaluation_session_rotation *rotation;
529 struct lttng_evaluation_session_rotation_comm comm = { 0 };
530
531 rotation = container_of(evaluation,
532 struct lttng_evaluation_session_rotation, parent);
533 comm.id = rotation->id;
534 comm.has_location = !!rotation->location;
535 ret = lttng_dynamic_buffer_append(
536 &payload->buffer, &comm, sizeof(comm));
537 if (ret) {
538 goto end;
539 }
540 if (!rotation->location) {
541 goto end;
542 }
543 ret = lttng_trace_archive_location_serialize(rotation->location,
544 &payload->buffer);
545 end:
546 return ret;
547 }
548
549 static
550 void lttng_evaluation_session_rotation_destroy(
551 struct lttng_evaluation *evaluation)
552 {
553 struct lttng_evaluation_session_rotation *rotation;
554
555 rotation = container_of(evaluation,
556 struct lttng_evaluation_session_rotation, parent);
557 lttng_trace_archive_location_put(rotation->location);
558 free(rotation);
559 }
560
561 enum lttng_evaluation_status
562 lttng_evaluation_session_rotation_get_id(
563 const struct lttng_evaluation *evaluation, uint64_t *id)
564 {
565 const struct lttng_evaluation_session_rotation *rotation;
566 enum lttng_evaluation_status status = LTTNG_EVALUATION_STATUS_OK;
567
568 if (!evaluation || !id || !is_rotation_evaluation(evaluation)) {
569 status = LTTNG_EVALUATION_STATUS_INVALID;
570 goto end;
571 }
572
573 rotation = container_of(evaluation,
574 struct lttng_evaluation_session_rotation, parent);
575 *id = rotation->id;
576 end:
577 return status;
578 }
579
580 /*
581 * The public API assumes that trace archive locations are always provided as
582 * "constant". This means that the user of liblttng-ctl never has to destroy a
583 * trace archive location. Hence, users of liblttng-ctl have no visibility of
584 * the reference counting of archive locations.
585 */
586 enum lttng_evaluation_status
587 lttng_evaluation_session_rotation_completed_get_location(
588 const struct lttng_evaluation *evaluation,
589 const struct lttng_trace_archive_location **location)
590 {
591 const struct lttng_evaluation_session_rotation *rotation;
592 enum lttng_evaluation_status status = LTTNG_EVALUATION_STATUS_OK;
593
594 if (!evaluation || !location ||
595 evaluation->type != LTTNG_CONDITION_TYPE_SESSION_ROTATION_COMPLETED) {
596 status = LTTNG_EVALUATION_STATUS_INVALID;
597 goto end;
598 }
599
600 rotation = container_of(evaluation,
601 struct lttng_evaluation_session_rotation, parent);
602 *location = rotation->location;
603 end:
604 return status;
605 }
606
607 static
608 enum lttng_error_code lttng_condition_session_rotation_mi_serialize(
609 const struct lttng_condition *condition,
610 struct mi_writer *writer)
611 {
612 int ret;
613 enum lttng_error_code ret_code;
614 enum lttng_condition_status status;
615 const char *session_name = NULL;
616 const char *type_element_str = NULL;
617
618 assert(condition);
619 assert(writer);
620 assert(is_rotation_condition(condition));
621
622 switch (lttng_condition_get_type(condition)) {
623 case LTTNG_CONDITION_TYPE_SESSION_ROTATION_COMPLETED:
624 type_element_str =
625 mi_lttng_element_condition_session_rotation_completed;
626 break;
627 case LTTNG_CONDITION_TYPE_SESSION_ROTATION_ONGOING:
628 type_element_str =
629 mi_lttng_element_condition_session_rotation_ongoing;
630 break;
631 default:
632 abort();
633 break;
634 }
635
636 status = lttng_condition_session_rotation_get_session_name(
637 condition, &session_name);
638 assert(status == LTTNG_CONDITION_STATUS_OK);
639 assert(session_name);
640
641 /* Open condition session rotation_* element. */
642 ret = mi_lttng_writer_open_element(writer, type_element_str);
643 if (ret) {
644 goto mi_error;
645 }
646
647 /* Session name. */
648 ret = mi_lttng_writer_write_element_string(
649 writer, mi_lttng_element_session_name, session_name);
650 if (ret) {
651 goto mi_error;
652 }
653
654 /* Close condition session rotation element. */
655 ret = mi_lttng_writer_close_element(writer);
656 if (ret) {
657 goto mi_error;
658 }
659
660 ret_code = LTTNG_OK;
661 goto end;
662
663 mi_error:
664 ret_code = LTTNG_ERR_MI_IO_FAIL;
665 end:
666 return ret_code;
667 }
This page took 0.042999 seconds and 4 git commands to generate.