Skip to content

Commit

Permalink
Rework netfilter test to use guarded allocations, and to test the cou…
Browse files Browse the repository at this point in the history
…nters array properly
  • Loading branch information
rocallahan committed Dec 26, 2023
1 parent 7183f53 commit e698a23
Showing 1 changed file with 35 additions and 40 deletions.
75 changes: 35 additions & 40 deletions src/test/netfilter.c
Original file line number Diff line number Diff line change
Expand Up @@ -16,17 +16,16 @@ int main(void) {
* iptables -t nat -A POSTROUTING -s 10.0.0.0/24 -j MASQUERADE
*/

int sock_fd;
struct ipt_getinfo info;
memset(&info, 0, sizeof(info));
strcpy(info.name, "nat");
uint32_t getinfo_size = sizeof(info);

sock_fd = socket(AF_INET, SOCK_RAW, IPPROTO_RAW);
int sock_fd = socket(AF_INET, SOCK_RAW, IPPROTO_RAW);
test_assert(sock_fd >= 0);

struct ipt_getinfo* info;
ALLOCATE_GUARD(info, 'a');
strcpy(info->name, "nat");
uint32_t getinfo_size = sizeof(*info);

errno = 0;
int ret = getsockopt(sock_fd, SOL_IP, IPT_SO_GET_INFO, &info, &getinfo_size);
int ret = getsockopt(sock_fd, SOL_IP, IPT_SO_GET_INFO, info, &getinfo_size);
if (ret < 0) {
switch (errno) {
case ENOPROTOOPT:
Expand All @@ -42,15 +41,15 @@ int main(void) {
}
return 0;
}
test_assert(getinfo_size == sizeof(info));
test_assert(getinfo_size == sizeof(*info));
VERIFY_GUARD(info);

atomic_printf("%d existing entries in nat table\n", info.num_entries);
atomic_printf("%d existing entries in nat table\n", info->num_entries);

struct ipt_get_entries* entries =
malloc(sizeof(struct ipt_get_entries) + info.size);
uint32_t getentries_size = sizeof(struct ipt_get_entries) + info->size;
struct ipt_get_entries* entries = allocate_guard(getentries_size, 'b');
strcpy(entries->name, "nat");
entries->size = info.size;
uint32_t getentries_size = sizeof(struct ipt_get_entries) + entries->size;
entries->size = info->size;
ret = getsockopt(sock_fd, SOL_IP, IPT_SO_GET_ENTRIES, entries,
&getentries_size);
if (ret < 0 && errno == EINVAL && sizeof(void*) == 4) {
Expand All @@ -59,51 +58,47 @@ int main(void) {
return 0;
}
test_assert(ret == 0);
test_assert(getentries_size == sizeof(struct ipt_get_entries) + info.size);

VERIFY_GUARD(entries);

size_t final_size = sizeof(struct ipt_replace) + info->size;
struct ipt_replace* final = allocate_guard(final_size, 'c');

strcpy(final->name, "nat");
final->valid_hooks = info->valid_hooks;
final->num_entries = info->num_entries;
final->size = info->size;
memcpy(final->hook_entry, info->hook_entry, sizeof(final->hook_entry));
memcpy(final->underflow, info->underflow, sizeof(final->underflow));
final->num_counters = info->num_entries;
// Allocate space to receive counters
struct xt_counters* counters =
malloc(sizeof(struct xt_counters) * info.num_entries);
// We will check for at least some of these bytes being replaced by the kernel
memset(counters, 0xff, sizeof(struct xt_counters) * info.num_entries);

struct ipt_replace repl;
strcpy(repl.name, "nat");
repl.valid_hooks = info.valid_hooks;
repl.num_entries = info.num_entries;
repl.size = info.size;
memcpy(repl.hook_entry, info.hook_entry, sizeof(repl.hook_entry));
memcpy(repl.underflow, info.underflow, sizeof(repl.underflow));
repl.num_counters = info.num_entries;
repl.counters = counters;

size_t final_size = sizeof(struct ipt_replace) + repl.size;
char* final = malloc(final_size);

// Assemble structure
memcpy(final, &repl, sizeof(struct ipt_replace));
struct xt_counters* counters =
allocate_guard(sizeof(struct xt_counters) * info->num_entries, 0xff);
final->counters = counters;

char* src_ptr = (char*)entries->entrytable;
char* dest_ptr = (char*)((struct ipt_replace*)final)->entries;
for (size_t i = 0; i < info.num_entries; ++i) {
char* dest_ptr = (char*)final->entries;
for (size_t i = 0; i < info->num_entries; ++i) {
struct ipt_entry* cur_entry = (struct ipt_entry*)src_ptr;
memcpy(dest_ptr, src_ptr, cur_entry->next_offset);
dest_ptr += cur_entry->next_offset;
src_ptr += cur_entry->next_offset;
}
test_assert(dest_ptr == final + final_size);
test_assert(dest_ptr == (char*)final + final_size);

// Finally pass this off to the kernel
ret = setsockopt(sock_fd, SOL_IP, IPT_SO_SET_REPLACE, final, final_size);
test_assert(ret == 0);
VERIFY_GUARD(final);
VERIFY_GUARD(final->counters);

// Verify that the counters array was overwritten. Since we don't know the
// exact value here, just make sure some bytes were written. After every byte
// comparison we also call getuid if they were not the same, which should
// catch any replay divergence, just from tick mismatch.
int any_changed = 0;
for (size_t i = 0; i < sizeof(struct xt_counters) * info.num_entries; ++i) {
if (((uint8_t*)entries)[i] != 0xff) {
for (size_t i = 0; i < sizeof(struct xt_counters) * info->num_entries; ++i) {
if (((uint8_t*)counters)[i] != 0xff) {
any_changed = 1;
(void)getuid();
}
Expand Down

0 comments on commit e698a23

Please sign in to comment.