LINUX.ORG.RU

KernelScript 0.1.0

 , kernelscript,


2

2

Представлен KernelScript — экспериментальный язык программирования для разработки eBPF-программ, пользовательских загрузчиков и расширений ядра Linux из единой кодовой базы. Проект развивает Multikernel Technologies, компания, продвигающая архитектуру split-kernel / multikernel для Linux. О KernelScript рассказал основатель компании Cong Wang на Linux Foundation Open Source Summit; код проекта опубликован на GitHub под лицензией Apache 2.0.

eBPF (Extended Berkeley Packet Filter) — это технология, которая позволяет запускать небольшие программы прямо в ядре Linux, не трогая его код и не подвергая риску стабильность системы. eBPF помогает решать множество задач, от мониторинга производительности до обеспечения безопасности и сетевой оптимизации. Например, с помощью eBPF можно отслеживать системные вызовы, сетевой трафик и другие события в режиме реального времени. Это позволяет находить узкие места в производительности и оптимизировать систему (Хабр).

Идея KernelScript — сделать разработку eBPF менее болезненной, чем при использовании связки C + libbpf, и при этом не ограничиваться только трассировкой, как bpftrace. Разработчики описывают язык как типобезопасный DSL, который объединяет eBPF, пользовательское пространство и kernelspace-разработку: из одного исходного файла компилятор должен генерировать код для eBPF-программ, userspace-части и интеграции с kernel modules через kfunc.

Заявленные возможности KernelScript:

  • Компиляция под разные цели из одного файла — функции с атрибутами вроде @xdp, @tc, @helper и @kfunc автоматически относятся к нужной части: XDP/TC-программе, helper-функции, kernel-функции или обычному userspace-коду.

  • Автоматизация tail calls — вместо ручной настройки program array и вызовов bpf_tail_call() разработчику предлагают писать обычный вызов другой функции, а генерацию низкоуровневого eBPF-кода оставлять компилятору.

  • Упрощённая работа с dynptr и eBPF maps — язык скрывает часть ручной работы с bpf_ringbuf_reserve_dynptr, bpf_dynptr_write и похожими API. Карты eBPF можно использовать как глобальные переменные, доступные разным программам.

  • Контроль жизненного цикла программ — eBPF-программы представлены как типизированные значения, что, по задумке авторов, позволяет на этапе компиляции предотвращать ошибки вроде попытки выполнить attach() до успешного load().

  • Поддержка kfunc — KernelScript позволяет объявлять функции с атрибутом @kfunc, которые выполняются в пространстве ядра и могут вызываться из eBPF-программ; для них обещана автоматическая генерация kernel module и BTF-регистраций.

  • Поддержка основных типов eBPF-программ — в README показаны примеры для XDP, TC, probe-программ и perf_event, включая работу с аппаратными счётчиками производительности.

Авторы отдельно подчёркивают, что KernelScript не является заменой ядру Linux или новым eBPF runtime. Это скорее компилятор и язык верхнего уровня, который должен сгенерировать привычные низкоуровневые компоненты: eBPF-код, userspace-загрузчики, Makefile и, при необходимости, kernel module.

Пока проект стоит воспринимать как ранний эксперимент. В репозитории прямо указано, что KernelScript находится в стадии beta, синтаксис и API могут меняться без сохранения обратной совместимости, а использовать его в production пока не рекомендуется.

>>> Источник

★★★★★

Проверено: hobbit ()
Последнее исправление: hobbit (всего исправлений: 6)

Лично я из этой новости узнал о существовании eBPF вообще и libbpf в частности.

Интересно, а можно ли на этой технологии сделать прошивку «ядро и больше ничего» для какой-нибудь слабой железяки? Да, я в курсе, что для таких вещей Linux обычно вообще не берут, берут что-нибудь минималистичное, но в ядре линукса есть много вкусного.

hobbit ★★★★★
()
Последнее исправление: hobbit (всего исправлений: 1)

Добавил тег ocaml.
Ещё из интересного — https://github.com/multikernel/kernelscript#why-not-existing-tools:

Why not Rust?

* Mixed compilation targets: Rust's crate-wide, single-target compilation model cannot emit both eBPF bytecode and userspace binaries from one source file. KernelScript's @xdp, @tc, and regular functions compile to different targets automatically

* No first-class eBPF program values: Rust lacks compile-time reflection to treat functions as values with load/attach lifecycle guarantees. KernelScript's type system prevents calling attach() before load() succeeds

* Cross-domain shared maps: Rust's visibility and orphan rules conflict with KernelScript's implicit map sharing across programs. Safe userspace APIs for BPF maps require complex build-time generation in Rust

* Verifier-incompatible features: Rust's generics and complex type system often produce code rejected by the eBPF verifier. KernelScript uses fixed-width arrays (u8[64]) and simplified types designed for verifier compatibility

* Error handling mismatch: Rust's Result<T,E> model doesn't align with eBPF's C-style integer error codes. KernelScript's throw/catch works seamlessly in both userspace and eBPF contexts

* Missing eBPF-specific codegen: Rust/LLVM cannot automatically generate BPF tail calls or kernel module code for @kfunc attributes - features that require deep compiler integration
dataman ★★★★★
()
Ответ на: комментарий от aiker

Я в том смысле, что некий скриптовый язык компилируется в промежуточный байткод и куда-то там загружается на исполнение. Питон с его *.pyc просто первый на ум пришёл.

Radjah ★★★★★
()
Ответ на: комментарий от Radjah

Там вроде не байткод, а промежуточный платформонезависимый машинный код, который JITится в нативный.

aiker ★★
()
Ответ на: комментарий от aiker

это и есть основа bpf - узкоспециализированная виртуальная машина

pfg ★★★★★
()
Ответ на: комментарий от hobbit

Нет. eBPF — это «а давайте какая-то функция ядра сделает еще что-то». Ну и способ передать накопленные eBPF-программой данные в юзерспейс.

в ядре линукса есть много вкусного.

И там нет «простых вещей». Например, переименовать файл находясь в ядре довольно затруднительно.

gns ★★★★★
()

Мало у нас дыр, так ещё и интерпретатор в ядре сидит. 🤔

wandrien ★★★★
()

eBPF (Extended Berkeley Packet Filter) — это технология, которая позволяет запускать небольшие программы прямо в ядре Linux, не трогая его код и не подвергая риску стабильность системы

Так ведь уже есть одна технология, которая позволяет запускать небольшие программы прямо в ядре - CVE называется. Зачем нам ещё одна под видом фильтра пакетов?

Lucky ★★
()

Iron Bug мне отвечала «какие ещё БПФ-программы?! БПФ — это БСД Пакетфильтер.» … Мне пришлось как-то выкручиваться, и вешать лапшу, что есть такая система е-БПФ, которая в ведре исполняет байткод, и уже написано пара десятков программ для неё, типа что-то между Жявой и микро-кернелом…

Set440 ★★
()

Если б не всратая лицензия - было бы полезно.

zabbal ★★★★☆
()
Ответ на: комментарий от dataman

Чёт подозрительно это всё.

Mixed compilation targets: Rust’s crate-wide, single-target compilation model cannot emit both eBPF bytecode and userspace binaries from one source file.

Во-первых, карго умеет — ещё как умеет. Во-вторых, при чём тут язык? Это же про систему сборки

Rust lacks compile-time reflection to treat functions as values with load/attach lifecycle guarantees. KernelScript’s type system prevents calling attach() before load() succeeds

Лол чего, в расте аффинные типы есть, как раз вот для подобного. А вот в окамле из коробки нет, они там пока костылятся.

Error handling mismatch: Rust’s Result<T,E> model doesn’t align with eBPF’s C-style integer error codes. KernelScript’s throw/catch works seamlessly in both userspace and eBPF contexts

Странная фкусовщина какая-то, особенно для функциональщиков, предпочитать исключения монадической обработке ошибок, тем более в ядре

Missing eBPF-specific codegen: Rust/LLVM cannot automatically generate BPF tail calls or kernel module code for @kfunc attributes - features that require deep compiler integration

Ну, тут, ладно частично правда. Раст не гарантирует оптимизацию tail calls, become пока не стабилизировали.

В общем, по духу похоже на отмазы фанатичных душнил плюсовиков

zurg ★★
()
Ответ на: комментарий от piwww

Вернее не только-лишь всех. Для мало кого.

Set440 ★★
()

Тут пока никто не упоминал про практический опыт с eEBF до этого компилятора, и не сразу понимают что он может)

Дам тот пример с коорым сталкивался. На одной железке оказался глючноватый EFI, и определённое обращение про оценку размера (то которые делает команда df и всякие мониторинги) к efivarfs подвешивало всю систему на 500мс. При этом примонтированный efivarfs был нужен для других задач.

В результате для того чтоб не тюнить все мониторинги было сделана заглушка на eBPF, которая будет игнорировать подвешивающий систему запрос.

То есть ниже минимальный рабочий жизненный цикл программы eBPF, реализованный на инструментах ~2022года, без всякого KernelScript.

Исходник на языке, выглядящем как С, реализующий фильтрацию системных вызовов на уровне LSM (много предопределённых точек фильтрации, но отнюдь не произвольная ифункция ядра):

// Any inclusions avoided and all structs declared manually in compiler terms to avoid build system mantainence
#define ERROR_EACCES 13
#define EFIVARFS_MAGIC 0xde5e81e4

__attribute__((section("license")))
const char gpl_license_declaration_required_for_BPF_programs[] = "GPL";

// BPF in "co-re" compile mode binds offsets by struct name+field name at load time, so declare only needed fields
struct super_block {
  long unsigned int s_magic;
} __attribute__((preserve_access_index));

struct dentry {
  struct super_block *d_sb;
} __attribute__((preserve_access_index));


// structure representing BPF context pointing args passed by LSM to sb_statfs callback
struct StatfsArgs {
  struct dentry* dir_entry;
  long ret;
};

__attribute__((section("lsm/sb_statfs")))
int extra_efivar_filter_statfs(struct StatfsArgs* ctx)
{
  if (ctx->dir_entry->d_sb->s_magic == EFIVARFS_MAGIC) {
    // statfs for efivarfs on some firmwares leads to slow irq processing, mark it unsupported
    // EACCES error code is used to make it more expected to programs, for example `df` tool just silence it
    return -ERROR_EACCES;
  }
  // return result from previous LSM, typically 0 - operation allowed
  return (int)ctx->ret;
}

По нему можно заметить странную для С вещь - в структурах объявлены только те поля, которые используются, а остальные пропущены. Это сделано потому что набор полей завсит от версии ядра, и опции компиляции ниже дают .o файл, который привязывается не к смещениям полей, а к их именам. То есть несмотря на выглядящий как С исходник - результат работы компилятора по своей сути больше похож не на бинарный файл для линкера, а промежутоное представление кода. Собственно вот команда компиляции на сборочном сервере:

bpf-gcc -mco-re -gbtf -c efivar-filter-statfs.bpf.c

Которая порождает efivar-filter-statfs.bpf.o файл, совместимый с любыми версиями ядра где в используемых в исхожнике структурах есть поля с соответсвующими именами.

И уже на целевой машине - просто загружаем его в ядро

/usr/lib/@LINUX_TOOLS_VERSION@/bpftool prog loadall efivar-filter-statfs.bpf.o /sys/fs/bpf autoattach 

Никакого специфичного для задачи userspace-кода на целевой машине не исполняется, только универсальный инструмент загрузки bpftool. В eBPF есть всякие продвинутые механизмы где userspace-код обязателен/необходим, но пример выше как раз для того чтоб показать что иожно и без него, просто добавить чуть-чуть кода в ядро, не привязывась к ABI конкретной версии.

GPFault ★★★
()
Последнее исправление: GPFault (всего исправлений: 2)
Ответ на: комментарий от hobbit

Лично я из этой новости узнал о существовании eBPF вообще и libbpf в частности.

Наверное нас таких много.

Вообще первое, что в голову пришло: если бы я был злоумышлеником, то получив доступ на компе/сервере жертвы, я бы теперь не обычный процесс от рута запускал, стараясь дать ему какое-то беспалевное имя, дабы юзер в ps ax по невнимательности не заметил, а использовал бы эту технологию. Оно мало того что в списке процессов или каком-нибудь lsmod отсутствует, большинство(?) пользователей вообще о ней не знают.

CrX ★★★★★
()

Идея KernelScript — сделать разработку eBPF менее болезненной, чем при использовании связки C + libbpf,

bpftrace еще есть с awk-образным языком, для многих сценариев анализа производительности более чем достаточно

Reset ★★★★★
()
Ответ на: комментарий от Reset

Это ясно дело. Я же и говорю «теперь не обычный процесс от рута запускал». То есть, в данной модели угроз подразумевается, что злоумышленик получил рута.

CrX ★★★★★
()
Ответ на: комментарий от gns

я решил найти интересные применения и вот что получилось

https://github.com/luainkernel/snihook

Snihook is a kernel script that uses the lunatik netfilter library to filter TLS packets

https://luainkernel.github.io/ktls/

Lua-скрипт через Lunatik выполняется после получения и расшифровки данных в recv

https://victornogueirario.github.io/xdplua/

It aims to create hooks as early as possible in the RX path (usally in the NIC driver), making packet processing in the Linux kernel much faste

https://github.com/luainkernel/nflua

биндинги к нетфильтру

https://netdevconf.info/0x17/sessions/talk/scripting-the-linux-routing-table-with-lua.html

адаптивный роутинг и манипуляции с роутинговой таблицей

https://github.com/luainkernel/lunatik/tree/master/examples/spyglass

внезапно кейлоггер

https://github.com/luainkernel/lunatik/blob/master/examples/filter/sni.lua

внезапно XDP/eBPF(!!!) + Lua SNI filter для HTTPS

https://github.com/luainkernel/lunatik/blob/master/examples/dnsdoctor/nf_dnsdoctor.lua

исправляет DNS ответы по заданным критериям

gagarin0
()
Последнее исправление: gagarin0 (всего исправлений: 1)
Ответ на: комментарий от gagarin0

Периодически тема лунатика тут всплывает при появлении нового релиза, так что это все тут обсуждалось. Там не только применительно к сетевой подсистеме это можно использовать. Можно и системные параметры покрутить, типа порегулировать скорость вентиляторов. Но насколько это все реально нужно никто не знает. По-моему, это все из серии «сделали потому, что могут». Да и сколько это все дыр безопасности с собой тащит тоже никто не проверял.

Вон io_uring тоже сделали, только его почему-то все запрещают в продакшене. И мы даже знаем почему :)

gns ★★★★★
()
Ответ на: комментарий от skyman

Ну eBPF и так есть. Но рано или поздно может быть и такое. Если только этот KernelScript до продакшена таки дозреет.

gns ★★★★★
()
Ответ на: комментарий от gagarin0

Ну, наверное затем же зачем существуют другие 100500 языков. Плюс, тут явная узкая специализация. Вернее даже, сделать новый язык специально под готовую виртуальную машину в виде eBPF которая уже в ядре, и встроить ещё одну виртуальную машину другого языка, просто совершенно разные подходы, ни лучше, ни хуже, это просто разное. Как концептуально, так и технически.

Там ещё момент вроде как байткод eBPF программы вроде как проходит ещё верификацию самим ядром перед запуском, запрещены всякие бесконечные циклы, рекурсии и так далее.

В любом случае этот KernelScript не уникальное явление, можно взять любой язык и написать компилятор/транслятор этого языка в eBPF и получить тоже самое. В случае lua и подобных языков, можно написать транслятор байткода языка в eBPF байт код, так будет ещё проще, правда придётся нехило так кастрировать ибо сумасшедшая гибкость динамического языка из плюса превращается в проблему.

А так, пусть будет ещё один язык, одним больше, одним меньше пфь

LINUX-ORG-RU ★★★★★
()
Ответ на: комментарий от hobbit

Лично я из этой новости узнал о существовании eBPF

Ну, про BPF в курсе был? Ну так и это просто его продолжение, extended штука. Крутая, но далеко не простая и не для всех. Не влезай - убьет, короче. Вот здесь занятная статья, чтобы понять, что к чему.

Gonzo ★★★★★
()
Последнее исправление: Gonzo (всего исправлений: 1)
Ответ на: комментарий от hobbit

В самом низу на офсайте можно почитать, кто и как использует eBPF.

Например, тот же Android юзает eBPF для мониторинга использования сети, энергопотребления и профилирования памяти.

Gonzo ★★★★★
()
Последнее исправление: Gonzo (всего исправлений: 1)

Кому интересно и кто хорош в английском, велкам сюда: old.reddit.com/r/eBPF
Там народ много чего интересного делает.

Gonzo ★★★★★
()
Ответ на: комментарий от hobbit

я из этой новости узнал о существовании eBPF вообще и libbpf в частности

Да ладно, несколько раз же sched_ext обсуждали в новостях.

zabbal ★★★★☆
()

Дядь стёп, у вас на лор монополия какая-то установилась, не могли бы вы чуть помедленнее?

daniyal
()
Последнее исправление: daniyal (всего исправлений: 1)

Интересно! Попробую. Ибо внатуре, писать на С с libbpf или это мать его ТАКОЙ ГИМОР! Верификатор постоянно ругается, даже циклы while do и for не пропускает, приходится их разворачивать.

SpaceRanger ★★★★
()
Для того чтобы оставить комментарий войдите или зарегистрируйтесь.