Re: New helper bpf_get_current_pidns_info


neirac
 


Hi All,

Just tested the code last night, and it did not work. Now I have fixed it and tested in a container, it's finally working except for the the device major and minor info.

Here is the updated code for helper   get_current_pidns_info

BPF_CALL_2(bpf_get_current_pidns_info, void *, buf, u32, size)
{
        struct task_struct *ts = current;
        struct pid_namespace *pidns = NULL;
        pid_t pid = 0;
        pid_t tgid = 0;
        int res = 0;
        const char *ppath = "/proc/self/ns/pid";
        mm_segment_t oldsegfs;
        struct kstat stat;

        if (unlikely(!ts))
            return -EINVAL;

        pidns = task_active_pid_ns(ts);

        if (unlikely(!pidns))
            return -EINVAL;

        ((struct bpf_current_pidns_info*)buf)->ns_id = (u64) pidns->ns.inum;

        pid = task_pid_nr_ns(ts, pidns);

        if (unlikely(!pid))
            return -EINVAL;

       tgid = task_tgid_nr_ns(ts, pidns);

        if (unlikely(!tgid))
                return -EINVAL;

        ((struct bpf_current_pidns_info*)buf)->tgid = (s32)tgid;
        ((struct bpf_current_pidns_info*)buf)->pid = (s32) pid;

        oldsegfs = get_fs();
        set_fs(KERNEL_DS);
        res = vfs_stat((const char __user*)ppath, &stat);
        set_fs(oldsegfs);

        if(unlikely(res))
                return -EINVAL;

        ((struct bpf_current_pidns_info*)buf)->major = (u32) MAJOR(stat.dev);
        ((struct bpf_current_pidns_info*)buf)->minor = (u32) MINOR(stat.dev);

        return 0;
}


const struct bpf_func_proto bpf_get_current_pidns_info_proto = {
        .func             = bpf_get_current_pidns_info,
        .gpl_only       = false,
        .ret_type       = RET_INTEGER,
    .arg1_type    = ARG_PTR_TO_RAW_STACK,
    .arg2_type    = ARG_CONST_STACK_SIZE,
};

And a BCC test program

#!/usr/bin/python

from bcc import BPF
from os import getpid
import sys, os


devinfo= os.lstat('/proc/self/ns/pid');
# Get major and minor device number
# define BPF program
prog = """
struct nsinfo_t {
    u64 ns;
    s32 pid;
    s32 tgid;
    s32 major;
    s32 minor;
};

BPF_HASH(nsdata,struct nsinfo_t);

int collect_ns(void *ctx) {
        struct nsinfo_t ns = {};
        u64 zero=0, *val;
        bpf_get_current_pidns_info(&ns,sizeof (ns));
        val = nsdata.lookup_or_init(&ns,&zero);
        (*val)++;
    return 0;
}
"""

# load BPF program
b = BPF(text=prog)
b.attach_kprobe(event="sys_read", fn_name="collect_ns")
fo = open("./test.py", "r")

minor = os.minor(devinfo.st_dev)
major = os.major(devinfo.st_dev)
pid = getpid();
pidns = os.readlink('/proc/%d/ns/pid' % pid).split('[')[-1][:-1]

print ('STARTING: user space pid %s ns %s major %s minor %s' % (pid, pidns, major , minor))

#exit()
while 1:
    try:
        fo.read(20)
        nsdata  = b.get_table('nsdata');
        for k, v in nsdata.items():
            if k.pid == pid :
                print ( 'OK : reading matched pid %s  ns %s  major %s minor %s' % (k.pid, k.ns, k.major, k.minor  ))
                exit()
            else:
                print ( 'MAP: pid  %s and ns %s' % (k.pid, k.ns))
               
    except ValueError:
        continue


For testing I created a container using lxd, and copy bcc and kernel modules needed to it,  the output of this test inside the container is :

root@test:~# ./test.py
STARTING: user space pid 403 ns 4026532211 major 0 minor 49
MAP: pid  1569 and ns 4026531836
MAP: pid  935 and ns 4026531836
MAP: pid  1596 and ns 4026531836
OK : reading matched pid 403  ns 4026532211  major 0 minor 3

it also works in root namespace

neirac@debian-dev:~$ sudo ./test2.py
STARTING: user space pid 1708 ns 4026531836 major 0 minor 4
MAP: pid  1553 and ns 4026531836
OK : reading matched pid 1708  ns 4026531836  major 0 minor 3

But I still I have the following doubts

- Should I be reading /proc/self/ns/pid using vfst_stat?.
- I'm using the Major/Minor macros but it seems it's not working Am I pointing to the wrong dev_t ?.

I'll put the full patch on the github issue for further analysis.

Bests




On Thu, Jul 26, 2018 at 6:20 PM, cnb <cneirabustos@...> wrote:
Hi,

I have resumed work on issue https://github.com/iovisor/bcc/issues/1329. I just added the needed fields in this helper structure and also I updated the bcc code to use this helper, but I have a couple of questions, regarding my implementation.

- Should I be reading /proc/self/ns/pid using vfst_stat?.
- For Major/Minor I'm not sure if I should be getting the value from stat.dev or stat.rdev.

I'm missing to put bcc in a container and replicate the actual issue, but I wanted to share what I have at this point and check if I'm in the right direction or something else is needed in this same helper.
 

BPF_CALL_2(bpf_get_current_pidns_info, void *, buf, u32, size)
{
        struct task_struct *ts = current;
        struct task_struct *ns_task = NULL;
        struct pid_namespace *pidns = NULL;
        pid_t pid = 0;
        int res = 0;
        const char ppath[] = "/proc/self/ns/pid";
        mm_segment_t oldsegfs;
        struct kstat stat;

        if (unlikely(!ts))
            return -EINVAL;

        pidns = task_active_pid_ns(ts);

        if (unlikely(!pidns))
            return -EINVAL;

        ((struct bpf_current_pidns_info*)buf)->ns_id = (u64) pidns->ns.inum;

        pid = task_pid_nr_ns(ts, pidns);

        if (unlikely(!pid))
            return -EINVAL;

        ns_task = find_task_by_pid_ns(pid, pidns);

        if (unlikely(!ns_task))
                return -EINVAL;

        ((struct bpf_current_pidns_info*)buf)->tgid = (s32)ns_task->tgid;
        ((struct bpf_current_pidns_info*)buf)->pid = (s32) ns_task->pid;

        oldsegfs = get_fs();
        set_fs(KERNEL_DS);
        res = vfs_stat((const char __user*)&ppath[0], &stat);
        set_fs(oldsegfs);

        if(unlikely(res))
                return -EINVAL;

        ((struct bpf_current_pidns_info*)buf)->major = (u32) MAJOR(stat.dev);
        ((struct bpf_current_pidns_info*)buf)->minor = (u32) MINOR(stat.dev);

        return 0;
}


const struct bpf_func_proto bpf_get_current_pidns_info_proto = {
        .func           = bpf_get_current_pidns_info,
        .gpl_only     = false,
        .ret_type     = RET_INTEGER,
    .arg1_type    = ARG_PTR_TO_RAW_STACK,
    .arg2_type    = ARG_CONST_STACK_SIZE,
};

 


Join {iovisor-dev@lists.iovisor.org to automatically receive all group messages.