Skip to content

Commit 39aadf8

Browse files
committed
fix: Don't use memcmp to compare IP_Ports.
`memcmp` compares padding bytes as well, which may be arbitrary or uninitialised.
1 parent d94246a commit 39aadf8

File tree

13 files changed

+197
-18
lines changed

13 files changed

+197
-18
lines changed
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
e5ccf844b7ece48d1153c226bdf8462d0e85d517dfcd720c8d6c4abad7da6929 /usr/local/bin/tox-bootstrapd
1+
af83f07bb96eb17a7ee69f174c9960d23758c9c9314144d73e0f57fdef5d55e4 /usr/local/bin/tox-bootstrapd

toxcore/TCP_server.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1043,7 +1043,7 @@ TCP_Server *new_tcp_server(const Logger *logger, const Memory *mem, const Random
10431043
memcpy(temp->secret_key, secret_key, CRYPTO_SECRET_KEY_SIZE);
10441044
crypto_derive_public_key(temp->public_key, temp->secret_key);
10451045

1046-
bs_list_init(&temp->accepted_key_list, CRYPTO_PUBLIC_KEY_SIZE, 8);
1046+
bs_list_init(&temp->accepted_key_list, CRYPTO_PUBLIC_KEY_SIZE, 8, memcmp);
10471047

10481048
return temp;
10491049
}

toxcore/group.c

Lines changed: 1 addition & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -956,11 +956,6 @@ static bool delpeer(Group_Chats *g_c, uint32_t groupnumber, int peer_index, void
956956
return true;
957957
}
958958

959-
static int cmp_u64(uint64_t a, uint64_t b)
960-
{
961-
return (a > b ? 1 : 0) - (a < b ? 1 : 0);
962-
}
963-
964959
/** Order peers with friends first and with more recently active earlier */
965960
non_null()
966961
static int cmp_frozen(const void *a, const void *b)
@@ -972,7 +967,7 @@ static int cmp_frozen(const void *a, const void *b)
972967
return pa->is_friend ? -1 : 1;
973968
}
974969

975-
return cmp_u64(pb->last_active, pa->last_active);
970+
return cmp_uint(pb->last_active, pa->last_active);
976971
}
977972

978973
/** @brief Delete frozen peers as necessary to ensure at most `g->maxfrozen` remain.

toxcore/list.c

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -60,7 +60,7 @@ static int find(const BS_List *list, const uint8_t *data)
6060
// closest match is found if we move back to where we have already been
6161

6262
while (true) {
63-
const int r = memcmp(data, list->data + list->element_size * i, list->element_size);
63+
const int r = list->cmp_callback(data, list->data + list->element_size * i, list->element_size);
6464

6565
if (r == 0) {
6666
return i;
@@ -135,14 +135,15 @@ static bool resize(BS_List *list, uint32_t new_size)
135135
}
136136

137137

138-
int bs_list_init(BS_List *list, uint32_t element_size, uint32_t initial_capacity)
138+
int bs_list_init(BS_List *list, uint32_t element_size, uint32_t initial_capacity, bs_list_cmp_cb *cmp_callback)
139139
{
140140
// set initial values
141141
list->n = 0;
142142
list->element_size = element_size;
143143
list->capacity = 0;
144144
list->data = nullptr;
145145
list->ids = nullptr;
146+
list->cmp_callback = cmp_callback;
146147

147148
if (initial_capacity != 0) {
148149
if (!resize(list, initial_capacity)) {

toxcore/list.h

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
#define C_TOXCORE_TOXCORE_LIST_H
1313

1414
#include <stdbool.h>
15+
#include <stddef.h> // size_t
1516
#include <stdint.h>
1617

1718
#include "attributes.h"
@@ -20,12 +21,15 @@
2021
extern "C" {
2122
#endif
2223

24+
typedef int bs_list_cmp_cb(const void *a, const void *b, size_t size);
25+
2326
typedef struct BS_List {
2427
uint32_t n; // number of elements
2528
uint32_t capacity; // number of elements memory is allocated for
2629
uint32_t element_size; // size of the elements
2730
uint8_t *data; // array of elements
2831
int *ids; // array of element ids
32+
bs_list_cmp_cb *cmp_callback;
2933
} BS_List;
3034

3135
/** @brief Initialize a list.
@@ -37,7 +41,7 @@ typedef struct BS_List {
3741
* @retval 0 failure
3842
*/
3943
non_null()
40-
int bs_list_init(BS_List *list, uint32_t element_size, uint32_t initial_capacity);
44+
int bs_list_init(BS_List *list, uint32_t element_size, uint32_t initial_capacity, bs_list_cmp_cb *cmp_callback);
4145

4246
/** Free a list initiated with list_init */
4347
nullable(1)

toxcore/list_test.cc

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,21 +7,21 @@ namespace {
77
TEST(List, CreateAndDestroyWithNonZeroSize)
88
{
99
BS_List list;
10-
bs_list_init(&list, sizeof(int), 10);
10+
bs_list_init(&list, sizeof(int), 10, memcmp);
1111
bs_list_free(&list);
1212
}
1313

1414
TEST(List, CreateAndDestroyWithZeroSize)
1515
{
1616
BS_List list;
17-
bs_list_init(&list, sizeof(int), 0);
17+
bs_list_init(&list, sizeof(int), 0, memcmp);
1818
bs_list_free(&list);
1919
}
2020

2121
TEST(List, DeleteFromEmptyList)
2222
{
2323
BS_List list;
24-
bs_list_init(&list, sizeof(int), 0);
24+
bs_list_init(&list, sizeof(int), 0, memcmp);
2525
const uint8_t data[sizeof(int)] = {0};
2626
bs_list_remove(&list, data, 0);
2727
bs_list_free(&list);

toxcore/net_crypto.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3163,7 +3163,7 @@ Net_Crypto *new_net_crypto(const Logger *log, const Memory *mem, const Random *r
31633163
networking_registerhandler(dht_get_net(dht), NET_PACKET_CRYPTO_HS, &udp_handle_packet, temp);
31643164
networking_registerhandler(dht_get_net(dht), NET_PACKET_CRYPTO_DATA, &udp_handle_packet, temp);
31653165

3166-
bs_list_init(&temp->ip_port_list, sizeof(IP_Port), 8);
3166+
bs_list_init(&temp->ip_port_list, sizeof(IP_Port), 8, ipport_cmp_handler);
31673167

31683168
return temp;
31693169
}

toxcore/network.c

Lines changed: 63 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1435,6 +1435,61 @@ bool ipport_equal(const IP_Port *a, const IP_Port *b)
14351435
return ip_equal(&a->ip, &b->ip);
14361436
}
14371437

1438+
non_null()
1439+
static int ip4_cmp(const IP4 *a, const IP4 *b)
1440+
{
1441+
return cmp_uint(a->uint32, b->uint32);
1442+
}
1443+
1444+
non_null()
1445+
static int ip6_cmp(const IP6 *a, const IP6 *b)
1446+
{
1447+
const int res = cmp_uint(a->uint64[0], b->uint64[0]);
1448+
if (res != 0) {
1449+
return res;
1450+
}
1451+
return cmp_uint(a->uint64[1], b->uint64[1]);
1452+
}
1453+
1454+
non_null()
1455+
static int ip_cmp(const IP *a, const IP *b)
1456+
{
1457+
const int res = cmp_uint(a->family.value, b->family.value);
1458+
if (res != 0) {
1459+
return res;
1460+
}
1461+
switch (a->family.value) {
1462+
case TOX_AF_UNSPEC:
1463+
return 0;
1464+
case TOX_AF_INET:
1465+
case TCP_INET:
1466+
case TOX_TCP_INET:
1467+
return ip4_cmp(&a->ip.v4, &b->ip.v4);
1468+
case TOX_AF_INET6:
1469+
case TCP_INET6:
1470+
case TOX_TCP_INET6:
1471+
case TCP_SERVER_FAMILY: // these happen to be ipv6 according to TCP_server.c.
1472+
case TCP_CLIENT_FAMILY:
1473+
return ip6_cmp(&a->ip.v6, &b->ip.v6);
1474+
}
1475+
// Invalid, we don't compare any further and consider them equal.
1476+
return 0;
1477+
}
1478+
1479+
int ipport_cmp_handler(const void *a, const void *b, size_t size)
1480+
{
1481+
const IP_Port *ipp_a = (const IP_Port *)a;
1482+
const IP_Port *ipp_b = (const IP_Port *)b;
1483+
assert(size == sizeof(IP_Port));
1484+
1485+
const int ip_res = ip_cmp(&ipp_a->ip, &ipp_b->ip);
1486+
if (ip_res != 0) {
1487+
return ip_res;
1488+
}
1489+
1490+
return cmp_uint(ipp_a->port, ipp_b->port);
1491+
}
1492+
14381493
/** nulls out ip */
14391494
void ip_reset(IP *ip)
14401495
{
@@ -1508,7 +1563,14 @@ void ipport_copy(IP_Port *target, const IP_Port *source)
15081563
return;
15091564
}
15101565

1511-
*target = *source;
1566+
// Write to a temporary object first, so that padding bytes are
1567+
// uninitialised and msan can catch mistakes in downstream code.
1568+
IP_Port tmp;
1569+
tmp.ip.family = source->ip.family;
1570+
tmp.ip.ip = source->ip.ip;
1571+
tmp.port = source->port;
1572+
1573+
*target = tmp;
15121574
}
15131575

15141576
const char *net_ip_ntoa(const IP *ip, Ip_Ntoa *ip_str)

toxcore/network.h

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -337,7 +337,7 @@ non_null()
337337
bool addr_parse_ip(const char *address, IP *to);
338338

339339
/**
340-
* Compares two IPAny structures.
340+
* Compares two IP structures.
341341
*
342342
* Unset means unequal.
343343
*
@@ -347,7 +347,7 @@ nullable(1, 2)
347347
bool ip_equal(const IP *a, const IP *b);
348348

349349
/**
350-
* Compares two IPAny_Port structures.
350+
* Compares two IP_Port structures.
351351
*
352352
* Unset means unequal.
353353
*
@@ -356,6 +356,18 @@ bool ip_equal(const IP *a, const IP *b);
356356
nullable(1, 2)
357357
bool ipport_equal(const IP_Port *a, const IP_Port *b);
358358

359+
/**
360+
* @brief IP_Port comparison function with `memcmp` signature.
361+
*
362+
* Casts the void pointers to `IP_Port *` for comparison.
363+
*
364+
* @retval -1 if `a < b`
365+
* @retval 0 if `a == b`
366+
* @retval 1 if `a > b`
367+
*/
368+
non_null()
369+
int ipport_cmp_handler(const void *a, const void *b, size_t size);
370+
359371
/** nulls out ip */
360372
non_null()
361373
void ip_reset(IP *ip);

toxcore/network_test.cc

Lines changed: 86 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -82,4 +82,90 @@ TEST(IpParseAddr, FormatsIPv6)
8282
EXPECT_EQ(std::string(ip_str), "ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff");
8383
}
8484

85+
TEST(IpportCmp, BehavesLikeMemcmp)
86+
{
87+
auto cmp_val = [](int val) { return val < 0 ? -1 : val > 0 ? 1 : 0; };
88+
89+
IP_Port a = {0};
90+
IP_Port b = {0};
91+
92+
a.ip.family = net_family_ipv4();
93+
b.ip.family = net_family_ipv4();
94+
95+
a.port = 10;
96+
b.port = 20;
97+
98+
EXPECT_EQ( //
99+
ipport_cmp_handler(&a, &b, sizeof(IP_Port)), -1)
100+
<< "a=" << a << "\n"
101+
<< "b=" << b;
102+
EXPECT_EQ( //
103+
ipport_cmp_handler(&a, &b, sizeof(IP_Port)), //
104+
cmp_val(memcmp(&a, &b, sizeof(IP_Port))))
105+
<< "a=" << a << "\n"
106+
<< "b=" << b;
107+
108+
a.ip.ip.v4.uint8[0] = 192;
109+
b.ip.ip.v4.uint8[0] = 10;
110+
111+
EXPECT_EQ( //
112+
ipport_cmp_handler(&a, &b, sizeof(IP_Port)), 1)
113+
<< "a=" << a << "\n"
114+
<< "b=" << b;
115+
EXPECT_EQ( //
116+
ipport_cmp_handler(&a, &b, sizeof(IP_Port)), //
117+
cmp_val(memcmp(&a, &b, sizeof(IP_Port))))
118+
<< "a=" << a << "\n"
119+
<< "b=" << b;
120+
}
121+
122+
TEST(IpportCmp, Ipv6BeginAndEndCompareCorrectly)
123+
{
124+
IP_Port a = {0};
125+
IP_Port b = {0};
126+
127+
a.ip.family = net_family_ipv6();
128+
b.ip.family = net_family_ipv6();
129+
130+
a.ip.ip.v6.uint8[0] = 0xab;
131+
b.ip.ip.v6.uint8[0] = 0xba;
132+
133+
EXPECT_EQ(ipport_cmp_handler(&a, &b, sizeof(IP_Port)), -1);
134+
135+
a.ip.ip.v6.uint8[0] = 0;
136+
b.ip.ip.v6.uint8[0] = 0;
137+
138+
a.ip.ip.v6.uint8[15] = 0xba;
139+
140+
EXPECT_EQ(ipport_cmp_handler(&a, &b, sizeof(IP_Port)), 1);
141+
}
142+
143+
TEST(IpportCmp, UnspecAlwaysComparesEqual)
144+
{
145+
IP_Port a = {0};
146+
IP_Port b = {0};
147+
148+
a.ip.family = net_family_unspec();
149+
b.ip.family = net_family_unspec();
150+
151+
a.ip.ip.v4.uint8[0] = 0xab;
152+
b.ip.ip.v4.uint8[0] = 0xba;
153+
154+
EXPECT_EQ(ipport_cmp_handler(&a, &b, sizeof(IP_Port)), 0);
155+
}
156+
157+
TEST(IpportCmp, InvalidAlwaysComparesEqual)
158+
{
159+
IP_Port a = {0};
160+
IP_Port b = {0};
161+
162+
a.ip.family.value = 0xff;
163+
b.ip.family.value = 0xff;
164+
165+
a.ip.ip.v4.uint8[0] = 0xab;
166+
b.ip.ip.v4.uint8[0] = 0xba;
167+
168+
EXPECT_EQ(ipport_cmp_handler(&a, &b, sizeof(IP_Port)), 0);
169+
}
170+
85171
} // namespace

0 commit comments

Comments
 (0)