Fix: Buggy string comparison in ust registry ht_match_event
[lttng-tools.git] / src / bin / lttng-sessiond / ust-registry.c
CommitLineData
d0b96690
DG
1/*
2 * Copyright (C) 2013 - David Goulet <dgoulet@efficios.com>
3 *
4 * This program is free software; you can redistribute it and/or modify it
5 * under the terms of the GNU General Public License, version 2 only, as
6 * published by the Free Software Foundation.
7 *
8 * This program is distributed in the hope that it will be useful, but WITHOUT
9 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
10 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
11 * more details.
12 *
13 * You should have received a copy of the GNU General Public License along with
14 * this program; if not, write to the Free Software Foundation, Inc., 51
15 * Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
16 */
17#define _GNU_SOURCE
6c1c0768 18#define _LGPL_SOURCE
d0b96690 19#include <assert.h>
7972aab2 20#include <inttypes.h>
d0b96690
DG
21
22#include <common/common.h>
7972aab2
DG
23#include <common/hashtable/utils.h>
24#include <lttng/lttng.h>
25
d0b96690 26#include "ust-registry.h"
8494bda5 27#include "ust-app.h"
0b2dc8df 28#include "utils.h"
d0b96690
DG
29
30/*
31 * Hash table match function for event in the registry.
32 */
33static int ht_match_event(struct cds_lfht_node *node, const void *_key)
34{
35 struct ust_registry_event *event;
36 const struct ust_registry_event *key;
37
38 assert(node);
39 assert(_key);
40
41 event = caa_container_of(node, struct ust_registry_event, node.node);
42 assert(event);
43 key = _key;
44
45 /* It has to be a perfect match. */
b4d096a6 46 if (strncmp(event->name, key->name, sizeof(event->name))) {
d0b96690
DG
47 goto no_match;
48 }
49
50 /* It has to be a perfect match. */
51 if (strncmp(event->signature, key->signature,
b4d096a6 52 strlen(event->signature))) {
d0b96690
DG
53 goto no_match;
54 }
55
56 /* Match */
57 return 1;
58
59no_match:
60 return 0;
61}
62
7972aab2
DG
63static unsigned long ht_hash_event(void *_key, unsigned long seed)
64{
65 uint64_t xored_key;
66 struct ust_registry_event *key = _key;
67
68 assert(key);
69
70 xored_key = (uint64_t) (hash_key_str(key->name, seed) ^
71 hash_key_str(key->signature, seed));
72
73 return hash_key_u64(&xored_key, seed);
74}
75
8494bda5
MD
76/*
77 * Return negative value on error, 0 if OK.
78 *
79 * TODO: we could add stricter verification of more types to catch
80 * errors in liblttng-ust implementation earlier than consumption by the
81 * trace reader.
82 */
83static
84int validate_event_field(struct ustctl_field *field,
85 const char *event_name,
86 struct ust_app *app)
87{
88 switch(field->type.atype) {
89 case ustctl_atype_integer:
90 case ustctl_atype_enum:
91 case ustctl_atype_array:
92 case ustctl_atype_sequence:
93 case ustctl_atype_string:
94 break;
95
96 case ustctl_atype_float:
97 switch (field->type.u.basic._float.mant_dig) {
98 case 0:
99 WARN("UST application '%s' (pid: %d) has unknown float mantissa '%u' "
100 "in field '%s', rejecting event '%s'",
101 app->name, app->pid,
102 field->type.u.basic._float.mant_dig,
103 field->name,
104 event_name);
105 return -EINVAL;
106 default:
107 break;
108 }
109 break;
110
111 default:
112 return -ENOENT;
113 }
114 return 0;
115}
116
117static
118int validate_event_fields(size_t nr_fields, struct ustctl_field *fields,
119 const char *event_name, struct ust_app *app)
120{
121 unsigned int i;
122
123 for (i = 0; i < nr_fields; i++) {
124 if (validate_event_field(&fields[i], event_name, app) < 0)
125 return -EINVAL;
126 }
127 return 0;
128}
129
d0b96690
DG
130/*
131 * Allocate event and initialize it. This does NOT set a valid event id from a
132 * registry.
133 */
134static struct ust_registry_event *alloc_event(int session_objd,
135 int channel_objd, char *name, char *sig, size_t nr_fields,
8494bda5
MD
136 struct ustctl_field *fields, int loglevel, char *model_emf_uri,
137 struct ust_app *app)
d0b96690
DG
138{
139 struct ust_registry_event *event = NULL;
140
8494bda5
MD
141 /*
142 * Ensure that the field content is valid.
143 */
144 if (validate_event_fields(nr_fields, fields, name, app) < 0) {
145 return NULL;
146 }
147
d0b96690
DG
148 event = zmalloc(sizeof(*event));
149 if (!event) {
150 PERROR("zmalloc ust registry event");
151 goto error;
152 }
153
154 event->session_objd = session_objd;
155 event->channel_objd = channel_objd;
156 /* Allocated by ustctl. */
157 event->signature = sig;
158 event->nr_fields = nr_fields;
159 event->fields = fields;
160 event->loglevel = loglevel;
161 event->model_emf_uri = model_emf_uri;
162 if (name) {
163 /* Copy event name and force NULL byte. */
164 strncpy(event->name, name, sizeof(event->name));
165 event->name[sizeof(event->name) - 1] = '\0';
166 }
7972aab2 167 cds_lfht_node_init(&event->node.node);
d0b96690
DG
168
169error:
170 return event;
171}
172
173/*
174 * Free event data structure. This does NOT delete it from any hash table. It's
175 * safe to pass a NULL pointer. This shoudl be called inside a call RCU if the
176 * event is previously deleted from a rcu hash table.
177 */
178static void destroy_event(struct ust_registry_event *event)
179{
180 if (!event) {
181 return;
182 }
183
184 free(event->fields);
185 free(event->model_emf_uri);
186 free(event->signature);
187 free(event);
188}
189
190/*
191 * Destroy event function call of the call RCU.
192 */
193static void destroy_event_rcu(struct rcu_head *head)
194{
7972aab2
DG
195 struct lttng_ht_node_u64 *node =
196 caa_container_of(head, struct lttng_ht_node_u64, head);
d0b96690
DG
197 struct ust_registry_event *event =
198 caa_container_of(node, struct ust_registry_event, node);
199
200 destroy_event(event);
201}
202
203/*
204 * Find an event using the name and signature in the given registry. RCU read
205 * side lock MUST be acquired before calling this function and as long as the
206 * event reference is kept by the caller.
207 *
208 * On success, the event pointer is returned else NULL.
209 */
210struct ust_registry_event *ust_registry_find_event(
211 struct ust_registry_channel *chan, char *name, char *sig)
212{
7972aab2 213 struct lttng_ht_node_u64 *node;
d0b96690
DG
214 struct lttng_ht_iter iter;
215 struct ust_registry_event *event = NULL;
216 struct ust_registry_event key;
217
218 assert(chan);
219 assert(name);
220 assert(sig);
221
222 /* Setup key for the match function. */
223 strncpy(key.name, name, sizeof(key.name));
224 key.name[sizeof(key.name) - 1] = '\0';
225 key.signature = sig;
226
7972aab2 227 cds_lfht_lookup(chan->ht->ht, chan->ht->hash_fct(&key, lttng_ht_seed),
d0b96690 228 chan->ht->match_fct, &key, &iter.iter);
7972aab2 229 node = lttng_ht_iter_get_node_u64(&iter);
d0b96690
DG
230 if (!node) {
231 goto end;
232 }
233 event = caa_container_of(node, struct ust_registry_event, node);
234
235end:
236 return event;
237}
238
239/*
240 * Create a ust_registry_event from the given parameters and add it to the
241 * registry hash table. If event_id is valid, it is set with the newly created
242 * event id.
243 *
244 * On success, return 0 else a negative value. The created event MUST be unique
245 * so on duplicate entry -EINVAL is returned. On error, event_id is untouched.
246 *
247 * Should be called with session registry mutex held.
248 */
249int ust_registry_create_event(struct ust_registry_session *session,
45893984
DG
250 uint64_t chan_key, int session_objd, int channel_objd, char *name,
251 char *sig, size_t nr_fields, struct ustctl_field *fields, int loglevel,
8494bda5
MD
252 char *model_emf_uri, int buffer_type, uint32_t *event_id_p,
253 struct ust_app *app)
d0b96690
DG
254{
255 int ret;
7972aab2 256 uint32_t event_id;
d0b96690
DG
257 struct cds_lfht_node *nptr;
258 struct ust_registry_event *event = NULL;
45893984 259 struct ust_registry_channel *chan;
d0b96690
DG
260
261 assert(session);
d0b96690
DG
262 assert(name);
263 assert(sig);
7972aab2 264 assert(event_id_p);
d0b96690 265
d5d629b5
DG
266 rcu_read_lock();
267
d0b96690
DG
268 /*
269 * This should not happen but since it comes from the UST tracer, an
270 * external party, don't assert and simply validate values.
271 */
272 if (session_objd < 0 || channel_objd < 0) {
273 ret = -EINVAL;
d5d629b5 274 goto error_free;
d0b96690
DG
275 }
276
45893984
DG
277 chan = ust_registry_channel_find(session, chan_key);
278 if (!chan) {
279 ret = -EINVAL;
d5d629b5 280 goto error_free;
45893984
DG
281 }
282
d0b96690
DG
283 /* Check if we've reached the maximum possible id. */
284 if (ust_registry_is_max_id(chan->used_event_id)) {
285 ret = -ENOENT;
d5d629b5 286 goto error_free;
d0b96690
DG
287 }
288
289 event = alloc_event(session_objd, channel_objd, name, sig, nr_fields,
8494bda5 290 fields, loglevel, model_emf_uri, app);
d0b96690
DG
291 if (!event) {
292 ret = -ENOMEM;
d5d629b5 293 goto error_free;
d0b96690
DG
294 }
295
d0b96690 296 DBG3("UST registry creating event with event: %s, sig: %s, id: %u, "
7972aab2
DG
297 "chan_objd: %u, sess_objd: %u, chan_id: %u", event->name,
298 event->signature, event->id, event->channel_objd,
299 event->session_objd, chan->chan_id);
d0b96690 300
d0b96690
DG
301 /*
302 * This is an add unique with a custom match function for event. The node
303 * are matched using the event name and signature.
304 */
7972aab2 305 nptr = cds_lfht_add_unique(chan->ht->ht, chan->ht->hash_fct(event,
d0b96690
DG
306 lttng_ht_seed), chan->ht->match_fct, event, &event->node.node);
307 if (nptr != &event->node.node) {
7972aab2
DG
308 if (buffer_type == LTTNG_BUFFER_PER_UID) {
309 /*
310 * This is normal, we just have to send the event id of the
311 * returned node and make sure we destroy the previously allocated
312 * event object.
313 */
314 destroy_event(event);
315 event = caa_container_of(nptr, struct ust_registry_event,
316 node.node);
317 assert(event);
318 event_id = event->id;
319 } else {
320 ERR("UST registry create event add unique failed for event: %s, "
321 "sig: %s, id: %u, chan_objd: %u, sess_objd: %u",
322 event->name, event->signature, event->id,
323 event->channel_objd, event->session_objd);
324 ret = -EINVAL;
325 goto error_unlock;
326 }
327 } else {
328 /* Request next event id if the node was successfully added. */
329 event_id = event->id = ust_registry_get_next_event_id(chan);
d0b96690
DG
330 }
331
7972aab2 332 *event_id_p = event_id;
d0b96690 333
7972aab2
DG
334 if (!event->metadata_dumped) {
335 /* Append to metadata */
336 ret = ust_metadata_event_statedump(session, chan, event);
337 if (ret) {
338 ERR("Error appending event metadata (errno = %d)", ret);
339 rcu_read_unlock();
340 return ret;
341 }
d0b96690
DG
342 }
343
45893984 344 rcu_read_unlock();
d0b96690
DG
345 return 0;
346
d5d629b5
DG
347error_free:
348 free(sig);
349 free(fields);
350 free(model_emf_uri);
d0b96690
DG
351error_unlock:
352 rcu_read_unlock();
d0b96690
DG
353 destroy_event(event);
354 return ret;
355}
356
357/*
358 * For a given event in a registry, delete the entry and destroy the event.
359 * This MUST be called within a RCU read side lock section.
360 */
361void ust_registry_destroy_event(struct ust_registry_channel *chan,
362 struct ust_registry_event *event)
363{
364 int ret;
365 struct lttng_ht_iter iter;
366
367 assert(chan);
368 assert(event);
369
370 /* Delete the node first. */
371 iter.iter.node = &event->node.node;
372 ret = lttng_ht_del(chan->ht, &iter);
373 assert(!ret);
374
375 call_rcu(&event->node.head, destroy_event_rcu);
376
377 return;
378}
379
36b588ed
MD
380/*
381 * We need to execute ht_destroy outside of RCU read-side critical
0b2dc8df
MD
382 * section and outside of call_rcu thread, so we postpone its execution
383 * using ht_cleanup_push. It is simpler than to change the semantic of
384 * the many callers of delete_ust_app_session().
36b588ed
MD
385 */
386static
387void destroy_channel_rcu(struct rcu_head *head)
388{
389 struct ust_registry_channel *chan =
390 caa_container_of(head, struct ust_registry_channel, rcu_head);
391
9dbcf332 392 if (chan->ht) {
0b2dc8df 393 ht_cleanup_push(chan->ht);
9dbcf332 394 }
3295105b 395 free(chan->ctx_fields);
36b588ed
MD
396 free(chan);
397}
398
d0b96690
DG
399/*
400 * Destroy every element of the registry and free the memory. This does NOT
401 * free the registry pointer since it might not have been allocated before so
402 * it's the caller responsability.
d0b96690 403 */
45893984 404static void destroy_channel(struct ust_registry_channel *chan)
d0b96690
DG
405{
406 struct lttng_ht_iter iter;
407 struct ust_registry_event *event;
408
409 assert(chan);
410
9209cee7 411 rcu_read_lock();
d0b96690
DG
412 /* Destroy all event associated with this registry. */
413 cds_lfht_for_each_entry(chan->ht->ht, &iter.iter, event, node.node) {
414 /* Delete the node from the ht and free it. */
415 ust_registry_destroy_event(chan, event);
416 }
9209cee7 417 rcu_read_unlock();
36b588ed 418 call_rcu(&chan->rcu_head, destroy_channel_rcu);
d0b96690
DG
419}
420
421/*
422 * Initialize registry with default values.
423 */
45893984
DG
424int ust_registry_channel_add(struct ust_registry_session *session,
425 uint64_t key)
426{
427 int ret = 0;
428 struct ust_registry_channel *chan;
429
430 assert(session);
431
432 chan = zmalloc(sizeof(*chan));
433 if (!chan) {
434 PERROR("zmalloc ust registry channel");
435 ret = -ENOMEM;
9dbcf332 436 goto error_alloc;
45893984
DG
437 }
438
439 chan->ht = lttng_ht_new(0, LTTNG_HT_TYPE_STRING);
440 if (!chan->ht) {
441 ret = -ENOMEM;
442 goto error;
443 }
444
445 /* Set custom match function. */
446 chan->ht->match_fct = ht_match_event;
7972aab2
DG
447 chan->ht->hash_fct = ht_hash_event;
448
449 /*
450 * Assign a channel ID right now since the event notification comes
451 * *before* the channel notify so the ID needs to be set at this point so
452 * the metadata can be dumped for that event.
453 */
454 if (ust_registry_is_max_id(session->used_channel_id)) {
455 ret = -1;
456 goto error;
457 }
458 chan->chan_id = ust_registry_get_next_chan_id(session);
45893984
DG
459
460 rcu_read_lock();
461 lttng_ht_node_init_u64(&chan->node, key);
462 lttng_ht_add_unique_u64(session->channels, &chan->node);
463 rcu_read_unlock();
464
9dbcf332
DG
465 return 0;
466
45893984 467error:
9dbcf332
DG
468 destroy_channel(chan);
469error_alloc:
45893984
DG
470 return ret;
471}
472
473/*
474 * Find a channel in the given registry. RCU read side lock MUST be acquired
475 * before calling this function and as long as the event reference is kept by
476 * the caller.
477 *
478 * On success, the pointer is returned else NULL.
479 */
480struct ust_registry_channel *ust_registry_channel_find(
481 struct ust_registry_session *session, uint64_t key)
482{
483 struct lttng_ht_node_u64 *node;
484 struct lttng_ht_iter iter;
485 struct ust_registry_channel *chan = NULL;
486
487 assert(session);
488 assert(session->channels);
489
7972aab2
DG
490 DBG3("UST registry channel finding key %" PRIu64, key);
491
45893984
DG
492 lttng_ht_lookup(session->channels, &key, &iter);
493 node = lttng_ht_iter_get_node_u64(&iter);
494 if (!node) {
495 goto end;
496 }
497 chan = caa_container_of(node, struct ust_registry_channel, node);
498
499end:
500 return chan;
501}
502
503/*
504 * Remove channel using key from registry and free memory.
505 */
506void ust_registry_channel_del_free(struct ust_registry_session *session,
507 uint64_t key)
508{
509 struct lttng_ht_iter iter;
510 struct ust_registry_channel *chan;
9209cee7 511 int ret;
45893984
DG
512
513 assert(session);
514
515 rcu_read_lock();
516 chan = ust_registry_channel_find(session, key);
517 if (!chan) {
9209cee7 518 rcu_read_unlock();
45893984
DG
519 goto end;
520 }
521
522 iter.iter.node = &chan->node.node;
9209cee7
MD
523 ret = lttng_ht_del(session->channels, &iter);
524 assert(!ret);
525 rcu_read_unlock();
45893984
DG
526 destroy_channel(chan);
527
528end:
45893984
DG
529 return;
530}
531
532/*
533 * Initialize registry with default values and set the newly allocated session
534 * pointer to sessionp.
535 *
536 * Return 0 on success and sessionp is set or else return -1 and sessionp is
537 * kept untouched.
538 */
539int ust_registry_session_init(struct ust_registry_session **sessionp,
d0b96690
DG
540 struct ust_app *app,
541 uint32_t bits_per_long,
542 uint32_t uint8_t_alignment,
543 uint32_t uint16_t_alignment,
544 uint32_t uint32_t_alignment,
545 uint32_t uint64_t_alignment,
546 uint32_t long_alignment,
af6142cf
MD
547 int byte_order,
548 uint32_t major,
d7ba1388 549 uint32_t minor,
3d071855 550 const char *root_shm_path,
d7ba1388
MD
551 const char *shm_path,
552 uid_t euid,
553 gid_t egid)
d0b96690
DG
554{
555 int ret;
45893984 556 struct ust_registry_session *session;
d0b96690 557
45893984 558 assert(sessionp);
d0b96690 559
45893984
DG
560 session = zmalloc(sizeof(*session));
561 if (!session) {
562 PERROR("zmalloc ust registry session");
9dbcf332 563 goto error_alloc;
45893984 564 }
d0b96690
DG
565
566 pthread_mutex_init(&session->lock, NULL);
567 session->bits_per_long = bits_per_long;
568 session->uint8_t_alignment = uint8_t_alignment;
569 session->uint16_t_alignment = uint16_t_alignment;
570 session->uint32_t_alignment = uint32_t_alignment;
571 session->uint64_t_alignment = uint64_t_alignment;
572 session->long_alignment = long_alignment;
573 session->byte_order = byte_order;
d7ba1388 574 session->metadata_fd = -1;
4628484a
MD
575 session->uid = euid;
576 session->gid = egid;
3d071855
MD
577 strncpy(session->root_shm_path, root_shm_path,
578 sizeof(session->root_shm_path));
579 session->root_shm_path[sizeof(session->root_shm_path) - 1] = '\0';
d7ba1388
MD
580 if (shm_path[0]) {
581 strncpy(session->shm_path, shm_path,
582 sizeof(session->shm_path));
583 session->shm_path[sizeof(session->shm_path) - 1] = '\0';
584 strncpy(session->metadata_path, shm_path,
585 sizeof(session->metadata_path));
586 session->metadata_path[sizeof(session->metadata_path) - 1] = '\0';
587 strncat(session->metadata_path, "/metadata",
588 sizeof(session->metadata_path)
589 - strlen(session->metadata_path) - 1);
590 }
591 if (session->shm_path[0]) {
592 ret = run_as_mkdir_recursive(session->shm_path,
593 S_IRWXU | S_IRWXG,
594 euid, egid);
595 if (ret) {
596 PERROR("run_as_mkdir_recursive");
597 goto error;
598 }
599 }
600 if (session->metadata_path[0]) {
601 /* Create metadata file */
4628484a 602 ret = run_as_open(session->metadata_path,
d7ba1388 603 O_WRONLY | O_CREAT | O_EXCL,
4628484a 604 S_IRUSR | S_IWUSR, euid, egid);
d7ba1388
MD
605 if (ret < 0) {
606 PERROR("Opening metadata file");
607 goto error;
608 }
609 session->metadata_fd = ret;
610 }
d0b96690 611
45893984
DG
612 session->channels = lttng_ht_new(0, LTTNG_HT_TYPE_U64);
613 if (!session->channels) {
614 goto error;
615 }
616
d0b96690
DG
617 ret = lttng_uuid_generate(session->uuid);
618 if (ret) {
619 ERR("Failed to generate UST uuid (errno = %d)", ret);
620 goto error;
621 }
622
623 pthread_mutex_lock(&session->lock);
af6142cf 624 ret = ust_metadata_session_statedump(session, app, major, minor);
d0b96690
DG
625 pthread_mutex_unlock(&session->lock);
626 if (ret) {
627 ERR("Failed to generate session metadata (errno = %d)", ret);
628 goto error;
629 }
630
45893984
DG
631 *sessionp = session;
632
d0b96690
DG
633 return 0;
634
635error:
9dbcf332 636 ust_registry_session_destroy(session);
d24ff3fd 637 free(session);
9dbcf332 638error_alloc:
d0b96690
DG
639 return -1;
640}
641
642/*
643 * Destroy session registry. This does NOT free the given pointer since it
644 * might get passed as a reference. The registry lock should NOT be acquired.
645 */
646void ust_registry_session_destroy(struct ust_registry_session *reg)
647{
648 int ret;
45893984
DG
649 struct lttng_ht_iter iter;
650 struct ust_registry_channel *chan;
d0b96690 651
286c991a
MD
652 if (!reg) {
653 return;
654 }
9d8efb0e 655
d0b96690
DG
656 /* On error, EBUSY can be returned if lock. Code flow error. */
657 ret = pthread_mutex_destroy(&reg->lock);
658 assert(!ret);
659
9d8efb0e
DG
660 if (reg->channels) {
661 rcu_read_lock();
662 /* Destroy all event associated with this registry. */
663 cds_lfht_for_each_entry(reg->channels->ht, &iter.iter, chan,
664 node.node) {
665 /* Delete the node from the ht and free it. */
666 ret = lttng_ht_del(reg->channels, &iter);
667 assert(!ret);
668 destroy_channel(chan);
669 }
670 rcu_read_unlock();
671 ht_cleanup_push(reg->channels);
45893984 672 }
45893984 673
d0b96690 674 free(reg->metadata);
d7ba1388
MD
675 if (reg->metadata_fd >= 0) {
676 ret = close(reg->metadata_fd);
677 if (ret) {
678 PERROR("close");
679 }
4628484a
MD
680 ret = run_as_unlink(reg->metadata_path,
681 reg->uid, reg->gid);
d7ba1388
MD
682 if (ret) {
683 PERROR("unlink");
684 }
685 }
3d071855
MD
686 if (reg->root_shm_path[0]) {
687 /*
688 * Try deleting the directory hierarchy.
689 */
4628484a
MD
690 (void) run_as_recursive_rmdir(reg->root_shm_path,
691 reg->uid, reg->gid);
3d071855 692 }
d0b96690 693}
This page took 0.063204 seconds and 4 git commands to generate.