LINUX.ORG.RU

Сообщения gns

 

Posix-style regeх now in kernel

Коллеги! Не бейте больно! :)

Мне для моего основного проекта понадобились в ядре регулярные выражения. Я понял, что писать автомат ala apparmor — дело долгое, а у меня времени не очень много. Я попробовал портировать в ядро хоть какую-то библиотеку для сопоставления строки регексу. И у меня получилось.

После недолгого копания в альтернативах, выбор пал на старую библиотеку TRE, которую использует библиотека musl и какой-то из *BSD (Net- или Open-, кто-то из них) в качестве реализации того, что написано в regex(3) и далее по тексту.

Портануть это дело получилось буквально за несколько часов и оно заработало с первой загрузки. Я фшоке и Респект автору!

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

Лежит здесь — https://github.com/gns48/tre/tree/linux-kernel

Как этим пользоваться:

1. Сливаем репу с гитхаба
2. cd tre; git checkout linux-kernel
3. cd linux_kernel; make
4. В Makefile своего модуля прописываем 
    KBUILD_EXTRA_SYMBOLS = <tre module source>/Module.symvers
5. Добавляем в свои исходники #include <tre.h> из дерева исходников
    <tre module source>
6. Пользуем в своем модуле tre_regcomp/rtre_regexec/tre_regfree, как    
    описано в regex(3). Да, для пользовательского пространства 
    библиотека объявляет имена regcomp, regexec, regfree для 
    совместимости, но я не стал этого делать.

Ограничения: 

1. нет поддержки "широких символов" и прочего юникода.
2. нет поддержки "приблизительного" сравнения (Approximate pattern matching), уж больно много соответствующие функции отжирают стека статическими массивами. Да и незачем оно в ядре. Основное назнчение -- это сравниватиь пути с "точным" образцом.

Что дальше в планах:

1. Сопроводить каждый регекс некоторым «контекстом использования» для того, что бы кучу регексов можно было объединить в один по '|' и скомпилировать их вместе. Далее regexec кроме «да/нет» должен возвратить, допустим, «да, и вот контекст того индивидуального регекса, которому соответствует строка».

2. Поправить распределение памяти при компиляции регекса с тем, что бы, во-первых, был известен объем выделенной памяти функцией regcomp и, во-вторых, выделенный объём памяти был скомпонован в единый непрерывный бандл. Сейчас regex_t внутри — это развесистая структура, из которой во все стороны торчат указатели, и память для них выделяется не единовременно.

 , , tre,

gns
()

И еще раз про syscalls...

Читал исходники ядра. Много думал...

А дело тут вот в чем. Как бы «всем хорошо известно» и по-умолчанию предполагалось, что ядро содержит массив указателей на системные вызовы sys_call_table.

Поколения куул-хацкеров и прочих честных разработчиков разработали 100500 примерно четыре метода разыскивания адреса этой таблицы в памяти и замены соответствующего сисколла на свой. И ладно бы только куул-хацкеры! Честные коммерсанты, которые по разным причинам не хотят открывать код своих ядерных модулей, делают то же самое. И все бы хорошо, но в коде ядра 5.15-107, например, мы видим (см. arch/x86/entry/syscall_64.c)

#define __SYSCALL(nr, sym) extern long __x64_##sym(const struct pt_regs *);
#include <asm/syscalls_64.h>
#undef __SYSCALL

#define __SYSCALL(nr, sym) __x64_##sym,

asmlinkage const sys_call_ptr_t sys_call_table[] = {
#include <asm/syscalls_64.h>
};

И все хорошо, как и ожидалось.

А в 5.15-158, к примеру, картинка уже другая:

/*
 * The sys_call_table[] is no longer used for system calls, but
 * kernel/trace/trace_syscalls.c still wants to know the system
 * call address.
 */
#define __SYSCALL(nr, sym) __x64_##sym,
const sys_call_ptr_t sys_call_table[] = {
#include <asm/syscalls_64.h>
};
#undef __SYSCALL

#define __SYSCALL(nr, sym) case nr: return __x64_##sym(regs);

long x64_sys_call(const struct pt_regs *regs, unsigned int nr)
{
	switch (nr) {
	#include <asm/syscalls_64.h>
	default: return __x64_sys_ni_syscall(regs);
	}
};

Поясняю. Теперь вместо вызова по индексу в массиве имеем «тупо свитч». Кстати, этот переход между способами вызова сисколла не однократный. В 6.1 опять используется традиционная схема. Вот мне интересно, кто-нибудь кроме меня в этом деле ковырялся? Как нам теперь сисколлы-то перехватывать надежным способом?

И да, «писать свой LSM» не предлагать. Не потому, что хотим что-то скрыть, а потому, что не можем или не хотим поддерживать свой форк ядра. Да и у клиентов будет стоять тот линукс, который будет стоять. А LSMы нонче модулями не грузятся.

 kernel hacking, ,

gns
()

Бардак, возникающий в /etc/hosts по умолчанию

Заглянул тут в /etc/hosts и увидел там буквально следующее

127.0.0.1 localhost.localdomain localhost gshost.service.jet.msk.su.

При этом, естественно, что nslookup об наш внутренний DNS говорит, что gshost.service.jet.msk.su имеет честный адрес из нашей внутренней сети.

uname -a = Linux gshost.service.jet.msk.su 2.2.12-20 (RedHat 6.2).

Я могу понять такое поведение инсталлятора, только если при инсталляции я указал что имя хоста у меня есть, а вот сети нет. (Типа чтобы ping `hostname` правильно работал). А вот если у меня из компушки сетеваяя карта торчит, считаю _серьезным_багом_ обзывать мой локальный интерфейс моим же FQDNом. Не порядок это, и, я не побоюсь этого слова :), бардак!

gns
()

RSS подписка на новые темы