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

ubpf: Segmentation fault when loading the ELF file #3

Open
osinstom opened this issue Oct 31, 2020 · 0 comments
Open

ubpf: Segmentation fault when loading the ELF file #3

osinstom opened this issue Oct 31, 2020 · 0 comments
Assignees
Labels
bug Something isn't working

Comments

@osinstom
Copy link
Owner

The segmentation fault occurs when loading the ELF file:

It seems that the instruction representing call to ubpf_map_lookup has wrong imm. The segmentation fault appears for the following piece of code, because ext_func with a given (malformed) imm is not found:

ubpf_jit_x86_64.c:

        case EBPF_OP_CALL:
            /* We reserve RCX for shifts */
            emit_mov(state, R9, RCX);
            emit_call(state, vm->ext_funcs[inst.imm].func);
            break;
$ llvm-objdump -d -r --section .text -print-imm-hex test.o
...
LBB0_16:
     114:	b7 01 00 00 32 00 00 00 	r1 = 0x32
     115:	63 1a e8 ff 00 00 00 00 	*(u32 *)(r10 - 0x18) = r1
     116:	bf a2 00 00 00 00 00 00 	r2 = r10
     117:	07 02 00 00 e8 ff ff ff 	r2 += -0x18
     118:	18 01 00 00 00 00 00 00 00 00 00 00 00 00 00 00 	r1 = 0x0 ll
     120:	85 00 00 00 01 00 00 00 	call 0x1
     121:	15 00 04 00 00 00 00 00 	if r0 == 0x0 goto +0x4 <LBB0_18>
     122:	79 01 00 00 00 00 00 00 	r1 = *(u64 *)(r0 + 0x0)
     123:	0f 71 00 00 00 00 00 00 	r1 += r7
     124:	7b 10 00 00 00 00 00 00 	*(u64 *)(r0 + 0x0) = r1
     125:	05 00 09 00 00 00 00 00 	goto +0x9 <LBB0_19>
...

Output from gdb:

(gdb) p i
$18 = 120
(gdb) p vm->insts[120]
$19 = {opcode = 133 '\205', dst = 0 '\000', src = 1 '\001', offset = 0, imm = 1438230128}

File test.c:

#include "test.h"
#include <stdint.h>
#include <stdbool.h>
#include <stddef.h>
#include "ubpf_common.h"

#define BPF_MASK(t, w) ((((t)(1)) << (w)) - (t)1)
#define BYTES(w) ((w) / 8)

void* memcpy(void* dest, const void* src, size_t num);

static void *(*ubpf_map_lookup)(const void *, const void *) = (void *)1;
static int (*ubpf_map_update)(void *, const void *, void *) = (void *)2;
static int (*ubpf_map_delete)(void *, const void *) = (void *)3;
static int (*ubpf_map_add)(void *, const void *) = (void *)4;
static uint64_t (*ubpf_time_get_ns)() = (void *)5;
static uint32_t (*ubpf_hash)(const void *, uint64_t) = (void *)6;
static void (*ubpf_printf)(const char *fmt, ...) = (void *)7;
static void *(*ubpf_packet_data)(const void *) = (void *)9;
static void *(*ubpf_adjust_head)(const void *, uint64_t) = (void *)8;
static uint32_t (*ubpf_truncate_packet)(const void *, uint64_t) = (void *)11;


#define write_partial(a, w, s, v) do { *((uint8_t*)a) = ((*((uint8_t*)a)) & ~(BPF_MASK(uint8_t, w) << s)) | (v << s) ; } while (0)
#define write_byte(base, offset, v) do { *(uint8_t*)((base) + (offset)) = (v); } while (0)

static uint32_t
bpf_htonl(uint32_t val) {
    return htonl(val);
}
static uint16_t
bpf_htons(uint16_t val) {
    return htons(val);
}
static uint64_t
bpf_htonll(uint64_t val) {
    return htonll(val);
}

struct ubpf_map_def counter_a_0 = {
    .type = UBPF_MAP_TYPE_ARRAY,
    .key_size = sizeof(uint32_t),
    .value_size = sizeof(uint64_t),
    .max_entries = 1024,
    .nb_hash_functions = 0,
};
struct ubpf_map_def counter_b_0 = {
    .type = UBPF_MAP_TYPE_ARRAY,
    .key_size = sizeof(uint32_t),
    .value_size = sizeof(uint64_t),
    .max_entries = 1024,
    .nb_hash_functions = 0,
};
struct ubpf_map_def counter_c_0 = {
    .type = UBPF_MAP_TYPE_ARRAY,
    .key_size = sizeof(uint32_t),
    .value_size = sizeof(struct counter_data),
    .max_entries = 1024,
    .nb_hash_functions = 0,
};
inline uint16_t csum16_add(uint16_t csum, uint16_t addend) {
    uint16_t res = csum;
    res += addend;
    return (res + (res < addend));
}
inline uint16_t csum16_sub(uint16_t csum, uint16_t addend) {
    return csum16_add(csum, ~addend);
}
inline uint16_t csum_replace2(uint16_t csum, uint16_t old, uint16_t new) {
    return (~csum16_add(csum16_sub(~csum, old), new));
}

inline uint16_t csum_fold(uint32_t csum) {
    uint32_t r = csum << 16 | csum >> 16;
    csum = ~csum;
    csum -= r;
    return (uint16_t)(csum >> 16);
}
inline uint32_t csum_unfold(uint16_t csum) {
    return (uint32_t)csum;
}
inline uint32_t csum32_add(uint32_t csum, uint32_t addend) {
    uint32_t res = csum;
    res += addend;
    return (res + (res < addend));
}
inline uint32_t csum32_sub(uint32_t csum, uint32_t addend) {
    return csum32_add(csum, ~addend);
}
inline uint16_t csum_replace4(uint16_t csum, uint32_t from, uint32_t to) {
    uint32_t tmp = csum32_sub(~csum_unfold(csum), from);
    return csum_fold(csum32_add(tmp, to));
}
uint64_t entry(void *ctx, struct standard_metadata *std_meta){
    void *pkt = ubpf_packet_data(ctx);
    uint32_t pkt_len = std_meta->packet_length;
    struct Headers_t headers = {
        .ethernet = {
            .ebpf_valid = 0
        },
    };
    struct metadata meta = {
    };
    int packetOffsetInBits = 0;
    uint8_t pass = 1;
    uint8_t hit = 0;
    unsigned char ebpf_byte;
    uint32_t ebpf_zero = 0;
    int packetTruncatedSize = -1;

    goto start;
    start: {
        /* extract(headers.ethernet)*/
        if (pkt_len < BYTES(packetOffsetInBits + 112)) {
            goto reject;
        }
        
        headers.ethernet.dstAddr = (uint64_t)((load_dword(pkt, BYTES(packetOffsetInBits)) >> 16) & BPF_MASK(uint64_t, 48));
        packetOffsetInBits += 48;

        headers.ethernet.srcAddr = (uint64_t)((load_dword(pkt, BYTES(packetOffsetInBits)) >> 16) & BPF_MASK(uint64_t, 48));
        packetOffsetInBits += 48;

        headers.ethernet.etherType = (uint16_t)((load_half(pkt, BYTES(packetOffsetInBits))));
        packetOffsetInBits += 16;

        headers.ethernet.ebpf_valid = 1;
        goto accept;
    }

    reject: { return 1; }

    accept:
    {
        {

            uint64_t *curr_val;
            uint32_t counter_key = 0;
            curr_val = ubpf_map_lookup(&counter_a_0, &counter_key);
            if (curr_val != NULL) {
                *curr_val += 1;
            } else {
                uint64_t init_val = 0;
                ubpf_map_update(&counter_a_0, &counter_key, &init_val);
            }
;

            uint64_t *curr_val_0;
            uint32_t counter_key_0 = 10;
            curr_val_0 = ubpf_map_lookup(&counter_a_0, &counter_key_0);
            if (curr_val_0 != NULL) {
                *curr_val_0 += 1;
            } else {
                uint64_t init_val = 0;
                ubpf_map_update(&counter_a_0, &counter_key_0, &init_val);
            }
;

            uint64_t *curr_val_1;
            uint32_t counter_key_1 = 50;
            curr_val_1 = ubpf_map_lookup(&counter_a_0, &counter_key_1);
            if (curr_val_1 != NULL) {
                *curr_val_1 += 1;
            } else {
                uint64_t init_val = 0;
                ubpf_map_update(&counter_a_0, &counter_key_1, &init_val);
            }
;

            uint64_t *curr_val_2;
            uint32_t counter_key_2 = 0;
            curr_val_2 = ubpf_map_lookup(&counter_b_0, &counter_key_2);
            if (curr_val_2 != NULL) {
                *curr_val_2 += pkt_len;
            } else {
                uint64_t init_val = 0;
                ubpf_map_update(&counter_b_0, &counter_key_2, &init_val);
            }
;

            uint64_t *curr_val_3;
            uint32_t counter_key_3 = 10;
            curr_val_3 = ubpf_map_lookup(&counter_b_0, &counter_key_3);
            if (curr_val_3 != NULL) {
                *curr_val_3 += pkt_len;
            } else {
                uint64_t init_val = 0;
                ubpf_map_update(&counter_b_0, &counter_key_3, &init_val);
            }
;

            uint64_t *curr_val_4;
            uint32_t counter_key_4 = 50;
            curr_val_4 = ubpf_map_lookup(&counter_b_0, &counter_key_4);
            if (curr_val_4 != NULL) {
                *curr_val_4 += pkt_len;
            } else {
                uint64_t init_val = 0;
                ubpf_map_update(&counter_b_0, &counter_key_4, &init_val);
            }
;

            struct counter_data *curr_val_5;
            uint32_t counter_key_5 = 0;
            curr_val_5 = ubpf_map_lookup(&counter_c_0, &counter_key_5);
            if (curr_val_5 != NULL) {
                curr_val_5->packets += 1;
                curr_val_5->bytes += pkt_len;
            } else {
                struct counter_data init_val = {0};
                ubpf_map_update(&counter_c_0, &counter_key_5, &init_val);
            }
;

            struct counter_data *curr_val_6;
            uint32_t counter_key_6 = 10;
            curr_val_6 = ubpf_map_lookup(&counter_c_0, &counter_key_6);
            if (curr_val_6 != NULL) {
                curr_val_6->packets += 1;
                curr_val_6->bytes += pkt_len;
            } else {
                struct counter_data init_val = {0};
                ubpf_map_update(&counter_c_0, &counter_key_6, &init_val);
            }
;

            struct counter_data *curr_val_7;
            uint32_t counter_key_7 = 50;
            curr_val_7 = ubpf_map_lookup(&counter_c_0, &counter_key_7);
            if (curr_val_7 != NULL) {
                curr_val_7->packets += 1;
                curr_val_7->bytes += pkt_len;
            } else {
                struct counter_data init_val = {0};
                ubpf_map_update(&counter_c_0, &counter_key_7, &init_val);
            }
;

        }    }
    deparser:
    {
        int outHeaderLength = 0;
        {
if (headers.ethernet.ebpf_valid) 
            outHeaderLength += 112;

        }
        int outHeaderOffset = BYTES(outHeaderLength) - BYTES(packetOffsetInBits);
        pkt = ubpf_adjust_head(ctx, outHeaderOffset);
        pkt_len += outHeaderOffset;
        packetOffsetInBits = 0;
        if (packetTruncatedSize > 0) {
            pkt_len -= ubpf_truncate_packet(ctx, packetTruncatedSize);
        }
        
        if (headers.ethernet.ebpf_valid) {
            if (pkt_len < BYTES(packetOffsetInBits + 112)) {
                goto reject;
            }
            
            headers.ethernet.dstAddr = htonll(headers.ethernet.dstAddr << 16);
            ebpf_byte = ((char*)(&headers.ethernet.dstAddr))[0];
            write_byte(pkt, BYTES(packetOffsetInBits) + 0, (ebpf_byte));
            ebpf_byte = ((char*)(&headers.ethernet.dstAddr))[1];
            write_byte(pkt, BYTES(packetOffsetInBits) + 1, (ebpf_byte));
            ebpf_byte = ((char*)(&headers.ethernet.dstAddr))[2];
            write_byte(pkt, BYTES(packetOffsetInBits) + 2, (ebpf_byte));
            ebpf_byte = ((char*)(&headers.ethernet.dstAddr))[3];
            write_byte(pkt, BYTES(packetOffsetInBits) + 3, (ebpf_byte));
            ebpf_byte = ((char*)(&headers.ethernet.dstAddr))[4];
            write_byte(pkt, BYTES(packetOffsetInBits) + 4, (ebpf_byte));
            ebpf_byte = ((char*)(&headers.ethernet.dstAddr))[5];
            write_byte(pkt, BYTES(packetOffsetInBits) + 5, (ebpf_byte));
            packetOffsetInBits += 48;

            headers.ethernet.srcAddr = htonll(headers.ethernet.srcAddr << 16);
            ebpf_byte = ((char*)(&headers.ethernet.srcAddr))[0];
            write_byte(pkt, BYTES(packetOffsetInBits) + 0, (ebpf_byte));
            ebpf_byte = ((char*)(&headers.ethernet.srcAddr))[1];
            write_byte(pkt, BYTES(packetOffsetInBits) + 1, (ebpf_byte));
            ebpf_byte = ((char*)(&headers.ethernet.srcAddr))[2];
            write_byte(pkt, BYTES(packetOffsetInBits) + 2, (ebpf_byte));
            ebpf_byte = ((char*)(&headers.ethernet.srcAddr))[3];
            write_byte(pkt, BYTES(packetOffsetInBits) + 3, (ebpf_byte));
            ebpf_byte = ((char*)(&headers.ethernet.srcAddr))[4];
            write_byte(pkt, BYTES(packetOffsetInBits) + 4, (ebpf_byte));
            ebpf_byte = ((char*)(&headers.ethernet.srcAddr))[5];
            write_byte(pkt, BYTES(packetOffsetInBits) + 5, (ebpf_byte));
            packetOffsetInBits += 48;

            headers.ethernet.etherType = bpf_htons(headers.ethernet.etherType);
            ebpf_byte = ((char*)(&headers.ethernet.etherType))[0];
            write_byte(pkt, BYTES(packetOffsetInBits) + 0, (ebpf_byte));
            ebpf_byte = ((char*)(&headers.ethernet.etherType))[1];
            write_byte(pkt, BYTES(packetOffsetInBits) + 1, (ebpf_byte));
            packetOffsetInBits += 16;

        }
;    }
    if (pass)
        return 1;
    else
        return 0;
}

File test.h:

#ifndef _P4_GEN_HEADER_
#define _P4_GEN_HEADER_
#include <stdint.h>
#include <stdbool.h>
#include <stddef.h>
#include "ubpf_common.h"


enum ubpf_action{
ABORT,
DROP,
PASS,
REDIRECT,
};

struct standard_metadata {
    uint32_t input_port; /* bit<32> */
    uint32_t packet_length; /* bit<32> */
    enum ubpf_action output_action; /* ubpf_action */
    uint32_t output_port; /* bit<32> */
    uint8_t clone; /* bool */
    uint32_t clone_port; /* bit<32> */
};

enum CounterType{
PACKETS,
BYTES,
PACKETS_AND_BYTES,
};

struct ethernet_t {
    uint64_t dstAddr; /* EthernetAddress */
    uint64_t srcAddr; /* EthernetAddress */
    uint16_t etherType; /* bit<16> */
    uint8_t ebpf_valid;
};

struct metadata {
};

struct Headers_t {
    struct ethernet_t ethernet; /* ethernet_t */
};


enum ubpf_map_type {
    UBPF_MAP_TYPE_ARRAY = 1,
    UBPF_MAP_TYPE_HASHMAP = 4,
    UBPF_MAP_TYPE_LPM_TRIE = 5,
};
struct ubpf_map_def {
    enum ubpf_map_type type;
    unsigned int key_size;
    unsigned int value_size;
    unsigned int max_entries;
    unsigned int nb_hash_functions;
};

struct counter_data {
    uint64_t packets;
    uint64_t bytes;
};
#if CONTROL_PLANE
static void init_tables() 
{
    uint32_t ebpf_zero = 0;
}
#endif
#endif
@osinstom osinstom added the bug Something isn't working label Oct 31, 2020
@osinstom osinstom self-assigned this Oct 31, 2020
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working
Projects
None yet
Development

No branches or pull requests

1 participant