Fix: sessiond: double free on duplicate removal of tracer source
[lttng-tools.git] / src / bin / lttng-sessiond / tracker.c
1 /*
2 * Copyright (C) 2018 Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
3 * Copyright (C) 2020 Jérémie Galarneau <jeremie.galarneau@efficios.com>
4 *
5 * SPDX-License-Identifier: GPL-2.0-only
6 *
7 */
8
9 #include "lttng/tracker.h"
10 #include "common/dynamic-array.h"
11 #include "common/macros.h"
12 #define _LGPL_SOURCE
13 #include <grp.h>
14 #include <pwd.h>
15 #include <sys/types.h>
16 #include <unistd.h>
17 #include <urcu.h>
18 #include <urcu/list.h>
19 #include <urcu/rculfhash.h>
20
21 #include "tracker.h"
22 #include <common/defaults.h>
23 #include <common/error.h>
24 #include <common/hashtable/hashtable.h>
25 #include <common/hashtable/utils.h>
26 #include <common/tracker.h>
27 #include <lttng/lttng-error.h>
28
29 struct process_attr_tracker_value_node {
30 struct process_attr_value *value;
31 struct cds_lfht_node inclusion_set_ht_node;
32 struct rcu_head rcu_head;
33 };
34
35 struct process_attr_tracker {
36 enum lttng_tracking_policy policy;
37 struct cds_lfht *inclusion_set_ht;
38 };
39
40 static void process_attr_tracker_value_node_rcu_free(struct rcu_head *rcu_head)
41 {
42 struct process_attr_tracker_value_node *node =
43 container_of(rcu_head, typeof(*node), rcu_head);
44
45 free(node);
46 }
47
48 struct process_attr_tracker *process_attr_tracker_create(void)
49 {
50 struct process_attr_tracker *tracker;
51
52 tracker = zmalloc(sizeof(*tracker));
53 if (!tracker) {
54 return NULL;
55 }
56
57 (void) process_attr_tracker_set_tracking_policy(
58 tracker, LTTNG_TRACKING_POLICY_INCLUDE_ALL);
59
60 tracker->inclusion_set_ht = cds_lfht_new(DEFAULT_HT_SIZE, 1, 0,
61 CDS_LFHT_AUTO_RESIZE | CDS_LFHT_ACCOUNTING, NULL);
62 if (!tracker->inclusion_set_ht) {
63 goto error;
64 }
65
66 return tracker;
67 error:
68 process_attr_tracker_destroy(tracker);
69 return NULL;
70 }
71
72 static void process_attr_tracker_remove_value_node(
73 struct process_attr_tracker *tracker,
74 struct process_attr_tracker_value_node *value_node)
75 {
76 cds_lfht_del(tracker->inclusion_set_ht,
77 &value_node->inclusion_set_ht_node);
78 process_attr_value_destroy(value_node->value);
79 call_rcu(&value_node->rcu_head,
80 process_attr_tracker_value_node_rcu_free);
81 }
82
83 static void process_attr_tracker_clear_inclusion_set(
84 struct process_attr_tracker *tracker)
85 {
86 int ret;
87 struct lttng_ht_iter iter;
88 struct process_attr_tracker_value_node *value_node;
89
90 if (!tracker->inclusion_set_ht) {
91 return;
92 }
93
94 rcu_read_lock();
95 cds_lfht_for_each_entry (tracker->inclusion_set_ht, &iter.iter,
96 value_node, inclusion_set_ht_node) {
97 process_attr_tracker_remove_value_node(tracker, value_node);
98 }
99 rcu_read_unlock();
100 ret = cds_lfht_destroy(tracker->inclusion_set_ht, NULL);
101 assert(ret == 0);
102 tracker->inclusion_set_ht = NULL;
103 }
104
105 static int process_attr_tracker_create_inclusion_set(
106 struct process_attr_tracker *tracker)
107 {
108 assert(!tracker->inclusion_set_ht);
109 tracker->inclusion_set_ht = cds_lfht_new(DEFAULT_HT_SIZE, 1, 0,
110 CDS_LFHT_AUTO_RESIZE | CDS_LFHT_ACCOUNTING, NULL);
111 return tracker->inclusion_set_ht ? 0 : -1;
112 }
113
114 void process_attr_tracker_destroy(struct process_attr_tracker *tracker)
115 {
116 if (!tracker) {
117 return;
118 }
119
120 process_attr_tracker_clear_inclusion_set(tracker);
121 free(tracker);
122 }
123
124 enum lttng_tracking_policy process_attr_tracker_get_tracking_policy(
125 const struct process_attr_tracker *tracker)
126 {
127 return tracker->policy;
128 }
129
130 int process_attr_tracker_set_tracking_policy(
131 struct process_attr_tracker *tracker,
132 enum lttng_tracking_policy tracking_policy)
133 {
134 int ret = 0;
135
136 if (tracker->policy == tracking_policy) {
137 goto end;
138 }
139
140 process_attr_tracker_clear_inclusion_set(tracker);
141 ret = process_attr_tracker_create_inclusion_set(tracker);
142 if (ret) {
143 goto end;
144 }
145 tracker->policy = tracking_policy;
146 end:
147 return ret;
148 }
149
150 static int match_inclusion_set_value(
151 struct cds_lfht_node *node, const void *key)
152 {
153 const struct process_attr_value *value_key = key;
154 const struct process_attr_tracker_value_node *value_node =
155 caa_container_of(node,
156 struct process_attr_tracker_value_node,
157 inclusion_set_ht_node);
158
159 return process_attr_tracker_value_equal(value_node->value, value_key);
160 }
161
162 static struct process_attr_tracker_value_node *process_attr_tracker_lookup(
163 const struct process_attr_tracker *tracker,
164 const struct process_attr_value *value)
165 {
166 struct cds_lfht_iter iter;
167 struct cds_lfht_node *node;
168
169 assert(tracker->policy == LTTNG_TRACKING_POLICY_INCLUDE_SET);
170
171 rcu_read_lock();
172 cds_lfht_lookup(tracker->inclusion_set_ht,
173 process_attr_value_hash(value),
174 match_inclusion_set_value, value, &iter);
175 node = cds_lfht_iter_get_node(&iter);
176 rcu_read_unlock();
177
178 return node ? container_of(node, struct process_attr_tracker_value_node,
179 inclusion_set_ht_node) :
180 NULL;
181 }
182
183 /* Protected by session mutex held by caller. */
184 enum process_attr_tracker_status process_attr_tracker_inclusion_set_add_value(
185 struct process_attr_tracker *tracker,
186 const struct process_attr_value *value)
187 {
188 enum process_attr_tracker_status status =
189 PROCESS_ATTR_TRACKER_STATUS_OK;
190 struct process_attr_value *value_copy = NULL;
191 struct process_attr_tracker_value_node *value_node = NULL;
192
193 rcu_read_lock();
194 if (tracker->policy != LTTNG_TRACKING_POLICY_INCLUDE_SET) {
195 status = PROCESS_ATTR_TRACKER_STATUS_INVALID_TRACKING_POLICY;
196 goto end;
197 }
198
199 if (process_attr_tracker_lookup(tracker, value)) {
200 status = PROCESS_ATTR_TRACKER_STATUS_EXISTS;
201 goto end;
202 }
203
204 value_node = zmalloc(sizeof(*value_node));
205 if (!value_node) {
206 status = PROCESS_ATTR_TRACKER_STATUS_ERROR;
207 goto end;
208 }
209
210 value_copy = process_attr_value_copy(value);
211 if (!value_copy) {
212 status = PROCESS_ATTR_TRACKER_STATUS_ERROR;
213 goto end;
214 }
215
216 value_node->value = value_copy;
217 cds_lfht_add(tracker->inclusion_set_ht,
218 process_attr_value_hash(value_copy),
219 &value_node->inclusion_set_ht_node);
220 value_copy = NULL;
221 value_node = NULL;
222 end:
223 if (value_copy) {
224 process_attr_value_destroy(value_copy);
225 }
226 if (value_node) {
227 free(value_node);
228 }
229 rcu_read_unlock();
230 return status;
231 }
232
233 /* Protected by session mutex held by caller. */
234 enum process_attr_tracker_status
235 process_attr_tracker_inclusion_set_remove_value(
236 struct process_attr_tracker *tracker,
237 const struct process_attr_value *value)
238 {
239 struct process_attr_tracker_value_node *value_node;
240 enum process_attr_tracker_status status =
241 PROCESS_ATTR_TRACKER_STATUS_OK;
242
243 rcu_read_lock();
244 if (tracker->policy != LTTNG_TRACKING_POLICY_INCLUDE_SET) {
245 status = PROCESS_ATTR_TRACKER_STATUS_INVALID_TRACKING_POLICY;
246 goto end;
247 }
248
249 value_node = process_attr_tracker_lookup(tracker, value);
250 if (!value_node) {
251 status = PROCESS_ATTR_TRACKER_STATUS_MISSING;
252 goto end;
253 }
254
255 process_attr_tracker_remove_value_node(tracker, value_node);
256 end:
257 rcu_read_unlock();
258 return status;
259 }
260
261 enum process_attr_tracker_status process_attr_tracker_get_inclusion_set(
262 const struct process_attr_tracker *tracker,
263 struct lttng_process_attr_values **_values)
264 {
265 struct lttng_ht_iter iter;
266 struct process_attr_tracker_value_node *value_node;
267 enum process_attr_tracker_status status =
268 PROCESS_ATTR_TRACKER_STATUS_OK;
269 struct lttng_process_attr_values *values;
270 struct process_attr_value *new_value = NULL;
271
272 values = lttng_process_attr_values_create();
273 if (!values) {
274 status = PROCESS_ATTR_TRACKER_STATUS_ERROR;
275 goto error;
276 }
277
278 if (tracker->policy != LTTNG_TRACKING_POLICY_INCLUDE_SET) {
279 status = PROCESS_ATTR_TRACKER_STATUS_INVALID_TRACKING_POLICY;
280 goto error;
281 }
282
283 rcu_read_lock();
284 cds_lfht_for_each_entry (tracker->inclusion_set_ht, &iter.iter,
285 value_node, inclusion_set_ht_node) {
286 int ret;
287
288 new_value = process_attr_value_copy(value_node->value);
289 if (!new_value) {
290 status = PROCESS_ATTR_TRACKER_STATUS_ERROR;
291 goto error_unlock;
292 }
293
294 ret = lttng_dynamic_pointer_array_add_pointer(
295 &values->array, new_value);
296 if (ret) {
297 status = PROCESS_ATTR_TRACKER_STATUS_ERROR;
298 goto error_unlock;
299 }
300
301 new_value = NULL;
302 }
303 rcu_read_unlock();
304 *_values = values;
305 return status;
306 error_unlock:
307 rcu_read_unlock();
308 error:
309 lttng_process_attr_values_destroy(values);
310 process_attr_value_destroy(new_value);
311 return status;
312 }
This page took 0.042307 seconds and 4 git commands to generate.