Skip to content

Commit 8b22720

Browse files
committed
fix(agent): address JSON, DBus, endianness, and robustness bugs
- Hostname JSON injection: use json_print_string() for proper escaping - Proxy JSON trailing commas: fix comma logic for valid JSON output - Duplicate DBus serial counters: single global g_dbus_serial - Uninitialized ip buffer in parse_target: initialize to empty - Big-endian DBus wire format: use native uint32_t write - Rename DBUS_ENDIAN_LITTLE to DBUS_NATIVE_ENDIAN - Route table ID: validate with strtol instead of atoi - Unchecked bind() return in open_netlink_genl
1 parent d6602df commit 8b22720

2 files changed

Lines changed: 35 additions & 24 deletions

File tree

src/rxnm-agent.c

Lines changed: 33 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -97,6 +97,10 @@ char g_conn_targets_v6[4096] = RXNM_PROBE_TARGETS_V6;
9797
/* Configurable DBus Timeout (Default 5s) */
9898
long g_dbus_timeout_us = 5000000;
9999

100+
/* Global DBus serial counter — shared across all DBus send functions to prevent
101+
* duplicate serial numbers within a single connection. */
102+
static uint32_t g_dbus_serial = 0;
103+
100104
/* Routing Table Filter (Default: Main) */
101105
uint32_t g_target_table = RT_TABLE_MAIN;
102106
bool g_filter_table = true; /* If false, dump all tables */
@@ -351,16 +355,9 @@ bool dyn_buf_append_string(dyn_buf_t *b, const char *str) {
351355
/* Ensure 4-byte alignment before appending string length (D-Bus Spec) */
352356
if (!dyn_buf_align4(b)) return false;
353357

354-
/* Explicitly encode length in Little Endian (DBUS_ENDIAN_LITTLE) */
358+
/* Encode length in native byte order to match DBUS_NATIVE_ENDIAN */
355359
uint32_t len = strlen(str);
356-
uint8_t len_bytes[4] = {
357-
(uint8_t)(len & 0xFF),
358-
(uint8_t)((len >> 8) & 0xFF),
359-
(uint8_t)((len >> 16) & 0xFF),
360-
(uint8_t)((len >> 24) & 0xFF)
361-
};
362-
363-
if (!dyn_buf_append(b, len_bytes, 4)) return false;
360+
if (!dyn_buf_append(b, &len, sizeof(len))) return false;
364361
if (!dyn_buf_append(b, str, len + 1)) return false;
365362
return true;
366363
}
@@ -678,14 +675,12 @@ int dbus_send_method_call(int sock, const char *dest, const char *path, const ch
678675

679676
dbus_header_t hdr;
680677
memset(&hdr, 0, sizeof(hdr));
681-
hdr.endian = DBUS_ENDIAN_LITTLE;
678+
hdr.endian = DBUS_NATIVE_ENDIAN;
682679
hdr.type = DBUS_MESSAGE_TYPE_METHOD_CALL;
683680
hdr.flags = expect_reply ? 0 : DBUS_MESSAGE_FLAGS_NO_REPLY_EXPECTED;
684681
hdr.version = DBUS_PROTOCOL_VERSION;
685682

686-
/* Ensure DBus Serial Number compliance (Unique per connection) */
687-
static uint32_t _serial_counter = 0;
688-
hdr.serial = ++_serial_counter;
683+
hdr.serial = ++g_dbus_serial;
689684

690685
if (!dyn_buf_append(&b, &hdr, sizeof(hdr))) { dyn_buf_free(&b); return -1; }
691686

@@ -789,7 +784,7 @@ int find_iwd_network_path(int sock, const char *ssid, const char *prefix, char *
789784
dyn_buf_t req = {0};
790785
dbus_header_t hdr;
791786
memset(&hdr, 0, sizeof(hdr));
792-
hdr.endian = DBUS_ENDIAN_LITTLE;
787+
hdr.endian = DBUS_NATIVE_ENDIAN;
793788
hdr.type = DBUS_MESSAGE_TYPE_METHOD_CALL;
794789
hdr.flags = 0; /* Expect Reply */
795790
hdr.version = DBUS_PROTOCOL_VERSION;
@@ -1212,7 +1207,10 @@ int open_netlink_genl() {
12121207
struct sockaddr_nl addr = { .nl_family = AF_NETLINK };
12131208
struct timeval tv = { .tv_sec = 2, .tv_usec = 0 };
12141209
setsockopt(sock, SOL_SOCKET, SO_RCVTIMEO, &tv, sizeof(tv));
1215-
bind(sock, (struct sockaddr *)&addr, sizeof(addr));
1210+
if (bind(sock, (struct sockaddr *)&addr, sizeof(addr)) < 0) {
1211+
close(sock);
1212+
return -1;
1213+
}
12161214
return sock;
12171215
}
12181216

@@ -1439,6 +1437,7 @@ bool tcp_probe(const char *ip_str, int port, int family) {
14391437
}
14401438

14411439
void parse_target(char *token, char *ip, size_t ip_size, int *port) {
1440+
ip[0] = '\0';
14421441
char *colon = strrchr(token, ':');
14431442
if (colon) {
14441443
*colon = '\0';
@@ -1540,15 +1539,21 @@ void print_json_status() {
15401539
FILE *f = fopen("/etc/hostname", "r");
15411540
if (f) { if (fgets(hostname, sizeof(hostname), f)) hostname[strcspn(hostname, "\n")] = 0; fclose(f); }
15421541
}
1543-
printf(" \"hostname\": \"%s\",\n", hostname);
1542+
printf(" "); json_print_string("hostname", hostname, true);
15441543

15451544
char p_http[256] = "", p_https[256] = "", p_no[256] = "";
15461545
get_proxy_config(p_http, p_https, p_no);
1547-
bool first_proxy = true; printf(" \"global_proxy\": {\n");
1548-
if (strlen(p_http) > 0) { json_print_string("http", p_http, false); printf(","); first_proxy = false; }
1549-
if (strlen(p_https) > 0) { if(!first_proxy) printf("\n"); json_print_string("https", p_https, false); printf(","); first_proxy = false; }
1550-
if (strlen(p_no) > 0) { if(!first_proxy) printf("\n"); json_print_string("noproxy", p_no, false); printf(","); first_proxy = false; }
1551-
if (first_proxy) printf(" \"status\": \"none\"\n"); else printf(" \"status\": \"active\"\n");
1546+
bool has_proxy = (strlen(p_http) > 0 || strlen(p_https) > 0 || strlen(p_no) > 0);
1547+
printf(" \"global_proxy\": {\n");
1548+
if (has_proxy) {
1549+
bool need_comma = false;
1550+
if (strlen(p_http) > 0) { printf(" "); json_print_string("http", p_http, false); need_comma = true; }
1551+
if (strlen(p_https) > 0) { if (need_comma) printf(",\n"); printf(" "); json_print_string("https", p_https, false); need_comma = true; }
1552+
if (strlen(p_no) > 0) { if (need_comma) printf(",\n"); printf(" "); json_print_string("noproxy", p_no, false); need_comma = true; }
1553+
printf(",\n \"status\": \"active\"\n");
1554+
} else {
1555+
printf(" \"status\": \"none\"\n");
1556+
}
15521557
printf(" },\n \"interfaces\": {\n");
15531558

15541559
bool first_iface = true;
@@ -2501,7 +2506,13 @@ int main(int argc, char *argv[]) {
25012506
if (g_ns_create) { return cmd_ns_create(g_ns_create); }
25022507
if (g_ns_delete) { return cmd_ns_delete(g_ns_delete); }
25032508
if (g_route_table) {
2504-
g_target_table = atoi(g_route_table);
2509+
char *endp;
2510+
long tbl = strtol(g_route_table, &endp, 10);
2511+
if (*endp != '\0' || tbl < 0 || tbl > UINT32_MAX) {
2512+
fprintf(stderr, "Invalid route table ID: %s\n", g_route_table);
2513+
return 1;
2514+
}
2515+
g_target_table = (uint32_t)tbl;
25052516
g_filter_table = true;
25062517
collect_network_state();
25072518
print_json_routes();

src/rxnm_dbus_lite.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -32,9 +32,9 @@
3232

3333
/* Detect Endianness at Compile Time */
3434
#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
35-
#define DBUS_ENDIAN_LITTLE 'l'
35+
#define DBUS_NATIVE_ENDIAN 'l'
3636
#else
37-
#define DBUS_ENDIAN_LITTLE 'B'
37+
#define DBUS_NATIVE_ENDIAN 'B'
3838
#endif
3939

4040
#define DBUS_PROTOCOL_VERSION 1

0 commit comments

Comments
 (0)