Czy mogę zastąpić funkcję jądra Linuksa modułem?
Wchodzę do pracy z jądrem przez trochę moich letnich badań. Chcemy wprowadzić modyfikacje TCP w konkretnych obliczeniach RTT. Chciałbym zastąpić rozdzielczość jednej z funkcji w tcp_input.c funkcją dostarczaną przez dynamicznie ładowany moduł jądra. Myślę, że poprawiłoby to tempo rozwoju i dystrybucji modyfikacji.
Funkcja, która mnie interesuje, została zadeklarowana jako statyczna, jednak ponownie skompilowałem jądro z funkcją niestatyczną i wyeksportowaną przez EXPORT_SYMBOL. Oznacza to, że funkcja jest teraz dostępna dla innych modułów / części jądra. Sprawdziłem to przez „cat / proc / kallsyms”.
Teraz chciałbym móc załadować moduł, który może przepisać adres symbolu z początkowej na dynamicznie ładowaną funkcję. Podobnie, gdy moduł ma zostać rozładowany, przywróci oryginalny adres. Czy to możliwe podejście? Czy wszyscy macie sugestie, w jaki sposób można to lepiej wdrożyć?
Dzięki!
Taki sam jakNadpisywanie funkcjonalności za pomocą modułów w jądrze Linux
Edytować:
To było moje ostateczne podejście.
Biorąc pod uwagę następującą funkcję (którą chciałem zastąpić i nie jest eksportowana):
static void internal_function(void)
{
// do something interesting
return;
}
zmodyfikuj w ten sposób:
static void internal_function_original(void)
{
// do something interesting
return;
}
static void (*internal_function)(void) = &internal_function_original;
EXPORT_SYMBOL(internal_function);
Zmienia to zamiast tego oczekiwany identyfikator funkcji jako wskaźnik funkcji (który można wywołać w podobny sposób) wskazując na pierwotną implementację. EXPORT_SYMBOL () sprawia, że adres jest globalnie dostępny, więc możemy go zmodyfikować z modułu (lub innej lokalizacji jądra).
Teraz możesz napisać moduł jądra o następującej formie:
static void (*original_function_reference)(void);
extern void (*internal_function)(void);
static void new_function_implementation(void)
{
// do something new and interesting
// return
}
int init_module(void)
{
original_function_reference = internal_function;
internal_function = &new_function_implementation;
return 0;
}
void cleanup_module(void)
{
internal_function = original_function_reference;
}
Moduł ten zastępuje oryginalną implementację wersją ładowaną dynamicznie. Po rozładowaniu przywracane jest oryginalne odwołanie (i implementacja). W moim konkretnym przypadku udostępniłem nowy estymator dla RTT w TCP. Korzystając z modułu, jestem w stanie dokonać drobnych poprawek i ponownie uruchomić testowanie, wszystko bez konieczności ponownej kompilacji i ponownego uruchomienia jądra.