Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add basic version of ai_su with cgroups script #9

Open
wants to merge 2 commits into
base: summer18
Choose a base branch
from

Conversation

Bozydarek
Copy link
Contributor

Dodałem wstępną wersje skryptu w bashu który odpala ./run.sh z ograniczeniami z użyciem cgroups.
Kilka komentarzy umieściłem w skrypcie oraz poniżej.

Problemy:

Do zmiany:

  • cpu_set pewnie powinien być wczytywany jako argument i walidowany w skrypcie
  • nie wiem w końcu czy dostajemy rdzeń czy wątek, to trzeba doprecyzować
  • prawdopodobnie zamiast memory.limit_in_bytes powinnobyć memory.memsw.limit_in_byte bo inaczej po zużyciu całego RAMu wchodzi na SWAP (w skrypcie ustawiłem ograniczenie pamięci na 6MiB więc szybko można zauważyć jak wchodzi na SWAP - docelowo powinno być 6G).

@Bozydarek
Copy link
Contributor Author

@janchorowski: O coś takiego chodziło?

@janchorowski
Copy link
Owner

Dzięki! Raczej zakładałem że to będzie robione przez ai_su.go - to będzie setuidowa binarka, która poustawia co trzeba i zrzuci uprawnienia. Jest jakaś obsługa cgroup w go (https://github.com/containerd/cgroups) i pewnie łatwo się w niej przepisze ten algorytm. Odnośnie do działania cpu_exclusive - nie wiem jak to działa, muszę posprawdzać.

@Bozydarek
Copy link
Contributor Author

Próbowałem to dopisać, ale zupełnie nie mogę się połapać co się dzieje w ai_su.go
Poniżej najistotniejszy fragment

	shares := uint64(100)
	memory_limit := int64(6*1024*1024)
	swap := int64(0)
	cpus := "0"
	mems := "0"

	control, err := cgroups.New(cgroups.V1, cgroups.StaticPath("/ailimitgroup"), &specs.LinuxResources{
		CPU: &specs.LinuxCPU{
			Shares: &shares,
			Cpus: cpus,
			Mems: mems,
		},
		Memory: &specs.LinuxMemory{
			Limit: &memory_limit,
			Swap: &swap,
		},
	})
	panicNonNull(err)

	fmt.Println("Pid " + string(pid))
	err1 := control.Add(cgroups.Process{Pid: pid})

@janchorowski
Copy link
Owner

Dzieki za pomoc,

ai_su ma być takim ograniczonym sudu. Pomysł był żebyście mogli uruchamiać wybrane rozwiązania (dostarczone przez pracowników klub kolegów) nie mogąc podglądać ich kodu, bo to by zepsuło zawody. Do tego nie chciałem pisać webserwisu czy jakiejś innej sprawdzarki i dać maksimum możliwości w wyborze technologii.

Więc ai_su.go robi z grubsza tyle:

  • startuje z uprawnieniami roota (ma ustawiony suid bit)
  • sprawdza czy istnieje podany w argumencie folder, czy jest w nim run.sh i czy leży w dobrym miejscu
  • sprawdza czy są dobre uprawnienia na zadanym folderze (żeby inni i grupa nie mogli ich wyświetlać)
  • sprawdza właściciela folderu i odpowiednio zrzuca uprawnienia (maybeSuid), przy czym zasadniczo ma te dwa przypadki:
    1. folder należy do grupy prac - wtedy zakładamy, że ot jest wzorcówka i studenci mogą ją uruchamiać. Proces przyjmuję grupę prac i użytkownika który uruchomił ai_su - czyli nie jest już rootem, tylko studentem w grupie prac.
    2. folder nie jest w grupie prac - wtedy zakładamy, że to jest rozwiązanie studenckie które mogą uruchamiać tylko właściciele folderu i pracownicy mogą je uruchamiać (do przeprowadzenia konkursu), a studenci nie mogą. Najpierw sprawdzamy kto wystartował ai_su i jeśli był studentem, to proces przyjmuje uprawnienia tego kto je wystartował, a jeśli był pracownikiem to osoby do której nalezy folder.
  • Po zrzuceniu uprawnień ai_su ustawia środowisko na okrojone standardowe (tylko PATH), wchodzi do zadanego folderu i startuje bashem run.sh.

Efekt jest taki, że ja jako pracownik mogę uruchamiać wasze programy (więc mogę zrobić konkurs), jeśli jakiś śmieszek postanowi aby program zrobił np. rm -Rf $HOME to wykasuje swoje własne pliki (programy studentów działają zawsze z uprawnieniami ich twórców) i studenci nie mogą czytać innych programów (wzorcowych lub kolegów).

Na cgroupy jest miejsce tuż przed https://github.com/janchorowski/ai_validator/blob/summer18/lista5/ai_su.go#L139: już sprawdziliśmy że będziemy uruchamiać zadanie, ale jeszcze jesteśmy rootem i możemy zmieniać ustawienia systemowe.

Tu trzeba:

  • o ile nie istnieje (z poprzedniego uruchomienia) zrobić cgrupę cpu biorącą jeden rdzeń (2 cpu, rdzeń może być zadany z linii poleceń).
  • wywalić z niej wszystkie inne procesy
  • ustawić limit pamięci
  • wejść do tej cgroupy

można założyć że po zawodach ręcznie innym procesem wykasujemy cgroupy i przywrócimy innym procesom wszystkie rdzenie - więc ai_su nie musi czekać aż program gracza się skończy i może tak jak dotychczas robić exec.

Mam nadzieję że to pomaga. Ja będę nad tym siedział jakoś jutro wieczorem/w czwartek, bo w piątek turnieje..

@Bozydarek
Copy link
Contributor Author

Co bym nie robił to dostaję:
panic: open /sys/fs/cgroup/memory/ailimitgroup/memory.memsw.limit_in_bytes: permission denied

@Bozydarek
Copy link
Contributor Author

Bozydarek commented Jun 6, 2018

@Bozydarek
Copy link
Contributor Author

Znalazłem nawet miejsce gdzie pola z tych struktur są jest tłumaczone na konkretne rzeczy z cgroups, ale to mnie tylko upewnia, że to powinno działać ;/
https://github.com/containerd/cgroups/blob/bf7d89f306222823b2b23f2d6e28cd39d4f8cbdf/memory.go#L279

{
	name:  "limit_in_bytes",
	value: mem.Limit,
},
{
	name:  "memsw.limit_in_bytes",
	value: mem.Swap,
}

@janchorowski
Copy link
Owner

Odnośnie do tych panik, głupie pytanie: zakładam że testuje to Pan u siebie jako root? Czy jako zwykły użytkownik?

@Bozydarek
Copy link
Contributor Author

Jako root. Trzeba być adminem, żeby tworzyć te grupy. Panic jest rzucany tylko przy próbie ograniczania swapu. Bez tego przechodzi, ale imo i tak nie działa jak powinno (wydaje mi się ze nic nie ogranicza :/ )

@janchorowski
Copy link
Owner

Czy może Pan zacommitować do tej gałęzi ile Pan ma - będę nad tym pracował.

@Bozydarek
Copy link
Contributor Author

Z niewiadomych mi powodów dziś mój bot nie pisze już na stdio po wykonaniu
exec_err := syscall.Exec(binary, argv, env), ale wczoraj to działało 😕

Poza tym:

  • dodanie cgroups spowodowało dodanie kolejnej Gorutyny co powoduje panic w maybeSuid
  • nie jestem pewien czy ustawiać CPU.Shares
  • nie znalazłem odpowiednika dla cpuset.cpu_exclusive
  • nie działa ograniczanie swap'u

@janchorowski
Copy link
Owner

Goroutyn nie używamy. Tu jest duży problem z setuid: w skrócie, to tego w GO juz i tak nie można robić, a ja dodałem te asserty żeby było bezpiecznie (więcej: golang/go#1435).

Być może z niedziałaniem cgroup jest podobnie - jak mamy goroutyny, to możemy wkładamy do cgroupy tylko cześc wątków?

@janchorowski
Copy link
Owner

Ostatecznie zrobiłem to trochę inaczej - robię 4 cgroupy dla 4 agantów na komputerze - zasadniczo ai_su nie stara się znaleźć wolnego procesora (mogłoby, ale wtedy jest sporo wyścigów z innymi ai_su które będą uruchamiane). ai_su jedynie przypisuje swój proces do danej cgroupy.

Swap panu panikował z dwóch powodów:

  1. memsw to jest łączny limit na pamięć i swap, moze musi być większy niż limit na tylko pamięć, ale
  2. nie mogłem tego sprawdzic bo ubuntu nie wkompilowuje limitów swap w jądro i zamiast tego wyłączam swap dla cgroup dl aagentów.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants