Fix: sessiond: NULL pointer dereference after NULL check
[lttng-tools.git] / src / common / tracker.c
1 /*
2 * Copyright (C) 2019 Jonathan Rajotte <jonathan.rajotte-julien@efficios.com>
3 * Copyright (C) 2020 Jérémie Galarneau <jeremie.galarneau@efficios.com>
4 *
5 * SPDX-License-Identifier: LGPL-2.1-only
6 *
7 */
8
9 #include <lttng/domain.h>
10 #include <lttng/lttng-error.h>
11 #include <lttng/tracker.h>
12
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
21 struct process_attr_tracker_values_comm_header {
22 uint32_t count;
23 };
24
25 struct 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; \
46 }
47
48 static 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;
53 }
54
55 static inline bool is_value_type_name(
56 enum lttng_process_attr_value_type value_type)
57 {
58 return value_type == LTTNG_PROCESS_ATTR_VALUE_TYPE_USER_NAME ||
59 value_type == LTTNG_PROCESS_ATTR_VALUE_TYPE_GROUP_NAME;
60 }
61
62 LTTNG_HIDDEN
63 enum 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)
70 {
71 char *name = NULL;
72 enum lttng_error_code ret = LTTNG_OK;
73 struct process_attr_value *value = zmalloc(sizeof(*value));
74
75 if (!value) {
76 ret = LTTNG_ERR_NOMEM;
77 goto error;
78 }
79
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;
88 goto error;
89 }
90 }
91
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 }
97
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 }
104
105 /* Only expect a payload for name value types. */
106 if (is_value_type_name(value_type) && value_view->size == 0) {
107 ret = LTTNG_ERR_INVALID_PROTOCOL;
108 goto error;
109 } else if (!is_value_type_name(value_type) && value_view &&
110 value_view->size != 0) {
111 ret = LTTNG_ERR_INVALID_PROTOCOL;
112 goto error;
113 }
114
115 value->type = value_type;
116 switch (process_attr) {
117 case LTTNG_PROCESS_ATTR_PROCESS_ID:
118 case LTTNG_PROCESS_ATTR_VIRTUAL_PROCESS_ID:
119 if (value_type != LTTNG_PROCESS_ATTR_VALUE_TYPE_PID) {
120 ERR("Invalid value type used for process ID process attribute");
121 ret = LTTNG_ERR_INVALID;
122 goto error;
123 }
124 value->value.pid =
125 GET_INTEGRAL_COMM_VALUE(integral_value, pid_t);
126 break;
127 case LTTNG_PROCESS_ATTR_USER_ID:
128 case LTTNG_PROCESS_ATTR_VIRTUAL_USER_ID:
129 switch (value_type) {
130 case LTTNG_PROCESS_ATTR_VALUE_TYPE_UID:
131 value->value.uid = GET_INTEGRAL_COMM_VALUE(
132 integral_value, uid_t);
133 break;
134 case LTTNG_PROCESS_ATTR_VALUE_TYPE_USER_NAME:
135 if (!name) {
136 ret = LTTNG_ERR_INVALID;
137 goto error;
138 }
139
140 value->value.user_name = name;
141 name = NULL;
142 break;
143 default:
144 ERR("Invalid value type used for user ID process attribute");
145 ret = LTTNG_ERR_INVALID;
146 goto error;
147 }
148 break;
149 case LTTNG_PROCESS_ATTR_GROUP_ID:
150 case LTTNG_PROCESS_ATTR_VIRTUAL_GROUP_ID:
151 switch (value_type) {
152 case LTTNG_PROCESS_ATTR_VALUE_TYPE_GID:
153 value->value.gid = GET_INTEGRAL_COMM_VALUE(
154 integral_value, gid_t);
155 break;
156 case LTTNG_PROCESS_ATTR_VALUE_TYPE_GROUP_NAME:
157 if (!name) {
158 ret = LTTNG_ERR_INVALID;
159 goto error;
160 }
161
162 value->value.group_name = name;
163 name = NULL;
164 break;
165 default:
166 ERR("Invalid value type used for group ID process attribute");
167 ret = LTTNG_ERR_INVALID;
168 goto error;
169 }
170 break;
171 default:
172 ret = LTTNG_ERR_INVALID_PROTOCOL;
173 goto error;
174 }
175
176 *_value = value;
177 value = NULL;
178 free(name);
179 return LTTNG_OK;
180 error:
181 free(name);
182 process_attr_value_destroy(value);
183 return ret;
184 }
185
186 LTTNG_HIDDEN
187 const char *lttng_process_attr_to_string(enum lttng_process_attr process_attr)
188 {
189 switch (process_attr) {
190 case LTTNG_PROCESS_ATTR_PROCESS_ID:
191 return "process ID";
192 case LTTNG_PROCESS_ATTR_VIRTUAL_PROCESS_ID:
193 return "virtual process ID";
194 case LTTNG_PROCESS_ATTR_USER_ID:
195 return "user ID";
196 case LTTNG_PROCESS_ATTR_VIRTUAL_USER_ID:
197 return "virtual user ID";
198 case LTTNG_PROCESS_ATTR_GROUP_ID:
199 return "group ID";
200 case LTTNG_PROCESS_ATTR_VIRTUAL_GROUP_ID:
201 return "virtual group ID";
202 default:
203 return "unknown process attribute";
204 }
205 }
206
207 static void process_attr_tracker_value_destructor(void *ptr)
208 {
209 struct process_attr_value *value = (typeof(value)) ptr;
210
211 process_attr_value_destroy(value);
212 }
213
214 LTTNG_HIDDEN
215 struct lttng_process_attr_values *lttng_process_attr_values_create(void)
216 {
217 struct lttng_process_attr_values *values = zmalloc(sizeof(*values));
218
219 if (!values) {
220 goto end;
221 }
222
223 lttng_dynamic_pointer_array_init(
224 &values->array, process_attr_tracker_value_destructor);
225 end:
226 return values;
227 }
228
229 LTTNG_HIDDEN
230 unsigned int _lttng_process_attr_values_get_count(
231 const struct lttng_process_attr_values *values)
232 {
233 return (unsigned int) lttng_dynamic_pointer_array_get_count(
234 &values->array);
235 }
236
237 LTTNG_HIDDEN
238 const struct process_attr_value *lttng_process_attr_tracker_values_get_at_index(
239 const struct lttng_process_attr_values *values,
240 unsigned int index)
241 {
242 return lttng_dynamic_pointer_array_get_pointer(&values->array, index);
243 }
244
245 static
246 int 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,
252 };
253 const char *name = NULL;
254
255 switch (value->type) {
256 case LTTNG_PROCESS_ATTR_VALUE_TYPE_PID:
257 SET_INTEGRAL_COMM_VALUE(
258 &value_comm.value.integral, value->value.pid);
259 break;
260 case LTTNG_PROCESS_ATTR_VALUE_TYPE_UID:
261 SET_INTEGRAL_COMM_VALUE(
262 &value_comm.value.integral, value->value.uid);
263 break;
264 case LTTNG_PROCESS_ATTR_VALUE_TYPE_GID:
265 SET_INTEGRAL_COMM_VALUE(
266 &value_comm.value.integral, value->value.gid);
267 break;
268 case LTTNG_PROCESS_ATTR_VALUE_TYPE_USER_NAME:
269 name = value->value.user_name;
270 break;
271 case LTTNG_PROCESS_ATTR_VALUE_TYPE_GROUP_NAME:
272 name = value->value.group_name;
273 break;
274 default:
275 abort();
276 }
277
278 if (name) {
279 value_comm.value.name_len = strlen(name) + 1;
280 }
281
282 ret = lttng_dynamic_buffer_append(
283 buffer, &value_comm, sizeof(value_comm));
284 if (ret) {
285 goto end;
286 }
287
288 if (name) {
289 ret = lttng_dynamic_buffer_append(
290 buffer, name, value_comm.value.name_len);
291 }
292 end:
293 return ret;
294 }
295
296 LTTNG_HIDDEN
297 int lttng_process_attr_values_serialize(
298 const struct lttng_process_attr_values *values,
299 struct lttng_dynamic_buffer *buffer)
300 {
301 int ret;
302 unsigned int count, i;
303 struct process_attr_tracker_values_comm_header header = {};
304
305 count = _lttng_process_attr_values_get_count(values);
306 header.count = (uint32_t) count;
307
308 ret = lttng_dynamic_buffer_append(buffer, &header, sizeof(header));
309 if (ret) {
310 goto end;
311 }
312
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);
317
318 ret = process_attr_tracker_value_serialize(value, buffer);
319 if (ret) {
320 goto end;
321 }
322 }
323 end:
324 return ret;
325 }
326
327 LTTNG_HIDDEN
328 ssize_t lttng_process_attr_values_create_from_buffer(
329 enum lttng_domain_type domain,
330 enum lttng_process_attr process_attr,
331 const struct lttng_buffer_view *buffer_view,
332 struct lttng_process_attr_values **_values)
333 {
334 ssize_t offset;
335 unsigned int i;
336 struct lttng_process_attr_values *values;
337 struct lttng_buffer_view header_view;
338 const struct process_attr_tracker_values_comm_header *header;
339
340 values = lttng_process_attr_values_create();
341 if (!values) {
342 goto error;
343 }
344
345 header_view = lttng_buffer_view_from_view(
346 buffer_view, 0, sizeof(*header));
347 if (!header_view.data) {
348 goto error;
349 }
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));
372 if (!value_view.data) {
373 goto error;
374 }
375
376 offset += value_view.size;
377 value_comm = (typeof(value_comm)) value_view.data;
378 type = (typeof(type)) value_comm->type;
379
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);
384 offset += value_name_view.size;
385 }
386 ret_code = process_attr_value_from_comm(domain, process_attr,
387 type, &value_comm->value.integral,
388 &value_name_view, &value);
389 if (ret_code != LTTNG_OK) {
390 goto error;
391 }
392
393 ret = lttng_dynamic_pointer_array_add_pointer(
394 &values->array, value);
395 if (ret) {
396 process_attr_value_destroy(value);
397 goto error;
398 }
399 }
400
401 *_values = values;
402 return offset;
403 error:
404 lttng_process_attr_values_destroy(values);
405 return -1;
406 }
407
408 LTTNG_HIDDEN
409 void lttng_process_attr_values_destroy(struct lttng_process_attr_values *values)
410 {
411 if (!values) {
412 return;
413 }
414 lttng_dynamic_pointer_array_reset(&values->array);
415 free(values);
416 }
417
418 LTTNG_HIDDEN
419 struct process_attr_value *process_attr_value_copy(
420 const struct process_attr_value *value)
421 {
422 struct process_attr_value *new_value = NULL;
423
424 if (!value) {
425 goto end;
426 }
427
428 new_value = zmalloc(sizeof(*new_value));
429 if (!new_value) {
430 goto end;
431 }
432 if (is_value_type_name(value->type)) {
433 const char *src =
434 value->type == LTTNG_PROCESS_ATTR_VALUE_TYPE_USER_NAME ?
435 value->value.user_name :
436 value->value.group_name;
437 char **dst = value->type == LTTNG_PROCESS_ATTR_VALUE_TYPE_USER_NAME ?
438 &new_value->value.user_name :
439 &new_value->value.group_name;
440
441 new_value->type = value->type;
442 *dst = strdup(src);
443 if (!*dst) {
444 goto error;
445 }
446 } else {
447 *new_value = *value;
448 }
449 end:
450 return new_value;
451 error:
452 free(new_value);
453 return NULL;
454 }
455
456 LTTNG_HIDDEN
457 unsigned long process_attr_value_hash(const struct process_attr_value *a)
458 {
459 unsigned long hash = hash_key_ulong((void *) a->type, lttng_ht_seed);
460
461 switch (a->type) {
462 case LTTNG_PROCESS_ATTR_VALUE_TYPE_PID:
463 hash ^= hash_key_ulong((void *) (unsigned long) a->value.pid,
464 lttng_ht_seed);
465 break;
466 case LTTNG_PROCESS_ATTR_VALUE_TYPE_UID:
467 hash ^= hash_key_ulong((void *) (unsigned long) a->value.uid,
468 lttng_ht_seed);
469 break;
470 case LTTNG_PROCESS_ATTR_VALUE_TYPE_GID:
471 hash ^= hash_key_ulong((void *) (unsigned long) a->value.gid,
472 lttng_ht_seed);
473 break;
474 case LTTNG_PROCESS_ATTR_VALUE_TYPE_USER_NAME:
475 hash ^= hash_key_str(a->value.user_name, lttng_ht_seed);
476 break;
477 case LTTNG_PROCESS_ATTR_VALUE_TYPE_GROUP_NAME:
478 hash ^= hash_key_str(a->value.group_name, lttng_ht_seed);
479 break;
480 default:
481 abort();
482 }
483
484 return hash;
485 }
486
487 LTTNG_HIDDEN
488 bool process_attr_tracker_value_equal(const struct process_attr_value *a,
489 const struct process_attr_value *b)
490 {
491 if (a->type != b->type) {
492 return false;
493 }
494 switch (a->type) {
495 case LTTNG_PROCESS_ATTR_VALUE_TYPE_PID:
496 return a->value.pid == b->value.pid;
497 case LTTNG_PROCESS_ATTR_VALUE_TYPE_UID:
498 return a->value.uid == b->value.uid;
499 case LTTNG_PROCESS_ATTR_VALUE_TYPE_GID:
500 return a->value.gid == b->value.gid;
501 case LTTNG_PROCESS_ATTR_VALUE_TYPE_USER_NAME:
502 return !strcmp(a->value.user_name, b->value.user_name);
503 case LTTNG_PROCESS_ATTR_VALUE_TYPE_GROUP_NAME:
504 return !strcmp(a->value.group_name, b->value.group_name);
505 default:
506 abort();
507 }
508 }
509
510 LTTNG_HIDDEN
511 void process_attr_value_destroy(struct process_attr_value *value)
512 {
513 if (!value) {
514 return;
515 }
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);
522 }
This page took 0.061506 seconds and 4 git commands to generate.