-1

I am sending this sentence through my BPF code through a BPF Char Array here:

jmommyijsadifjasdijfa, hello, world

And when I print out my output, I only seem to get this output

jmommyij

I seem to be hitting some kind of String size limit. Is there any way to go over this string size limit and print the entire string?

Here is what my BPF code looks like:

#include <uapi/linux/bpf.h>
#define ARRAYSIZE 512

BPF_ARRAY(lookupTable, char**, ARRAYSIZE);

int helloworld2(void *ctx)
{
    int k = 0;
    //print the values in the lookup table
    #pragma clang loop unroll(full)
    for (int i = 0; i < sizeof(lookupTable); i++) {
        //need to use an intermiate variable to hold the value since the pointer will not increment correctly.
        k = i;
        char *key = lookupTable.lookup(&k);
        // if the key is not null, print the value
        if (key != NULL && sizeof(key) > 1) {
            bpf_trace_printk("%s\n", key);
        }
    }
    return 0;
}

Here is my py file:

import ctypes
from bcc import BPF


b = BPF(src_file="hello.c")

lookupTable = b["lookupTable"]
#add hello.csv to the lookupTable array
f = open("hello.csv","r")
file_contents = f.read()
#append file contents to the lookupTable array
b_string1 = file_contents.encode('utf-8')
print(b_string1)
lookupTable[ctypes.c_int(0)] = ctypes.create_string_buffer(b_string1, len(b_string1))
#print(file_contents)
f.close()
# This attaches the compiled BPF program to a kernel event of your choosing,
#in this case to the sys_clone syscall which will cause the BPF program to run
#everytime the sys_clone call occurs.
b.attach_kprobe(event=b.get_syscall_fnname("clone"), fn_name="helloworld2")
# Capture and print the BPF program's trace output
b.trace_print()
  • Have you tried creating your string (e.g. `mystring`) first as its own variable, then passing it into `bpf_trace_printk` like this: `bpf_trace_printk(mystring, sizeof(mystring));`? – wxz Jul 29 '21 at 15:14
  • Not sure that would work, the verifier needs a constant format string I think. Not sure why the output is truncated, but a few observations: `sizeof(key) > 1` seems useless, `key` is a `char *` and the size is always the size of a pointer. It's not `strlen()`. Regarding `bpf_trace_printk("%s\n", key);`, if you use `%s` it should pring all the string at once, so not sure why you would call that in a loop. Aren't you trying to print each character? In that case you'd use `%c`? (Although they would likely end up in separate lines in the trace logs). – Qeole Jul 29 '21 at 15:21
  • I just tried it as of now and I get a weird output: `jmommyij\x94\x1e\xc2y'`. Here is what I added to my code: `char keyArray[sizeof(key)]; __builtin_memcpy(keyArray, key, sizeof(key)); bpf_trace_printk("%s\n", keyArray, sizeof(keyArray));` – maxterthrowaway Jul 29 '21 at 15:32
  • Yes `sizeof(key) > 1` was some old code I forgot to remove, sorry about that. My goal is to print the string all at once and using %c just nets me with no output(just takes forever to load, still waiting at 20 minutes). I am using %s in a loop to capture the keys in the array because I might have multiple lines of strings inputted and I want to process each line one by one. – maxterthrowaway Jul 29 '21 at 16:05
  • OK, makes sense. Hmm. Did you double-check that your map contains the expected value? – Qeole Jul 29 '21 at 17:12
  • Yes, I made sure to check within the userspace and print it just as a fail-safe but I am unsure as to why it's truncating when printing out BPF. – maxterthrowaway Jul 29 '21 at 19:40
  • It gets a bit weirder, I seem to get different responses randomly at this point, This is one of the outputs from my two lines `Name,Cit@' b'\x81\xbb\xae\x0f\xff\xff'` , and here is another one `Name,Cit\xc0:\x88\x11' b' bash-18165 [003] d..2 282539.320234: 0: Joshua,N\xc0:\x88\x11'`. They end around the same area after 8 characters. Wonder what's going on. – maxterthrowaway Jul 29 '21 at 20:55

1 Answers1

2

You're creating an array of 512 char** (basically u64). So you're just storing the first 8 bytes of your string the rest is discarded.

What you need is an array of 1 holding a 512 byte value:

struct data_t {
  char buf[ARRAYSIZE];
};

BPF_ARRAY(lookupTable, struct data_t, ARRAYSIZE);

Also see https://github.com/iovisor/bpftrace/issues/1957

fbs
  • 36
  • 1
  • Just a question for the future. Would it be possible to increase the string size limit even beyond what you wrote? Like I did some testing putting in an arbitrarily long string and it still does cut off some of the string. – maxterthrowaway Aug 03 '21 at 16:34
  • The BPF stack is 512 bytes so that could limiting, not sure if this loads onto the stack though but thats easily checked with e.g. bpftool – fbs Aug 03 '21 at 19:09
  • It won't load on the stack or it wouldn't work. You can write directly from a packet to the map value for example, without going through the stack (at least on Linux 4.12+). – pchaigno Aug 04 '21 at 10:24
  • And yes, it should be possible to increase the size of the string beyond 512 bytes. There's a limit on the maximum size of BPF map values IIRC, but it's much higher. – pchaigno Aug 04 '21 at 10:25
  • Would you be able to elaborate more on what you're speaking of? Could I maybe see an example of how this might be completed? – maxterthrowaway Aug 04 '21 at 15:51