avsr
avsr

Reputation: 143

How to modify userspace memory using eBPF?

I'm trying to write a sample code and see how it works practically.

As said here and discussed here.

If everything is correct the output should be:

$ cat foo1
this is foo1 content
$ cat foo2
this is foo2 content
$ sudo bcc_mangle_open.py &
[1] 63453
$ cat foo1
this is foo2 content

I wrote a sample in BCC, which looks like this:

from bcc import BPF

# define BPF program
prog = """
#include <uapi/linux/ptrace.h>
#include <linux/sched.h>
int trace_entry(struct pt_regs *ctx)
{
    char buf[10];
    char foo2[] = "foo2";
    char *fname = (char *) PT_REGS_PARM1(ctx);

    bpf_probe_read_str(buf, sizeof(buf), fname);
    if (buf[0] != 'f' || buf[1] != 'o' || buf[2] != 'o' || buf[3] != '1') {
        return 0;
    }

    bpf_probe_write_user(fname, foo2, sizeof(foo2));

    return 0;
};
"""

# load BPF program
b = BPF(text=prog)

b.attach_kprobe("do_sys_open", fn_name="trace_entry")

The content of foo1 is supposed to change, but it's not happening.

And I have tried to print fname and even buf using bpf_trace_printk(), but I got nothing in my screen.

Any idea why the content is not changing?

update-1

As suggested by @Queole

.It worked..So we have to give (char *) PT_REGS_PARM2(ctx) instead of (char *) PT_REGS_PARM1(ctx). I got the output but a bit weirdly. after some 3-4 cat foo1, the content is changing.

$ cat foo1
this is foo1 content
$ cat foo1
this is foo1 content
$ cat foo1
this is foo2 content
$ cat foo1
this is foo1 content
$ cat foo1
this is foo1 content
$ cat foo1
this is foo1 content
$ cat foo1
this is foo1 content
$ cat foo1
this is foo1 content
$ cat foo1
this is foo1 content
$ cat foo1
this is foo1 content
$ cat foo1
this is foo1 content
$ cat foo1
this is foo1 content
$ cat foo1
this is foo1 content
$ cat foo1
this is foo1 content
$ cat foo1
this is foo1 content
$ cat foo1
this is foo2 content

What is the reason for this behavior?

Upvotes: 2

Views: 2102

Answers (2)

Jay Tan
Jay Tan

Reputation: 1

I've been very interested in ebpf lately. And I ran your experiment on Ubuntu 18.04 (5.4.0) and got the same result. I did not look at the source code of cat. But I wrote a simple cat program, like this:

#include <unistd.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
int main()
{
    char c = '\0';
    int fd;
    char file_name[16];
    memcpy(file_name, "foo1", 4);
    fd = open(file_name, O_RDONLY);
    if(fd < 0)
        return 0;
    while (read(fd, &c, 1) == 1)
    {
        printf("%c", c);
    }
    close(fd);

    return 0;
}

I got what I wanted. If I chang "fd = open("file_name", O_RDONLY);" to "fd = open("foo1", O_RDONLY);", the experiment would fail.

Upvotes: 0

xxx69
xxx69

Reputation: 1

I had the problem too. I found that the address of param is r--p. Maybe the param is in .rodata and .data which means it can't be written. You can try to malloc some mem, copy param to this area and then send this area to the func.

Upvotes: 0

Related Questions