Fix: lttng: enable-channel: leak of popt arguments
[lttng-tools.git] / src / common / tracker.cpp
CommitLineData
2d97a006 1/*
4942c256 2 * Copyright (C) 2019 Jonathan Rajotte <jonathan.rajotte-julien@efficios.com>
159b042f 3 * Copyright (C) 2020 Jérémie Galarneau <jeremie.galarneau@efficios.com>
2d97a006 4 *
ab5be9fa 5 * SPDX-License-Identifier: LGPL-2.1-only
2d97a006 6 *
2d97a006
JR
7 */
8
159b042f
JG
9#include <lttng/domain.h>
10#include <lttng/lttng-error.h>
11#include <lttng/tracker.h>
2d97a006 12
c9e313bc
SM
13#include <common/dynamic-array.hpp>
14#include <common/error.hpp>
15#include <common/hashtable/hashtable.hpp>
16#include <common/hashtable/utils.hpp>
17#include <common/tracker.hpp>
159b042f
JG
18
19#include <stdbool.h>
20
c10f9cdd
MJ
21#include <type_traits>
22
f1494934 23namespace {
159b042f
JG
24struct process_attr_tracker_values_comm_header {
25 uint32_t count;
2d7da303 26} LTTNG_PACKED;
159b042f
JG
27
28struct process_attr_tracker_value_comm {
29 /* enum lttng_process_attr_value_type */
30 int32_t type;
31 union {
32 struct process_attr_integral_value_comm integral;
33 /* Includes the '\0' terminator. */
34 uint32_t name_len;
35 } value;
2d7da303 36} LTTNG_PACKED;
f1494934 37} /* namespace */
159b042f
JG
38
39#define GET_INTEGRAL_COMM_VALUE(value_ptr, as_type) \
c10f9cdd 40 ((as_type)(std::is_signed<as_type>::value ? (value_ptr)->u._signed : \
159b042f
JG
41 (value_ptr)->u._unsigned))
42
c10f9cdd
MJ
43#define SET_INTEGRAL_COMM_VALUE(comm_value, val) \
44 if (std::is_signed<typeof(val)>::value) { \
159b042f 45 (comm_value)->u._signed = \
c10f9cdd 46 (typeof((comm_value)->u._signed)) val; \
159b042f
JG
47 } else { \
48 (comm_value)->u._unsigned = \
c10f9cdd 49 (typeof((comm_value)->u._unsigned)) val; \
2d97a006
JR
50 }
51
159b042f
JG
52static inline bool is_virtual_process_attr(enum lttng_process_attr process_attr)
53{
54 return process_attr == LTTNG_PROCESS_ATTR_VIRTUAL_PROCESS_ID ||
55 process_attr == LTTNG_PROCESS_ATTR_VIRTUAL_USER_ID ||
56 process_attr == LTTNG_PROCESS_ATTR_VIRTUAL_GROUP_ID;
2d97a006
JR
57}
58
159b042f
JG
59static inline bool is_value_type_name(
60 enum lttng_process_attr_value_type value_type)
2d97a006 61{
159b042f
JG
62 return value_type == LTTNG_PROCESS_ATTR_VALUE_TYPE_USER_NAME ||
63 value_type == LTTNG_PROCESS_ATTR_VALUE_TYPE_GROUP_NAME;
2d97a006
JR
64}
65
159b042f
JG
66enum lttng_error_code process_attr_value_from_comm(
67 enum lttng_domain_type domain,
68 enum lttng_process_attr process_attr,
69 enum lttng_process_attr_value_type value_type,
70 const struct process_attr_integral_value_comm *integral_value,
71 const struct lttng_buffer_view *value_view,
72 struct process_attr_value **_value)
2d97a006 73{
159b042f
JG
74 char *name = NULL;
75 enum lttng_error_code ret = LTTNG_OK;
64803277 76 struct process_attr_value *value = zmalloc<process_attr_value>();
2d97a006 77
159b042f
JG
78 if (!value) {
79 ret = LTTNG_ERR_NOMEM;
2d97a006
JR
80 goto error;
81 }
82
159b042f
JG
83 if (value_view && value_view->size > 0) {
84 if (value_view->data[value_view->size - 1] != '\0') {
85 ret = LTTNG_ERR_INVALID;
86 goto error;
87 }
88 name = strdup(value_view->data);
89 if (!name) {
90 ret = LTTNG_ERR_NOMEM;
74675e31 91 goto error;
159b042f
JG
92 }
93 }
2d97a006 94
159b042f
JG
95 if (domain != LTTNG_DOMAIN_UST && domain != LTTNG_DOMAIN_KERNEL) {
96 ERR("Only the user space and kernel space domains may be specified to configure process attribute trackers");
97 ret = LTTNG_ERR_UNSUPPORTED_DOMAIN;
98 goto error;
99 }
2d97a006 100
159b042f
JG
101 if (!is_virtual_process_attr(process_attr) &&
102 domain != LTTNG_DOMAIN_KERNEL) {
103 ERR("Non-virtual process attributes can only be used in the kernel domain");
104 ret = LTTNG_ERR_UNSUPPORTED_DOMAIN;
105 goto error;
106 }
2d97a006 107
159b042f 108 /* Only expect a payload for name value types. */
b78dab17
JG
109 if (is_value_type_name(value_type) &&
110 (!value_view || value_view->size == 0)) {
159b042f
JG
111 ret = LTTNG_ERR_INVALID_PROTOCOL;
112 goto error;
1ad5cb59
JG
113 } else if (!is_value_type_name(value_type) && value_view &&
114 value_view->size != 0) {
159b042f
JG
115 ret = LTTNG_ERR_INVALID_PROTOCOL;
116 goto error;
2d97a006
JR
117 }
118
159b042f
JG
119 value->type = value_type;
120 switch (process_attr) {
121 case LTTNG_PROCESS_ATTR_PROCESS_ID:
122 case LTTNG_PROCESS_ATTR_VIRTUAL_PROCESS_ID:
123 if (value_type != LTTNG_PROCESS_ATTR_VALUE_TYPE_PID) {
124 ERR("Invalid value type used for process ID process attribute");
125 ret = LTTNG_ERR_INVALID;
126 goto error;
127 }
128 value->value.pid =
129 GET_INTEGRAL_COMM_VALUE(integral_value, pid_t);
130 break;
131 case LTTNG_PROCESS_ATTR_USER_ID:
132 case LTTNG_PROCESS_ATTR_VIRTUAL_USER_ID:
133 switch (value_type) {
134 case LTTNG_PROCESS_ATTR_VALUE_TYPE_UID:
135 value->value.uid = GET_INTEGRAL_COMM_VALUE(
136 integral_value, uid_t);
137 break;
138 case LTTNG_PROCESS_ATTR_VALUE_TYPE_USER_NAME:
139 if (!name) {
140 ret = LTTNG_ERR_INVALID;
141 goto error;
142 }
143
144 value->value.user_name = name;
145 name = NULL;
146 break;
147 default:
148 ERR("Invalid value type used for user ID process attribute");
149 ret = LTTNG_ERR_INVALID;
150 goto error;
151 }
152 break;
153 case LTTNG_PROCESS_ATTR_GROUP_ID:
154 case LTTNG_PROCESS_ATTR_VIRTUAL_GROUP_ID:
155 switch (value_type) {
156 case LTTNG_PROCESS_ATTR_VALUE_TYPE_GID:
157 value->value.gid = GET_INTEGRAL_COMM_VALUE(
158 integral_value, gid_t);
159 break;
160 case LTTNG_PROCESS_ATTR_VALUE_TYPE_GROUP_NAME:
161 if (!name) {
162 ret = LTTNG_ERR_INVALID;
163 goto error;
164 }
165
166 value->value.group_name = name;
167 name = NULL;
168 break;
169 default:
170 ERR("Invalid value type used for group ID process attribute");
171 ret = LTTNG_ERR_INVALID;
172 goto error;
173 }
174 break;
175 default:
176 ret = LTTNG_ERR_INVALID_PROTOCOL;
177 goto error;
2d97a006
JR
178 }
179
159b042f
JG
180 *_value = value;
181 value = NULL;
d4e37173 182 free(name);
159b042f
JG
183 return LTTNG_OK;
184error:
185 free(name);
186 process_attr_value_destroy(value);
187 return ret;
2d97a006
JR
188}
189
159b042f 190const char *lttng_process_attr_to_string(enum lttng_process_attr process_attr)
2d97a006 191{
159b042f
JG
192 switch (process_attr) {
193 case LTTNG_PROCESS_ATTR_PROCESS_ID:
194 return "process ID";
195 case LTTNG_PROCESS_ATTR_VIRTUAL_PROCESS_ID:
196 return "virtual process ID";
197 case LTTNG_PROCESS_ATTR_USER_ID:
198 return "user ID";
199 case LTTNG_PROCESS_ATTR_VIRTUAL_USER_ID:
200 return "virtual user ID";
201 case LTTNG_PROCESS_ATTR_GROUP_ID:
202 return "group ID";
203 case LTTNG_PROCESS_ATTR_VIRTUAL_GROUP_ID:
204 return "virtual group ID";
205 default:
206 return "unknown process attribute";
2d97a006 207 }
2d97a006
JR
208}
209
159b042f 210static void process_attr_tracker_value_destructor(void *ptr)
2d97a006 211{
159b042f
JG
212 struct process_attr_value *value = (typeof(value)) ptr;
213
214 process_attr_value_destroy(value);
2d97a006
JR
215}
216
159b042f 217struct lttng_process_attr_values *lttng_process_attr_values_create(void)
2d97a006 218{
64803277 219 struct lttng_process_attr_values *values = zmalloc<lttng_process_attr_values>();
2d97a006 220
159b042f
JG
221 if (!values) {
222 goto end;
2d97a006
JR
223 }
224
159b042f
JG
225 lttng_dynamic_pointer_array_init(
226 &values->array, process_attr_tracker_value_destructor);
227end:
228 return values;
2d97a006
JR
229}
230
159b042f
JG
231unsigned int _lttng_process_attr_values_get_count(
232 const struct lttng_process_attr_values *values)
2d97a006 233{
159b042f
JG
234 return (unsigned int) lttng_dynamic_pointer_array_get_count(
235 &values->array);
2d97a006
JR
236}
237
159b042f
JG
238const struct process_attr_value *lttng_process_attr_tracker_values_get_at_index(
239 const struct lttng_process_attr_values *values,
240 unsigned int index)
2d97a006 241{
a6bc4ca9 242 return (process_attr_value *) lttng_dynamic_pointer_array_get_pointer(&values->array, index);
159b042f 243}
2d97a006 244
159b042f
JG
245static
246int process_attr_tracker_value_serialize(const struct process_attr_value *value,
247 struct lttng_dynamic_buffer *buffer)
248{
249 int ret;
250 struct process_attr_tracker_value_comm value_comm = {
251 .type = (int32_t) value->type,
1c9a0b0e 252 .value = {},
159b042f
JG
253 };
254 const char *name = NULL;
255
256 switch (value->type) {
257 case LTTNG_PROCESS_ATTR_VALUE_TYPE_PID:
258 SET_INTEGRAL_COMM_VALUE(
259 &value_comm.value.integral, value->value.pid);
2d97a006 260 break;
159b042f
JG
261 case LTTNG_PROCESS_ATTR_VALUE_TYPE_UID:
262 SET_INTEGRAL_COMM_VALUE(
263 &value_comm.value.integral, value->value.uid);
2d97a006 264 break;
159b042f
JG
265 case LTTNG_PROCESS_ATTR_VALUE_TYPE_GID:
266 SET_INTEGRAL_COMM_VALUE(
267 &value_comm.value.integral, value->value.gid);
2d97a006 268 break;
159b042f
JG
269 case LTTNG_PROCESS_ATTR_VALUE_TYPE_USER_NAME:
270 name = value->value.user_name;
2d97a006 271 break;
159b042f
JG
272 case LTTNG_PROCESS_ATTR_VALUE_TYPE_GROUP_NAME:
273 name = value->value.group_name;
274 break;
275 default:
276 abort();
2d97a006
JR
277 }
278
159b042f
JG
279 if (name) {
280 value_comm.value.name_len = strlen(name) + 1;
a7a533cd 281 }
159b042f
JG
282
283 ret = lttng_dynamic_buffer_append(
284 buffer, &value_comm, sizeof(value_comm));
285 if (ret) {
286 goto end;
287 }
288
289 if (name) {
290 ret = lttng_dynamic_buffer_append(
291 buffer, name, value_comm.value.name_len);
292 }
293end:
a7a533cd
JR
294 return ret;
295}
296
159b042f
JG
297int lttng_process_attr_values_serialize(
298 const struct lttng_process_attr_values *values,
299 struct lttng_dynamic_buffer *buffer)
a7a533cd
JR
300{
301 int ret;
159b042f
JG
302 unsigned int count, i;
303 struct process_attr_tracker_values_comm_header header = {};
a7a533cd 304
159b042f
JG
305 count = _lttng_process_attr_values_get_count(values);
306 header.count = (uint32_t) count;
a7a533cd 307
159b042f 308 ret = lttng_dynamic_buffer_append(buffer, &header, sizeof(header));
a7a533cd 309 if (ret) {
159b042f 310 goto end;
2d97a006
JR
311 }
312
159b042f
JG
313 for (i = 0; i < count; i++) {
314 const struct process_attr_value *value =
315 lttng_process_attr_tracker_values_get_at_index(
316 values, i);
2d97a006 317
159b042f
JG
318 ret = process_attr_tracker_value_serialize(value, buffer);
319 if (ret) {
320 goto end;
321 }
2d97a006 322 }
159b042f
JG
323end:
324 return ret;
2d97a006 325}
a7a533cd 326
159b042f
JG
327ssize_t lttng_process_attr_values_create_from_buffer(
328 enum lttng_domain_type domain,
329 enum lttng_process_attr process_attr,
330 const struct lttng_buffer_view *buffer_view,
331 struct lttng_process_attr_values **_values)
a7a533cd 332{
159b042f
JG
333 ssize_t offset;
334 unsigned int i;
335 struct lttng_process_attr_values *values;
336 struct lttng_buffer_view header_view;
337 const struct process_attr_tracker_values_comm_header *header;
a7a533cd 338
159b042f
JG
339 values = lttng_process_attr_values_create();
340 if (!values) {
a7a533cd
JR
341 goto error;
342 }
343
159b042f
JG
344 header_view = lttng_buffer_view_from_view(
345 buffer_view, 0, sizeof(*header));
3e6e0df2 346 if (!lttng_buffer_view_is_valid(&header_view)) {
a7a533cd
JR
347 goto error;
348 }
3e6e0df2 349
159b042f
JG
350 offset = header_view.size;
351 header = (typeof(header)) header_view.data;
352
353 /*
354 * Check that the number of values is not absurdly large with respect to
355 * the received buffer's size.
356 */
357 if (buffer_view->size <
358 header->count * sizeof(struct process_attr_tracker_value_comm)) {
359 goto error;
360 }
361 for (i = 0; i < (unsigned int) header->count; i++) {
362 int ret;
363 enum lttng_error_code ret_code;
364 const struct process_attr_tracker_value_comm *value_comm;
365 struct process_attr_value *value;
366 enum lttng_process_attr_value_type type;
367 struct lttng_buffer_view value_view;
368 struct lttng_buffer_view value_name_view = {};
369
370 value_view = lttng_buffer_view_from_view(
371 buffer_view, offset, sizeof(*value_comm));
3e6e0df2 372 if (!lttng_buffer_view_is_valid(&value_view)) {
159b042f
JG
373 goto error;
374 }
a7a533cd 375
159b042f
JG
376 offset += value_view.size;
377 value_comm = (typeof(value_comm)) value_view.data;
378 type = (typeof(type)) value_comm->type;
a7a533cd 379
159b042f
JG
380 if (is_value_type_name(type)) {
381 value_name_view = lttng_buffer_view_from_view(
382 buffer_view, offset,
383 value_comm->value.name_len);
3e6e0df2
JG
384 if (!lttng_buffer_view_is_valid(&value_name_view)) {
385 goto error;
386 }
387
159b042f
JG
388 offset += value_name_view.size;
389 }
3e6e0df2 390
159b042f
JG
391 ret_code = process_attr_value_from_comm(domain, process_attr,
392 type, &value_comm->value.integral,
393 &value_name_view, &value);
394 if (ret_code != LTTNG_OK) {
395 goto error;
396 }
a7a533cd 397
159b042f
JG
398 ret = lttng_dynamic_pointer_array_add_pointer(
399 &values->array, value);
400 if (ret) {
401 process_attr_value_destroy(value);
402 goto error;
403 }
a7a533cd
JR
404 }
405
159b042f
JG
406 *_values = values;
407 return offset;
408error:
409 lttng_process_attr_values_destroy(values);
410 return -1;
a7a533cd
JR
411}
412
159b042f 413void lttng_process_attr_values_destroy(struct lttng_process_attr_values *values)
a7a533cd 414{
159b042f
JG
415 if (!values) {
416 return;
417 }
418 lttng_dynamic_pointer_array_reset(&values->array);
419 free(values);
a7a533cd
JR
420}
421
159b042f
JG
422struct process_attr_value *process_attr_value_copy(
423 const struct process_attr_value *value)
a7a533cd 424{
159b042f 425 struct process_attr_value *new_value = NULL;
e283e4a0 426
159b042f 427 if (!value) {
e283e4a0
JR
428 goto end;
429 }
430
64803277 431 new_value = zmalloc<process_attr_value>();
159b042f
JG
432 if (!new_value) {
433 goto end;
434 }
435 if (is_value_type_name(value->type)) {
436 const char *src =
437 value->type == LTTNG_PROCESS_ATTR_VALUE_TYPE_USER_NAME ?
438 value->value.user_name :
439 value->value.group_name;
440 char **dst = value->type == LTTNG_PROCESS_ATTR_VALUE_TYPE_USER_NAME ?
441 &new_value->value.user_name :
442 &new_value->value.group_name;
443
444 new_value->type = value->type;
445 *dst = strdup(src);
446 if (!*dst) {
447 goto error;
448 }
449 } else {
450 *new_value = *value;
451 }
e283e4a0 452end:
159b042f
JG
453 return new_value;
454error:
455 free(new_value);
456 return NULL;
a7a533cd
JR
457}
458
159b042f 459unsigned long process_attr_value_hash(const struct process_attr_value *a)
a7a533cd 460{
159b042f 461 unsigned long hash = hash_key_ulong((void *) a->type, lttng_ht_seed);
9df6c82a 462
159b042f
JG
463 switch (a->type) {
464 case LTTNG_PROCESS_ATTR_VALUE_TYPE_PID:
465 hash ^= hash_key_ulong((void *) (unsigned long) a->value.pid,
466 lttng_ht_seed);
467 break;
468 case LTTNG_PROCESS_ATTR_VALUE_TYPE_UID:
469 hash ^= hash_key_ulong((void *) (unsigned long) a->value.uid,
470 lttng_ht_seed);
471 break;
472 case LTTNG_PROCESS_ATTR_VALUE_TYPE_GID:
473 hash ^= hash_key_ulong((void *) (unsigned long) a->value.gid,
474 lttng_ht_seed);
475 break;
476 case LTTNG_PROCESS_ATTR_VALUE_TYPE_USER_NAME:
477 hash ^= hash_key_str(a->value.user_name, lttng_ht_seed);
478 break;
479 case LTTNG_PROCESS_ATTR_VALUE_TYPE_GROUP_NAME:
480 hash ^= hash_key_str(a->value.group_name, lttng_ht_seed);
481 break;
482 default:
483 abort();
a7a533cd
JR
484 }
485
159b042f 486 return hash;
a7a533cd 487}
f19f5c96 488
159b042f
JG
489bool process_attr_tracker_value_equal(const struct process_attr_value *a,
490 const struct process_attr_value *b)
f19f5c96 491{
159b042f
JG
492 if (a->type != b->type) {
493 return false;
f19f5c96 494 }
159b042f
JG
495 switch (a->type) {
496 case LTTNG_PROCESS_ATTR_VALUE_TYPE_PID:
497 return a->value.pid == b->value.pid;
498 case LTTNG_PROCESS_ATTR_VALUE_TYPE_UID:
499 return a->value.uid == b->value.uid;
500 case LTTNG_PROCESS_ATTR_VALUE_TYPE_GID:
501 return a->value.gid == b->value.gid;
502 case LTTNG_PROCESS_ATTR_VALUE_TYPE_USER_NAME:
503 return !strcmp(a->value.user_name, b->value.user_name);
504 case LTTNG_PROCESS_ATTR_VALUE_TYPE_GROUP_NAME:
505 return !strcmp(a->value.group_name, b->value.group_name);
506 default:
507 abort();
508 }
509}
f19f5c96 510
159b042f
JG
511void process_attr_value_destroy(struct process_attr_value *value)
512{
513 if (!value) {
514 return;
f19f5c96 515 }
159b042f
JG
516 if (is_value_type_name(value->type)) {
517 free(value->type == LTTNG_PROCESS_ATTR_VALUE_TYPE_USER_NAME ?
518 value->value.user_name :
519 value->value.group_name);
520 }
521 free(value);
f19f5c96 522}
This page took 0.086463 seconds and 4 git commands to generate.