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