Fix: sessiond: user/group name can be leaked on malformed command
[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 }
89 }
90
91 if (domain != LTTNG_DOMAIN_UST && domain != LTTNG_DOMAIN_KERNEL) {
92 ERR("Only the user space and kernel space domains may be specified to configure process attribute trackers");
93 ret = LTTNG_ERR_UNSUPPORTED_DOMAIN;
94 goto error;
95 }
96
97 if (!is_virtual_process_attr(process_attr) &&
98 domain != LTTNG_DOMAIN_KERNEL) {
99 ERR("Non-virtual process attributes can only be used in the kernel domain");
100 ret = LTTNG_ERR_UNSUPPORTED_DOMAIN;
101 goto error;
102 }
103
104 /* Only expect a payload for name value types. */
105 if (is_value_type_name(value_type) && value_view->size == 0) {
106 ret = LTTNG_ERR_INVALID_PROTOCOL;
107 goto error;
108 } else if (!is_value_type_name(value_type) && value_view->size != 0) {
109 ret = LTTNG_ERR_INVALID_PROTOCOL;
110 goto error;
111 }
112
113 value->type = value_type;
114 switch (process_attr) {
115 case LTTNG_PROCESS_ATTR_PROCESS_ID:
116 case LTTNG_PROCESS_ATTR_VIRTUAL_PROCESS_ID:
117 if (value_type != LTTNG_PROCESS_ATTR_VALUE_TYPE_PID) {
118 ERR("Invalid value type used for process ID process attribute");
119 ret = LTTNG_ERR_INVALID;
120 goto error;
121 }
122 value->value.pid =
123 GET_INTEGRAL_COMM_VALUE(integral_value, pid_t);
124 break;
125 case LTTNG_PROCESS_ATTR_USER_ID:
126 case LTTNG_PROCESS_ATTR_VIRTUAL_USER_ID:
127 switch (value_type) {
128 case LTTNG_PROCESS_ATTR_VALUE_TYPE_UID:
129 value->value.uid = GET_INTEGRAL_COMM_VALUE(
130 integral_value, uid_t);
131 break;
132 case LTTNG_PROCESS_ATTR_VALUE_TYPE_USER_NAME:
133 if (!name) {
134 ret = LTTNG_ERR_INVALID;
135 goto error;
136 }
137
138 value->value.user_name = name;
139 name = NULL;
140 break;
141 default:
142 ERR("Invalid value type used for user ID process attribute");
143 ret = LTTNG_ERR_INVALID;
144 goto error;
145 }
146 break;
147 case LTTNG_PROCESS_ATTR_GROUP_ID:
148 case LTTNG_PROCESS_ATTR_VIRTUAL_GROUP_ID:
149 switch (value_type) {
150 case LTTNG_PROCESS_ATTR_VALUE_TYPE_GID:
151 value->value.gid = GET_INTEGRAL_COMM_VALUE(
152 integral_value, gid_t);
153 break;
154 case LTTNG_PROCESS_ATTR_VALUE_TYPE_GROUP_NAME:
155 if (!name) {
156 ret = LTTNG_ERR_INVALID;
157 goto error;
158 }
159
160 value->value.group_name = name;
161 name = NULL;
162 break;
163 default:
164 ERR("Invalid value type used for group ID process attribute");
165 ret = LTTNG_ERR_INVALID;
166 goto error;
167 }
168 break;
169 default:
170 ret = LTTNG_ERR_INVALID_PROTOCOL;
171 goto error;
172 }
173
174 *_value = value;
175 value = NULL;
176 free(name);
177 return LTTNG_OK;
178 error:
179 free(name);
180 process_attr_value_destroy(value);
181 return ret;
182 }
183
184 LTTNG_HIDDEN
185 const char *lttng_process_attr_to_string(enum lttng_process_attr process_attr)
186 {
187 switch (process_attr) {
188 case LTTNG_PROCESS_ATTR_PROCESS_ID:
189 return "process ID";
190 case LTTNG_PROCESS_ATTR_VIRTUAL_PROCESS_ID:
191 return "virtual process ID";
192 case LTTNG_PROCESS_ATTR_USER_ID:
193 return "user ID";
194 case LTTNG_PROCESS_ATTR_VIRTUAL_USER_ID:
195 return "virtual user ID";
196 case LTTNG_PROCESS_ATTR_GROUP_ID:
197 return "group ID";
198 case LTTNG_PROCESS_ATTR_VIRTUAL_GROUP_ID:
199 return "virtual group ID";
200 default:
201 return "unknown process attribute";
202 }
203 }
204
205 static void process_attr_tracker_value_destructor(void *ptr)
206 {
207 struct process_attr_value *value = (typeof(value)) ptr;
208
209 process_attr_value_destroy(value);
210 }
211
212 LTTNG_HIDDEN
213 struct lttng_process_attr_values *lttng_process_attr_values_create(void)
214 {
215 struct lttng_process_attr_values *values = zmalloc(sizeof(*values));
216
217 if (!values) {
218 goto end;
219 }
220
221 lttng_dynamic_pointer_array_init(
222 &values->array, process_attr_tracker_value_destructor);
223 end:
224 return values;
225 }
226
227 LTTNG_HIDDEN
228 unsigned int _lttng_process_attr_values_get_count(
229 const struct lttng_process_attr_values *values)
230 {
231 return (unsigned int) lttng_dynamic_pointer_array_get_count(
232 &values->array);
233 }
234
235 LTTNG_HIDDEN
236 const struct process_attr_value *lttng_process_attr_tracker_values_get_at_index(
237 const struct lttng_process_attr_values *values,
238 unsigned int index)
239 {
240 return lttng_dynamic_pointer_array_get_pointer(&values->array, index);
241 }
242
243 static
244 int process_attr_tracker_value_serialize(const struct process_attr_value *value,
245 struct lttng_dynamic_buffer *buffer)
246 {
247 int ret;
248 struct process_attr_tracker_value_comm value_comm = {
249 .type = (int32_t) value->type,
250 };
251 const char *name = NULL;
252
253 switch (value->type) {
254 case LTTNG_PROCESS_ATTR_VALUE_TYPE_PID:
255 SET_INTEGRAL_COMM_VALUE(
256 &value_comm.value.integral, value->value.pid);
257 break;
258 case LTTNG_PROCESS_ATTR_VALUE_TYPE_UID:
259 SET_INTEGRAL_COMM_VALUE(
260 &value_comm.value.integral, value->value.uid);
261 break;
262 case LTTNG_PROCESS_ATTR_VALUE_TYPE_GID:
263 SET_INTEGRAL_COMM_VALUE(
264 &value_comm.value.integral, value->value.gid);
265 break;
266 case LTTNG_PROCESS_ATTR_VALUE_TYPE_USER_NAME:
267 name = value->value.user_name;
268 break;
269 case LTTNG_PROCESS_ATTR_VALUE_TYPE_GROUP_NAME:
270 name = value->value.group_name;
271 break;
272 default:
273 abort();
274 }
275
276 if (name) {
277 value_comm.value.name_len = strlen(name) + 1;
278 }
279
280 ret = lttng_dynamic_buffer_append(
281 buffer, &value_comm, sizeof(value_comm));
282 if (ret) {
283 goto end;
284 }
285
286 if (name) {
287 ret = lttng_dynamic_buffer_append(
288 buffer, name, value_comm.value.name_len);
289 }
290 end:
291 return ret;
292 }
293
294 LTTNG_HIDDEN
295 int lttng_process_attr_values_serialize(
296 const struct lttng_process_attr_values *values,
297 struct lttng_dynamic_buffer *buffer)
298 {
299 int ret;
300 unsigned int count, i;
301 struct process_attr_tracker_values_comm_header header = {};
302
303 count = _lttng_process_attr_values_get_count(values);
304 header.count = (uint32_t) count;
305
306 ret = lttng_dynamic_buffer_append(buffer, &header, sizeof(header));
307 if (ret) {
308 goto end;
309 }
310
311 for (i = 0; i < count; i++) {
312 const struct process_attr_value *value =
313 lttng_process_attr_tracker_values_get_at_index(
314 values, i);
315
316 ret = process_attr_tracker_value_serialize(value, buffer);
317 if (ret) {
318 goto end;
319 }
320 }
321 end:
322 return ret;
323 }
324
325 LTTNG_HIDDEN
326 ssize_t lttng_process_attr_values_create_from_buffer(
327 enum lttng_domain_type domain,
328 enum lttng_process_attr process_attr,
329 const struct lttng_buffer_view *buffer_view,
330 struct lttng_process_attr_values **_values)
331 {
332 ssize_t offset;
333 unsigned int i;
334 struct lttng_process_attr_values *values;
335 struct lttng_buffer_view header_view;
336 const struct process_attr_tracker_values_comm_header *header;
337
338 values = lttng_process_attr_values_create();
339 if (!values) {
340 goto error;
341 }
342
343 header_view = lttng_buffer_view_from_view(
344 buffer_view, 0, sizeof(*header));
345 if (!header_view.data) {
346 goto error;
347 }
348 offset = header_view.size;
349 header = (typeof(header)) header_view.data;
350
351 /*
352 * Check that the number of values is not absurdly large with respect to
353 * the received buffer's size.
354 */
355 if (buffer_view->size <
356 header->count * sizeof(struct process_attr_tracker_value_comm)) {
357 goto error;
358 }
359 for (i = 0; i < (unsigned int) header->count; i++) {
360 int ret;
361 enum lttng_error_code ret_code;
362 const struct process_attr_tracker_value_comm *value_comm;
363 struct process_attr_value *value;
364 enum lttng_process_attr_value_type type;
365 struct lttng_buffer_view value_view;
366 struct lttng_buffer_view value_name_view = {};
367
368 value_view = lttng_buffer_view_from_view(
369 buffer_view, offset, sizeof(*value_comm));
370 if (!value_view.data) {
371 goto error;
372 }
373
374 offset += value_view.size;
375 value_comm = (typeof(value_comm)) value_view.data;
376 type = (typeof(type)) value_comm->type;
377
378 if (is_value_type_name(type)) {
379 value_name_view = lttng_buffer_view_from_view(
380 buffer_view, offset,
381 value_comm->value.name_len);
382 offset += value_name_view.size;
383 }
384 ret_code = process_attr_value_from_comm(domain, process_attr,
385 type, &value_comm->value.integral,
386 &value_name_view, &value);
387 if (ret_code != LTTNG_OK) {
388 goto error;
389 }
390
391 ret = lttng_dynamic_pointer_array_add_pointer(
392 &values->array, value);
393 if (ret) {
394 process_attr_value_destroy(value);
395 goto error;
396 }
397 }
398
399 *_values = values;
400 return offset;
401 error:
402 lttng_process_attr_values_destroy(values);
403 return -1;
404 }
405
406 LTTNG_HIDDEN
407 void lttng_process_attr_values_destroy(struct lttng_process_attr_values *values)
408 {
409 if (!values) {
410 return;
411 }
412 lttng_dynamic_pointer_array_reset(&values->array);
413 free(values);
414 }
415
416 LTTNG_HIDDEN
417 struct process_attr_value *process_attr_value_copy(
418 const struct process_attr_value *value)
419 {
420 struct process_attr_value *new_value = NULL;
421
422 if (!value) {
423 goto end;
424 }
425
426 new_value = zmalloc(sizeof(*new_value));
427 if (!new_value) {
428 goto end;
429 }
430 if (is_value_type_name(value->type)) {
431 const char *src =
432 value->type == LTTNG_PROCESS_ATTR_VALUE_TYPE_USER_NAME ?
433 value->value.user_name :
434 value->value.group_name;
435 char **dst = value->type == LTTNG_PROCESS_ATTR_VALUE_TYPE_USER_NAME ?
436 &new_value->value.user_name :
437 &new_value->value.group_name;
438
439 new_value->type = value->type;
440 *dst = strdup(src);
441 if (!*dst) {
442 goto error;
443 }
444 } else {
445 *new_value = *value;
446 }
447 end:
448 return new_value;
449 error:
450 free(new_value);
451 return NULL;
452 }
453
454 LTTNG_HIDDEN
455 unsigned long process_attr_value_hash(const struct process_attr_value *a)
456 {
457 unsigned long hash = hash_key_ulong((void *) a->type, lttng_ht_seed);
458
459 switch (a->type) {
460 case LTTNG_PROCESS_ATTR_VALUE_TYPE_PID:
461 hash ^= hash_key_ulong((void *) (unsigned long) a->value.pid,
462 lttng_ht_seed);
463 break;
464 case LTTNG_PROCESS_ATTR_VALUE_TYPE_UID:
465 hash ^= hash_key_ulong((void *) (unsigned long) a->value.uid,
466 lttng_ht_seed);
467 break;
468 case LTTNG_PROCESS_ATTR_VALUE_TYPE_GID:
469 hash ^= hash_key_ulong((void *) (unsigned long) a->value.gid,
470 lttng_ht_seed);
471 break;
472 case LTTNG_PROCESS_ATTR_VALUE_TYPE_USER_NAME:
473 hash ^= hash_key_str(a->value.user_name, lttng_ht_seed);
474 break;
475 case LTTNG_PROCESS_ATTR_VALUE_TYPE_GROUP_NAME:
476 hash ^= hash_key_str(a->value.group_name, lttng_ht_seed);
477 break;
478 default:
479 abort();
480 }
481
482 return hash;
483 }
484
485 LTTNG_HIDDEN
486 bool process_attr_tracker_value_equal(const struct process_attr_value *a,
487 const struct process_attr_value *b)
488 {
489 if (a->type != b->type) {
490 return false;
491 }
492 switch (a->type) {
493 case LTTNG_PROCESS_ATTR_VALUE_TYPE_PID:
494 return a->value.pid == b->value.pid;
495 case LTTNG_PROCESS_ATTR_VALUE_TYPE_UID:
496 return a->value.uid == b->value.uid;
497 case LTTNG_PROCESS_ATTR_VALUE_TYPE_GID:
498 return a->value.gid == b->value.gid;
499 case LTTNG_PROCESS_ATTR_VALUE_TYPE_USER_NAME:
500 return !strcmp(a->value.user_name, b->value.user_name);
501 case LTTNG_PROCESS_ATTR_VALUE_TYPE_GROUP_NAME:
502 return !strcmp(a->value.group_name, b->value.group_name);
503 default:
504 abort();
505 }
506 }
507
508 LTTNG_HIDDEN
509 void process_attr_value_destroy(struct process_attr_value *value)
510 {
511 if (!value) {
512 return;
513 }
514 if (is_value_type_name(value->type)) {
515 free(value->type == LTTNG_PROCESS_ATTR_VALUE_TYPE_USER_NAME ?
516 value->value.user_name :
517 value->value.group_name);
518 }
519 free(value);
520 }
This page took 0.039881 seconds and 5 git commands to generate.