Всегда получайте 0 идентификатор сеанса в программе BPF

Я пытаюсь написать программу BPF, которая проверяет идентификатор сеанса любого процесса, вызывающего функцию ядра tty_write. Я пытаюсь сделать это, извлекая поле из текущей структуры task_struct. Мой код выглядит следующим образом:

SEC("kprobe/tty_write")
int kprobe__tty_write(struct pt_regs *ctx)
{
    struct task_struct *task;
    struct task_struct *group_leader;
    struct pid_link pid_link;
    struct pid pid;
    int sessionid;

    // get current sessionid
    task = (struct task_struct *)bpf_get_current_task();
    bpf_probe_read(&group_leader, sizeof(group_leader), &task->group_leader);
    bpf_probe_read(&pid_link, sizeof(pid_link), group_leader->pids + PIDTYPE_SID);
    bpf_probe_read(&pid, sizeof(pid), pid_link.pid);
    sessionid = pid.numbers[0].nr;

    // do stuff with sessionid

    return 0;
}

Обратите внимание, что я компилирую свою программу BPF с помощью clang в файл ELF и загружаю его с пакетом ELF gobpf. К сожалению, значение sessionid всегда равно 0. Почему так? Я не думаю, что неправильно обращаюсь к идентификатору сеанса, поскольку я сделал это до использования bcc на ядро 4.11 (из-за того, как bcc переписывает программы BPF, я не могу просто использовать тот же код, когда хочу сам скомпилировать программу). Эквивалентный рабочий код скрытой копии для доступа к sessionid выглядит следующим образом. Обратите внимание, что это работает только с ядром 4.11, следующий код не работает с ядром 4.13. Однако приведенный выше код не работает ни на одном ядре.

#!/usr/bin/python

from bcc import BPF
import ctypes as ct
import os
import threading
import time
import sys

prog=r"""
#include <uapi/linux/ptrace.h>

#include <linux/sched.h>
#include <linux/fs.h>
#include <linux/nsproxy.h>
#include <linux/ns_common.h>

#define BUFSIZE 256
struct tty_write_t {
    int count;
    char buf[BUFSIZE];
    unsigned int sessionid;
};

// define maps
BPF_PERF_OUTPUT(tty_writes);

int kprobe__tty_write(struct pt_regs *ctx, struct file *file,
    const char __user *buf, size_t count)
{
    struct task_struct *task;
    struct pid_link pid_link;
    struct pid pid;
    int sessionid;

    // get current sessionid
    task = (struct task_struct *)bpf_get_current_task();
    bpf_probe_read(&pid_link, sizeof(pid_link), (void *)&task->group_leader->pids[PIDTYPE_SID]);
    bpf_probe_read(&pid, sizeof(pid), (void *)pid_link.pid);
    sessionid = pid.numbers[0].nr;

    // bpf_probe_read() can only use a fixed size, so truncate to count
    // in user space:
    struct tty_write_t tty_write = {};
    bpf_probe_read(&tty_write.buf, BUFSIZE, (void *)buf);
    if (count > BUFSIZE) {
        tty_write.count = BUFSIZE;
    } else {
        tty_write.count = count;
    }

    // add sessionid to tty_write structure and submit
    tty_write.sessionid = sessionid;
    tty_writes.perf_submit(ctx, &tty_write, sizeof(tty_write));

    return 0;
}

"""

b = BPF(text=prog)

BUFSIZE = 256
class TTYWrite(ct.Structure):
    _fields_ = [
        ("count", ct.c_int),
        ("buf", ct.c_char * BUFSIZE),
        ("sessionid", ct.c_int)
    ]

# process tty_write
def print_tty_write(cpu, data, size):
    tty_write = ct.cast(data, ct.POINTER(TTYWrite)).contents
    print(str(tty_write.sessionid))

b["tty_writes"].open_perf_buffer(print_tty_write)
while 1:
    b.kprobe_poll()

ядро 4.11:

uname -a:Linux ubuntu16 4.11.0-14-generic #20~16.04.1-Ubuntu SMP Ср, 9 августа, 09:06:22 UTC 2017 x86_64 x86_64 x86_64 GNU/Linux

ядро 4.13:

uname -a: Linux ubuntu1710 4.13.0-32-generic #35-Ubuntu SMP Чт, 25 января, 09:13:46 UTC 2018 x86_64 x86_64 x86_64 GNU/Linux


person dippynark    schedule 13.02.2018    source источник
comment
Версия bcc всегда печатает для меня sessionid=0, как и ваша версия C...   -  person pchaigno    schedule 14.02.2018
comment
@pchaigno хм, у меня определенно все работало раньше - сегодня вечером я выложу весь код, чтобы проверить   -  person dippynark    schedule 14.02.2018
comment
@pchaigno Я добавил свой полный код BCC BPF, который печатает ненулевые идентификаторы сеанса.   -  person dippynark    schedule 14.02.2018
comment
@pchaigno Аааа нет, он печатает только ненулевые идентификаторы сеанса на ядре 4.11 - я обновлю вопрос   -  person dippynark    schedule 14.02.2018
comment
Первый пример кода работает для меня в Linux 4.11, если я загружаю его с помощью bcc (я отключил переписчик bcc, чтобы убедиться, что загружается тот же код C). Не уверен, что еще может вызвать разницу в стоимости...   -  person pchaigno    schedule 15.02.2018
comment
@pchaigno, это действительно странно, я попытался установить sessionid на 1 вручную, чтобы убедиться, что я вывожу его правильно, и все это работает, так что, похоже, проблема в самой программе BPF - сбивает с толку   -  person dippynark    schedule 15.02.2018


Ответы (1)


Это произошло из-за того, что я не понимал, как скомпилировать программу BPF для конкретной версии ядра — я компилировал с использованием контейнера Docker с установленными заголовками ядра для ядра 4.15, но пытался запустить программу на ядре 4.11.

Чтобы исправить это, я скомпилировал свою программу, используя заголовки ядра 4.11.

person dippynark    schedule 23.02.2018