Linux kodola droŔība, tÄs funkcijas un Seccomp
BPF nodroÅ”ina jaudÄ«gu veidu, kÄ paplaÅ”inÄt kodolu, nezaudÄjot stabilitÄti, droŔību vai Ätrumu. Å Ä« iemesla dÄļ kodola izstrÄdÄtÄji uzskatÄ«ja, ka bÅ«tu laba ideja izmantot tÄ daudzpusÄ«bu, lai uzlabotu procesa izolÄciju Seccomp, ievieÅ”ot Seccomp filtrus, ko atbalsta BPF programmas, kas pazÄ«stami arÄ« kÄ Seccomp BPF. Å ajÄ nodaÄ¼Ä mÄs paskaidrosim, kas ir Seccomp un kÄ tas tiek lietots. PÄc tam jÅ«s uzzinÄsit, kÄ rakstÄ«t Seccomp filtrus, izmantojot BPF programmas. PÄc tam mÄs apskatÄ«sim iebÅ«vÄtos BPF ÄÄ·us, kas ir iekļauti Linux droŔības moduļu kodolÄ.
Linux droŔības moduļi (LSM) ir ietvars, kas nodroÅ”ina funkciju kopumu, ko var izmantot dažÄdu droŔības modeļu ievieÅ”anai standartizÄtÄ veidÄ. LSM var izmantot tieÅ”i kodola avota kokÄ, piemÄram, Apparmor, SELinux un Tomoyo.
SÄksim, pÄrrunÄjot Linux iespÄjas.
SpÄjas
Linux iespÄju bÅ«tÄ«ba ir tÄda, ka jums ir jÄpieŔķir nepievilinÄtam procesam atļauja veikt noteiktu uzdevumu, bet neizmantojot Å”im nolÅ«kam suid, vai kÄ citÄdi padarÄ«t procesu priviliÄ£Ätu, samazinot uzbrukuma iespÄju un ļaujot procesam veikt noteiktus uzdevumus. PiemÄram, ja jÅ«su lietojumprogrammai ir jÄatver priviliÄ£Äts ports, piemÄram, 80, tÄ vietÄ, lai palaistu procesu kÄ root, varat vienkÄrÅ”i pieŔķirt tai CAP_NET_BIND_SERVICE iespÄju.
Apsveriet Go programmu ar nosaukumu main.go:
package main
import (
"net/http"
"log"
)
func main() {
log.Fatalf("%v", http.ListenAndServe(":80", nil))
}
Å Ä« programma apkalpo HTTP serveri 80. portÄ (tas ir priviliÄ£Äts ports). Parasti mÄs to palaižam uzreiz pÄc kompilÄcijas:
$ go build -o capabilities main.go
$ ./capabilities
TomÄr, tÄ kÄ mÄs nepieŔķiram root tiesÄ«bas, Å”is kods radÄ«s kļūdu, saistot portu:
2019/04/25 23:17:06 listen tcp :80: bind: permission denied
exit status 1
capsh (Äaulas pÄrvaldnieks) ir rÄ«ks, kas palaiž Äaulu ar noteiktu iespÄju kopu.
Å ajÄ gadÄ«jumÄ, kÄ jau minÄts, tÄ vietÄ, lai pieŔķirtu visas saknes tiesÄ«bas, varat iespÄjot priviliÄ£Äto portu saistÄ«Å”anu, nodroÅ”inot cap_net_bind_service iespÄju kopÄ ar visu pÄrÄjo, kas jau ir programmÄ. Lai to izdarÄ«tu, mÄs varam pievienot mÅ«su programmu capsh:
# 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"
Mazliet sapratīsim Ŕo komandu.
- capsh - izmantojiet capsh kÄ apvalku.
- ācaps='cap_net_bind_service+eip cap_setpcap,cap_setuid,cap_setgid+ep' ā tÄ kÄ mums ir jÄmaina lietotÄjs (mÄs nevÄlamies palaist kÄ root), mÄs norÄdÄ«sim cap_net_bind_service un iespÄju faktiski mainÄ«t lietotÄja ID no root nevienam, proti, cap_setuid un cap_setgid.
- ākeep=1 ā mÄs vÄlamies saglabÄt instalÄtÄs iespÄjas, pÄrejot no saknes konta.
- āuser=āneviensā ā galalietotÄjs, kas palaiž programmu, nebÅ«s neviens.
- āaddamb=cap_net_bind_service ā iestatiet saistÄ«to iespÄju notÄ«rÄ«Å”anu pÄc pÄrslÄgÅ”anÄs no saknes režīma.
- - -c "./capabilities" - vienkÄrÅ”i palaidiet programmu.
SaistÄ«tÄs iespÄjas ir Ä«paÅ”a veida iespÄjas, kuras manto pakÄrtotÄs programmas, kad paÅ”reizÄjÄ programma tÄs izpilda, izmantojot execve(). Var mantot tikai tÄs iespÄjas, kuras ir atļauts saistÄ«t vai, citiem vÄrdiem sakot, kÄ vides iespÄjas.
JÅ«s droÅ”i vien domÄjat, ko nozÄ«mÄ +eip pÄc iespÄjas norÄdÄ«Å”anas opcijÄ --caps. Å ie karodziÅi tiek izmantoti, lai noteiktu, ka iespÄja:
-jÄbÅ«t aktivizÄtam (p);
- pieejams lietoŔanai (e);
-var mantot ar bÄrnu procesiem (i).
TÄ kÄ mÄs vÄlamies izmantot cap_net_bind_service, mums tas jÄdara ar karogu e. PÄc tam mÄs sÄksim Äaulu komandÄ. Tas palaidÄ«s iespÄjas binÄri, un mums tas ir jÄatzÄ«mÄ ar karogu i. Visbeidzot, mÄs vÄlamies, lai Ŕī funkcija tiktu iespÄjota (to darÄ«jÄm, nemainot UID), izmantojot p. Tas izskatÄs kÄ cap_net_bind_service+eip.
JÅ«s varat pÄrbaudÄ«t rezultÄtu, izmantojot ss. Nedaudz saÄ«sinÄsim izvadi, lai tÄ ietilptu lapÄ, taÄu tajÄ tiks parÄdÄ«ts saistÄ«tais ports un lietotÄja ID, kas nav 0, Å”ajÄ gadÄ«jumÄ 65:
# ss -tulpn -e -H | cut -d' ' -f17-
128 *:80 *:*
users:(("capabilities",pid=30040,fd=3)) uid:65534 ino:11311579 sk:2c v6only:0
Å ajÄ piemÄrÄ mÄs izmantojÄm capsh, bet jÅ«s varat rakstÄ«t Äaulu, izmantojot libcap. PapildinformÄciju skatiet man 3 libcap.
Rakstot programmas, diezgan bieži izstrÄdÄtÄjs iepriekÅ” nezina visas programmas darbÄ«bas laikÄ nepiecieÅ”amÄs funkcijas; TurklÄt Ŕīs funkcijas var mainÄ«ties jaunajÄs versijÄs.
Lai labÄk izprastu mÅ«su programmas iespÄjas, mÄs varam izmantot rÄ«ku BCC, kas iestata kprobe kodola funkcijai 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 1
MÄs varam sasniegt to paÅ”u, izmantojot bpftrace ar vienas lÄ«nijas kprobe kodola funkcijÄ cap_capable:
bpftrace -e
'kprobe:cap_capable {
time("%H:%M:%S ");
printf("%-6d %-6d %-16s %-4d %dn", uid, pid, comm, arg2, arg3);
}'
| grep -i capabilities
Ja mÅ«su programmas iespÄjas ir iespÄjotas pÄc kprobe, tas izvadÄ«s kaut ko lÄ«dzÄ«gu:
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 1
PiektajÄ kolonnÄ ir norÄdÄ«tas procesam nepiecieÅ”amÄs iespÄjas, un, tÄ kÄ Å”ajÄ izvadÄ ir ietverti ar auditu nesaistÄ«ti notikumi, mÄs redzam visas ar auditu nesaistÄ«tÄs pÄrbaudes un visbeidzot vajadzÄ«gÄs iespÄjas ar audita karogu (pÄdÄjais izvadÄ), kas iestatÄ«ts uz 1. IespÄja. viens, kas mÅ«s interesÄ, ir CAP_NET_BIND_SERVICE, tas ir definÄts kÄ konstante kodola avota kodÄ failÄ include/uapi/linux/ability.h ar identifikatoru 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">
Konteineru, piemÄram, runC vai Docker, iespÄjas bieži tiek iespÄjotas izpildes laikÄ, lai ļautu tiem darboties nepievilcÄ«gÄ režīmÄ, taÄu tÄm ir atļautas tikai tÄs iespÄjas, kas nepiecieÅ”amas, lai palaistu lielÄko daļu lietojumprogrammu. Ja lietojumprogrammai ir nepiecieÅ”amas noteiktas iespÄjas, Docker var tÄs nodroÅ”inÄt, izmantojot --cap-add:
docker run -it --rm --cap-add=NET_ADMIN ubuntu ip link add dummy0 type dummy
Å Ä« komanda konteineram pieŔķirs CAP_NET_ADMIN iespÄju, ļaujot tam konfigurÄt tÄ«kla saiti, lai pievienotu dummy0 interfeisu.
NÄkamajÄ sadaÄ¼Ä ir parÄdÄ«ts, kÄ izmantot tÄdas funkcijas kÄ filtrÄÅ”ana, bet izmantojot citu paÅÄmienu, kas ļauj programmatiski ieviest savus filtrus.
Seccomp
Seccomp apzÄ«mÄ Secure Computing un ir droŔības slÄnis, kas ieviests Linux kodolÄ, kas ļauj izstrÄdÄtÄjiem filtrÄt noteiktus sistÄmas zvanus. Lai gan Seccomp pÄc iespÄjÄm ir salÄ«dzinÄms ar Linux, tÄ spÄja pÄrvaldÄ«t noteiktus sistÄmas zvanus padara to daudz elastÄ«gÄku salÄ«dzinÄjumÄ ar tiem.
Seccomp un Linux lÄ«dzekļi viens otru neizslÄdz un bieži tiek izmantoti kopÄ, lai gÅ«tu labumu no abÄm pieejÄm. PiemÄram, iespÄjams, vÄlÄsities procesam pieŔķirt CAP_NET_ADMIN iespÄju, bet neļaut tam pieÅemt ligzdas savienojumus, bloÄ·Äjot akceptÄt un pieÅemt4 sistÄmas zvanus.
Seccomp filtrÄÅ”anas metode ir balstÄ«ta uz BPF filtriem, kas darbojas SECCOMP_MODE_FILTER režīmÄ, un sistÄmas zvanu filtrÄÅ”ana tiek veikta tÄpat kÄ paketÄm.
Seccomp filtri tiek ielÄdÄti, izmantojot prctl, izmantojot darbÄ«bu PR_SET_SECCOMP. Å ie filtri ir BPF programmas formÄ, kas tiek izpildÄ«ta katrai Seccomp paketei, ko attÄlo seccomp_data struktÅ«ra. Å Ä« struktÅ«ra satur atsauces arhitektÅ«ru, rÄdÄ«tÄju uz procesora instrukcijÄm sistÄmas izsaukuma laikÄ un ne vairÄk kÄ seÅ”us sistÄmas izsaukuma argumentus, kas izteikti kÄ uint64.
LÅ«k, kÄ seccomp_data struktÅ«ra izskatÄs no kodola pirmkoda failÄ linux/seccomp.h:
struct seccomp_data {
int nr;
__u32 arch;
__u64 instruction_pointer;
__u64 args[6];
};
KÄ redzams no Ŕīs struktÅ«ras, mÄs varam filtrÄt pÄc sistÄmas izsaukuma, tÄ argumentiem vai abu kombinÄcijas.
PÄc katras Seccomp paketes saÅemÅ”anas filtram jÄveic apstrÄde, lai pieÅemtu galÄ«go lÄmumu un pateiktu kodolam, kÄ rÄ«koties tÄlÄk. GalÄ«go lÄmumu izsaka viena no atgrieÅ”anas vÄrtÄ«bÄm (statusa kodi).
- SECCOMP_RET_KILL_PROCESS - nogalina visu procesu uzreiz pÄc sistÄmas zvana filtrÄÅ”anas, kas Ŕī iemesla dÄļ netiek izpildÄ«ts.
- SECCOMP_RET_KILL_THREAD - pÄrtrauc paÅ”reizÄjo pavedienu tÅ«lÄ«t pÄc sistÄmas izsaukuma filtrÄÅ”anas, kas Ŕī iemesla dÄļ netiek izpildÄ«ts.
ā SECCOMP_RET_KILL ā aizstÄjvÄrds SECCOMP_RET_KILL_THREAD, atstÄts atpakaļsaderÄ«bai.
- SECCOMP_RET_TRAP - sistÄmas izsaukums ir aizliegts, un SIGSYS (Bad System Call) signÄls tiek nosÅ«tÄ«ts uzdevumam, kas to izsauc.
- SECCOMP_RET_ERRNO - sistÄmas izsaukums netiek izpildÄ«ts, un daļa no SECCOMP_RET_DATA filtra atgrieÅ”anas vÄrtÄ«bas tiek nodota lietotÄja telpai kÄ kļūdas vÄrtÄ«ba. AtkarÄ«bÄ no kļūdas iemesla tiek atgrieztas dažÄdas errno vÄrtÄ«bas. Kļūdu numuru saraksts ir sniegts nÄkamajÄ sadaļÄ.
- SECCOMP_RET_TRACE - izmanto, lai paziÅotu ptrace tracer, izmantojot - PTRACE_O_TRACESECCOMP, lai pÄrtvertu, kad tiek izpildÄ«ts sistÄmas izsaukums, lai redzÄtu un kontrolÄtu Å”o procesu. Ja izsekotÄjs nav pievienots, tiek atgriezta kļūda, errno tiek iestatÄ«ts uz -ENOSYS un sistÄmas izsaukums netiek izpildÄ«ts.
- SECCOMP_RET_LOG - sistÄmas zvans ir atrisinÄts un reÄ£istrÄts.
- SECCOMP_RET_ALLOW ā sistÄmas izsaukums ir vienkÄrÅ”i atļauts.
ptrace ir sistÄmas izsaukums, lai ieviestu izsekoÅ”anas mehÄnismus procesÄ, ko sauc par tracee, ar iespÄju uzraudzÄ«t un kontrolÄt procesa izpildi. IzsekoÅ”anas programma var efektÄ«vi ietekmÄt izpildi un modificÄt tracee atmiÅas reÄ£istrus. Seccomp kontekstÄ ptrace tiek izmantots, ja to aktivizÄ statusa kods SECCOMP_RET_TRACE, tÄpÄc izsekotÄjs var novÄrst sistÄmas izsaukuma izpildi un ieviest savu loÄ£iku.
Seccomp kļūdas
Laiku pa laikam, strÄdÄjot ar Seccomp, jÅ«s saskaraties ar dažÄdÄm kļūdÄm, kuras identificÄ pÄc SECCOMP_RET_ERRNO tipa atgrieÅ”anas vÄrtÄ«bas. Lai ziÅotu par kļūdu, seccomp sistÄmas izsaukums atgriezÄ«s -1, nevis 0.
Ir iespÄjamas Å”Ädas kļūdas:
- EACCESS - zvanÄ«tÄjam nav atļauts veikt sistÄmas zvanu. Tas parasti notiek tÄpÄc, ka tai nav CAP_SYS_ADMIN privilÄÄ£iju vai no_new_privs nav iestatÄ«ts, izmantojot prctl (par to mÄs runÄsim vÄlÄk);
ā EFAULT ā nodotajiem argumentiem (args seccomp_data struktÅ«rÄ) nav derÄ«gas adreses;
ā EINVAL ā Å”eit var bÅ«t Äetri iemesli:
-pieprasÄ«tÄ darbÄ«ba nav zinÄma vai kodols paÅ”reizÄjÄ konfigurÄcijÄ to neatbalsta;
-norÄdÄ«tie karodziÅi nav derÄ«gi pieprasÄ«tajai darbÄ«bai;
-operÄcija ietver BPF_ABS, taÄu ir problÄmas ar norÄdÄ«to nobÄ«di, kas var pÄrsniegt seccomp_data struktÅ«ras izmÄru;
-filtram nodoto instrukciju skaits pÄrsniedz maksimÄlo;
ā ENOMEM ā nepietiek atmiÅas programmas izpildei;
- EOPNOTSUPP - operÄcija norÄdÄ«ja, ka ar SECCOMP_GET_ACTION_AVAIL darbÄ«ba bija pieejama, bet kodols neatbalsta atgrieÅ”anos argumentos;
ā ESRCH ā radÄs problÄma, sinhronizÄjot citu straumi;
- ENOSYS - darbÄ«bai SECCOMP_RET_TRACE nav pievienots izsekotÄjs.
prctl ir sistÄmas izsaukums, kas ļauj lietotÄja telpas programmai manipulÄt (iestatÄ«t un iegÅ«t) konkrÄtus procesa aspektus, piemÄram, baitu endianitÄti, pavedienu nosaukumus, droÅ”o skaitļoÅ”anas režīmu (Seccomp), privilÄÄ£ijas, Perf notikumus utt.
Seccomp jums var Ŕķist smilÅ”kastes tehnoloÄ£ija, taÄu tÄ nav. Seccomp ir utilÄ«ta, kas lietotÄjiem ļauj izstrÄdÄt smilÅ”kastes mehÄnismu. Tagad apskatÄ«sim, kÄ tiek izveidotas lietotÄju mijiedarbÄ«bas programmas, izmantojot filtru, ko tieÅ”i izsauc Seccomp sistÄmas izsaukums.
BPF Seccomp filtra piemÄrs
Å eit mÄs parÄdÄ«sim, kÄ apvienot divas iepriekÅ” apspriestÄs darbÄ«bas, proti:
ā uzrakstÄ«sim Seccomp BPF programmu, kas tiks izmantota kÄ filtrs ar dažÄdiem atgrieÅ”anas kodiem atkarÄ«bÄ no pieÅemtajiem lÄmumiem;
ā ielÄdÄjiet filtru, izmantojot prctl.
Vispirms jums ir vajadzÄ«gas galvenes no standarta bibliotÄkas un Linux kodola:
#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>
Pirms mÄÄ£inÄt Å”o piemÄru, mums ir jÄpÄrliecinÄs, ka kodols ir kompilÄts ar CONFIG_SECCOMP un CONFIG_SECCOMP_FILTER iestatÄ«tu uz y. Darba maŔīnÄ to var pÄrbaudÄ«t Å”Ädi:
cat /proc/config.gz| zcat | grep -i CONFIG_SECCOMP
PÄrÄjÄ koda daļa ir divdaļīga install_filter funkcija. PirmajÄ daÄ¼Ä ir mÅ«su BPF filtrÄÅ”anas instrukciju saraksts:
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),
};
NorÄdÄ«jumi ir iestatÄ«ti, izmantojot makro BPF_STMT un BPF_JUMP, kas definÄti failÄ linux/filter.h.
Iesim cauri instrukcijÄm.
- BPF_STMT(BPF_LD + BPF_W + BPF_ABS (offsetof(struct seccomp_data, arch))) - sistÄma ielÄdÄ un uzkrÄj no BPF_LD vÄrda BPF_W formÄ, pakeÅ”u dati atrodas fiksÄtÄ nobÄ«dÄ BPF_ABS.
- BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, arka, 0, 3) - pÄrbauda, āāizmantojot BPF_JEQ, vai arhitektÅ«ras vÄrtÄ«ba akumulatora konstantÄ BPF_K ir vienÄda ar arku. Ja tÄ, pÄrlec pie nobÄ«des 0 uz nÄkamo instrukciju, pretÄjÄ gadÄ«jumÄ pÄrlec pie nobÄ«des 3 (Å”ajÄ gadÄ«jumÄ), lai radÄ«tu kļūdu, jo arka nesakrÄ«t.
- BPF_STMT(BPF_LD + BPF_W + BPF_ABS (offsetof(struct seccomp_data, nr))) - IelÄdÄ un uzkrÄj no BPF_LD vÄrda BPF_W formÄ, kas ir sistÄmas izsaukuma numurs, kas ietverts BPF_ABS fiksÄtajÄ nobÄ«dÄ.
ā BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, nr, 0, 1) ā salÄ«dzina sistÄmas izsaukuma numuru ar mainÄ«gÄ nr vÄrtÄ«bu. Ja tie ir vienÄdi, pÄriet uz nÄkamo instrukciju un atspÄjo sistÄmas izsaukumu, pretÄjÄ gadÄ«jumÄ atļauj sistÄmas izsaukumu ar SECCOMP_RET_ALLOW.
- BPF_STMT(BPF_RET + BPF_K, SECCOMP_RET_ERRNO | (kļūda & SECCOMP_RET_DATA)) - pÄrtrauc programmu ar BPF_RET un rezultÄtÄ rada kļūdu SECCOMP_RET_ERRNO ar numuru no kļūdas mainÄ«gÄ.
- BPF_STMT(BPF_RET + BPF_K, SECCOMP_RET_ALLOW) - pÄrtrauc programmu ar BPF_RET un ļauj izpildÄ«t sistÄmas izsaukumu, izmantojot SECCOMP_RET_ALLOW.
SECCOMP IS CBPF
Jums var rasties jautÄjums, kÄpÄc kompilÄta ELF objekta vai JIT kompilÄtas C programmas vietÄ tiek izmantots instrukciju saraksts.Tam ir divi iemesli.
ā¢ PirmkÄrt, Seccomp izmanto cBPF (klasisko BPF), nevis eBPF, kas nozÄ«mÄ: tai nav reÄ£istru, bet tikai akumulators, lai saglabÄtu pÄdÄjo aprÄÄ·ina rezultÄtu, kÄ redzams piemÄrÄ.
ā¢ OtrkÄrt, Seccomp pieÅem rÄdÄ«tÄju uz BPF instrukciju masÄ«vu tieÅ”i un neko citu. MÅ«su izmantotie makro vienkÄrÅ”i palÄ«dz norÄdÄ«t Å”os norÄdÄ«jumus programmÄtÄjam draudzÄ«gÄ veidÄ.
Ja jums nepiecieŔama papildu palīdzība, lai izprastu Ŕo komplektu, apsveriet pseidokodu, kas veic to paŔu:
if (arch != AUDIT_ARCH_X86_64) {
return SECCOMP_RET_ALLOW;
}
if (nr == __NR_write) {
return SECCOMP_RET_ERRNO;
}
return SECCOMP_RET_ALLOW;
PÄc filtra koda definÄÅ”anas socket_filter struktÅ«rÄ ir jÄdefinÄ sock_fprog, kas satur kodu un aprÄÄ·inÄto filtra garumu. Å Ä« datu struktÅ«ra ir nepiecieÅ”ama kÄ arguments, lai paziÅotu, ka process tiks palaists vÄlÄk:
struct sock_fprog prog = {
.len = (unsigned short)(sizeof(filter) / sizeof(filter[0])),
.filter = filter,
};
FunkcijÄ install_filter atlicis darÄ«t tikai vienu ā ielÄdÄt paÅ”u programmu! Lai to izdarÄ«tu, mÄs izmantojam prctl, izmantojot PR_SET_SECCOMP kÄ opciju, lai pÄrietu droÅ”Ä skaitļoÅ”anas režīmÄ. PÄc tam mÄs sakÄm režīmam, lai ielÄdÄtu filtru, izmantojot SECCOMP_MODE_FILTER, kas atrodas sock_fprog tipa prog mainÄ«gajÄ:
if (prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, &prog)) {
perror("prctl(PR_SET_SECCOMP)");
return 1;
}
return 0;
}
Visbeidzot, mÄs varam izmantot funkciju install_filter, taÄu pirms tam mums ir jÄizmanto prctl, lai iestatÄ«tu PR_SET_NO_NEW_PRIVS paÅ”reizÄjai izpildei un tÄdÄjÄdi izvairÄ«tos no situÄcijas, kad bÄrnu procesi saÅem vairÄk privilÄÄ£iju nekÄ viÅu vecÄki. Izmantojot to, mÄs varam veikt Å”Ädus prctl izsaukumus funkcijÄ install_filter bez root tiesÄ«bÄm.
Tagad mÄs varam izsaukt funkciju install_filter. BloÄ·Äsim visus rakstÄ«Å”anas sistÄmas zvanus, kas saistÄ«ti ar X86-64 arhitektÅ«ru, un vienkÄrÅ”i pieŔķirsim atļauju, kas bloÄ·Ä visus mÄÄ£inÄjumus. PÄc filtra instalÄÅ”anas mÄs turpinÄm izpildi, izmantojot pirmo argumentu:
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]);
}
SÄksim. Lai kompilÄtu mÅ«su programmu, mÄs varam izmantot vai nu clang, vai gcc, jebkurÄ gadÄ«jumÄ tÄ ir tikai faila main.c kompilÄÅ”ana bez Ä«paÅ”Äm opcijÄm:
clang main.c -o filter-write
KÄ minÄts, mÄs esam bloÄ·ÄjuÅ”i visus programmas ierakstus. Lai to pÄrbaudÄ«tu, ir nepiecieÅ”ama programma, kas kaut ko izvada - ls Ŕķiet labs kandidÄts. ViÅa parasti uzvedas Å”Ädi:
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
BrÄ«niŔķīgi! LÅ«k, kÄ izskatÄs mÅ«su iesaiÅojuma programmas izmantoÅ”ana: MÄs vienkÄrÅ”i nododam programmu, kuru vÄlamies pÄrbaudÄ«t, kÄ pirmo argumentu:
./filter-write "ls -la"
Kad Ŕī programma tiek izpildÄ«ta, tÄ rada pilnÄ«gi tukÅ”u izvadi. TomÄr mÄs varam izmantot strace, lai redzÄtu, kas notiek:
strace -f ./filter-write "ls -la"
Darba rezultÄts ir ievÄrojami saÄ«sinÄts, bet tÄ atbilstoÅ”Ä daļa parÄda, ka ieraksti ir bloÄ·Äti ar EPERM kļūdu - to paÅ”u, kuru mÄs konfigurÄjÄm. Tas nozÄ«mÄ, ka programma neko neizvada, jo tÄ nevar piekļūt rakstÄ«Å”anas sistÄmas izsaukumam:
[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)
Tagad jÅ«s saprotat, kÄ darbojas Seccomp BPF, un jums ir laba ideja par to, ko ar to varat darÄ«t. Bet vai jÅ«s nevÄlaties panÄkt to paÅ”u ar eBPF, nevis cBPF, lai pilnÄ«bÄ izmantotu tÄ jaudu?
DomÄjot par eBPF programmÄm, lielÄkÄ daļa cilvÄku domÄ, ka tÄs vienkÄrÅ”i raksta un ielÄdÄ ar administratora privilÄÄ£ijÄm. Lai gan Å”is apgalvojums kopumÄ ir patiess, kodols ievieÅ” mehÄnismu kopumu, lai aizsargÄtu eBPF objektus dažÄdos lÄ«meÅos. Å os mehÄnismus sauc par BPF LSM lamatÄm.
BPF LSM slazdi
Lai nodroÅ”inÄtu no arhitektÅ«ras neatkarÄ«gu sistÄmas notikumu uzraudzÄ«bu, LSM ievieÅ” slazdu koncepciju. ÄÄ·a zvans ir tehniski lÄ«dzÄ«gs sistÄmas zvanam, taÄu ir sistÄmas neatkarÄ«gs un integrÄts ar infrastruktÅ«ru. LSM nodroÅ”ina jaunu koncepciju, kurÄ abstrakcijas slÄnis var palÄ«dzÄt izvairÄ«ties no problÄmÄm, kas rodas, strÄdÄjot ar sistÄmas izsaukumiem dažÄdÄs arhitektÅ«rÄs.
RakstÄ«Å”anas laikÄ kodolam ir septiÅi ÄÄ·i, kas saistÄ«ti ar BPF programmÄm, un SELinux ir vienÄ«gais iebÅ«vÄtais LSM, kas tos ievieÅ”.
Slazdu pirmkods atrodas kodola kokÄ failÄ 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);
Katrs no tiem tiks izsaukts dažÄdos izpildes posmos:
ā security_bpf ā veic izpildÄ«to BPF sistÄmas izsaukumu sÄkotnÄjo pÄrbaudi;
- security_bpf_map - pÄrbauda, āākad kodols atgriež kartes faila deskriptoru;
- security_bpf_prog - pÄrbauda, āākad kodols atgriež eBPF programmas faila deskriptoru;
ā security_bpf_map_alloc ā pÄrbauda, āāvai droŔības lauks BPF kartÄs ir inicializÄts;
- security_bpf_map_free - pÄrbauda, āāvai droŔības lauks ir notÄ«rÄ«ts BPF kartÄs;
ā security_bpf_prog_alloc ā pÄrbauda, āāvai droŔības lauks ir inicializÄts BPF programmÄs;
- security_bpf_prog_free - pÄrbauda, āāvai droŔības lauks ir notÄ«rÄ«ts BPF programmÄs.
Tagad, redzot to visu, mÄs saprotam: LSM BPF pÄrtvÄrÄju ideja ir tÄda, ka tie var nodroÅ”inÄt aizsardzÄ«bu katram eBPF objektam, nodroÅ”inot, ka tikai tie, kuriem ir atbilstoÅ”as āāprivilÄÄ£ijas, var veikt darbÄ«bas ar kartÄm un programmÄm.
Kopsavilkums
DroŔība nav kaut kas tÄds, ko jÅ«s varat ieviest vienÄdi visam, ko vÄlaties aizsargÄt. Ir svarÄ«gi spÄt aizsargÄt sistÄmas dažÄdos lÄ«meÅos un dažÄdos veidos. Ticiet vai nÄ, bet vislabÄkais veids, kÄ nodroÅ”inÄt sistÄmu, ir organizÄt dažÄdus aizsardzÄ«bas lÄ«meÅus no dažÄdÄm pozÄ«cijÄm, lai viena lÄ«meÅa droŔības samazinÄÅ”ana neļautu piekļūt visai sistÄmai. Galvenie izstrÄdÄtÄji ir paveikuÅ”i lielisku darbu, nodroÅ”inot mums dažÄdu slÄÅu un saskares punktu kopumu. MÄs ceram, ka esam devuÅ”i jums labu izpratni par to, kas ir slÄÅi un kÄ izmantot BPF programmas darbam ar tiem.
Par autoriem
Deivids Kalavera ir Netlify tehnoloÄ£iju vadÄ«tÄjs. ViÅÅ” strÄdÄja Docker atbalsta jomÄ un piedalÄ«jÄs Runc, Go un BCC rÄ«ku, kÄ arÄ« citu atvÄrtÄ pirmkoda projektu izstrÄdÄ. PazÄ«stams ar savu darbu pie Docker projektiem un Docker spraudÅu ekosistÄmas izstrÄdi. Deivids ļoti aizraujas ar liesmu diagrammÄm un vienmÄr cenÅ”as optimizÄt veiktspÄju.
Lorenco Fontana strÄdÄ Sysdig atvÄrtÄ pirmkoda komandÄ, kur galvenokÄrt koncentrÄjas uz Falco ā Cloud Native Computing Foundation projektu, kas nodroÅ”ina konteinera izpildlaika droŔību un anomÄliju noteikÅ”anu, izmantojot kodola moduli un eBPF. ViÅÅ” aizraujas ar izplatÄ«tajÄm sistÄmÄm, programmatÅ«ras definÄtu tÄ«klu izveidi, Linux kodolu un veiktspÄjas analÄ«zi.
Ā» SÄ«kÄku informÄciju par grÄmatu var atrast vietnÄ
Ā»
Ā»
Par Khabrozhiteley 25% atlaide, izmantojot kuponu - Linux
ApmaksÄjot grÄmatas papÄ«ra versiju, pa e-pastu tiks nosÅ«tÄ«ta elektroniskÄ grÄmata.
Avots: www.habr.com