Tere, Habrikad! BPF virtuaalmasin on ĂŒks Linuxi tuuma olulisemaid komponente. Selle Ă”ige rakendamine vĂ”imaldab sĂŒsteemitehnikutel tuvastada rikkeid ja lahendada isegi kĂ”ige keerulisemaid probleeme. Te Ă”pite looma programme, mis jĂ€lgivad ja muudavad tuuma kĂ€itumist, rakendate turvaliselt koodi tuuma sĂŒndmuste jĂ€lgimiseks ja palju muud. David Calavera ja Lorenzo Fontana aitavad teil avastada BPF vĂ”imalusi. Laiendage oma teadmisi jĂ”udluse, vĂ”rkude ja turvalisuse optimeerimise kohta. - Kasutage BPF tuuma Linuxi kĂ€itumise jĂ€lgimiseks ja muutmiseks. - Rakendage koodi sĂŒndmuste turvaliseks jĂ€lgimiseks tuumas - ilma tuuma taascompyleerimise vĂ”i sĂŒsteemi taaskĂ€ivitamiseta. - Kasutage mugavaid C, Go vĂ”i Python koodi nĂ€iteid. - Hallake olukordi, valdav programmist BPF elu tsĂŒklit.
Linuxi tuuma turvalisus, selle vÔimalused ja Seccomp
BPF pakub jĂ”ulise viisi tuuma laiendamiseks, sĂ€ilitades samal ajal stabiilsuse, turvalisuse ja kiirus. Sel pĂ”hjusel mĂ”tlesid tuumaarendajad, et oleks tore kasutada selle paindlikkust protsesside isoleerimise parandamiseks Seccompis, rakendades Seccompi filtreid, mida toetavad BPF programmid, tuntud ka kui Seccomp BPF. Selles peatĂŒkis kĂ€sitleme, mis on Seccomp ja kuidas seda rakendatakse. SeejĂ€rel Ă”pid, kuidas kirjutada Seccompi filtreid BPF programmide abil. PĂ€rast seda vaatame ĂŒle BPF-i sisseehitatud lĂ”ksud, mis on tuumas olemas Linuxi turvemoodulite jaoks.
Linuxi turvemoodulid (LSM) on platvorm, mis pakub funktsioonide kogumit, mida saab rakendada erinevate turvamodelide standardiseeritud elluviimiseks. LSM-i saab kasutada otseselt tuuma allika puus, nÀiteks Apparmor, SELinux ja Tomoyo.
Alustame Linuxi vÔimaluste arutelust.
VÔimalused
Linuxi vĂ”imaluste olemus seisneb selles, et peate andma tavalisest protsessist vĂ€ljaspool privileege teatud ĂŒlesande tĂ€itmiseks Ă”iguse, kuid ilma suid kasutamata vĂ”i muul viisil tegemata protsessi privileeritud, vĂ€hendades rĂŒnnakute vĂ”imalusi ja vĂ”imaldades protsessil teatud ĂŒlesandeid tĂ€ita. NĂ€iteks kui teie rakendusel on vaja avada privileegitud port, ĂŒtleme, 80, siis vĂ”ite lihtsalt anda sellele Ă”iguse CAP_NET_BIND_SERVICE, selle asemel et kĂ€ivitada protsess root kasutajana.
Vaadake Go programmi nimega main.go:
package main
import (
"net/http"
"log"
)
func main() {
log.Fatalf("%v", http.ListenAndServe(":80", nil))
}See programm teenindab HTTP-serverit pordil 80 (see on privileegitud port). Tavaliselt kÀivitame selle kohe pÀrast kompileerimist:
$ go build -o capabilities main.go
$ ./capabilitiesKuid kuna me ei anna root Ôigusi, annab see kood porti sidumisel vea:
2019/04/25 23:17:06 listen tcp :80: bind: permission denied
exit status 1capsh (vÔimaluste haldamise tööriist) on tööriist, mis kÀivitab shelli teatud vÔimaluste kogumiga.
Sel juhul, nagu mainitud, saame tÀielike root-Ôiguste asemel lubada privileegitud portide sidumist, andes cap_net_bind_service Ôiguse koos kÔigi teistega, mis programmis juba on. Selle jaoks saame meie programmi paigutada capsh-i.
# capsh --caps='cap_net_bind_service+eip cap_setpcap,cap_setuid,cap_setgid+ep'
--keep=1 --user="nobody"
--addamb=cap_net_bind_service -- -c "./capabilities"Vaatame seda kÀsku veidi lÀhemalt.
- capsh â kasutame capsh-i kui shellâi.
- âcaps=âcap_net_bind_service+eip cap_setpcap,cap_setuid,cap_setgid+epâ â kuna peame kasutajat vahetama (me ei soovi töötada root-Ă”igustega), mÀÀrame cap_net_bind_service ja vĂ”imaluse tegelikult muuta kasutaja identifikaatorit rootâilt nobodyâks, nimelt cap_setuid ja cap_setgid.
- âkeep=1 â soovime sĂ€ilitada seatud Ă”igused pĂ€rast vahetamist root-kontolt.
- âuser=«nobody» â programmi kĂ€ivitav lĂ”ppkasutaja on nobody.
- âaddamb=cap_net_bind_service â seame seotud Ă”iguste puhastamise pĂ€rast vahetamist root-reĆŸiimist.
- â -c "./capabilities" â lihtsalt kĂ€ivitame programmi.
Seotud Ôigused on eriline Ôiguste liik, mis pÀrandatakse alamrakenduste poolt, kui praegune rakendus neid kÀivitab execve() kaudu. PÀrandada saab ainult Ôigusi, mis on lubatud kui seotud, vÔi teisisÔnu, kui keskkonna Ôigusi.
TĂ”enĂ€oliselt olete huvitatud, mida +eip tĂ€hendab pĂ€rast Ă”iguse mÀÀramist valikus âcaps. Need lipud mÀÀravad, kas Ă”igus:
- peab olema aktiveeritud (p);
- on kohaldatav (e);
- vÔib olla pÀrandatud alamprotsesside poolt (i).
Kuna me soovime kasutada cap_net_bind_service'i, peame seda tegema lipuga e. SeejÀrel kÀivitame kÀsureas shelli. Tulemuseks on, et kÀivitatakse binaarfail capabilities ning peame selle mÀrkima lipuga i. LÔpuks tahame, et Ôigus oleks aktiveeritud (oleme seda teinud UID-d muutmata) lipuga p. See nÀeb vÀlja nagu cap_net_bind_service+eip.
Saate tulemuse kontrollida ss abil. Veidi lĂŒhendame vĂ€ljundit, et see mahtuks lehekĂŒljele, kuid see nĂ€itab seotud porti ja kasutaja identifitseerimist, mis ei ole 0, antud juhul 65 534:
# ss -tulpn -e -H | cut -d' ' -f17-
128 *:80 *:*
users:(("capabilities",pid=30040,fd=3)) uid:65534 ino:11311579 sk:2c v6only:0Selles nÀites kasutasime capsh, kuid saate luua ka shelli libcap abil. Lisainformatsiooni saamiseks vaadake man 3 libcap.
Programmi kirjutamise ajal ei tea arendaja sageli ette kÔiki vÔimalusi, mida programm jooksutamise ajal vajab; veelgi enam, uutes versioonides vÔivad need vÔimalused muutuda.
Kuna meie programmi vÔimalusi paremini mÔista, vÔtame nÀiteks tööriista BCC capable, mis seadistab kprobe tuuma funktsioonile cap_capable:
/usr/share/bcc/tools/capable
TIME UID PID TID COMM CAP NAME AUDIT
10:12:53 0 424 424 systemd-udevd 12 CAP_NET_ADMIN 1
10:12:57 0 1103 1101 timesync 25 CAP_SYS_TIME 1
10:12:57 0 19545 19545 capabilities 10 CAP_NET_BIND_SERVICE 1Sama tulemuse saavutamiseks saame kasutada bpftrace'i ĂŒhe reaga kprobe't tuuma funktsiooni cap_capable puhul:
bpftrace -e
'kprobe:cap_capable {
time("%H:%M:%S ");
printf("%-6d %-6d %-16s %-4d %dn", uid, pid, comm, arg2, arg3);
}'
| grep -i capabilitiesSee vÀljastab midagi jÀrgmist, kui meie programmi vÔimalused aktiveeritakse pÀrast kprobe't:
12:01:56 1000 13524 capabilities 21 0
12:01:56 1000 13524 capabilities 21 0
12:01:56 1000 13524 capabilities 21 0
12:01:56 1000 13524 capabilities 12 0
12:01:56 1000 13524 capabilities 12 0
12:01:56 1000 13524 capabilities 12 0
12:01:56 1000 13524 capabilities 12 0
12:01:56 1000 13524 capabilities 10 1Viies veerg on vĂ”imalused, mida protsess vajab, ja kuna need vĂ€ljundid sisaldavad ka mitteauditeeritud sĂŒndmusi, nĂ€eme kĂ”iki mitteauditeeritud kontrolle ja lĂ”puks vajalikke vĂ”imalusi, mille auditeerimise lipp (viimane vĂ€ljundis) on seatud 1. Meid huvitav vĂ”imalus on CAP_NET_BIND_SERVICE, mis on mÀÀratud pidevaks vaates failis include/uapi/linux/ability.h identifikaatoriga 10:
/* Allows binding to TCP/UDP sockets below 1024 */
/* Allows binding to ATM VCIs below 32 */
#define CAP_NET_BIND_SERVICE 10<source lang="go">VĂ”imalusi kasutatakse sageli konteinerite kĂ€itamisel, nĂ€iteks runC vĂ”i Docker, et need töötaksid ebamugavates tingimustes, kuid lubada ainult neid vĂ”imalusi, mis on vajalikud enamiku rakenduste kĂ€itamiseks. Kui rakendusele on vaja teatud vĂ”imalusi, saab Dockeris neid tagada âcap-add abil:
docker run -it --rm --cap-add=NET_ADMIN ubuntu ip link add dummy0 type dummySee kĂ€sk annab konteinerile vĂ”imaluse CAP_NET_ADMIN, mis vĂ”imaldab tal seadistada vĂ”rguĂŒhenduse dummy0 liidese lisamiseks.
JÀrgmises osas nÀitatakse selliste vÔimaluste kasutamist nagu filtreerimine, kuid teise meetodi abil, mis vÔimaldab meil programmiliselt rakendada oma filtreid.
Seccomp
Seccomp tĂ€hendab Secure Computing, see on turvalisuse tase, mis on rakendatud Linuxi tuumas, vĂ”imaldades arendajatel filtreerida teatud sĂŒsteemi kĂ”nesid. Kuigi Seccomp on vĂ”rreldav Linuxi vĂ”imalustega, muudab selle vĂ”ime hallata teatud sĂŒsteemi kĂ”nesid selle palju paindlikumaks.
Seccomp ja Linuxi vĂ”imalused ei vĂ€lista ĂŒksteist, neid kasutatakse sageli koos, et saada kasu mĂ”lemast lĂ€henemisviisist. NĂ€iteks vĂ”ite soovida anda protsessile Ă”iguse CAP_NET_ADMIN, kuid mitte lubada tal luua ĂŒhendusi soketi kaudu, blokeerides sĂŒsteemi kĂ”ned accept ja accept4.
Seccompi filtreerimisviis pĂ”hineb BPF filtritel, mis töötavad SECCOMP_MODE_FILTER reĆŸiimis, ja sĂŒsteemi kĂ”nede filtreerimine toimub sama moodi nagu pakettide puhul.
Seccomp filtrid laaditakse prctl'i abil PR_SET_SECCOMP operatsiooni kaudu. Need filtrid on BPF programmi kujul, mis tĂ€idetakse iga Seccomp paketi jaoks, mis esitatakse seccomp_data struktuuri kaudu. See struktuur sisaldab arhitektuuri viidet, protsessori kĂ€su nĂ€itajat sĂŒsteemikutsumise ajal ja kuni kuut sĂŒsteemikutsumise argumenti, vĂ€ljendatuna uint64 formaadis.
Nii nÀeb vÀlja seccomp_data struktuur tuuma lÀhtekoodis failis linux/seccomp.h:
struct seccomp_data {
int nr;
__u32 arch;
__u64 instruction_pointer;
__u64 args[6];
};Nagu nĂ€ha sellest struktuurist, saame filtreerida sĂŒsteemikutsumise, selle argumentide vĂ”i nende kombinatsiooni jĂ€rgi.
PĂ€rast iga Seccomp paketi vastuvĂ”tmist peab filter tegema töötlemise, et teha lĂ”plik otsus ja teavitada tuuma, mida edasi teha. LĂ”plik otsus vĂ€ljendatakse ĂŒhes tagastatavatest vÀÀrtustest (olekukoodidest).
â SECCOMP_RET_KILL_PROCESS â kogu protsessi kohene lĂ”petamine pĂ€rast sĂŒsteemikutsumise filtreerimist, mida ei tĂ€ideta.
â SECCOMP_RET_KILL_THREAD â praeguse thread'i kohene lĂ”petamine pĂ€rast sĂŒsteemikutsumise filtreerimist, mida ei tĂ€ideta.
â SECCOMP_RET_KILL â alias SECCOMP_RET_KILL_THREAD, jĂ€etud tagasipöörduvuse huvides.
â SECCOMP_RET_TRAP â sĂŒsteemikutsung on keelatud ja SIGSYS (Bad System Call) signaal saadetakse kutsuvat ĂŒlesannet.
â SECCOMP_RET_ERRNO â sĂŒsteemikutsungit ei tĂ€ideta ja osa tagastatavast vÀÀrtusest filtrist SECCOMP_RET_DATA edastatakse kasutaja ruumi errno vÀÀrtusena. Erinevad errno vÀÀrtused tagastatakse sĂ”ltuvalt vigade pĂ”hjusest. Vigade numbrite loetelu on toodud jĂ€rgmises jaotises.
â SECCOMP_RET_TRACE â kasutatakse ptrace jĂ€lgija teavitamiseks â PTRACE_O_TRACESECCOMP, et katkestada, kui sĂŒsteemikutsung kĂ€ivitatakse ja nĂ€ha ning kontrollida seda protsessi. Kui jĂ€lgijat ei ole ĂŒhendatud, tagastatakse viga, errno seadistatakse vÀÀrtusele -ENOSYS ja sĂŒsteemikutsungit ei tĂ€ideta.
â SECCOMP_RET_LOG â sĂŒsteemikutsung on lubatud ja logitakse.
â SECCOMP_RET_ALLOW â sĂŒsteemikutsung on lihtsalt lubatud.
ptrace â see sĂŒsteemikutsung jĂ€lgimise mehhanismide rakendamiseks protsessis, nimetatakse tracee, vĂ”imaldades jĂ€lgida ja kontrollida protsessi tĂ€itmist. JĂ€lgimisprogramm suudab tĂ”husalt mĂ”jutada ja muuta tracee mĂ€lu registreid. Seccomp kontekstis kasutatakse ptrace, kui kĂ€ivitatakse SECCOMP_RET_TRACE olek, seetĂ”ttu saab jĂ€lgija takistada sĂŒsteemikutsungi tĂ€itmist ja rakendada oma loogikat.
Seccompi vead
Aeg-ajalt, töötades Seccompiga, vĂ”ite kokku puutuda erinevate vigadega, mis tuvastatakse SECCOMP_RET_ERRNO tĂŒĂŒpi tagastatava vÀÀrtuse kaudu. Veast teatamiseks tagastab sĂŒsteemikutsung seccomp -1 asemel 0.
VÔimalikud jÀrgmised vead:
â EACCESS â kutse pooled ei ole lubatud sĂŒsteemikutsungit tegema. See juhtub tavaliselt seetĂ”ttu, et neil ei ole privileege CAP_SYS_ADMIN vĂ”i no_new_privs ei ole prctl abil seatud (sellest rÀÀgime hiljem);
â EFAULT â edastatud argumendid (args struktuuris seccomp_data) ei omada kehtivat aadressi;
â EINVAL â siin vĂ”ib olla neli pĂ”hjust:
- taotletud operatsioon on teadmata vÔi tuuma poolt antud konfiguratsioonis mittekohaldatav;
- mÀÀratud lipud on taotletud operatsiooni jaoks kehtetud;
- operatsioon hĂ”lmab BPF_ABS, kuid mĂ”ningaid probleeme on mÀÀratud offsetiga, mis vĂ”ib ĂŒletada struktuuri seccomp_data suurust;
- filtrisse edastatud kĂ€skude arv ĂŒletab maksimaalse arvu;
â ENOMEM â programmiks vajaliku mĂ€lu puudumine;
â EOPNOTSUPP â operatsioon nĂ€itas, et SECCOMP_GET_ACTION_AVAIL toiming oli saadaval, kuid tuum ei toeta argumentide tagastamist;
â ESRCH â probleemi tekkimine teise niidi sĂŒnkroniseerimisel;
â ENOSYS â ei ole jĂ€lgijat, mis on seotud SECCOMP_RET_TRACE toiminguga.
prctl on sĂŒsteemikĂ”ne, mis vĂ”imaldab kasutaja ruumi programmil hallata (seada ja saada) teatud protsessi spetsiifilisi aspekte, nagu baitide jĂ€rjekord, tee nimed, kaitstud arvutustasandi reĆŸiim (Seccomp), privileegid, Perf ĂŒritused jne.
Seccomp vĂ”ib teile tunduda liivakasti tehnoloogiana, kuid see pole nii. Seccomp on utiliit, mis vĂ”imaldab kasutajatel vĂ€lja töötada liivakasti mehhanismi. Vaatame nĂŒĂŒd, kuidas luua kasutaja interaktsioonide programme, kasutades vahetult Seccomp sĂŒsteemikutsumisele kutsutud filtrit.
BPF Seccomp filtri nÀide
Siin nĂ€itame, kuidas ĂŒhendada kaks varem kĂ€sitletud toimingut, nimelt:
â kirjutame Seccomp BPF programmi, mida rakendatakse filtrina erinevate tagastuskoode kasutades vastavalt vĂ”etavatele otsustele;
â laadime filtrit, kasutades prctl.
Kuna alguses on vajalikud pealkirjad standardraamatukogust ja Linuxi kernelist:
#include <errno.h>
#include <linux/audit.h>
#include <linux/bpf.h>
#include <linux/filter.h>
#include <linux/seccomp.h>
#include <linux/unistd.h>
#include <stddef.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/prctl.h>
#include <unistd.h>Enne selle nÀite tÀitmist peame veenduma, et kerneli on kompileeritud CONFIG_SECCOMP ja CONFIG_SECCOMP_FILTERga, mille vÀÀrtus on y. Töötavas masinas saab seda kontrollida nii:
cat /proc/config.gz | zcat | grep -i CONFIG_SECCOMP
KoodijÀÀnus on install_filter funktsioon, mis koosneb kahest osast. Esimene osa sisaldab meie BPF filtreerimisjuhiste loetelu:
static int install_filter(int nr, int arch, int error) {
struct sock_filter filter[] = {
BPF_STMT(BPF_LD + BPF_W + BPF_ABS, (offsetof(struct seccomp_data, arch))),
BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, arch, 0, 3),
BPF_STMT(BPF_LD + BPF_W + BPF_ABS, (offsetof(struct seccomp_data, nr))),
BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, nr, 0, 1),
BPF_STMT(BPF_RET + BPF_K, SECCOMP_RET_ERRNO | (error & SECCOMP_RET_DATA)),
BPF_STMT(BPF_RET + BPF_K, SECCOMP_RET_ALLOW),
}; KĂ€skluseid seadistatakse BPF_STMT ja BPF_JUMP makrode abil, mis on defineeritud failis linux/filter.h.
Vaatame kÀsklusi.
â BPF_STMT(BPF_LD + BPF_W + BPF_ABS (offsetof(struct seccomp_data, arch))) â sĂŒsteem laadib ja kogub BPF_LD abil sĂ”nana BPF_W, paketi andmed asuvad fikseeritud nihkega BPF_ABS.
â BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, arch, 0, 3) â kontrollib, kasutades BPF_JEQ-d, kas arhitektuuri vÀÀrtus konstantse akumulaatori BPF_K sees on vĂ”rdsed arch-iga. Kui jah, suundub see nihkega 0 jĂ€rgmisele kĂ€sklusele, vastasel juhul hĂŒppab see nihkega 3 (antud juhul), sest arch ei kattu.
â BPF_STMT(BPF_LD + BPF_W + BPF_ABS (offsetof(struct seccomp_data, nr))) â laadib ja kogub BPF_LD abil sĂ”nana BPF_W, mis on sĂŒsteemi kutsumise number, mis asub fikseeritud nihkega BPF_ABS.
â BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, nr, 0, 1) â vĂ”rdleb sĂŒsteemikĂ”ne numbrit muutujaga nr. Kui need on vĂ”rdsed, liigutakse jĂ€rgmisele kĂ€sule ja keelatakse sĂŒsteemikĂ”ne; vastasel juhul lubatakse sĂŒsteemikĂ”ne SECCOMP_RET_ALLOW abil.
â BPF_STMT(BPF_RET + BPF_K, SECCOMP_RET_ERRNO | (error & SECCOMP_RET_DATA)) â lĂ”petab programmi BPF_RET-ga ja annab tulemuseks SECCOMP_RET_ERRNO veateate numbriga muutujast err.
â BPF_STMT(BPF_RET + BPF_K, SECCOMP_RET_ALLOW) â lĂ”petab programmi BPF_RET-ga ja lubab sĂŒsteemikĂ”ne tĂ€itmise SECCOMP_RET_ALLOW abil.
SECCOMP â SEE ON CBPF
VÔib-olla huvitab teid, miks kasutatakse koostatud ELF objekti vÔi JIT-iga koostatud C-programmi asemel kÀskude loendit.Selleks on kaks pÔhjust.
⹠Esiteks, Seccomp rakendab cBPF (klassikaline BPF), mitte eBPF, mis tÀhendab: puuduvad registrid, on ainult akumulatsioon viimase arvutustulemuse hoidmiseks, nagu nÀha on nÀites.
⹠Teiseks, Seccomp vÔtab BPF-kÀskude massiivi otse ja mitte midagi muud. Makrod, mida me kasutasime, aitavad lihtsalt neid kÀskusid esitada programmaritele mugavas vormis.
Kui vajate tÀiendavat abi selle kogumi mÔistmisel, vaadake pseudokoodi, mis teeb sama:
if (arch != AUDIT_ARCH_X86_64) {
return SECCOMP_RET_ALLOW;
}
if (nr == __NR_write) {
return SECCOMP_RET_ERRNO;
}
return SECCOMP_RET_ALLOW;PÀrast filter-koodi mÀÀratlemist socket_filter struktuuris on vajalik mÀÀratleda sock_fprog, mis sisaldab koodi ja arvutatud filter'i pikkust. Seda andmestruktuuri on vajalik kasutada protsessi töödeklaratsiooni argumendina edaspidi:
struct sock_fprog prog = {
.len = (unsigned short)(sizeof(filter) / sizeof(filter[0])),
.filter = filter,
};Viimase asjana tuleb funktsioonis install_filter laadida programm ise! Selleks kasutame prctl-i, valides PR_SET_SECCOMP valikuna, et siseneda kaitstud arvutuste reĆŸiimi. SeejĂ€rel mÀÀrame reĆŸiimile filteri laadimise SECCOMP_MODE_FILTER abil, mis on mÀÀratud sock_fprog tĂŒĂŒpi muutuja prog:
if (prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, &prog)) {
perror("prctl(PR_SET_SECCOMP)");
return 1;
}
return 0;
}LÔpuks saame kasutada meie install_filter funktsiooni, kuid enne seda tuleb aktiveerida prctl, et seadistada PR_SET_NO_NEW_PRIVS praegusele protsessile, vÀltimaks olukorda, kus alamprotsessid saavad laiemad Ôigused kui vanemprotsess. Sellega seoses vÔime teha jÀrgmised prctl kutsed install_filter funktsioonis, omamata root Ôigusi.
NĂŒĂŒd saame kutsuda install_filter funktsiooni. Blokeerime kĂ”ik write sĂŒsteemi kutsed, mis on seotud X86-64 arhitektuuriga, ja anname lihtsalt loa, mis takistab kĂ”iki katseid. PĂ€rast filtri seadistamist jĂ€tkame tĂ€itmist, kasutades esimest argumenti:
int main(int argc, char const *argv[]) {
if (prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0)) {
perror("prctl(NO_NEW_PRIVS)");
return 1;
}
install_filter(__NR_write, AUDIT_ARCH_X86_64, EPERM);
return system(argv[1]);
}Alustame. Meie programmi kompileerimiseks vÔime kasutada kas clang'i vÔi gcc'd, igal juhul on see lihtsalt main.c faili kompileerimine ilma eriliste valikuteta:
clang main.c -o filter-writeNagu mainitud, oleme blokeerinud kÔik kirjutamised meie programmis. Selle kontrollimiseks on vajalik programm, mis midagi vÀljastab - ls tundub olevat hea kandidaat. Nii kÀitub see tavaliselt:
ls -la
total 36
drwxr-xr-x 2 fntlnz users 4096 Apr 28 21:09 .
drwxr-xr-x 4 fntlnz users 4096 Apr 26 13:01 ..
-rwxr-xr-x 1 fntlnz users 16800 Apr 28 21:09 filter-write
-rw-r--r-- 1 fntlnz users 19 Apr 28 21:09 .gitignore
-rw-r--r-- 1 fntlnz users 1282 Apr 28 21:08 main.c
SuurepÀrane! Nii nÀeb vÀlja meie shell-programmi kasutamine: me edastame lihtsalt testitava programmi esimese argumendina:
./filter-write "ls -la"PĂ€rast tĂ€itmist annab see programm tĂ€iesti tĂŒhja vĂ€ljundi. Siiski saame kasutada strace'i, et nĂ€ha, mis toimub:
strace -f ./filter-write "ls -la"Tulemuse vĂ€ljaanne on oluliselt lĂŒhendatud, kuid vastav osa nĂ€itab, et kirjete blokeerimine toimub EPERM viga â just see, mille me seadistasime. See tĂ€hendab, et programm ei prikku vĂ€ljundit, kuna ei saa juurde pÀÀseda sĂŒsteemikutsumisele write:
[pid 25099] write(2, "ls: ", 4) = -1 EPERM (Operation not permitted)
[pid 25099] write(2, "write error", 11) = -1 EPERM (Operation not permitted)
[pid 25099] write(2, "n", 1) = -1 EPERM (Operation not permitted)NĂŒĂŒd mĂ”istate, kuidas Seccomp BPF töötab, ja teil on hea ettekujutus sellest, mida sellega saavutada saab. Kuid kas poleks tore saavutada sama eBPF'i abil, mitte cBPF'iga, et kasutada selle kogu jĂ”ud?
MĂ”eldes eBPF programmidele, arvavad paljud inimesed, et nad lihtsalt kirjutavad need ja laadivad administraatori Ă”igustega ĂŒles. Kuigi see vĂ€ide on enamasti Ă”ige, rakendab kernel eBPF objektide kaitsmiseks erinevatel tasanditel komplekti mehhanisme. Neid mehhanisme nimetatakse BPF LSM lĂ”ksudeks.
BPF LSM lÔksud
SĂŒsteemsete sĂŒndmuste arhitektuurist sĂ”ltumatu kontrolli tagamiseks rakendab LSM lĂ”ksude kontseptsiooni. Tehniliselt lĂ”ksukutsumine sarnaneb sĂŒsteeminĂ”udmisega, kuid on sĂŒsteemist sĂ”ltumatu ja integreeritud infrastruktuuriga. LSM pakub uut kontseptsiooni, kus abstraktsioonitase aitab vĂ€ltida probleeme, mis tekivad sĂŒsteeminĂ”udmistega töötamisel erinevates arhitektuurides.
Raamatute kirjutamise hetkel oli kernelil seitse lĂ”ksu, mis on seotud BPF programmide ja SELinuxiga â ainus sisseehitatud LSM, mis neid rakendab.
LÔksude lÀhtekood asub kernelipuudes failis include/linux/security.h:
extern int security_bpf(int cmd, union bpf_attr *attr, unsigned int size);
extern int security_bpf_map(struct bpf_map *map, fmode_t fmode);
extern int security_bpf_prog(struct bpf_prog *prog);
extern int security_bpf_map_alloc(struct bpf_map *map);
extern void security_bpf_map_free(struct bpf_map *map);
extern int security_bpf_prog_alloc(struct bpf_prog_aux *aux);
extern void security_bpf_prog_free(struct bpf_prog_aux *aux);Iga neist kutsutakse erinevates etappides:
â security_bpf â viib lĂ€bi esialgse kontrolli BPF sĂŒsteemikutsest;
â security_bpf_map â kontrollib, kui tuum tagastab failideskirja kaardile;
â security_bpf_prog â kontrollib, kui tuum tagastab failideskirja eBPF programmile;
â security_bpf_map_alloc â kontrollib, kas turvavĂ€li on initsialiseeritud BPF kaartide sees;
â security_bpf_map_free â kontrollib, kas turvavĂ€li puhastatakse BPF kaartide sees;
â security_bpf_prog_alloc â kontrollib, kas turvavĂ€li initsialiseeritakse BPF programmide sees;
â security_bpf_prog_free â kontrollib, kas turvavĂ€li puhastatakse BPF programmide sees.
NĂŒĂŒd, kui me seda kĂ”ike nĂ€eme, mĂ”istame: LSM BPF hĂ€kkerite idee on see, et nad saavad tagada iga eBPF objekti kaitse, tagades, et ainult need, kellel on vastavad volitused, saavad kaarte ja programme töödelda.
KokkuvÔte
Turvalisus ei ole midagi, mida saate universaalselt rakendada kĂ”igile, mida soovite kaitsta. Oluline on suuteline kaitsma sĂŒsteeme erinevatel tasanditel ja erinevate meetoditega. Usugu, vĂ”i mitte, parim viis sĂŒsteemi turvamiseks on korraldada erinevad kaitsetasemed erinevatest positsioonidest, et ĂŒhe tasandi turvalisuse langus ei vĂ”imaldaks pÀÀseda kogu sĂŒsteemile. SĂŒdamiku arendajad on teinud suurepĂ€rase töö, et anda meile erinevate kihtide ja suhtluspunktide kogum. Loodame, et oleme andnud teile hea ĂŒlevaate sellest, mis on kihid ja kuidas kasutada BPF programme nende töötamiseks.
Autoritest
David Calavera on tehnilise direktori ametipostil Netlify. Ta on töötanud Docker'i klienditoes ja osalenud Runc, Go ja BCC tööriistade arenduses, samuti teistes avatud lĂ€htekoodiga projektides. Ta on tuntud oma töö poolest Docker'i projektide ja Docker'i pluginakeskuse arendamise valdkonnas. David armastab vĂ€ga flame graphs'i ja pĂŒĂŒdleb pidevalt jĂ”udluse optimeerimise poole.
Lorenzo Fontana töötab avatud lĂ€htekoodiga tarkvaraarendajate meeskonnas Sysdigis, kus ta tegeleb peamiselt Falco projektiga â Cloud Native Computing Foundation'i algatusega, mis tagab konteinerite kĂ€ituskeskkonna turvalisuse ja anomaaliate avastamise lĂ€bi kernel mooduli ja eBPF-i. Ta on kirglik jaotatud sĂŒsteemide, programmide mÀÀratletud vĂ”rkude, Linuxi tuuma ja jĂ”udluse analĂŒĂŒsi vastu.
» Raamatu kohta on tÀiendavat teavet saadaval
»
»
Habr'i lugejatele 25% allahindlus kupongiga â Linux
Paberraamatu eest tasumise korral saadetakse e-raamat e-kirjaga.
Allikas: habr.com
