Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix: Don't use memcmp to compare IP_Ports. #2605

Merged
merged 1 commit into from
Jan 29, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion other/bootstrap_daemon/docker/tox-bootstrapd.sha256
Original file line number Diff line number Diff line change
@@ -1 +1 @@
e5ccf844b7ece48d1153c226bdf8462d0e85d517dfcd720c8d6c4abad7da6929 /usr/local/bin/tox-bootstrapd
af83f07bb96eb17a7ee69f174c9960d23758c9c9314144d73e0f57fdef5d55e4 /usr/local/bin/tox-bootstrapd
2 changes: 1 addition & 1 deletion toxcore/TCP_server.c
Original file line number Diff line number Diff line change
Expand Up @@ -1043,7 +1043,7 @@ TCP_Server *new_tcp_server(const Logger *logger, const Memory *mem, const Random
memcpy(temp->secret_key, secret_key, CRYPTO_SECRET_KEY_SIZE);
crypto_derive_public_key(temp->public_key, temp->secret_key);

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

return temp;
}
Expand Down
7 changes: 1 addition & 6 deletions toxcore/group.c
Original file line number Diff line number Diff line change
Expand Up @@ -956,11 +956,6 @@ static bool delpeer(Group_Chats *g_c, uint32_t groupnumber, int peer_index, void
return true;
}

static int cmp_u64(uint64_t a, uint64_t b)
{
return (a > b ? 1 : 0) - (a < b ? 1 : 0);
}

/** Order peers with friends first and with more recently active earlier */
non_null()
static int cmp_frozen(const void *a, const void *b)
Expand All @@ -972,7 +967,7 @@ static int cmp_frozen(const void *a, const void *b)
return pa->is_friend ? -1 : 1;
}

return cmp_u64(pb->last_active, pa->last_active);
return cmp_uint(pb->last_active, pa->last_active);
}

/** @brief Delete frozen peers as necessary to ensure at most `g->maxfrozen` remain.
Expand Down
5 changes: 3 additions & 2 deletions toxcore/list.c
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@ static int find(const BS_List *list, const uint8_t *data)
// closest match is found if we move back to where we have already been

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

if (r == 0) {
return i;
Expand Down Expand Up @@ -135,14 +135,15 @@ static bool resize(BS_List *list, uint32_t new_size)
}


int bs_list_init(BS_List *list, uint32_t element_size, uint32_t initial_capacity)
int bs_list_init(BS_List *list, uint32_t element_size, uint32_t initial_capacity, bs_list_cmp_cb *cmp_callback)
{
// set initial values
list->n = 0;
list->element_size = element_size;
list->capacity = 0;
list->data = nullptr;
list->ids = nullptr;
list->cmp_callback = cmp_callback;

if (initial_capacity != 0) {
if (!resize(list, initial_capacity)) {
Expand Down
6 changes: 5 additions & 1 deletion toxcore/list.h
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
#define C_TOXCORE_TOXCORE_LIST_H

#include <stdbool.h>
#include <stddef.h> // size_t
#include <stdint.h>

#include "attributes.h"
Expand All @@ -20,12 +21,15 @@
extern "C" {
#endif

typedef int bs_list_cmp_cb(const void *a, const void *b, size_t size);

typedef struct BS_List {
uint32_t n; // number of elements
uint32_t capacity; // number of elements memory is allocated for
uint32_t element_size; // size of the elements
uint8_t *data; // array of elements
int *ids; // array of element ids
bs_list_cmp_cb *cmp_callback;
} BS_List;

/** @brief Initialize a list.
Expand All @@ -37,7 +41,7 @@ typedef struct BS_List {
* @retval 0 failure
*/
non_null()
int bs_list_init(BS_List *list, uint32_t element_size, uint32_t initial_capacity);
int bs_list_init(BS_List *list, uint32_t element_size, uint32_t initial_capacity, bs_list_cmp_cb *cmp_callback);

/** Free a list initiated with list_init */
nullable(1)
Expand Down
6 changes: 3 additions & 3 deletions toxcore/list_test.cc
Original file line number Diff line number Diff line change
Expand Up @@ -7,21 +7,21 @@ namespace {
TEST(List, CreateAndDestroyWithNonZeroSize)
{
BS_List list;
bs_list_init(&list, sizeof(int), 10);
bs_list_init(&list, sizeof(int), 10, memcmp);
bs_list_free(&list);
}

TEST(List, CreateAndDestroyWithZeroSize)
{
BS_List list;
bs_list_init(&list, sizeof(int), 0);
bs_list_init(&list, sizeof(int), 0, memcmp);
bs_list_free(&list);
}

TEST(List, DeleteFromEmptyList)
{
BS_List list;
bs_list_init(&list, sizeof(int), 0);
bs_list_init(&list, sizeof(int), 0, memcmp);
const uint8_t data[sizeof(int)] = {0};
bs_list_remove(&list, data, 0);
bs_list_free(&list);
Expand Down
2 changes: 1 addition & 1 deletion toxcore/net_crypto.c
Original file line number Diff line number Diff line change
Expand Up @@ -3163,7 +3163,7 @@ Net_Crypto *new_net_crypto(const Logger *log, const Memory *mem, const Random *r
networking_registerhandler(dht_get_net(dht), NET_PACKET_CRYPTO_HS, &udp_handle_packet, temp);
networking_registerhandler(dht_get_net(dht), NET_PACKET_CRYPTO_DATA, &udp_handle_packet, temp);

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

return temp;
}
Expand Down
64 changes: 63 additions & 1 deletion toxcore/network.c
Original file line number Diff line number Diff line change
Expand Up @@ -1435,6 +1435,61 @@
return ip_equal(&a->ip, &b->ip);
}

non_null()
static int ip4_cmp(const IP4 *a, const IP4 *b)
{
return cmp_uint(a->uint32, b->uint32);
}

non_null()
static int ip6_cmp(const IP6 *a, const IP6 *b)
{
const int res = cmp_uint(a->uint64[0], b->uint64[0]);
if (res != 0) {
return res;

Check warning on line 1449 in toxcore/network.c

View check run for this annotation

Codecov / codecov/patch

toxcore/network.c#L1447-L1449

Added lines #L1447 - L1449 were not covered by tests
}
return cmp_uint(a->uint64[1], b->uint64[1]);

Check warning on line 1451 in toxcore/network.c

View check run for this annotation

Codecov / codecov/patch

toxcore/network.c#L1451

Added line #L1451 was not covered by tests
}

non_null()
static int ip_cmp(const IP *a, const IP *b)
{
const int res = cmp_uint(a->family.value, b->family.value);
if (res != 0) {
return res;
}
switch (a->family.value) {
case TOX_AF_UNSPEC:
return 0;

Check warning on line 1463 in toxcore/network.c

View check run for this annotation

Codecov / codecov/patch

toxcore/network.c#L1462-L1463

Added lines #L1462 - L1463 were not covered by tests
case TOX_AF_INET:
case TCP_INET:
case TOX_TCP_INET:
return ip4_cmp(&a->ip.v4, &b->ip.v4);
case TOX_AF_INET6:
case TCP_INET6:
case TOX_TCP_INET6:
case TCP_SERVER_FAMILY: // these happen to be ipv6 according to TCP_server.c.
case TCP_CLIENT_FAMILY:
return ip6_cmp(&a->ip.v6, &b->ip.v6);

Check warning on line 1473 in toxcore/network.c

View check run for this annotation

Codecov / codecov/patch

toxcore/network.c#L1468-L1473

Added lines #L1468 - L1473 were not covered by tests
}
// Invalid, we don't compare any further and consider them equal.
return 0;

Check warning on line 1476 in toxcore/network.c

View check run for this annotation

Codecov / codecov/patch

toxcore/network.c#L1476

Added line #L1476 was not covered by tests
}

int ipport_cmp_handler(const void *a, const void *b, size_t size)
{
const IP_Port *ipp_a = (const IP_Port *)a;
const IP_Port *ipp_b = (const IP_Port *)b;
assert(size == sizeof(IP_Port));

const int ip_res = ip_cmp(&ipp_a->ip, &ipp_b->ip);
if (ip_res != 0) {
return ip_res;
}

return cmp_uint(ipp_a->port, ipp_b->port);
}

/** nulls out ip */
void ip_reset(IP *ip)
{
Expand Down Expand Up @@ -1508,7 +1563,14 @@
return;
}

*target = *source;
// Write to a temporary object first, so that padding bytes are
// uninitialised and msan can catch mistakes in downstream code.
IP_Port tmp;
tmp.ip.family = source->ip.family;
tmp.ip.ip = source->ip.ip;
tmp.port = source->port;

*target = tmp;
}

const char *net_ip_ntoa(const IP *ip, Ip_Ntoa *ip_str)
Expand Down
16 changes: 14 additions & 2 deletions toxcore/network.h
Original file line number Diff line number Diff line change
Expand Up @@ -337,7 +337,7 @@ non_null()
bool addr_parse_ip(const char *address, IP *to);

/**
* Compares two IPAny structures.
* Compares two IP structures.
*
* Unset means unequal.
*
Expand All @@ -347,7 +347,7 @@ nullable(1, 2)
bool ip_equal(const IP *a, const IP *b);

/**
* Compares two IPAny_Port structures.
* Compares two IP_Port structures.
*
* Unset means unequal.
*
Expand All @@ -356,6 +356,18 @@ bool ip_equal(const IP *a, const IP *b);
nullable(1, 2)
bool ipport_equal(const IP_Port *a, const IP_Port *b);

/**
* @brief IP_Port comparison function with `memcmp` signature.
*
* Casts the void pointers to `IP_Port *` for comparison.
*
* @retval -1 if `a < b`
* @retval 0 if `a == b`
* @retval 1 if `a > b`
*/
non_null()
int ipport_cmp_handler(const void *a, const void *b, size_t size);

/** nulls out ip */
non_null()
void ip_reset(IP *ip);
Expand Down
86 changes: 86 additions & 0 deletions toxcore/network_test.cc
Original file line number Diff line number Diff line change
Expand Up @@ -82,4 +82,90 @@ TEST(IpParseAddr, FormatsIPv6)
EXPECT_EQ(std::string(ip_str), "ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff");
}

TEST(IpportCmp, BehavesLikeMemcmp)
{
auto cmp_val = [](int val) { return val < 0 ? -1 : val > 0 ? 1 : 0; };

IP_Port a = {0};
IP_Port b = {0};

a.ip.family = net_family_ipv4();
b.ip.family = net_family_ipv4();

a.port = 10;
b.port = 20;

EXPECT_EQ( //
ipport_cmp_handler(&a, &b, sizeof(IP_Port)), -1)
<< "a=" << a << "\n"
<< "b=" << b;
EXPECT_EQ( //
ipport_cmp_handler(&a, &b, sizeof(IP_Port)), //
cmp_val(memcmp(&a, &b, sizeof(IP_Port))))
<< "a=" << a << "\n"
<< "b=" << b;

a.ip.ip.v4.uint8[0] = 192;
b.ip.ip.v4.uint8[0] = 10;

EXPECT_EQ( //
ipport_cmp_handler(&a, &b, sizeof(IP_Port)), 1)
<< "a=" << a << "\n"
<< "b=" << b;
EXPECT_EQ( //
ipport_cmp_handler(&a, &b, sizeof(IP_Port)), //
cmp_val(memcmp(&a, &b, sizeof(IP_Port))))
<< "a=" << a << "\n"
<< "b=" << b;
}

TEST(IpportCmp, Ipv6BeginAndEndCompareCorrectly)
{
IP_Port a = {0};
IP_Port b = {0};

a.ip.family = net_family_ipv6();
b.ip.family = net_family_ipv6();

a.ip.ip.v6.uint8[0] = 0xab;
b.ip.ip.v6.uint8[0] = 0xba;

EXPECT_EQ(ipport_cmp_handler(&a, &b, sizeof(IP_Port)), -1);

a.ip.ip.v6.uint8[0] = 0;
b.ip.ip.v6.uint8[0] = 0;

a.ip.ip.v6.uint8[15] = 0xba;

EXPECT_EQ(ipport_cmp_handler(&a, &b, sizeof(IP_Port)), 1);
}

TEST(IpportCmp, UnspecAlwaysComparesEqual)
{
IP_Port a = {0};
IP_Port b = {0};

a.ip.family = net_family_unspec();
b.ip.family = net_family_unspec();

a.ip.ip.v4.uint8[0] = 0xab;
b.ip.ip.v4.uint8[0] = 0xba;

EXPECT_EQ(ipport_cmp_handler(&a, &b, sizeof(IP_Port)), 0);
}

TEST(IpportCmp, InvalidAlwaysComparesEqual)
{
IP_Port a = {0};
IP_Port b = {0};

a.ip.family.value = 0xff;
b.ip.family.value = 0xff;

a.ip.ip.v4.uint8[0] = 0xab;
b.ip.ip.v4.uint8[0] = 0xba;

EXPECT_EQ(ipport_cmp_handler(&a, &b, sizeof(IP_Port)), 0);
}

} // namespace
5 changes: 5 additions & 0 deletions toxcore/util.c
Original file line number Diff line number Diff line change
Expand Up @@ -161,6 +161,11 @@ uint64_t min_u64(uint64_t a, uint64_t b)
return a < b ? a : b;
}

int cmp_uint(uint64_t a, uint64_t b)
{
return (a > b ? 1 : 0) - (a < b ? 1 : 0);
}

uint32_t jenkins_one_at_a_time_hash(const uint8_t *key, size_t len)
{
uint32_t hash = 0;
Expand Down
3 changes: 3 additions & 0 deletions toxcore/util.h
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,9 @@ uint16_t min_u16(uint16_t a, uint16_t b);
uint32_t min_u32(uint32_t a, uint32_t b);
uint64_t min_u64(uint64_t a, uint64_t b);

// Comparison function: return -1 if a<b, 0 if a==b, 1 if a>b.
int cmp_uint(uint64_t a, uint64_t b);

/** @brief Returns a 32-bit hash of key of size len */
non_null()
uint32_t jenkins_one_at_a_time_hash(const uint8_t *key, size_t len);
Expand Down
11 changes: 11 additions & 0 deletions toxcore/util_test.cc
Original file line number Diff line number Diff line change
Expand Up @@ -34,4 +34,15 @@ TEST(Util, IdCopyMakesKeysEqual)
EXPECT_TRUE(pk_equal(pk1, pk2));
}

TEST(Cmp, OrdersNumbersCorrectly)
{
EXPECT_EQ(cmp_uint(1, 2), -1);
EXPECT_EQ(cmp_uint(0, UINT32_MAX), -1);
EXPECT_EQ(cmp_uint(UINT32_MAX, 0), 1);
EXPECT_EQ(cmp_uint(UINT32_MAX, UINT32_MAX), 0);
EXPECT_EQ(cmp_uint(0, UINT64_MAX), -1);
EXPECT_EQ(cmp_uint(UINT64_MAX, 0), 1);
EXPECT_EQ(cmp_uint(UINT64_MAX, UINT64_MAX), 0);
}

} // namespace
Loading