I'm writing a custom application that reads C code, calls LLVM to generate BPF byte code from that C code, then relocates any bpf map symbols and uploads it to the kernel. I can successfully upload and run programs that don't use BPF maps, but as soon as I relocate a program to use a BPF map I get the following error:
invalid mem access 'map_ptr'
Details follow:
The following input is given to LLVM:
// Placeholder values for user-requested maps
void *a;
#include <linux/ptrace.h>
#include <uapi/linux/bpf.h>
#include "bpf_helpers.h"
int kprobe__blk_start_request(struct pt_regs *ctx) {
long rq = PT_REGS_PARM1(ctx);
u64 val = bpf_ktime_get_ns();
bpf_map_update_elem(a, &rq, &val, BPF_ANY);
return 0;
}
which generates the following bytecode
Found function: kprobe__blk_start_request
size: 120 bytes
addr: 0
relocate: a # 32
/tmp/bpf7990/bpf.o: file format ELF64-BPF
Disassembly of section .text:
kprobe__blk_start_request:
0: 79 11 70 00 00 00 00 00 r1 = *(u64 *)(r1 + 112)
1: 7b 1a f8 ff 00 00 00 00 *(u64 *)(r10 - 8) = r1
2: 85 00 00 00 05 00 00 00 call 5
3: 7b 0a f0 ff 00 00 00 00 *(u64 *)(r10 - 16) = r0
4: 18 01 00 00 00 00 00 00 00 00 00 00 00 00 00 00 r1 = 0ll
6: 79 11 00 00 00 00 00 00 r1 = *(u64 *)(r1 + 0)
7: bf a2 00 00 00 00 00 00 r2 = r10
8: 07 02 00 00 f8 ff ff ff r2 += -8
9: bf a3 00 00 00 00 00 00 r3 = r10
10: 07 03 00 00 f0 ff ff ff r3 += -16
11: b7 04 00 00 00 00 00 00 r4 = 0
12: 85 00 00 00 02 00 00 00 call 2
13: b7 00 00 00 00 00 00 00 r0 = 0
14: 95 00 00 00 00 00 00 00 exit
and the "a" symbol gets relocated in instruction #4 as follows:
Relocating instruction 4
from code:0x18 dst_reg:1 src_reg:0 off:0x0 imm:0x0
to code:0x18 dst_reg:1 src_reg:1 off:0x0 imm:0x4
kprobe__blk_start_request:
0: 79 11 70 00 00 00 00 00
1: 7b 1a f8 ff 00 00 00 00
2: 85 00 00 00 05 00 00 00
3: 7b 0a f0 ff 00 00 00 00
4: 18 11 00 00 04 00 00 00
5: 00 00 00 00 00 00 00 00
6: 79 11 00 00 00 00 00 00
7: bf a2 00 00 00 00 00 00
8: 07 02 00 00 f8 ff ff ff
9: bf a3 00 00 00 00 00 00
10: 07 03 00 00 f0 ff ff ff
11: b7 04 00 00 00 00 00 00
12: 85 00 00 00 02 00 00 00
13: b7 00 00 00 00 00 00 00
14: 95 00 00 00 00 00 00 00
The "04" in instruction #4 is the FD to the map for symbol "a".
After calling BPF_PROG_LOAD I get the following in the error log from the kernel.
Failed to load kprobe__blk_start_request BPF code
0: R1=ctx(id=0,off=0,imm=0) R10=fp0
0: (79) r1 = *(u64 *)(r1 +112)
1: R1=inv(id=0) R10=fp0
1: (7b) *(u64 *)(r10 -8) = r1
2: R1=inv(id=0) R10=fp0
2: (85) call bpf_ktime_get_ns#5
3: R0=inv(id=0) R10=fp0
3: (7b) *(u64 *)(r10 -16) = r0
4: R0=inv(id=0) R10=fp0
4: (18) r1 = 0xffff88042be0b000
6: R0=inv(id=0) R1=map_ptr(id=0,off=0,ks=8,vs=8) R10=fp0
6: (79) r1 = *(u64 *)(r1 +0)
R1 invalid mem access 'map_ptr'
Errno: 13 (Permission denied)
I'm having trouble deciphering this error log. What is the kernel trying to tell me?
Error explanation
invalid mem access 'map_ptr' means you're trying to read from an invalid memory location, in particular one pointed to by a map pointer.
Indeed, referring to your bytecode:
4: 18 01 00 00 00 00 00 00 00 00 00 00 00 00 00 00 r1 = 0ll
6: 79 11 00 00 00 00 00 00 r1 = *(u64 *)(r1 + 0)
you first load an immediate value inside r1, then read the memory location pointed to by r1. However, the kernel verifier identifies BPF_LD_IMM instructions as map pointer loading. So, it tags r1 with the map_ptr type. The verifier then rejects instruction #6 because it tries to read the memory location pointed to by the map pointer (you're only supposed to pass it to map helpers, not use it otherwise in BPF programs).
Basically, instruction #6 is both invalid and unneeded. Without it, your program should pass the verifier.
Likely fix
I don't have your relocation code so I can't reproduce, but I'd guess this invalid bytecode as to do with how you declare the map. If you take a look at BPF samples in the Linux kernel, you'll see that maps are usually declared as global structure to which the first map helper argument points:
// Placeholder values for user-requested maps
struct bpf_map_def a = {
.type = BPF_MAP_TYPE_ARRAY,
.key_size = sizeof(u32),
.value_size = sizeof(int),
.max_entries = 1024,
};
#include <linux/ptrace.h>
#include <uapi/linux/bpf.h>
#include "bpf_helpers.h"
int kprobe__blk_start_request(struct pt_regs *ctx) {
long rq = PT_REGS_PARM1(ctx);
u64 val = bpf_ktime_get_ns();
bpf_map_update_elem(&a, &rq, &val, BPF_ANY);
return 0;
}
Related
I am currently reading the book CS:APP. I am working on the labs too which are for self-study. After I got stuck at phase 3. I tried two methods basically to solve this phase. One of them results in a seg fault. The other doesn't even read the address of my cookie.Here is the assembly for get buff. I have 0x28 padding
.
My %rsp from phase 2 is 0x5561f8c0. The first way I tried to solve it was like the following:
48 c7 c7 d0 f8 61 55 c3 /* mov %rsp + 0x10, rdi --->movq $0x5561f8d0, %rdi ret /
00 00 00 00 00 00 00 00 / padding to complete 0x28 */
00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00
98 f8 61 55 00 00 00 00 /* rsp -0x28 padding */
fe 18 40 00 00 00 00 00 /* address of touch 3 /
32 33 32 61 64 64 31 62 / my cookies in hexa */
This gets the valid solution but result in seg fault. See the next picture:
Valid solution for level 3 with target ctarget
Ouch!: You caused a segmentation fault!
Better luck next time
I tried another way where I push the address of touch3 before the padding but it doesn't even read my 48 c7 c7 d0 f0 61 55 /* mov %rsp + 0x10, rdi --->movq $0x5561f8d0, %rdi /
68 fe 18 40 00 / pushq address of touch 3*/
c3 /* ret /
00 00 00
00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00
98 f8 61 55 00 00 00 00 / rsp -0x28 padding */
32 33 32 61 64 64 31 62 * my cookies in hexa */
You called touch3("��aU")
I don't know why the segmentation fault is happening while it validates, any help will be appreciated.
I tried the two ways as I mentioned above.
I'm experimenting with flatbuffers, in C, just getting a feel for it. I'm having a weird issue. Well, a couple more than likely.
I think I'm building the flatbuffers and adding all the correct components in the correct manner. However, when I try to read a vector of tables, _vec_len(T) is returning size 0, even though when I hexdump the buffer I can clearly see the said tables being added to/removed from the buffer.
I've used more methods of getting the vector of tables to be readable than I can count. Most have ended with type mismatch compile errors. None of the ones that have actually compiled have resulted in _vec_len(T) returning anything other than 0.
I've also tried using _vec_at(0), but this causes an assertion to fail stating that the given index is out of range.
At this point, I'm either: a) missing something really simple, b) building the flatbuffer completely wrong, or c) making assumptions about how flatbuffers are built that are just plain incorrect.
I have attached my schema and source code, as well as debugging output from the program.
(I realized after posting that the code blocks dont include line numbers.)
The line that seems to be failing is size_t hops_vec_len = TransitHop_vec_len(hopsTable); in the C code, near the bottom. Either that, or the entire block starting at // test_root routing near the top is wrong.
By my understanding, using _start(B) and _end(B), everything that gets added to said component of the schema should be added to the buffer and placed into the v-tables for access automatically.
So, I'm not sure where to go. Can anyone point to what I'm doing wrong/misunderstanding? Any help is greatly appreciated.
flatbuffers_test.fbs
table Ping {
sent:uint;
}
table Pong {
sent:uint;
}
union Type {
Ping,
Pong,
}
enum ServerTypes:ubyte {
mach = 0,
cnc,
mill,
press,
drill,
controller,
unknown,
}
table TransitHop {
serverID: uint64;
serverType: ServerTypes;
}
table TransitHeader {
from: TransitHop;
to: TransitHop;
hops: [TransitHop];
}
table TransitSequence {
transitID: uint64;
begin: uint8;
current: uint8;
total: uint8;
}
table TestRoot {
type: Type;
sequence: TransitSequence;
routing: TransitHeader;
}
root_type TestRoot;
flatbuffers_test.c
#include <stdio.h>
#include "flatcc/support/hexdump.h"
#include "flatbuffers_test_builder.h"
// This allows us to verify result in optimized builds.
#define test_assert(x) do { if (!(x)) { assert(0); return -1; }} while(0)
int main(void) {
flatcc_builder_t builder, *B;
B = &builder;
void *buff = NULL;
size_t size;
FILE *fh = NULL;
flatcc_builder_init(B);
printf("TestRoot - Routing\n\n");
TestRoot_start_as_root(B);
{
// test_root type
{
Ping_ref_t testType = Ping_create(B, 0); // the 0 here would be the time the ping is sent
TestRoot_type_add(B, Type_as_Ping(testType));
}
// test_root sequence
{
TransitSequence_ref_t sequence = TransitSequence_create(B, 1, 1, 1, 1);
TestRoot_sequence_add(B, sequence);
}
// test_root routing
{
TransitHeader_start(B);
{
TransitHop_ref_t hopFrom = 0;
TransitHop_ref_t hopTo = 0;
TransitHeader_hops_start(B);
{
hopFrom = TransitHop_create(B, 1, ServerTypes_mach);
TransitHop_create(B, 2, ServerTypes_controller);
TransitHop_create(B, 3, ServerTypes_controller);
hopTo = TransitHop_create(B, 4, ServerTypes_cnc);
}
TransitHop_ref_t hops = TransitHeader_hops_end(B);
TransitHeader_from_add(B, hopFrom);
TransitHeader_to_add(B, hopTo);
TransitHeader_hops_add(B, hops);
}
TransitHeader_ref_t routing = TransitHeader_end(B);
TestRoot_routing_add(B, routing);
}
}
TestRoot_end_as_root(B);
buff = flatcc_builder_finalize_aligned_buffer(&builder, &size);
printf("flatbuffer size: %ld\n", size);
TestRoot_table_t test_root = TestRoot_as_root(buff);
test_assert(test_root != 0);
int type_present = TestRoot_type_is_present(test_root);
int sequence_present = TestRoot_sequence_is_present(test_root);
int routing_present = TestRoot_routing_is_present(test_root);
printf(" type present: %d\n", type_present);
if (type_present == 1) {
Type_union_type_t type = TestRoot_type_type(test_root);
printf("\ttype: %s\n", Type_type_name(type));
}
printf("sequence present: %d\n", sequence_present);
if (sequence_present == 1) {
TransitSequence_table_t sequence = TestRoot_sequence(test_root);
printf("\ttransitID: %ld\n", TransitSequence_transitID(sequence));
printf("\t begin: %d\n", TransitSequence_begin(sequence));
printf("\t current: %d\n", TransitSequence_current(sequence));
printf("\t total: %d\n", TransitSequence_total(sequence));
}
printf(" routing present: %d\n", routing_present);
if (routing_present == 1) {
TransitHeader_table_t routing = TestRoot_routing(test_root);
TransitHop_table_t from = TransitHeader_from(routing);
TransitHop_table_t to = TransitHeader_to(routing);
TransitHop_vec_t hopsTable = TransitHeader_hops(routing);
test_assert(hopsTable != 0);
ServerTypes_enum_t serverTypeFrom = TransitHop_serverType(from);
ServerTypes_enum_t serverTypeTo = TransitHop_serverType(to);
printf("\tfrom: %ld\t%s\n", TransitHop_serverID(from), ServerTypes_name(serverTypeFrom));
printf("\t to: %ld\t%s\n", TransitHop_serverID(to), ServerTypes_name(serverTypeTo));
int hops_present = TransitHeader_hops_is_present(routing);
if (hops_present == 1) {
// // this causes [Assertion `flatbuffers_vec_len(vec) > (i) && "index out of range"' failed.] ?????
// TransitHop_table_t hopsTableZero = TransitHop_vec_at(hopsTable, 0);
//
// test_assert(hopsTableZero == 0);
size_t hops_vec_len = TransitHop_vec_len(hopsTable);
printf("\thops: %lu\n", hops_vec_len);
for (size_t i = 0; i < hops_vec_len; i++) {
printf("\t\t%lu\n", i);
}
}
}
fh = fopen("/tmp/fbhd-test1", "w");
if (fh == NULL) {
printf("Cannot open /tmp/fbhd-test1 for writing\n\n");
return -1;
} else {
hexdump(NULL, buff, size, fh);
}
fclose(fh);
flatcc_builder_aligned_free(buff);
return 0;
}
debug1.txt
Program output with the vector of tables being added to the flatbuffer:
TestRoot - Routing
flatbuffer size: 188
type present: 1
type: Ping
sequence present: 1
transitID: 1
begin: 1
current: 1
total: 1
routing present: 1
from: 1 mach
to: 4 cnc
hops: 0
00000000 0c 00 00 00 54 45 53 54 00 00 00 00 5c ff ff ff |....TEST....\...|
00000010 01 00 00 00 70 00 00 00 5c 00 00 00 04 00 00 00 |....p...\.......|
00000020 7a ff ff ff 0c 00 00 00 3c 00 00 00 08 00 00 00 |z.......<.......|
00000030 00 00 00 00 96 ff ff ff 04 00 00 00 00 00 00 00 |................|
00000040 01 00 00 00 a6 ff ff ff 03 00 00 00 00 00 00 00 |................|
00000050 05 00 00 00 b6 ff ff ff 02 00 00 00 00 00 00 00 |................|
00000060 05 00 00 00 cc ff ff ff 01 00 00 00 00 00 00 00 |................|
00000070 00 00 00 00 e8 ff ff ff 01 00 00 00 00 00 00 00 |................|
00000080 01 01 01 00 fc ff ff ff 04 00 04 00 0c 00 0f 00 |................|
00000090 04 00 0c 00 0d 00 0e 00 06 00 0c 00 04 00 08 00 |................|
000000a0 0d 00 04 00 0c 00 0a 00 10 00 08 00 0c 00 04 00 |................|
000000b0 0c 00 14 00 04 00 08 00 0c 00 10 00 |............|
Program output without the vector of tables being added to the flatbuffer:
TestRoot - Routing
flatbuffer size: 74
type present: 1
type: Ping
sequence present: 1
transitID: 1
begin: 1
current: 1
total: 1
routing present: 0
00000000 0c 00 00 00 54 45 53 54 00 00 00 00 cc ff ff ff |....TEST........|
00000010 01 00 00 00 18 00 00 00 04 00 00 00 e8 ff ff ff |................|
00000020 01 00 00 00 00 00 00 00 01 01 01 00 fc ff ff ff |................|
00000030 04 00 04 00 0c 00 0f 00 04 00 0c 00 0d 00 0e 00 |................|
00000040 0a 00 10 00 04 00 08 00 0c 00 |..........|
Program output when trying to use _vec_at(0):
TestRoot - Routing
flatbuffer size: 188
type present: 1
type: Ping
sequence present: 1
transitID: 1
begin: 1
current: 1
total: 1
routing present: 1
from: 1 mach
to: 4 cnc
flatbuffers_test: /home/vadtec/schema/generated/flatbuffers_test_reader.h:192: TransitHop_vec_at: Assertion `flatbuffers_vec_len(vec) > (i) && "index out of range"' failed.
I received a response from the flatcc author.
See https://groups.google.com/g/flatbuffers/c/mjkyhbA6vS8 for the complete response.
This is all my XDP / BPF kernel code:
struct bpf_map_def SEC("maps") xsks_map = {
.type = BPF_MAP_TYPE_XSKMAP,
.key_size = sizeof(int),
.value_size = sizeof(int),
.max_entries = 64, /* Assume netdev has no more than 64 queues */
};
struct bpf_map_def SEC("maps") rx_queue_pckt_counter_map = {
.type = BPF_MAP_TYPE_ARRAY,
.key_size = sizeof(int),
.value_size = sizeof(unsigned long),
.max_entries = 48,
};
SEC("xdp_sock")
int xdp_sock_prog(struct xdp_md *ctx) {
int index = ctx->rx_queue_index;
void *data_end = (void *)(long)ctx->data_end;
void *data = (void *)(long)ctx->data;
void *pos = data;
struct ethhdr *eth = (struct ethhdr*)(pos);
if(eth + sizeof(struct ethhdr) <= data_end) {
if(bpf_ntohs(eth->h_proto) == ETH_P_IP) {
struct iphdr *iph = (struct iphdr*)(pos + sizeof(struct ethhdr));
if(iph + sizeof(struct iphdr) <= data_end) {
if(iph->protocol == IPPROTO_UDP) {
const __u16 iph_sz_in_bytes = iph->ihl * 4;
if(iph + iph_sz_in_bytes <= data_end) {
struct udphdr *udh = (struct udphdr*)(pos + sizeof(struct ethhdr) + iph_sz_in_bytes);
if(udh + sizeof(struct udphdr) <= data_end) {
void *rec = bpf_map_lookup_elem(&rx_queue_pckt_counter_map, &index);
if(rec) {
long *pckt_counter_val = (long*)(rec);
*pckt_counter_val += 1;
} else {
return XDP_PASS;
}
if (bpf_map_lookup_elem(&xsks_map, &index)) {
const int ret_val = bpf_redirect_map(&xsks_map, index, 0);
bpf_printk("RET-VAL: %d\n", ret_val);
return ret_val;
}
}
}
}
}
}
}
return XDP_PASS;
}
char _license[] SEC("license") = "GPL";
I am trying to filter all IP-UDP packets and send them into user-space. I also count the number of packets arriving for each RX-Queue (indicated by ctx->rx_queue_index).
My program compiles fine but for whatever reason I don't receive any packets in my user-space program. I already talked about this in another post of mine: AF_XDP: No packets from multicast although steered on RX-Queue 0
I executed sudo ethtool -N eth20 flow-type udp4 action 0 beforehand to steer all packets onto RX-Queue 0.
I can see all bpf maps currently active via
$ sudo bpftool map list
32: lpm_trie flags 0x1
key 8B value 8B max_entries 1 memlock 4096B
33: lpm_trie flags 0x1
key 20B value 8B max_entries 1 memlock 4096B
34: lpm_trie flags 0x1
key 8B value 8B max_entries 1 memlock 4096B
35: lpm_trie flags 0x1
key 20B value 8B max_entries 1 memlock 4096B
36: lpm_trie flags 0x1
key 8B value 8B max_entries 1 memlock 4096B
37: lpm_trie flags 0x1
key 20B value 8B max_entries 1 memlock 4096B
125: array name rx_queue_pckt_c flags 0x0
key 4B value 8B max_entries 48 memlock 4096B
126: xskmap name xsks_map flags 0x0
key 4B value 4B max_entries 64 memlock 4096B
But I think only 125 and 126 are related to my program.
The queue-steering works because with sudo bpftool map dump id 125 I get:
key: 00 00 00 00 value: 99 1a cc 04 00 00 00 00
key: 01 00 00 00 value: 00 00 00 00 00 00 00 00
key: 02 00 00 00 value: 00 00 00 00 00 00 00 00
key: 03 00 00 00 value: 00 00 00 00 00 00 00 00
key: 04 00 00 00 value: 00 00 00 00 00 00 00 00
key: 05 00 00 00 value: 00 00 00 00 00 00 00 00
key: 06 00 00 00 value: 00 00 00 00 00 00 00 00
key: 07 00 00 00 value: 00 00 00 00 00 00 00 00
key: 08 00 00 00 value: 00 00 00 00 00 00 00 00
key: 09 00 00 00 value: 00 00 00 00 00 00 00 00
key: 0a 00 00 00 value: 00 00 00 00 00 00 00 00
key: 0b 00 00 00 value: 00 00 00 00 00 00 00 00
key: 0c 00 00 00 value: 00 00 00 00 00 00 00 00
key: 0d 00 00 00 value: 00 00 00 00 00 00 00 00
key: 0e 00 00 00 value: 00 00 00 00 00 00 00 00
key: 0f 00 00 00 value: 00 00 00 00 00 00 00 00
key: 10 00 00 00 value: 00 00 00 00 00 00 00 00
key: 11 00 00 00 value: 00 00 00 00 00 00 00 00
key: 12 00 00 00 value: 00 00 00 00 00 00 00 00
key: 13 00 00 00 value: 00 00 00 00 00 00 00 00
key: 14 00 00 00 value: 00 00 00 00 00 00 00 00
key: 15 00 00 00 value: 00 00 00 00 00 00 00 00
key: 16 00 00 00 value: 00 00 00 00 00 00 00 00
key: 17 00 00 00 value: 00 00 00 00 00 00 00 00
key: 18 00 00 00 value: 00 00 00 00 00 00 00 00
key: 19 00 00 00 value: 00 00 00 00 00 00 00 00
key: 1a 00 00 00 value: 00 00 00 00 00 00 00 00
key: 1b 00 00 00 value: 00 00 00 00 00 00 00 00
key: 1c 00 00 00 value: 00 00 00 00 00 00 00 00
key: 1d 00 00 00 value: 00 00 00 00 00 00 00 00
key: 1e 00 00 00 value: 00 00 00 00 00 00 00 00
key: 1f 00 00 00 value: 00 00 00 00 00 00 00 00
key: 20 00 00 00 value: 00 00 00 00 00 00 00 00
key: 21 00 00 00 value: 00 00 00 00 00 00 00 00
key: 22 00 00 00 value: 00 00 00 00 00 00 00 00
key: 23 00 00 00 value: 00 00 00 00 00 00 00 00
key: 24 00 00 00 value: 00 00 00 00 00 00 00 00
key: 25 00 00 00 value: 00 00 00 00 00 00 00 00
key: 26 00 00 00 value: 00 00 00 00 00 00 00 00
key: 27 00 00 00 value: 00 00 00 00 00 00 00 00
key: 28 00 00 00 value: 00 00 00 00 00 00 00 00
key: 29 00 00 00 value: 00 00 00 00 00 00 00 00
key: 2a 00 00 00 value: 00 00 00 00 00 00 00 00
key: 2b 00 00 00 value: 00 00 00 00 00 00 00 00
key: 2c 00 00 00 value: 00 00 00 00 00 00 00 00
key: 2d 00 00 00 value: 00 00 00 00 00 00 00 00
key: 2e 00 00 00 value: 00 00 00 00 00 00 00 00
key: 2f 00 00 00 value: 00 00 00 00 00 00 00 00
Found 48 elements
As you can see, only the counter for RX-Queue 0 is greater than 0.
But, if I take a look at the BPF_MAP_TYPE_XSKMAP (which is used to transfer packets into user-space), I get:
$ sudo bpftool map dump id 126
key:
00 00 00 00
value:
Operation not supported
key:
01 00 00 00
value:
Operation not supported
key:
02 00 00 00
value:
Operation not supported
key:
03 00 00 00
value:
Operation not supported
key:
04 00 00 00
value:
Operation not supported
...
key:
3e 00 00 00
value:
Operation not supported
key:
3f 00 00 00
value:
Operation not supported
Found 0 elements
Is the message Operation not supported an indicator why I don't receive any packets in my user-space program? Or is it just not possible to receive the value during runtime? I also find it strange to see Found 0 elements.
Any ideas what is wrong here?
This is simply because maps of type BPF_MAP_TYPE_XSKMAP do not support lookup from user space (you'd get addresses from kernel space, which does not make sense from user space point of view and might be a security issue).
So because attempting the lookup returns -EOPNOTSUPP, bpftool is unable to show the values. It could error out and print nothing, but instead we made it print the keys it finds, and print the error messages we get for the values.
As for the Found 0 elements, the count is for the elements that bpftool could retrieve without any error, so it's only logical that it remains at zero in this case.
So nothing seems wrong in your case, I do not believe this output is related to your issue with the missing packets.
I have a program (ctarget) that uses the gets() function into a buffer. I need to overflow the buffer and call another program. From the assembly code (I don't have the source code) I can see the size of the stack allocation (0x38):
000000000040194a <getbuf>:
40194a: 48 83 ec 38 sub $0x38,%rsp
40194e: 48 89 e7 mov %rsp,%rdi
401951: e8 8a 02 00 00 callq 401be0 <Gets>
401956: b8 01 00 00 00 mov $0x1,%eax
40195b: 48 83 c4 38 add $0x38,%rsp
40195f: c3 retq
I have another program (hex2raw) that reads in a text file and converts hex characters to raw binary data. So I have the following in exploit1.txt
00 00 00 00 00 00
00 00 00 00 00 00
00 00 00 00 00 00
00 00 00 00 00 00
00 00 00 00 00 00
00 00 00 00 00 00
00 00 00 00 00 00
00 00 00 00 00 00
00 00 00 00 00 00
00
/* at this point there is no seg fault */
00 00 00 00 00 00 00 00 /* 8 byte old rbp */
60 19 40 00 00 00 00 00 /* 8 bytes address */
The leading zeros are padding the buffer. I've made a comment at the point in which the program does not seg fault. I've added 8 more bytes to fill in the old %rbp place on the stack. Lastly, I've added the address of the desired function into (what is supposed to be) the return space -- in little endian order.
Using the hex2raw program I can execute the program with the following command: ./hex2raw < exploit1.txt | ./ctarget
When I do run with the above, I get a seg fault.
Here is the assembly for the function I'm trying to call:
0000000000401960 <touch1>:
401960: 48 83 ec 08 sub $0x8,%rsp
401964: c7 05 ae 3b 20 00 01 movl $0x1,0x203bae(%rip) # 60551c <vlevel>
40196b: 00 00 00
40196e: bf 6a 32 40 00 mov $0x40326a,%edi
401973: e8 68 f3 ff ff callq 400ce0 <puts#plt>
401978: bf 01 00 00 00 mov $0x1,%edi
40197d: e8 b4 04 00 00 callq 401e36 <validate>
401982: bf 00 00 00 00 mov $0x0,%edi
401987: e8 e4 f4 ff ff callq 400e70 <exit#plt>
What do I have wrong?
I'm given the functions getbuf() and touch1() if it helps:
4 int getbuf() {
6 char buf[BUFFER_SIZE];
7 Gets(buf);
8 return 1;
9 }
void touch1() {
vlevel = 1; /* Part of validation protocol */
printf("Touch1!: You called touch1()\n");
validate(1);
exit(0);
}
I think this code should produce a buffer overflow error but apparently, this prints fine.. is there anyway to detect it has overflown?
Valgrind didn't picked it up either...
static void e(void) {
char buffer[5];
char data1[] = "abc";
char data2[] = "de";
memcpy(buffer, data1, sizeof(data1));
// strcat appends data2 to buffer and adds '\0' at the end dest
strcat(buffer, data2);
//printf("%s\n", buffer);
}
The -fsanitize=address of gcc is the option you're looking for. E.g.:
$ cat test.cpp
#include <stdio.h>
#include <string.h>
static void e(void) {
char buffer[5];
char data1[] = "abc";
char data2[] = "de";
memcpy(buffer, data1, sizeof(data1));
// strcat appends data2 to buffer and adds '\0' at the end dest
strcat(buffer, data2);
//printf("%s\n", buffer);
}
int main() {
e();
}
$ g++ test.cpp -o a -fsanitize=address -g3
$ ./a
=================================================================
==21537== ERROR: AddressSanitizer: stack-buffer-overflow on address 0x7ffd1d8c0313 at pc 0x7f96ebedd94b bp 0x7ffd1d8c0260 sp 0x7ffd1d8bfa20
WRITE of size 3 at 0x7ffd1d8c0313 thread T0
#0 0x7f96ebedd94a (/usr/lib/x86_64-linux-gnu/libasan.so.0.0.0+0xe94a)
#1 0x40091b (/tmp/a+0x40091b)
#2 0x400959 (/tmp/a+0x400959)
#3 0x7f96ebb2bec4 (/lib/x86_64-linux-gnu/libc-2.19.so+0x21ec4)
#4 0x400748 (/tmp/a+0x400748)
Address 0x7ffd1d8c0313 is located at offset 163 in frame <e> of T0's stack:
This frame has 3 object(s):
[32, 35) 'data2'
[96, 100) 'data1'
[160, 165) 'buffer'
HINT: this may be a false positive if your program uses some custom stack unwind mechanism or swapcontext
(longjmp and C++ exceptions *are* supported)
Shadow bytes around the buggy address:
0x100023b10010: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0x100023b10020: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0x100023b10030: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0x100023b10040: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 f1 f1
0x100023b10050: f1 f1 03 f4 f4 f4 f2 f2 f2 f2 04 f4 f4 f4 f2 f2
=>0x100023b10060: f2 f2[05]f4 f4 f4 00 00 00 00 00 00 00 00 00 00
0x100023b10070: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0x100023b10080: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0x100023b10090: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0x100023b100a0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0x100023b100b0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
Shadow byte legend (one shadow byte represents 8 application bytes):
Addressable: 00
Partially addressable: 01 02 03 04 05 06 07
Heap left redzone: fa
Heap righ redzone: fb
Freed Heap region: fd
Stack left redzone: f1
Stack mid redzone: f2
Stack right redzone: f3
Stack partial redzone: f4
Stack after return: f5
Stack use after scope: f8
Global redzone: f9
Global init order: f6
Poisoned by user: f7
ASan internal: fe
==21537== ABORTING