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:
16gcc -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
35static bool g_debug = false;
36static char g_msg_flag[DBUS_MESSAGE_TYPE_SIGNAL+1] = {0};
37
38//NOTE: snprintf not call new syscall, or dead lock!
39
40static 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
190static 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
251static 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
283typedef dbus_bool_t (*DBUS_CONNECTION_SEND_WITH_REPLY)(DBusConnection *connection,
284 DBusMessage *message,
285 DBusPendingCall **pending_return,
286 int timeout_milliseconds);
287DBUS_CONNECTION_SEND_WITH_REPLY real_dbus_connection_send_with_reply = NULL;
288
289dbus_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
309typedef DBusMessage* (*DBUS_PENDING_CALL_STEAL_REPLY)(DBusPendingCall* pending);
310
311DBUS_PENDING_CALL_STEAL_REPLY real_dbus_pending_call_steal_reply = NULL;
312
313DBusMessage* 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
331typedef DBusMessage* (*DBUS_CONNECTION_POP_MESSAGE)(DBusConnection *connection);
332DBUS_CONNECTION_POP_MESSAGE real_dbus_connection_pop_message = NULL;
333
334DBusMessage* 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
352typedef dbus_bool_t (*DBUS_CONNECTION_SEND)(DBusConnection *connection,
353 DBusMessage *message, dbus_uint32_t *serial);
354DBUS_CONNECTION_SEND real_dbus_connection_send = NULL;
355dbus_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
374typedef 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
383DBUS_CONNECTION_SEND_WITH_REPLY_AND_BLOCK real_dbus_connection_send_with_reply_and_block = NULL;
384DBusMessage* 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
410static 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