1 | // SPDX-FileCopyrightText: 2023 UnionTech Software Technology Co., Ltd. |
2 | // |
3 | // SPDX-License-Identifier: GPL-3.0-or-later |
4 | |
5 | #include <dbus/dbus.h> |
6 | #include <unistd.h> |
7 | #include <stdio.h> |
8 | #include <stdlib.h> |
9 | #include <dlfcn.h> |
10 | #include <memory.h> |
11 | |
12 | #include "shared_mem_dump.h" |
13 | #include "event_man.h" |
14 | |
15 | /* build: |
16 | gcc -g -O0 -o dbuspreload.so dbus_preload.c -fPIC -shared -D_GNU_SOURCE -I/usr/lib/x86_64-linux-gnu/dbus-1.0/include/ -I/usr/include/dbus-1.0/ -ldbus-1 -ldl |
17 | |
18 | note: |
19 | -D_GNU_SOURCE flag is specified to satisfy #ifdef conditions that allow us to use the |
20 | RTLD_NEXT enum. |
21 | The RTLD_NEXT enum tells the dynamic loader API that we want to return the next instance |
22 | of the function associated with the second argument (in this case puts) in the load |
23 | order. |
24 | |
25 | usage: |
26 | LD_PRELOAD=libdbuspreload.so dbus-send |
27 | |
28 | /usr/bin/dbus-send --system --print-reply --dest=org.freedesktop.DBus \ |
29 | / org.freedesktop.DBus.GetId |
30 | |
31 | /usr/bin/dbus-send --system --print-reply --dest=org.freedesktop.NetworkManager \ |
32 | /org/freedesktop/NetworkManager org.freedesktop.NetworkManager.GetAllDevices |
33 | */ |
34 | |
35 | static bool g_debug = false; |
36 | static char g_msg_flag[DBUS_MESSAGE_TYPE_SIGNAL+1] = {0}; |
37 | |
38 | //NOTE: snprintf not call new syscall, or dead lock! |
39 | |
40 | static int dump_iter(DBusMessageIter* iter, char* buf, int size) |
41 | { |
42 | char* walk = buf; |
43 | int remain = size; |
44 | do |
45 | { |
46 | int type = dbus_message_iter_get_arg_type(iter); |
47 | if (type == DBUS_TYPE_INVALID) break; |
48 | switch (type) |
49 | { |
50 | case DBUS_TYPE_STRING: |
51 | case DBUS_TYPE_SIGNATURE: |
52 | case DBUS_TYPE_OBJECT_PATH: |
53 | { |
54 | char *val = NULL; |
55 | dbus_message_iter_get_basic(iter, &val); |
56 | if (val) { |
57 | int len = snprintf(walk, remain, "%s," , val); |
58 | walk += len; |
59 | remain -= len; |
60 | } |
61 | break; |
62 | } |
63 | |
64 | case DBUS_TYPE_INT16: |
65 | { |
66 | dbus_int16_t val = 0; |
67 | dbus_message_iter_get_basic (iter, &val); |
68 | int len = snprintf(walk, remain, "%d," , val); |
69 | walk += len; |
70 | remain -= len; |
71 | break; |
72 | } |
73 | |
74 | case DBUS_TYPE_UINT16: |
75 | { |
76 | dbus_uint16_t val = 0; |
77 | dbus_message_iter_get_basic (iter, &val); |
78 | int len = snprintf(walk, remain, "%u," , val); |
79 | walk += len; |
80 | remain -= len; |
81 | break; |
82 | } |
83 | |
84 | case DBUS_TYPE_INT32: |
85 | { |
86 | dbus_int32_t val = 0; |
87 | dbus_message_iter_get_basic (iter, &val); |
88 | int len = snprintf(walk, remain, "%d," , val); |
89 | walk += len; |
90 | remain -= len; |
91 | break; |
92 | } |
93 | |
94 | case DBUS_TYPE_UINT32: |
95 | { |
96 | dbus_uint32_t val = 0; |
97 | dbus_message_iter_get_basic (iter, &val); |
98 | int len = snprintf(walk, remain, "%u," , val); |
99 | walk += len; |
100 | remain -= len; |
101 | break; |
102 | } |
103 | |
104 | case DBUS_TYPE_INT64: |
105 | { |
106 | dbus_int64_t val = 0; |
107 | dbus_message_iter_get_basic (iter, &val); |
108 | int len = snprintf(walk, remain, "%ld," , val); |
109 | walk += len; |
110 | remain -= len; |
111 | break; |
112 | } |
113 | |
114 | case DBUS_TYPE_UINT64: |
115 | { |
116 | dbus_uint64_t val = 0; |
117 | dbus_message_iter_get_basic (iter, &val); |
118 | int len = snprintf(walk, remain, "%lu," , val); |
119 | walk += len; |
120 | remain -= len; |
121 | break; |
122 | } |
123 | |
124 | case DBUS_TYPE_DOUBLE: |
125 | { |
126 | double val = 0; |
127 | dbus_message_iter_get_basic (iter, &val); |
128 | int len = snprintf(walk, remain, "%f," , val); |
129 | walk += len; |
130 | remain -= len; |
131 | break; |
132 | } |
133 | |
134 | case DBUS_TYPE_BYTE: |
135 | { |
136 | unsigned char val = 0; |
137 | dbus_message_iter_get_basic (iter, &val); |
138 | int len = snprintf(walk, remain, "%u," , val); |
139 | walk += len; |
140 | remain -= len; |
141 | break; |
142 | } |
143 | |
144 | case DBUS_TYPE_BOOLEAN: |
145 | { |
146 | dbus_bool_t val = 0; |
147 | dbus_message_iter_get_basic (iter, &val); |
148 | int len = snprintf(walk, remain, "%s," , val ? "true" : "false" ); |
149 | walk += len; |
150 | remain -= len; |
151 | break; |
152 | } |
153 | |
154 | case DBUS_TYPE_VARIANT: |
155 | { |
156 | int len = snprintf(walk, remain, "variant," ); |
157 | walk += len; |
158 | remain -= len; |
159 | break; |
160 | } |
161 | case DBUS_TYPE_ARRAY: |
162 | { |
163 | int len = snprintf(walk, remain, "array," ); |
164 | walk += len; |
165 | remain -= len; |
166 | break; |
167 | } |
168 | case DBUS_TYPE_DICT_ENTRY: |
169 | { |
170 | int len = snprintf(walk, remain, "entry," ); |
171 | walk += len; |
172 | remain -= len; |
173 | break; |
174 | } |
175 | case DBUS_TYPE_STRUCT: |
176 | { |
177 | int len = snprintf(walk, remain, "struct," ); |
178 | walk += len; |
179 | remain -= len; |
180 | break; |
181 | } |
182 | default: |
183 | break; |
184 | } |
185 | } while (dbus_message_iter_next (iter)); |
186 | |
187 | return (walk - buf); |
188 | } |
189 | |
190 | static int get_msg_detail(DBusMessage* msg, int* pmsg_type, char* buf, int size) |
191 | { |
192 | const char* sender; |
193 | const char* destination; |
194 | int len = 0; |
195 | int msg_type = dbus_message_get_type(msg); |
196 | |
197 | if (pmsg_type) { |
198 | *pmsg_type = msg_type; |
199 | } |
200 | else { |
201 | // FIXME: msg_type = DBUS_MESSAGE_TYPE_METHOD_RETURN; |
202 | } |
203 | if (!g_msg_flag[msg_type]) return 0; |
204 | |
205 | sender = dbus_message_get_sender(msg); |
206 | destination = dbus_message_get_destination(msg); |
207 | |
208 | switch (msg_type) |
209 | { |
210 | case DBUS_MESSAGE_TYPE_METHOD_CALL: |
211 | case DBUS_MESSAGE_TYPE_SIGNAL: { |
212 | const char* path = dbus_message_get_path(msg); |
213 | const char* interface = dbus_message_get_interface(msg); |
214 | const char* member = dbus_message_get_member(msg); |
215 | if (sender) { |
216 | len = snprintf(buf, size, "%s->%s,p=%s,i=%s,m=%s;" , |
217 | sender, destination != nullptr ? destination:"null" , |
218 | path, interface, member); |
219 | } |
220 | else { |
221 | len = snprintf(buf, size, "d=%s,p=%s,i=%s,m=%s;" , |
222 | destination != nullptr ? destination:"null" , |
223 | path, interface, member); |
224 | } |
225 | } |
226 | break; |
227 | |
228 | case DBUS_MESSAGE_TYPE_METHOD_RETURN: { |
229 | DBusMessageIter msgIter; |
230 | dbus_message_iter_init(msg, &msgIter); |
231 | len = dump_iter(&msgIter, buf, size); |
232 | } |
233 | break; |
234 | |
235 | case DBUS_MESSAGE_TYPE_ERROR: { |
236 | const char* err = dbus_message_get_error_name(msg); |
237 | len = snprintf(buf, size, "%s->%s,e=%s;" , |
238 | sender != nullptr ? sender:"null" , |
239 | destination != nullptr ? destination:"null" , |
240 | err); |
241 | } |
242 | break; |
243 | |
244 | default: |
245 | break; |
246 | } |
247 | |
248 | return (len > 0) ? len : 0; |
249 | } |
250 | |
251 | static void dump(DBusMessage* msg, DBusMessage* reply) |
252 | { |
253 | char detail[EVENT_EXTRA_INFO_SIZE]; |
254 | char* walk = &detail[0]; |
255 | char* walk_end = walk + EVENT_EXTRA_INFO_SIZE; |
256 | int length = 0; |
257 | int msg_type = -1; |
258 | |
259 | if (msg) { |
260 | walk += get_msg_detail(msg, &msg_type, walk, walk_end - walk); |
261 | } |
262 | if (reply) { |
263 | walk += get_msg_detail(reply, nullptr, walk, walk_end - walk); |
264 | if (msg_type < 0) msg_type = DBUS_MESSAGE_TYPE_METHOD_RETURN; |
265 | } |
266 | |
267 | length = walk - &detail[0]; |
268 | if (length > 0) { |
269 | MemoryDumper* dump = get_memory_dumper(); |
270 | if (dump) { |
271 | record_event_simple(dump, DUMP_REASON_dbus + msg_type, detail, length); |
272 | } |
273 | else { |
274 | syscall(SYS_dump_dbus, msg_type, detail, length, 0, 0); |
275 | } |
276 | if (g_debug) { |
277 | // if (strstr(detail, "/lfs/idc300test/listener")) |
278 | printf("dbus preload %d:%s\n" , msg_type, detail); |
279 | } |
280 | } |
281 | } |
282 | |
283 | typedef dbus_bool_t (*DBUS_CONNECTION_SEND_WITH_REPLY)(DBusConnection *connection, |
284 | DBusMessage *message, |
285 | DBusPendingCall **pending_return, |
286 | int timeout_milliseconds); |
287 | DBUS_CONNECTION_SEND_WITH_REPLY real_dbus_connection_send_with_reply = NULL; |
288 | |
289 | dbus_bool_t dbus_connection_send_with_reply(DBusConnection *connection, |
290 | DBusMessage *message, |
291 | DBusPendingCall **pending_return, |
292 | int timeout_milliseconds) |
293 | { |
294 | dbus_bool_t ret = 0; |
295 | if (NULL == real_dbus_connection_send_with_reply) { |
296 | real_dbus_connection_send_with_reply = (DBUS_CONNECTION_SEND_WITH_REPLY)dlsym(RTLD_NEXT, |
297 | "dbus_connection_send_with_reply" ); |
298 | } |
299 | |
300 | if (NULL != real_dbus_connection_send_with_reply) { |
301 | ret = real_dbus_connection_send_with_reply(connection, |
302 | message, pending_return, timeout_milliseconds); |
303 | dump(message, nullptr); |
304 | } |
305 | |
306 | return ret; |
307 | } |
308 | |
309 | typedef DBusMessage* (*DBUS_PENDING_CALL_STEAL_REPLY)(DBusPendingCall* pending); |
310 | |
311 | DBUS_PENDING_CALL_STEAL_REPLY real_dbus_pending_call_steal_reply = NULL; |
312 | |
313 | DBusMessage* dbus_pending_call_steal_reply(DBusPendingCall* pending) |
314 | { |
315 | DBusMessage* msg = NULL; |
316 | |
317 | if (NULL == real_dbus_pending_call_steal_reply) { |
318 | real_dbus_pending_call_steal_reply = (DBUS_PENDING_CALL_STEAL_REPLY)dlsym(RTLD_NEXT, |
319 | "dbus_pending_call_steal_reply" ); |
320 | } |
321 | if (NULL != real_dbus_pending_call_steal_reply) { |
322 | msg = real_dbus_pending_call_steal_reply(pending); |
323 | if (msg) { |
324 | dump(nullptr, msg); |
325 | } |
326 | } |
327 | |
328 | return msg; |
329 | } |
330 | |
331 | typedef DBusMessage* (*DBUS_CONNECTION_POP_MESSAGE)(DBusConnection *connection); |
332 | DBUS_CONNECTION_POP_MESSAGE real_dbus_connection_pop_message = NULL; |
333 | |
334 | DBusMessage* dbus_connection_pop_message (DBusConnection *connection) |
335 | { |
336 | DBusMessage* msg = NULL; |
337 | |
338 | if (NULL == real_dbus_connection_pop_message) { |
339 | real_dbus_connection_pop_message = (DBUS_CONNECTION_POP_MESSAGE)dlsym(RTLD_NEXT, |
340 | "dbus_connection_pop_message" ); |
341 | } |
342 | if (NULL != real_dbus_connection_pop_message) { |
343 | msg = real_dbus_connection_pop_message(connection); |
344 | if (msg) { |
345 | dump(nullptr, msg); |
346 | } |
347 | } |
348 | |
349 | return msg; |
350 | } |
351 | |
352 | typedef dbus_bool_t (*DBUS_CONNECTION_SEND)(DBusConnection *connection, |
353 | DBusMessage *message, dbus_uint32_t *serial); |
354 | DBUS_CONNECTION_SEND real_dbus_connection_send = NULL; |
355 | dbus_bool_t dbus_connection_send(DBusConnection *connection, |
356 | DBusMessage *message, dbus_uint32_t *serial) |
357 | { |
358 | dbus_bool_t ret = 0; |
359 | |
360 | if (NULL == real_dbus_connection_send) { |
361 | real_dbus_connection_send = (DBUS_CONNECTION_SEND)dlsym(RTLD_NEXT, |
362 | "dbus_connection_send" ); |
363 | } |
364 | if (NULL != real_dbus_connection_send) { |
365 | ret = real_dbus_connection_send(connection, message, serial); |
366 | if (ret) { |
367 | dump(message, nullptr); |
368 | } |
369 | } |
370 | |
371 | return ret; |
372 | } |
373 | |
374 | typedef DBusMessage* (*DBUS_CONNECTION_SEND_WITH_REPLY_AND_BLOCK)( |
375 | DBusConnection *connection, |
376 | DBusMessage *message, |
377 | int timeout_milliseconds, |
378 | DBusError *error); |
379 | |
380 | |
381 | // NOTE: dbus_connection_send_with_reply_and_block will call dbus_connection_send_with_reply internally! |
382 | #if 0 |
383 | DBUS_CONNECTION_SEND_WITH_REPLY_AND_BLOCK real_dbus_connection_send_with_reply_and_block = NULL; |
384 | DBusMessage* dbus_connection_send_with_reply_and_block( |
385 | DBusConnection *connection, |
386 | DBusMessage *message, |
387 | int timeout_milliseconds, |
388 | DBusError *error) |
389 | { |
390 | DBusMessage* reply = NULL; |
391 | |
392 | if (NULL == real_dbus_connection_send_with_reply_and_block) { |
393 | real_dbus_connection_send_with_reply_and_block = |
394 | (DBUS_CONNECTION_SEND_WITH_REPLY_AND_BLOCK)dlsym(RTLD_NEXT, |
395 | "dbus_connection_send_with_reply_and_block" ); |
396 | } |
397 | if (NULL != real_dbus_connection_send_with_reply_and_block) { |
398 | reply = real_dbus_connection_send_with_reply_and_block( |
399 | connection, message, timeout_milliseconds, error); |
400 | |
401 | if (reply) { |
402 | dump(message, reply); |
403 | } |
404 | } |
405 | |
406 | return reply; |
407 | } |
408 | #endif |
409 | |
410 | static void __attribute__((constructor)) init_process(void) { |
411 | const char* filter = getenv("ST2_DBUS_FILTER" ); |
412 | if (filter != nullptr) { |
413 | const char* walk = filter; |
414 | char* stop = nullptr; |
415 | while (*walk > 0) { |
416 | int v = strtol(walk, &stop, 10); |
417 | if (v >= DBUS_MESSAGE_TYPE_METHOD_CALL && |
418 | v <= DBUS_MESSAGE_TYPE_SIGNAL) { |
419 | g_msg_flag[v] = 1; |
420 | } |
421 | if (0 == *stop) break; |
422 | walk = stop + 1; |
423 | } |
424 | } |
425 | else { |
426 | memset(g_msg_flag, 1, sizeof(g_msg_flag)); |
427 | } |
428 | if (getenv("ST2_DEBUG_DBUS" ) != nullptr) { |
429 | g_debug = true; |
430 | printf("dbus preload: ST2_DBUS_FILTER=%s\n" , filter); |
431 | } |
432 | } |
433 | |