2010-12-11 8 views
5

Chciałbym wdrożyć piaskownicę przez ptrace() proces, który rozpoczynam i wszystkie jego dzieci będą tworzyć (w tym wnuki itp.). Proces macierzysty ptrace(), tj. Kierownik. byłby prostym programem w języku C lub Python i koncepcyjnie ograniczyłby dostęp do systemu plików (w oparciu o nazwę ścieżki i kierunek dostępu (odczyt lub zapis) oraz dostęp do gniazda (np. uniemożliwiający utworzenie gniazda). tak, aby ptrace() d przetwarzać i jego dzieci (rekursywnie) nie będzie w stanie ominąć piaskownicy? Czy jest coś specjalnego, co powinien zrobić przełożony w fork(), aby uniknąć warunków wyścigu? Czy jest możliwe odczytanie argumentów nazw plików np. rename() z procesu dziecka bez warunków wyścigu?W jaki sposób śledzenie systemu Linux może być niebezpieczne lub zawierać warunki wyścigu?

Oto, co już planowałem zrobić:

  • PTRACE_O_TRACEFORK | PTRACE_O_TRACEVFORK | PTRACE_O_TRACECLONE uniknąć (troche) coditions wyścigu kiedy fork() ing
  • Disallow wszystkich wywołań systemowych domyślnie i komponować biała lista dozwolonych wywołań systemowych
  • upewnić się, że *at() warianty wywołanie systemowe (takie jak openat) są prawidłowo chronione

Na co jeszcze powinienem zwrócić uwagę?

+0

Tak więc, w zasadzie, próbujesz replikować oparty na ptrace backend Systrace (http://www.systrace.org/)? – thkala

+0

Tak, mój przełożony działałby podobnie do systrace. Niestety, systrace wydaje się być nieobsługiwany, nie kompiluje się czysto, a także wydaje się być wadliwy (zawiesił się w nieskończoność, gdy piaskowałem GCC z uruchomionym GNU as). – pts

Odpowiedz

11

Głównym problemem jest to, że wiele argumentów syscall, takich jak nazwy plików, jest przekazywanych do jądra jako wskaźniki przestrzeni użytkownika. Każde zadanie, które może działać jednocześnie i ma prawo zapisu do pamięci wskazywanej przez wskaźnik, może skutecznie modyfikować te argumenty po ich sprawdzeniu przez przełożonego i przed działaniem jądra. Do czasu, gdy jądro podąża za wskaźnikiem, wskazana zawartość mogła zostać celowo zmieniona przez inne planowalne zadanie (proces lub wątek) z dostępem do tej pamięci. Na przykład:

Thread 1       Supervisor    Thread 2 
----------------------------------------------------------------------------------------------------- 
strcpy(filename, "/dev/null"); 
open(filename, O_RDONLY); 
            Check filename - OK 
                  strcpy(filename, "/home/user/.ssh/id_rsa"); 
(in kernel) opens "/home/user/.ssh/id_rsa" 

Jednym ze sposobów, aby zatrzymać to, aby nie pozwolić na wywołanie clone() z flagą CLONE_VM, a dodatkowo uniknąć tworzenia zapisywalny MAP_SHARED mapowania pamięci (lub przynajmniej śledzić nich takie, które zaprzeczają syscall który próbuje bezpośrednio odnieść się do danych z takiego mapowania). Można również skopiować dowolny taki argument do nie-współdzielonego bufora-bufora przed zezwoleniem na kontynuowanie procedury. Zapobiegnie to skutecznie uruchomieniu dowolnej aplikacji z gwintem w piaskownicy.

Alternatywą jest SIGSTOP każdy inny proces w śledzonej grupie wokół każdej potencjalnie niebezpiecznej syscall, oczekiwanie na ich faktyczne zatrzymanie, a następnie zezwolenie na syscall do kontynuowania. Po jego powrocie są one następnie SIGCONT (chyba że zostały już zatrzymane). Nie trzeba dodawać, że może to mieć znaczący wpływ na wydajność.

(Istnieją również analogiczne problemy z argumentami syscall przekazywanymi na stosie oraz z udostępnionymi otwartymi tabelami plików).

+0

Zaakceptowany, bardzo wnikliwy, dzięki! – pts

+0

dlaczego rozwiązanie do kopiowania zapobiega aplikacjom z wątkami? Czy aplikacja nie oczekuje, że wywołanie systemowe będzie "trochę" atomowe? – keppla

+1

@keppla: Ponieważ nie można utworzyć nieocenionego regionu pamięci w aplikacji gwintowanej, ponieważ wszystkie wątki mają tę samą maszynę wirtualną. Rozwiązanie typu copy-to-non-shared dotyczy przypadku argumentów syscall w regionach pamięci współdzielonych z innymi procesami. – caf

3

Czy ptrace nie otrzymuje powiadomień tylko po fakcie? Nie wydaje mi się, żebyś miał szansę powstrzymać działanie systemu, ale zabić go tak szybko, jak tylko możesz, gdy zobaczysz coś "złego".

Wygląda na to, że szukasz czegoś bardziej podobnego do SELinux lub AppArmor, gdzie możesz zagwarantować, że nawet jedno nielegalne połączenie nie zostanie odebrane.

+0

W systemie Linux istnieje PTRACE_SYSEMU, który może zatrzymać syscall. Dziękuję również za wzmiankę o alternatywach. Jednak nie rozumiem, dlaczego SELinux lub AppArmor będą bezpieczniejsze - pod warunkiem, że nie ma błędów i warunków wyścigu. Czy to rozsądne założenie? – pts

+1

Powszechnym sposobem wyłączenia syscall jest zmiana go na getpid (2). – maat

Powiązane problemy