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