Fix: unchecked buffer size for communication header
[lttng-tools.git] / src / common / event-rule / uprobe.c
1 /*
2 * Copyright (C) 2019 Jonathan Rajotte <jonathan.rajotte-julien@efficios.com>
3 *
4 * SPDX-License-Identifier: LGPL-2.1-only
5 *
6 */
7
8 #include <assert.h>
9 #include <common/error.h>
10 #include <common/macros.h>
11 #include <common/payload.h>
12 #include <common/payload-view.h>
13 #include <common/runas.h>
14 #include <lttng/event-rule/event-rule-internal.h>
15 #include <lttng/event-rule/uprobe-internal.h>
16 #include <lttng/userspace-probe-internal.h>
17
18 #define IS_UPROBE_EVENT_RULE(rule) \
19 (lttng_event_rule_get_type(rule) == LTTNG_EVENT_RULE_TYPE_UPROBE)
20
21 static void lttng_event_rule_uprobe_destroy(struct lttng_event_rule *rule)
22 {
23 struct lttng_event_rule_uprobe *uprobe;
24
25 uprobe = container_of(rule, struct lttng_event_rule_uprobe, parent);
26
27 lttng_userspace_probe_location_destroy(uprobe->location);
28 free(uprobe->name);
29 free(uprobe);
30 }
31
32 static bool lttng_event_rule_uprobe_validate(
33 const struct lttng_event_rule *rule)
34 {
35 bool valid = false;
36 struct lttng_event_rule_uprobe *uprobe;
37
38 if (!rule) {
39 goto end;
40 }
41
42 uprobe = container_of(rule, struct lttng_event_rule_uprobe, parent);
43
44 /* Required field. */
45 if (!uprobe->name) {
46 ERR("Invalid uprobe event rule: a pattern must be set.");
47 goto end;
48 }
49
50 if (!uprobe->location) {
51 ERR("Invalid uprobe event rule: a location must be set.");
52 goto end;
53 }
54
55 valid = true;
56 end:
57 return valid;
58 }
59
60 static int lttng_event_rule_uprobe_serialize(
61 const struct lttng_event_rule *rule,
62 struct lttng_payload *payload)
63 {
64 int ret;
65 size_t name_len, header_offset, size_before_probe;
66 struct lttng_event_rule_uprobe *uprobe;
67 struct lttng_event_rule_uprobe_comm uprobe_comm = {};
68 struct lttng_event_rule_uprobe_comm *header;
69
70 if (!rule || !IS_UPROBE_EVENT_RULE(rule)) {
71 ret = -1;
72 goto end;
73 }
74
75 header_offset = payload->buffer.size;
76
77 DBG("Serializing uprobe event rule.");
78 uprobe = container_of(rule, struct lttng_event_rule_uprobe, parent);
79
80 name_len = strlen(uprobe->name) + 1;
81
82 uprobe_comm.name_len = name_len;
83
84 ret = lttng_dynamic_buffer_append(
85 &payload->buffer, &uprobe_comm, sizeof(uprobe_comm));
86 if (ret) {
87 goto end;
88 }
89 ret = lttng_dynamic_buffer_append(
90 &payload->buffer, uprobe->name, name_len);
91 if (ret) {
92 goto end;
93 }
94
95 size_before_probe = payload->buffer.size;
96
97 /* This serialize return the size taken in the buffer. */
98 ret = lttng_userspace_probe_location_serialize(
99 uprobe->location, payload);
100 if (ret < 0) {
101 goto end;
102 }
103
104 /* Update the header regarding the probe size. */
105 header = (struct lttng_event_rule_uprobe_comm
106 *) ((char *) payload->buffer.data +
107 header_offset);
108 header->location_len = payload->buffer.size - size_before_probe;
109
110 ret = 0;
111
112 end:
113 return ret;
114 }
115
116 static bool lttng_event_rule_uprobe_is_equal(const struct lttng_event_rule *_a,
117 const struct lttng_event_rule *_b)
118 {
119 bool is_equal = false;
120 struct lttng_event_rule_uprobe *a, *b;
121
122 a = container_of(_a, struct lttng_event_rule_uprobe, parent);
123 b = container_of(_b, struct lttng_event_rule_uprobe, parent);
124
125 /* uprobe is invalid if this is not true. */
126 assert(a->name);
127 assert(b->name);
128 if (strcmp(a->name, b->name)) {
129 goto end;
130 }
131
132 assert(a->location);
133 assert(b->location);
134 is_equal = lttng_userspace_probe_location_is_equal(
135 a->location, b->location);
136 end:
137 return is_equal;
138 }
139
140 static enum lttng_error_code lttng_event_rule_uprobe_generate_filter_bytecode(
141 struct lttng_event_rule *rule, uid_t uid, gid_t gid)
142 {
143 /* Nothing to do. */
144 return LTTNG_OK;
145 }
146
147 static const char *lttng_event_rule_uprobe_get_filter(
148 const struct lttng_event_rule *rule)
149 {
150 /* Unsupported. */
151 return NULL;
152 }
153
154 static const struct lttng_filter_bytecode *
155 lttng_event_rule_uprobe_get_filter_bytecode(const struct lttng_event_rule *rule)
156 {
157 /* Unsupported. */
158 return NULL;
159 }
160
161 static struct lttng_event_exclusion *
162 lttng_event_rule_uprobe_generate_exclusions(const struct lttng_event_rule *rule)
163 {
164 /* Unsupported. */
165 return NULL;
166 }
167
168 struct lttng_event_rule *lttng_event_rule_uprobe_create()
169 {
170 struct lttng_event_rule *rule = NULL;
171 struct lttng_event_rule_uprobe *urule;
172
173 urule = zmalloc(sizeof(struct lttng_event_rule_uprobe));
174 if (!urule) {
175 goto end;
176 }
177
178 rule = &urule->parent;
179 lttng_event_rule_init(&urule->parent, LTTNG_EVENT_RULE_TYPE_UPROBE);
180 urule->parent.validate = lttng_event_rule_uprobe_validate;
181 urule->parent.serialize = lttng_event_rule_uprobe_serialize;
182 urule->parent.equal = lttng_event_rule_uprobe_is_equal;
183 urule->parent.destroy = lttng_event_rule_uprobe_destroy;
184 urule->parent.generate_filter_bytecode =
185 lttng_event_rule_uprobe_generate_filter_bytecode;
186 urule->parent.get_filter = lttng_event_rule_uprobe_get_filter;
187 urule->parent.get_filter_bytecode =
188 lttng_event_rule_uprobe_get_filter_bytecode;
189 urule->parent.generate_exclusions =
190 lttng_event_rule_uprobe_generate_exclusions;
191 end:
192 return rule;
193 }
194
195 LTTNG_HIDDEN
196 ssize_t lttng_event_rule_uprobe_create_from_payload(
197 struct lttng_payload_view *view,
198 struct lttng_event_rule **_event_rule)
199 {
200 ssize_t ret, offset = 0;
201 const struct lttng_event_rule_uprobe_comm *uprobe_comm;
202 const char *name;
203 struct lttng_buffer_view current_buffer_view;
204 struct lttng_event_rule *rule = NULL;
205 struct lttng_userspace_probe_location *location;
206 struct lttng_event_rule_uprobe *uprobe;
207 enum lttng_event_rule_status status;
208
209 if (!_event_rule) {
210 ret = -1;
211 goto end;
212 }
213
214 current_buffer_view = lttng_buffer_view_from_view(
215 &view->buffer, offset, sizeof(*uprobe_comm));
216 if (!lttng_buffer_view_is_valid(&current_buffer_view)) {
217 ERR("Failed to initialize from malformed event rule uprobe: buffer too short to contain header");
218 ret = -1;
219 goto end;
220 }
221
222 uprobe_comm = (typeof(uprobe_comm)) current_buffer_view.data;
223
224 rule = lttng_event_rule_uprobe_create();
225 if (!rule) {
226 ERR("Failed to create event rule uprobe");
227 ret = -1;
228 goto end;
229 }
230
231 /* Skip to payload. */
232 offset += current_buffer_view.size;
233
234 /* Map the name. */
235 current_buffer_view = lttng_buffer_view_from_view(
236 &view->buffer, offset, uprobe_comm->name_len);
237 if (!lttng_buffer_view_is_valid(&current_buffer_view)) {
238 ret = -1;
239 goto end;
240 }
241
242 name = current_buffer_view.data;
243 if (!lttng_buffer_view_contains_string(&current_buffer_view, name,
244 uprobe_comm->name_len)) {
245 ret = -1;
246 goto end;
247 }
248
249 /* Skip after the name. */
250 offset += uprobe_comm->name_len;
251
252 /* Map the location. */
253 {
254 struct lttng_payload_view current_payload_view =
255 lttng_payload_view_from_view(view, offset,
256 uprobe_comm->location_len);
257
258 if (!lttng_payload_view_is_valid(&current_payload_view)) {
259 ERR("Failed to initialize from malformed event rule uprobe: buffer too short to contain location");
260 ret = -1;
261 goto end;
262 }
263
264 ret = lttng_userspace_probe_location_create_from_payload(
265 &current_payload_view, &location);
266 if (ret < 0) {
267 ret = -1;
268 goto end;
269 }
270 }
271
272 assert(ret == uprobe_comm->location_len);
273
274 /* Skip after the location. */
275 offset += uprobe_comm->location_len;
276
277 uprobe = container_of(rule, struct lttng_event_rule_uprobe, parent);
278 uprobe->location = location;
279
280 status = lttng_event_rule_uprobe_set_name(rule, name);
281 if (status != LTTNG_EVENT_RULE_STATUS_OK) {
282 ret = -1;
283 goto end;
284 }
285
286 if (!lttng_event_rule_uprobe_validate(rule)) {
287 ret = -1;
288 goto end;
289 }
290
291 *_event_rule = rule;
292 rule = NULL;
293 ret = offset;
294 end:
295 lttng_event_rule_destroy(rule);
296 return ret;
297 }
298
299 enum lttng_event_rule_status lttng_event_rule_uprobe_set_location(
300 struct lttng_event_rule *rule,
301 const struct lttng_userspace_probe_location *location)
302 {
303 struct lttng_userspace_probe_location *location_copy = NULL;
304 struct lttng_event_rule_uprobe *uprobe;
305 enum lttng_event_rule_status status = LTTNG_EVENT_RULE_STATUS_OK;
306
307 if (!rule || !IS_UPROBE_EVENT_RULE(rule) || !location) {
308 status = LTTNG_EVENT_RULE_STATUS_INVALID;
309 goto end;
310 }
311
312 uprobe = container_of(rule, struct lttng_event_rule_uprobe, parent);
313 location_copy = lttng_userspace_probe_location_copy(location);
314 if (!location_copy) {
315 status = LTTNG_EVENT_RULE_STATUS_ERROR;
316 goto end;
317 }
318
319 if (uprobe->location) {
320 lttng_userspace_probe_location_destroy(uprobe->location);
321 }
322
323 uprobe->location = location_copy;
324 location_copy = NULL;
325 end:
326 lttng_userspace_probe_location_destroy(location_copy);
327 return status;
328 }
329
330 enum lttng_event_rule_status lttng_event_rule_uprobe_get_location(
331 const struct lttng_event_rule *rule,
332 const struct lttng_userspace_probe_location **location)
333 {
334 enum lttng_event_rule_status status = LTTNG_EVENT_RULE_STATUS_OK;
335
336 if (!rule || !IS_UPROBE_EVENT_RULE(rule) || !location) {
337 status = LTTNG_EVENT_RULE_STATUS_INVALID;
338 goto end;
339 }
340
341 *location = lttng_event_rule_uprobe_get_location_mutable(rule);
342 if (!*location) {
343 status = LTTNG_EVENT_RULE_STATUS_UNSET;
344 goto end;
345 }
346
347 end:
348 return status;
349 }
350
351 LTTNG_HIDDEN
352 struct lttng_userspace_probe_location *
353 lttng_event_rule_uprobe_get_location_mutable(
354 const struct lttng_event_rule *rule)
355 {
356 struct lttng_event_rule_uprobe *uprobe;
357
358 assert(rule);
359 uprobe = container_of(rule, struct lttng_event_rule_uprobe, parent);
360
361 return uprobe->location;
362 }
363
364 enum lttng_event_rule_status lttng_event_rule_uprobe_set_name(
365 struct lttng_event_rule *rule, const char *name)
366 {
367 char *name_copy = NULL;
368 struct lttng_event_rule_uprobe *uprobe;
369 enum lttng_event_rule_status status = LTTNG_EVENT_RULE_STATUS_OK;
370
371 if (!rule || !IS_UPROBE_EVENT_RULE(rule) || !name ||
372 strlen(name) == 0) {
373 status = LTTNG_EVENT_RULE_STATUS_INVALID;
374 goto end;
375 }
376
377 uprobe = container_of(rule, struct lttng_event_rule_uprobe, parent);
378 name_copy = strdup(name);
379 if (!name_copy) {
380 status = LTTNG_EVENT_RULE_STATUS_ERROR;
381 goto end;
382 }
383
384 if (uprobe->name) {
385 free(uprobe->name);
386 }
387
388 uprobe->name = name_copy;
389 name_copy = NULL;
390 end:
391 return status;
392 }
393
394 enum lttng_event_rule_status lttng_event_rule_uprobe_get_name(
395 const struct lttng_event_rule *rule, const char **name)
396 {
397 struct lttng_event_rule_uprobe *uprobe;
398 enum lttng_event_rule_status status = LTTNG_EVENT_RULE_STATUS_OK;
399
400 if (!rule || !IS_UPROBE_EVENT_RULE(rule) || !name) {
401 status = LTTNG_EVENT_RULE_STATUS_INVALID;
402 goto end;
403 }
404
405 uprobe = container_of(rule, struct lttng_event_rule_uprobe, parent);
406 if (!uprobe->name) {
407 status = LTTNG_EVENT_RULE_STATUS_UNSET;
408 goto end;
409 }
410
411 *name = uprobe->name;
412 end:
413 return status;
414 }
This page took 0.055082 seconds and 4 git commands to generate.