Hallo, ynwenners fan Khabro! De BPF firtuele masine is ien fan 'e wichtichste komponinten fan' e Linux kernel. It juste gebrûk dêrfan sil systeemingenieurs tastean om fouten te finen en sels de meast komplekse problemen op te lossen. Jo sille leare hoe't jo programma's skriuwe dy't it gedrach fan 'e kernel kontrolearje en oanpasse, hoe't jo koade feilich kinne ymplementearje om eveneminten yn' e kernel te kontrolearjen, en folle mear. David Calavera en Lorenzo Fontana sille jo helpe om de krêft fan BPF te ûntsluten. Wreidzje jo kennis út oer prestaasjesoptimalisaasje, netwurking, feiligens. - Brûk BPF om it gedrach fan 'e Linux-kernel te kontrolearjen en te feroarjen. - Koade ynjeksje om kernel-eveneminten feilich te kontrolearjen sûnder de kernel opnij te kompilearjen of it systeem opnij te booten. - Brûk handige koadefoarbylden yn C, Go of Python. - Nim kontrôle troch de libbenssyklus fan it BPF-programma te besit.
Linux Kernel Security, syn funksjes en Secomp
BPF biedt in krêftige manier om de kernel te ferlingjen sûnder stabiliteit, feiligens of snelheid op te offerjen. Om dizze reden tochten de kernel-ûntwikkelders dat it in goed idee wêze soe om syn veelzijdigheid te brûken om prosesisolaasje yn Seccomp te ferbetterjen troch Seccomp-filters te ymplementearjen stipe troch BPF-programma's, ek bekend as Seccomp BPF. Yn dit haadstik sille wy útlizze wat Secomp is en hoe't it wurdt brûkt. Dan sille jo leare hoe't jo Secomp-filters skriuwe mei BPF-programma's. Dêrnei sjogge wy nei de ynboude BPF-haken dy't binne opnommen yn 'e kernel foar Linux-befeiligingsmodules.
Linux Security Modules (LSM) binne in ramt dat in set fan funksjes leveret dy't kinne wurde brûkt om ferskate feiligensmodellen op in standerdisearre manier te ymplementearjen. LSM kin direkt brûkt wurde yn 'e kearnboarnebeam, lykas Apparmor, SELinux en Tomoyo.
Litte wy begjinne mei it besprekken fan de mooglikheden fan Linux.
Eigenskippen
De essinsje fan 'e mooglikheden fan Linux is dat jo in net-befoarrjochte proses tastimming jaan moatte om in bepaalde taak út te fieren, mar sûnder suid foar dat doel te brûken, of oars it proses privilegearre meitsje, wêrtroch't de mooglikheid fan oanfal ferminderet en it proses bepaalde taken kin útfiere. Bygelyks, as jo applikaasje in befoarrjochte poarte moat iepenje, sis 80, ynstee fan it proses as root út te fieren, kinne jo it gewoan de CAP_NET_BIND_SERVICE-mooglikheid jaan.
Tink oan in Go-programma mei de namme main.go:
package main
import (
"net/http"
"log"
)
func main() {
log.Fatalf("%v", http.ListenAndServe(":80", nil))
}Dit programma tsjinnet in HTTP-tsjinner op poarte 80 (dit is in befoarrjochte poarte). Normaal rinne wy it fuort nei kompilaasje:
$ go build -o capabilities main.go
$ ./capabilitiesOm't wy lykwols gjin root-privileezjes jouwe, sil dizze koade in flater smyt by it ferbinen fan de poarte:
2019/04/25 23:17:06 listen tcp :80: bind: permission denied
exit status 1capsh (shell manager) is in ark dat rint in shell mei in spesifike set fan mooglikheden.
Yn dit gefal, lykas al neamd, kinne jo ynstee fan it jaan fan folsleine rootrjochten, befoarrjochte poartebinding ynskeakelje troch de cap_net_bind_service-mooglikheid te leverjen tegearre mei al it oare dat al yn it programma is. Om dit te dwaan kinne wy ús programma yn capsh ynslute:
# 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"Litte wy dit team in bytsje begripe.
- capsh - brûke capsh as shell.
- —caps='cap_net_bind_service+eip cap_setpcap,cap_setuid,cap_setgid+ep' - om't wy de brûker moatte feroarje (wy wolle net as root útfiere), spesifisearje wy cap_net_bind_service en de mooglikheid om de brûkers-ID eins te feroarjen fan root oan nimmen, nammentlik cap_setuid en cap_setgid.
- —keep=1 — wy wolle de ynstallearre mooglikheden behâlde by it wikseljen fan it root-akkount.
- -user="gjinien" - de ein brûker dy't it programma rint sil nimmen wêze.
- -addamb = cap_net_bind_service - set it wiskjen fan relatearre mooglikheden yn nei it wikseljen fan root-modus.
- - -c "./mooglikheden" - gewoan it programma útfiere.
Keppele mooglikheden binne in spesjale soarte fan mooglikheden dy't erfde troch bern programma doe't de hjoeddeiske programma útfiert se mei help fan execve (). Allinnich mooglikheden dy't meie wurde assosjearre, of mei oare wurden, as miljeu mooglikheden, kinne erfd wurde.
Jo freegje jo jo wierskynlik ôf wat +eip betsjut nei't jo de mooglikheid hawwe opjûn yn 'e --caps opsje. Dizze flaggen wurde brûkt om te bepalen dat de mooglikheid:
-moat aktivearre wurde (p);
-beskikber foar gebrûk (e);
-kin wurde erfd troch bern prosessen (i).
Om't wy cap_net_bind_service wolle brûke, moatte wy dit dwaan mei de e-flagge. Dan begjinne wy de shell yn it kommando. Dit sil de mooglikheden binêr útfiere en wy moatte it markearje mei de flagge i. Uteinlik wolle wy dat de funksje ynskeakele wurdt (wy hawwe dit dien sûnder de UID te feroarjen) mei p. It liket op cap_net_bind_service+eip.
Jo kinne it resultaat kontrolearje mei ss. Litte wy de útfier in bytsje ynkoartje om op 'e side te passen, mar it sil de assosjearre poarte en brûkers-ID oars as 0 sjen litte, yn dit gefal 65:
# ss -tulpn -e -H | cut -d' ' -f17-
128 *:80 *:*
users:(("capabilities",pid=30040,fd=3)) uid:65534 ino:11311579 sk:2c v6only:0Yn dit foarbyld hawwe wy capsh brûkt, mar jo kinne in shell skriuwe mei libcap. Foar mear ynformaasje, sjoch mann 3 libcap.
By it skriuwen fan programma's wit de ûntwikkelder faaks net fan tefoaren alle funksjes dy't it programma nedich is by runtiid; Boppedat kinne dizze funksjes feroarje yn nije ferzjes.
Om de mooglikheden fan ús programma better te begripen, kinne wy it BCC-kapabel ark nimme, dat de kprobe ynstelt foar de cap_capable kernelfunksje:
/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 1Wy kinne itselde ding berikke troch bpftrace te brûken mei in one-liner kprobe yn 'e cap_capable kernelfunksje:
bpftrace -e
'kprobe:cap_capable {
time("%H:%M:%S ");
printf("%-6d %-6d %-16s %-4d %dn", uid, pid, comm, arg2, arg3);
}'
| grep -i capabilitiesDit sil wat as it folgjende útfiere as de mooglikheden fan ús programma binne ynskeakele nei kprobe:
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 1De fyfde kolom is de mooglikheden dy't it proses nedich, en sûnt dizze útfier omfiemet net-audit events, wy sjogge alle net-audit kontrôles en op it lêst de fereaske mooglikheid mei de audit flagge (lêste yn de útfier) ynsteld op 1. Capability De ien wêryn wy ynteressearre binne is CAP_NET_BIND_SERVICE, it wurdt definieare as in konstante yn 'e kearnboarnekoade yn' e triem include/uapi/linux/ability.h mei identifier 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">Mooglikheden wurde faak ynskeakele by runtime foar konteners lykas runC of Docker om se yn unprivilegearre modus út te fieren, mar se hawwe allinich de mooglikheden tastien om de measte applikaasjes út te fieren. As in applikaasje bepaalde mooglikheden fereasket, kin Docker se leverje mei --cap-add:
docker run -it --rm --cap-add=NET_ADMIN ubuntu ip link add dummy0 type dummyDit kommando sil de kontener de CAP_NET_ADMIN-mooglikheid jaan, wêrtroch it in netwurkkeppeling kin konfigurearje om de dummy0-ynterface ta te foegjen.
De folgjende seksje lit sjen hoe't jo funksjes brûke lykas filterjen, mar mei in oare technyk wêrmei't wy ús eigen filters programmatysk kinne ymplementearje.
Secomp
Secomp stiet foar Secure Computing en is in befeiligingslaach ymplementearre yn 'e Linux-kernel wêrtroch ûntwikkelders bepaalde systeemoproppen kinne filterje. Hoewol Secomp yn mooglikheden fergelykber is mei Linux, makket har fermogen om bepaalde systeemoproppen te behearjen it folle fleksibeler yn ferliking mei har.
Secomp- en Linux-funksjes binne net ûnderling eksklusyf en wurde faak tegearre brûkt om te profitearjen fan beide oanpakken. Jo kinne bygelyks in proses de CAP_NET_ADMIN-mooglikheid jaan, mar it net tastean om socketferbiningen te akseptearjen, blokkearje de akseptearje en akseptearje4-systeemoproppen.
De Seccomp-filtermetoade is basearre op BPF-filters dy't wurkje yn 'e SECCOMP_MODE_FILTER-modus, en systeemopropfiltering wurdt útfierd op deselde manier as foar pakketten.
Seccomp-filters wurde laden mei prctl fia de PR_SET_SECCOMP-operaasje. Dizze filters nimme de foarm fan in BPF-programma dat wurdt útfierd foar elk Seccomp-pakket fertsjintwurdige troch de seccomp_data-struktuer. Dizze struktuer befettet de referinsjearsjitektuer, in oanwizer nei prosessorynstruksjes op it momint fan 'e systeemoprop, en maksimaal seis systeemoprop-arguminten, útdrukt as uint64.
Dit is hoe't de secomp_data-struktuer derút sjocht fan 'e kearnboarnekoade yn it linux/secomp.h-bestân:
struct seccomp_data {
int nr;
__u32 arch;
__u64 instruction_pointer;
__u64 args[6];
};Sa't jo sjen kinne út dizze struktuer, kinne wy filterje troch de systeem oprop, syn arguminten, of in kombinaasje fan beide.
Nei it ûntfangen fan elk Seccomp-pakket, moat it filter ferwurking útfiere om in definityf beslút te meitsjen en de kearn te fertellen wat it folgjende moat dwaan. It definitive beslút wurdt útdrukt troch ien fan 'e weromkommende wearden (statuskoades).
- SECCOMP_RET_KILL_PROCESS - deadet it hiele proses fuortendaliks nei it filterjen fan in systeemoprop dy't hjirtroch net wurdt útfierd.
- SECCOMP_RET_KILL_THREAD - beëiniget de hjoeddeistige thread fuortendaliks nei it filterjen fan in systeemoprop dy't hjirtroch net wurdt útfierd.
- SECCOMP_RET_KILL - alias foar SECCOMP_RET_KILL_THREAD, lofts foar efterkompatibiliteit.
- SECCOMP_RET_TRAP - de systeemoprop is ferbean, en it sinjaal SIGSYS (Bad System Call) wurdt stjoerd nei de taak dy't it neamt.
- SECCOMP_RET_ERRNO - It systeem oprop wurdt net útfierd, en in part fan de SECCOMP_RET_DATA filter werom wearde wurdt trochjûn oan brûkersromte as de errno wearde. Ofhinklik fan 'e oarsaak fan' e flater wurde ferskate error-wearden weromjûn. In list mei flaternûmers wurdt jûn yn 'e folgjende paragraaf.
- SECCOMP_RET_TRACE - Wurdt brûkt om de ptrace tracer te melden mei - PTRACE_O_TRACESECCOMP om te ûnderskeppen as in systeemoprop wurdt útfierd om dat proses te sjen en te kontrolearjen. As in tracer net ferbûn is, wurdt in flater weromjûn, errno is ynsteld op -ENOSYS, en it systeemoprop wurdt net útfierd.
- SECCOMP_RET_LOG - de systeemoprop wurdt oplost en oanmeld.
- SECCOMP_RET_ALLOW - it systeem oprop is gewoan tastien.
ptrace is in systeemoprop om tracingmeganismen út te fieren yn in proses neamd tracee, mei de mooglikheid om de útfiering fan it proses te kontrolearjen en te kontrolearjen. It spoarprogramma kin de útfiering effektyf beynfloedzje en de ûnthâldregisters fan tracee wizigje. Yn 'e Secomp-kontekst wurdt ptrace brûkt as trigger troch de SECCOMP_RET_TRACE-statuskoade, sadat de tracer kin foarkomme dat de systeemoprop syn eigen logika útfiert en útfiert.
Secomp flaters
Fan tiid ta tiid, wylst jo wurkje mei Seccomp, sille jo ferskate flaters tsjinkomme, dy't wurde identifisearre troch in weromkommende wearde fan it type SECCOMP_RET_ERRNO. Om in flater te rapportearjen, sil de seccomp-systeemoprop -1 weromjaan ynstee fan 0.
De folgjende flaters binne mooglik:
- EACCESS - De beller is net tastien om in systeemoprop te meitsjen. Dit bart meastentiids omdat it hat gjin CAP_SYS_ADMIN privileezjes of no_new_privs is net ynsteld mei help prctl (wy sille prate oer dit letter);
- EFAULT - de trochjûne arguminten (args yn 'e seccomp_data-struktuer) hawwe gjin jildich adres;
- EINVAL - d'r kinne hjir fjouwer redenen wêze:
-de frege operaasje is ûnbekend of net stipe troch de kearn yn de aktuele konfiguraasje;
-de oantsjutte flaggen binne net jildich foar de frege operaasje;
-operaasje omfiemet BPF_ABS, mar der binne problemen mei de oantsjutte offset, dat kin grutter wêze as de grutte fan de seccomp_data struktuer;
- it oantal ynstruksjes trochjûn oan it filter is grutter as it maksimum;
- ENOMEM - net genôch ûnthâld om it programma út te fieren;
- EOPNOTSUPP - de operaasje joech oan dat mei SECCOMP_GET_ACTION_AVAIL de aksje beskikber wie, mar de kearn stipet gjin rendeminten yn arguminten;
- ESRCH - in probleem barde by it syngronisearjen fan in oare stream;
- ENOSYS - D'r is gjin tracer ferbûn oan 'e SECCOMP_RET_TRACE-aksje.
prctl is in systeemoprop wêrmei in brûkersromteprogramma spesifike aspekten fan in proses kin manipulearje (ynstelle en krije), lykas byte-endianness, threadnammen, feilige berekkeningsmodus (Seccomp), privileezjes, Perf-eveneminten, ensfh.
Secomp kin foar jo lykje as in sânboxtechnology, mar it is it net. Secomp is in hulpprogramma wêrmei brûkers in sânboxmeganisme kinne ûntwikkelje. Litte wy no sjen hoe't brûkersynteraksjeprogramma's wurde makke mei in filter dat direkt wurdt neamd troch de Secomp-systeemoprop.
BPF Secomp Filter Foarbyld
Hjir sille wy sjen litte hoe't jo de twa earder besprutsen aksjes kombinearje kinne, nammentlik:
- wy sille in Seccomp BPF-programma skriuwe, dat sil wurde brûkt as in filter mei ferskate weromkommende koades ôfhinklik fan de besluten makke;
- lade it filter mei prctl.
Earst hawwe jo kopteksten nedich fan 'e standertbibleteek en de Linux-kernel:
#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>Foardat jo dit foarbyld besykje, moatte wy derfoar soargje dat de kernel is kompilearre mei CONFIG_SECCOMP en CONFIG_SECCOMP_FILTER ynsteld op y. Op in wurkjende masine kinne jo dit kontrolearje:
cat /proc/config.gz| zcat | grep -i CONFIG_SECCOMP
De rest fan 'e koade is in twa-dielige install_filter-funksje. It earste diel befettet ús list mei BPF-filterynstruksjes:
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),
}; De ynstruksjes wurde ynsteld mei help fan de BPF_STMT en BPF_JUMP makro definiearre yn de linux/filter.h triem.
Lit ús gean troch de ynstruksjes.
- BPF_STMT(BPF_LD + BPF_W + BPF_ABS (offsetof(struct seccomp_data, arch))) - it systeem laden en sammelet fan BPF_LD yn 'e foarm fan it wurd BPF_W, pakketgegevens leit op in fêste offset BPF_ABS.
- BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, bôge, 0, 3) - kontrolearret mei BPF_JEQ oft de arsjitektuerwearde yn 'e BPF_K-akkumulatorkonstante gelyk is oan bôge. As dat sa is, springt op offset 0 nei de folgjende ynstruksje, oars springt op offset 3 (yn dit gefal) om in flater te smiten omdat bôge net oerienkomt.
- BPF_STMT(BPF_LD + BPF_W + BPF_ABS (offsetof(struct seccomp_data, nr))) - Laadt en accumulearret fan BPF_LD yn 'e foarm fan it wurd BPF_W, dat is it systeemopropnûmer befette yn' e fêste offset fan BPF_ABS.
- BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, nr, 0, 1) - fergeliket it systeemopropnûmer mei de wearde fan 'e nr-fariabele. As se binne gelyk, giet oer nei de folgjende ynstruksje en skeakelet it systeem oprop, oars kinne it systeem oprop mei SECCOMP_RET_ALLOW.
- BPF_STMT(BPF_RET + BPF_K, SECCOMP_RET_ERRNO | (flater & SECCOMP_RET_DATA)) - beëiniget it programma mei BPF_RET en produsearret as gefolch in flater SECCOMP_RET_ERRNO mei it nûmer fan 'e flaterfariabele.
- BPF_STMT(BPF_RET + BPF_K, SECCOMP_RET_ALLOW) - beëiniget it programma mei BPF_RET en lit de systeemoprop útfiere mei SECCOMP_RET_ALLOW.
SECCOMP IS CBPF
Jo kinne jo ôffreegje wêrom't in list mei ynstruksjes wurdt brûkt ynstee fan in kompilearre ELF-objekt of in JIT-kompilearre C-programma.D'r binne twa redenen foar dit.
• As earste brûkt Seccomp cBPF (klassike BPF) en net eBPF, wat betsjut: it hat gjin registers, mar allinich in akkumulator om it lêste resultaat fan 'e berekkening op te slaan, lykas yn it foarbyld te sjen is.
• Second, Secomp akseptearret in oanwizer nei in rige fan BPF ynstruksjes direkt en neat oars. De makro's dy't wy hawwe brûkt, helpe gewoan dizze ynstruksjes op in programmeurfreonlike manier oan te jaan.
As jo mear help nedich hawwe om dizze gearkomste te begripen, beskôgje dan de pseudokoade dy't itselde docht:
if (arch != AUDIT_ARCH_X86_64) {
return SECCOMP_RET_ALLOW;
}
if (nr == __NR_write) {
return SECCOMP_RET_ERRNO;
}
return SECCOMP_RET_ALLOW;Nei it definiearjen fan de filterkoade yn de socket_filter-struktuer, moatte jo in sock_fprog definiearje mei de koade en de berekkene lingte fan it filter. Dizze gegevensstruktuer is nedich as argumint foar it ferklearjen fan it proses om letter út te fieren:
struct sock_fprog prog = {
.len = (unsigned short)(sizeof(filter) / sizeof(filter[0])),
.filter = filter,
};D'r is mar ien ding te dwaan yn 'e install_filter-funksje - lade it programma sels! Om dit te dwaan, brûke wy prctl, nimme PR_SET_SECCOMP as opsje om feilige komputermodus yn te gean. Dan fertelle wy de modus om it filter te laden mei SECCOMP_MODE_FILTER, dy't befette is yn 'e progfariabele fan type sock_fprog:
if (prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, &prog)) {
perror("prctl(PR_SET_SECCOMP)");
return 1;
}
return 0;
}Uteinlik kinne wy ús install_filter-funksje brûke, mar dêrfoar moatte wy prctl brûke om PR_SET_NO_NEW_PRIVS yn te stellen foar de aktuele útfiering en dêrmei de situaasje te foarkommen dat bernprosessen mear privileezjes krije as har âlders. Hjirmei kinne wy de folgjende prctl-oproppen meitsje yn 'e install_filter-funksje sûnder rootrjochten te hawwen.
No kinne wy de install_filter-funksje neame. Litte wy alle skriuwsysteemoproppen yn ferbân mei de X86-64-arsjitektuer blokkearje en gewoan in tastimming jaan dy't alle besykjen blokkeart. Nei it ynstallearjen fan it filter geane wy troch mei de útfiering mei it earste argumint:
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]);
}Litte wy begjinne. Om ús programma te kompilearjen kinne wy of clang of gcc brûke, yn beide gefallen is it gewoan it kompilearjen fan it main.c-bestân sûnder spesjale opsjes:
clang main.c -o filter-writeLykas opmurken, hawwe wy alle yngongen yn it programma blokkearre. Om dit te testen hawwe jo in programma nedich dat wat útfiert - ls liket in goede kandidaat. Dit is hoe't se normaal gedraacht:
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
Prachtich! Hjir is hoe't it brûken fan ús wrapperprogramma derút sjocht: Wy passe gewoan it programma dat wy wolle testen as it earste argumint:
./filter-write "ls -la"As it wurdt útfierd, produsearret dit programma folslein lege útfier. Wy kinne lykwols strace brûke om te sjen wat der bart:
strace -f ./filter-write "ls -la"It resultaat fan it wurk is sterk ynkoarte, mar it oerienkommende diel dêrfan lit sjen dat records binne blokkearre mei de EPERM-flater - deselde dy't wy konfigureare. Dit betsjut dat it programma neat útfiert, om't it gjin tagong hat ta de skriuwsysteemoprop:
[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)No begripe jo hoe't Secomp BPF wurket en hawwe in goed idee fan wat jo dermei kinne dwaan. Mar wolle jo net itselde ding berikke mei eBPF ynstee fan cBPF om har folsleine krêft te benutten?
As jo tinke oan eBPF-programma's, tinke de measte minsken dat se se gewoan skriuwe en se laden mei beheardersrjochten. Hoewol dizze ferklearring oer it algemien wier is, ymplementearret de kernel in set meganismen om eBPF-objekten op ferskate nivo's te beskermjen. Dizze meganismen wurde neamd BPF LSM traps.
BPF LSM traps
Om arsjitektuer-ûnôfhinklike tafersjoch fan systeemeveneminten te leverjen, ymplementearret LSM it konsept fan trapen. In heak oprop is technysk gelyk oan in systeem oprop, mar is systeem ûnôfhinklik en yntegrearre mei de ynfrastruktuer. LSM leveret in nij konsept wêryn in abstraksjelaach kin helpe om problemen te foarkommen by it omgean mei systeemoproppen op ferskate arsjitektuer.
Op it stuit fan dit skriuwen hat de kernel sân haken ferbûn mei BPF-programma's, en SELinux is de ienige ynboude LSM dy't se ymplementearret.
De boarnekoade foar de traps leit yn 'e kernelbeam yn' e triem 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);Elk fan harren sil wurde neamd yn ferskate stadia fan útfiering:
- security_bpf - fiert in earste kontrôle út fan útfierde BPF-systeemoproppen;
- security_bpf_map - kontrolearret wannear't de kearn in triembeskriuwer foar de kaart werombringt;
- security_bpf_prog - kontrolearret wannear't de kernel in triembeskriuwing foar it eBPF-programma werombringt;
- security_bpf_map_alloc - kontrolearret oft it befeiligingsfjild yn BPF-kaarten is inisjalisearre;
- security_bpf_map_free - kontrolearret oft it befeiligingsfjild is wiske binnen BPF-kaarten;
- security_bpf_prog_alloc - kontrolearret oft it befeiligingsfjild is inisjalisearre binnen BPF-programma's;
- security_bpf_prog_free - kontrolearret oft it befeiligingsfjild is wiske binnen BPF-programma's.
No, as wy dit alles sjogge, begripe wy: it idee efter LSM BPF-interceptors is dat se beskerming kinne leverje oan elk eBPF-objekt, en soargje dat allinich dejingen mei de passende privileezjes operaasjes kinne útfiere op kaarten en programma's.
Gearfetting
Feiligens is net iets dat jo kinne ymplementearje op in ien-grutte-past-alle manier foar alles wat jo wolle beskermje. It is wichtich om systemen op ferskate nivo's en op ferskate manieren te beskermjen. Leau it of net, de bêste manier om in systeem te befeiligjen is om ferskate nivo's fan beskerming te organisearjen fan ferskate posysjes, sadat it ferminderjen fan de feiligens fan ien nivo gjin tagong ta it heule systeem jout. De kearnûntwikkelders hawwe in geweldige baan dien om ús in set fan ferskate lagen en touchpoints te jaan. Wy hoopje dat wy jo in goed begryp hawwe jûn fan wat lagen binne en hoe't jo BPF-programma's kinne brûke om mei te wurkjen.
Oer de skriuwers
David Calavera is de CTO by Netlify. Hy wurke yn Docker-stipe en droech by oan de ûntwikkeling fan Runc-, Go- en BCC-ark, lykas oare iepen boarne-projekten. Bekend om syn wurk oan Docker-projekten en ûntwikkeling fan it Docker-plugin-ekosysteem. David is heul hertstochtlik oer flammegrafiken en siket altyd om prestaasjes te optimalisearjen.
Lorenzo Fontana wurket op it iepen boarne-team by Sysdig, wêr't hy primêr rjochte is op Falco, in Cloud Native Computing Foundation-projekt dat kontenerruntimefeiligens en anomalydeteksje leveret fia in kernelmodule en eBPF. Hy is hertstochtlik oer ferspraat systemen, software definieare netwurken, de Linux kernel, en prestaasjesanalyse.
» Mear details oer it boek is te finen op
»
»
Foar Khabrozhiteley 25% koarting mei coupon - linux
By betelling fan de papieren ferzje fan it boek wurdt in elektroanysk boek per e-post ferstjoerd.
Boarne: www.habr.com
