Diogelwch Cnewyllyn Linux, Ei Nodweddion a Seccomp
Mae BPF yn darparu ffordd bwerus i ymestyn y cnewyllyn heb aberthu sefydlogrwydd, diogelwch na chyflymder. Am y rheswm hwn, roedd y datblygwyr cnewyllyn yn meddwl y byddai'n syniad da defnyddio ei amlbwrpasedd i wella ynysu prosesau yn Seccomp trwy weithredu hidlwyr Seccomp a gefnogir gan raglenni BPF, a elwir hefyd yn Seccomp BPF. Yn y bennod hon byddwn yn egluro beth yw Seccomp a sut y caiff ei ddefnyddio. Yna byddwch chi'n dysgu sut i ysgrifennu hidlwyr Seccomp gan ddefnyddio rhaglenni BPF. Ar ôl hynny, byddwn yn edrych ar y bachau BPF adeiledig sydd wedi'u cynnwys yn y cnewyllyn ar gyfer modiwlau diogelwch Linux.
Mae Modiwlau Diogelwch Linux (LSM) yn fframwaith sy'n darparu set o swyddogaethau y gellir eu defnyddio i weithredu modelau diogelwch amrywiol mewn modd safonol. Gellir defnyddio LSM yn uniongyrchol yn y goeden ffynhonnell cnewyllyn, fel Apparmor, SELinux a Tomoyo.
Gadewch i ni ddechrau trwy drafod galluoedd Linux.
Galluoedd
Hanfod galluoedd Linux yw bod angen i chi roi caniatâd proses ddi-freintiedig i gyflawni tasg benodol, ond heb ddefnyddio suid at y diben hwnnw, neu wneud y broses yn freintiedig fel arall, gan leihau'r posibilrwydd o ymosodiad a chaniatáu i'r broses gyflawni tasgau penodol. Er enghraifft, os oes angen i'ch cais agor porthladd breintiedig, dyweder 80, yn hytrach na rhedeg y broses fel gwraidd, gallwch chi roi'r gallu CAP_NET_BIND_SERVICE iddo.
Ystyriwch raglen Go o'r enw main.go:
package main
import (
"net/http"
"log"
)
func main() {
log.Fatalf("%v", http.ListenAndServe(":80", nil))
}
Mae'r rhaglen hon yn gwasanaethu gweinydd HTTP ar borthladd 80 (mae hwn yn borthladd breintiedig). Fel arfer rydym yn ei redeg yn syth ar ôl ei lunio:
$ go build -o capabilities main.go
$ ./capabilities
Fodd bynnag, gan nad ydym yn rhoi breintiau gwraidd, bydd y cod hwn yn taflu gwall wrth rwymo'r porthladd:
2019/04/25 23:17:06 listen tcp :80: bind: permission denied
exit status 1
Mae capsh (rheolwr cragen) yn offeryn sy'n rhedeg cragen gyda set benodol o alluoedd.
Yn yr achos hwn, fel y crybwyllwyd eisoes, yn lle rhoi hawliau gwraidd llawn, gallwch chi alluogi rhwymiad porthladd breintiedig trwy ddarparu'r gallu cap_net_bind_service ynghyd â phopeth arall sydd eisoes yn y rhaglen. I wneud hyn, gallwn amgáu ein rhaglen mewn 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"
Gadewch i ni ddeall y tîm hwn ychydig.
- capsh - defnyddiwch capsh fel cragen.
- —caps='cap_net_bind_service+eip cap_setpcap, cap_setuid, cap_setgid+ep' - gan fod angen i ni newid y defnyddiwr (nid ydym am redeg fel gwraidd), byddwn yn nodi cap_net_bind_service a'r gallu i newid yr ID defnyddiwr o gwraidd i neb, sef cap_setuid a cap_setgid.
- —keep=1 — rydym am gadw'r galluoedd gosodedig wrth newid o'r cyfrif gwraidd.
- —user="neb" — ni fydd y defnyddiwr terfynol sy'n rhedeg y rhaglen yn neb.
- —addamb=cap_net_bind_service — gosodwch glirio galluoedd cysylltiedig ar ôl newid o'r modd gwraidd.
- - -c "./capabilities" - rhedeg y rhaglen yn unig.
Mae galluoedd cysylltiedig yn fath arbennig o alluoedd sy'n cael eu hetifeddu gan raglenni plant pan fydd y rhaglen gyfredol yn eu gweithredu gan ddefnyddio execve (). Dim ond galluoedd y caniateir eu cysylltu, neu mewn geiriau eraill, fel galluoedd amgylchedd, a all gael eu hetifeddu.
Mae'n debyg eich bod yn pendroni beth mae +eip yn ei olygu ar ôl nodi'r gallu yn yr opsiwn --caps. Defnyddir y baneri hyn i benderfynu bod y gallu:
-rhaid ei actifadu (p);
-ar gael i'w ddefnyddio (e);
-gellir ei etifeddu gan brosesau plentyn (i).
Gan ein bod ni eisiau defnyddio cap_net_bind_service, mae angen i ni wneud hyn gyda'r e-faner. Yna byddwn yn cychwyn y gragen yn y gorchymyn. Bydd hyn yn rhedeg y galluoedd deuaidd ac mae angen i ni ei farcio gyda baner i. Yn olaf, rydym am i'r nodwedd gael ei galluogi (gwnaethom hyn heb newid yr UID) gyda t. Mae'n edrych fel cap_net_bind_service+eip.
Gallwch wirio'r canlyniad gan ddefnyddio ss. Gadewch i ni fyrhau'r allbwn ychydig i ffitio ar y dudalen, ond bydd yn dangos y porthladd cysylltiedig a'r ID defnyddiwr heblaw 0, yn yr achos hwn 65:
# ss -tulpn -e -H | cut -d' ' -f17-
128 *:80 *:*
users:(("capabilities",pid=30040,fd=3)) uid:65534 ino:11311579 sk:2c v6only:0
Yn yr enghraifft hon fe wnaethom ddefnyddio capsh, ond gallwch chi ysgrifennu cragen gan ddefnyddio libcap. Am ragor o wybodaeth, gweler dyn 3 libcap.
Wrth ysgrifennu rhaglenni, yn aml nid yw'r datblygwr yn gwybod ymlaen llaw yr holl nodweddion sydd eu hangen ar y rhaglen ar amser rhedeg; Ar ben hynny, gall y nodweddion hyn newid mewn fersiynau newydd.
Er mwyn deall galluoedd ein rhaglen yn well, gallwn gymryd yr offeryn gallu BCC, sy'n gosod y kprobe ar gyfer y swyddogaeth cnewyllyn 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
Gallwn gyflawni'r un peth trwy ddefnyddio bpftrace gyda kprobe un-leinin yn y swyddogaeth cnewyllyn 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
Bydd hyn yn allbynnu rhywbeth fel y canlynol os yw galluoedd ein rhaglen yn cael eu galluogi ar ôl 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 1
Y bumed golofn yw'r galluoedd sydd eu hangen ar y broses, a chan fod yr allbwn hwn yn cynnwys digwyddiadau nad ydynt yn rhai archwilio, gwelwn yr holl wiriadau nad ydynt yn rhai archwilio ac yn olaf y gallu gofynnol gyda'r faner archwilio (yn olaf yn yr allbwn) wedi'i gosod i 1. Gallu Y un y mae gennym ddiddordeb ynddo yw CAP_NET_BIND_SERVICE, fe'i diffinnir fel cysonyn yn y cod ffynhonnell cnewyllyn yn y ffeil cynnwys/uapi/linux/ability.h gyda dynodwr 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">
Mae galluoedd yn aml yn cael eu galluogi ar amser rhedeg ar gyfer cynwysyddion fel runC neu Docker i'w galluogi i redeg mewn modd di-freintiedig, ond dim ond y galluoedd sydd eu hangen i redeg y mwyafrif o gymwysiadau y caniateir iddynt. Pan fydd angen galluoedd penodol ar raglen, gall Docker eu darparu gan ddefnyddio --cap-add:
docker run -it --rm --cap-add=NET_ADMIN ubuntu ip link add dummy0 type dummy
Bydd y gorchymyn hwn yn rhoi'r gallu CAP_NET_ADMIN i'r cynhwysydd, gan ganiatáu iddo ffurfweddu cyswllt rhwydwaith i ychwanegu'r rhyngwyneb dymmy0.
Mae'r adran nesaf yn dangos sut i ddefnyddio nodweddion fel hidlo, ond gan ddefnyddio techneg wahanol sy'n ein galluogi i weithredu ein hidlwyr ein hunain yn rhaglennol.
Seccomp
Ystyr Seccomp yw Cyfrifiadura Diogel ac mae'n haen ddiogelwch a weithredir yn y cnewyllyn Linux sy'n caniatáu i ddatblygwyr hidlo rhai galwadau system. Er bod Seccomp yn debyg o ran galluoedd i Linux, mae ei allu i reoli rhai galwadau system yn ei gwneud yn llawer mwy hyblyg o'i gymharu â nhw.
Nid yw nodweddion Seccomp a Linux yn annibynnol ar ei gilydd ac fe'u defnyddir yn aml gyda'i gilydd i elwa o'r ddau ddull. Er enghraifft, efallai y byddwch am roi'r gallu CAP_NET_ADMIN i broses ond peidio â chaniatáu iddi dderbyn cysylltiadau soced, gan rwystro'r derbyn a derbyn4 galwadau system.
Mae'r dull hidlo Seccomp yn seiliedig ar hidlwyr BPF sy'n gweithredu yn y modd SECCOMP_MODE_FILTER, ac mae hidlo galwadau system yn cael ei berfformio yn yr un modd ag ar gyfer pecynnau.
Mae hidlwyr Seccomp yn cael eu llwytho gan ddefnyddio prctl trwy'r gweithrediad PR_SET_SECCOMP. Mae'r hidlwyr hyn ar ffurf rhaglen BPF a weithredir ar gyfer pob pecyn Seccomp a gynrychiolir gan y strwythur seccomp_data. Mae'r strwythur hwn yn cynnwys y saernïaeth gyfeirio, pwyntydd i gyfarwyddiadau prosesydd ar adeg yr alwad system, ac uchafswm o chwe dadl galwad system, wedi'u mynegi fel uint64.
Dyma sut olwg sydd ar y strwythur seccomp_data o'r cod ffynhonnell cnewyllyn yn y ffeil linux/seccomp.h:
struct seccomp_data {
int nr;
__u32 arch;
__u64 instruction_pointer;
__u64 args[6];
};
Fel y gwelwch o'r strwythur hwn, gallwn hidlo yn ôl galwad y system, ei ddadleuon, neu gyfuniad o'r ddau.
Ar ôl derbyn pob pecyn Seccomp, rhaid i'r hidlydd berfformio prosesu i wneud penderfyniad terfynol a dweud wrth y cnewyllyn beth i'w wneud nesaf. Mynegir y penderfyniad terfynol gan un o'r gwerthoedd dychwelyd (codau statws).
- SECCOMP_RET_KILL_PROCESS - yn lladd y broses gyfan yn syth ar ôl hidlo galwad system nad yw'n cael ei weithredu oherwydd hyn.
- SECCOMP_RET_KILL_THREAD - yn terfynu'r edefyn cyfredol yn syth ar ôl hidlo galwad system nad yw'n cael ei weithredu oherwydd hyn.
— SECCOMP_RET_KILL — alias ar gyfer SECCOMP_RET_KILL_THREAD, wedi'i adael ar gyfer cydweddoldeb yn ôl.
- SECCOMP_RET_TRAP - gwaherddir galwad system, ac anfonir signal SIGSYS (Galwad System Drwg) i'r dasg sy'n ei alw.
- SECCOMP_RET_ERRNO - Nid yw'r alwad system yn cael ei gweithredu, ac mae rhan o werth dychwelyd hidlydd SECCOMP_RET_DATA yn cael ei drosglwyddo i ofod defnyddiwr fel y gwerth errno. Yn dibynnu ar achos y gwall, dychwelir gwahanol werthoedd errno. Darperir rhestr o rifau gwall yn yr adran nesaf.
- SECCOMP_RET_TRACE - Fe'i defnyddir i hysbysu'r olrhain ptrace gan ddefnyddio - PTRACE_O_TRACESECCOMP i ryng-gipio pan weithredir galwad system i weld a rheoli'r broses honno. Os nad yw olrheiniwr wedi'i gysylltu, dychwelir gwall, gosodir errno i -ENOSYS, ac ni weithredir galwad y system.
- SECCOMP_RET_LOG - mae'r alwad system wedi'i datrys a'i chofnodi.
- SECCOMP_RET_ALLOW - yn syml, caniateir galwad system.
Mae ptrace yn alwad system i weithredu mecanweithiau olrhain mewn proses o'r enw tracee, gyda'r gallu i fonitro a rheoli gweithrediad y broses. Gall y rhaglen olrhain ddylanwadu'n effeithiol ar weithrediad ac addasu cofrestrau cof tracee. Yng nghyd-destun Seccomp, defnyddir ptrace pan gaiff ei sbarduno gan god statws SECCOMP_RET_TRACE, felly gall yr olrheiniwr atal galwad y system rhag gweithredu a gweithredu ei resymeg ei hun.
Gwallau Seccomp
O bryd i'w gilydd, wrth weithio gyda Seccomp, byddwch yn dod ar draws gwallau amrywiol, sy'n cael eu nodi gan werth dychwelyd o'r math SECCOMP_RET_ERRNO. I riportio gwall, bydd galwad y system seccomp yn dychwelyd -1 yn lle 0.
Mae'r gwallau canlynol yn bosibl:
- HYFFORDDIANT - Ni chaniateir i'r galwr wneud galwad system. Mae hyn fel arfer yn digwydd oherwydd nad oes ganddo breintiau CAP_SYS_ADMIN neu nid yw no_new_privs wedi'i osod gan ddefnyddio prctl (byddwn yn siarad am hyn yn nes ymlaen);
— EFAULT — nid oes gan y dadleuon a basiwyd (args yn y strwythur seccomp_data) gyfeiriad dilys;
- EINVAL - gall fod pedwar rheswm yma:
-mae'r gweithrediad y gofynnwyd amdano yn anhysbys neu heb ei gefnogi gan y cnewyllyn yn y ffurfweddiad cyfredol;
- nid yw'r baneri penodedig yn ddilys ar gyfer y gweithrediad y gofynnwyd amdano;
-operation yn cynnwys BPF_ABS, ond mae problemau gyda'r gwrthbwyso penodedig, a all fod yn fwy na maint y strwythur seccomp_data;
- mae nifer y cyfarwyddiadau a drosglwyddir i'r hidlydd yn fwy na'r uchafswm;
— ENOMEM - dim digon o gof i weithredu'r rhaglen;
- EOPNOTSUPP - dangosodd y gweithrediad fod y weithred ar gael gyda SECCOMP_GET_ACTION_AVAIL, ond nid yw'r cnewyllyn yn cefnogi dychweliadau mewn dadleuon;
— ESRCH — digwyddodd problem wrth gydamseru ffrwd arall;
- ENOSYS - Nid oes unrhyw olrheiniwr ynghlwm wrth y weithred SECCOMP_RET_TRACE.
Mae prctl yn alwad system sy'n caniatáu i raglen gofod defnyddiwr drin (gosod a chael) agweddau penodol ar broses, megis dycnwch beit, enwau edau, modd cyfrifiannu diogel (Seccomp), breintiau, digwyddiadau Perf, ac ati.
Efallai y bydd Seccomp yn ymddangos fel technoleg blwch tywod i chi, ond nid yw. Cyfleustodau yw Seccomp sy'n galluogi defnyddwyr i ddatblygu mecanwaith blwch tywod. Nawr, gadewch i ni edrych ar sut mae rhaglenni rhyngweithio defnyddwyr yn cael eu creu gan ddefnyddio hidlydd a elwir yn uniongyrchol gan alwad system Seccomp.
Enghraifft Hidlo Seccomp BPF
Yma byddwn yn dangos sut i gyfuno'r ddau gam gweithredu a drafodwyd yn gynharach, sef:
— byddwn yn ysgrifennu rhaglen Seccomp BPF, a fydd yn cael ei defnyddio fel hidlydd gyda chodau dychwelyd gwahanol yn dibynnu ar y penderfyniadau a wneir;
— llwythwch yr hidlydd gan ddefnyddio prctl.
Yn gyntaf mae angen penawdau arnoch o'r llyfrgell safonol a'r cnewyllyn Linux:
#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>
Cyn rhoi cynnig ar yr enghraifft hon, rhaid i ni sicrhau bod y cnewyllyn yn cael ei lunio gyda CONFIG_SECCOMP a CONFIG_SECCOMP_FILTER set i y. Ar beiriant gweithio gallwch wirio hyn fel hyn:
cat /proc/config.gz| zcat | grep -i CONFIG_SECCOMP
Mae gweddill y cod yn swyddogaeth install_filter dwy ran. Mae'r rhan gyntaf yn cynnwys ein rhestr o gyfarwyddiadau hidlo BPF:
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),
};
Gosodir y cyfarwyddiadau gan ddefnyddio'r macros BPF_STMT a BPF_JUMP a ddiffinnir yn y ffeil linux/filter.h.
Gadewch i ni fynd drwy'r cyfarwyddiadau.
- BPF_STMT(BPF_LD + BPF_W + BPF_ABS (offsetof(struct seccomp_data, bwa)))) - mae'r system yn llwytho ac yn cronni o BPF_LD ar ffurf y gair BPF_W, mae data pecyn wedi'i leoli ar wrthbwyso sefydlog BPF_ABS.
- BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, bwa, 0, 3) - gwirio gan ddefnyddio BPF_JEQ a yw gwerth pensaernïaeth yn y cysonyn cronadur BPF_K yn hafal i bwa. Os felly, mae'n neidio ar wrthbwyso 0 i'r cyfarwyddyd nesaf, fel arall yn neidio ar wrthbwyso 3 (yn yr achos hwn) i daflu gwall oherwydd nad yw bwa yn cyfateb.
- BPF_STMT(BPF_LD + BPF_W + BPF_ABS (offsetof(struct seccomp_data, nr))) - Yn llwytho ac yn cronni o BPF_LD ar ffurf y gair BPF_W, sef rhif galwad y system sydd wedi'i gynnwys yn y gwrthbwyso sefydlog o BPF_ABS.
— BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, nr, 0, 1) — yn cymharu rhif galwad y system â gwerth y newidyn nr. Os ydynt yn gyfartal, yn symud ymlaen i'r cyfarwyddyd nesaf ac yn analluogi'r alwad system, fel arall yn caniatáu galwad system gyda SECCOMP_RET_ALLOW.
- BPF_STMT(BPF_RET + BPF_K, SECCOMP_RET_ERRNO | (gwall & SECCOMP_RET_DATA)) - yn terfynu'r rhaglen gyda BPF_RET ac o ganlyniad yn cynhyrchu gwall SECCOMP_RET_ERRNO gyda'r rhif o'r newidyn gwall.
- BPF_STMT(BPF_RET + BPF_K, SECCOMP_RET_ALLOW) - yn terfynu'r rhaglen gyda BPF_RET ac yn caniatáu i'r alwad system gael ei gweithredu gan ddefnyddio SECCOMP_RET_ALLOW.
SECCOMP YN CBPF
Efallai eich bod yn pendroni pam y defnyddir rhestr o gyfarwyddiadau yn lle gwrthrych ELF wedi'i lunio neu raglen C a luniwyd gan JIT.Mae dau reswm am hyn.
• Yn gyntaf, mae Seccomp yn defnyddio cBPF (BPF clasurol) ac nid eBPF, sy'n golygu: nid oes ganddo gofrestrau, ond dim ond cronadur i storio canlyniad y cyfrifiad olaf, fel y gwelir yn yr enghraifft.
• Yn ail, mae Seccomp yn derbyn pwyntydd i amrywiaeth o gyfarwyddiadau BPF yn uniongyrchol a dim byd arall. Mae'r macros rydyn ni wedi'u defnyddio yn helpu i nodi'r cyfarwyddiadau hyn mewn ffordd sy'n gyfeillgar i raglenwyr.
Os oes angen mwy o help arnoch i ddeall y gwasanaeth hwn, ystyriwch y ffuggod sy'n gwneud yr un peth:
if (arch != AUDIT_ARCH_X86_64) {
return SECCOMP_RET_ALLOW;
}
if (nr == __NR_write) {
return SECCOMP_RET_ERRNO;
}
return SECCOMP_RET_ALLOW;
Ar ôl diffinio'r cod hidlo yn y strwythur socket_filter, mae angen i chi ddiffinio sock_fprog sy'n cynnwys y cod a hyd yr hidlydd a gyfrifwyd. Mae angen y strwythur data hwn fel dadl dros ddatgan bod y broses yn rhedeg yn ddiweddarach:
struct sock_fprog prog = {
.len = (unsigned short)(sizeof(filter) / sizeof(filter[0])),
.filter = filter,
};
Dim ond un peth sydd ar ôl i'w wneud yn y swyddogaeth install_filter - llwythwch y rhaglen ei hun! I wneud hyn, rydym yn defnyddio prctl, gan gymryd PR_SET_SECOMP fel opsiwn i fynd i mewn i fodd cyfrifiadura diogel. Yna rydyn ni'n dweud wrth y modd i lwytho'r hidlydd gan ddefnyddio SECCOMP_MODE_FILTER, sydd wedi'i gynnwys yn y newidyn prog math sock_fprog:
if (prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, &prog)) {
perror("prctl(PR_SET_SECCOMP)");
return 1;
}
return 0;
}
Yn olaf, gallwn ddefnyddio ein swyddogaeth install_filter, ond cyn hynny mae angen i ni ddefnyddio prctl i osod PR_SET_NO_NEW_PRIVS ar gyfer y gweithrediad cyfredol a thrwy hynny osgoi'r sefyllfa lle mae prosesau plentyn yn derbyn mwy o freintiau na'u rhieni. Gyda hyn, gallwn wneud y galwadau prctl canlynol yn y swyddogaeth install_filter heb gael hawliau gwraidd.
Nawr gallwn alw'r swyddogaeth install_filter. Gadewch i ni rwystro pob galwad system ysgrifennu sy'n ymwneud â phensaernïaeth X86-64 a rhoi caniatâd yn unig sy'n rhwystro pob ymgais. Ar ôl gosod yr hidlydd, rydym yn parhau i weithredu gan ddefnyddio'r ddadl gyntaf:
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]);
}
Gadewch i ni ddechrau. I lunio ein rhaglen gallwn ddefnyddio naill ai clang neu gcc, y naill ffordd neu'r llall, dim ond llunio'r ffeil main.c heb opsiynau arbennig:
clang main.c -o filter-write
Fel y nodwyd, rydym wedi rhwystro pob cofnod yn y rhaglen. I brofi hyn mae angen rhaglen sy'n allbynnu rhywbeth - mae'n ymddangos fel ymgeisydd da. Dyma sut mae hi fel arfer yn ymddwyn:
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
Gwych! Dyma sut olwg sydd ar ddefnyddio ein rhaglen lapio: Yn syml, rydyn ni'n pasio'r rhaglen rydyn ni am ei phrofi fel y ddadl gyntaf:
./filter-write "ls -la"
Pan gaiff ei gweithredu, mae'r rhaglen hon yn cynhyrchu allbwn hollol wag. Fodd bynnag, gallwn ddefnyddio strace i weld beth sy'n digwydd:
strace -f ./filter-write "ls -la"
Mae canlyniad y gwaith yn cael ei fyrhau'n fawr, ond mae'r rhan gyfatebol ohono yn dangos bod cofnodion wedi'u rhwystro â'r gwall EPERM - yr un un ag y gwnaethom ei ffurfweddu. Mae hyn yn golygu nad yw'r rhaglen yn allbynnu dim oherwydd na all gael mynediad i'r alwad system ysgrifennu:
[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)
Nawr rydych chi'n deall sut mae Seccomp BPF yn gweithio ac mae gennych chi syniad da o'r hyn y gallwch chi ei wneud ag ef. Ond oni fyddech chi'n hoffi cyflawni'r un peth gydag eBPF yn lle cBPF i harneisio ei bŵer llawn?
Wrth feddwl am raglenni eBPF, mae'r rhan fwyaf o bobl yn meddwl eu bod yn eu hysgrifennu ac yn eu llwytho â breintiau gweinyddwr. Er bod y datganiad hwn yn gyffredinol wir, mae'r cnewyllyn yn gweithredu set o fecanweithiau i amddiffyn gwrthrychau eBPF ar wahanol lefelau. Gelwir y mecanweithiau hyn yn drapiau LSM BPF.
Trapiau LSM BPF
Er mwyn darparu monitro pensaernïaeth-annibynnol o ddigwyddiadau system, mae LSM yn gweithredu'r cysyniad o drapiau. Mae galwad bachyn yn dechnegol debyg i alwad system, ond mae'n annibynnol ar y system ac wedi'i hintegreiddio â'r seilwaith. Mae LSM yn darparu cysyniad newydd lle gall haen tynnu dŵr helpu i osgoi problemau a wynebir wrth ddelio â galwadau system ar wahanol bensaernïaeth.
Ar adeg ysgrifennu, mae gan y cnewyllyn saith bachau sy'n gysylltiedig â rhaglenni BPF, a SELinux yw'r unig LSM adeiledig sy'n eu gweithredu.
Mae'r cod ffynhonnell ar gyfer y trapiau wedi'i leoli yn y goeden cnewyllyn yn y ffeil cynnwys/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);
Bydd pob un ohonynt yn cael eu galw ar wahanol gamau gweithredu:
— security_bpf — yn cynnal gwiriad cychwynnol o alwadau system BPF a weithredwyd;
- security_bpf_map - yn gwirio pan fydd y cnewyllyn yn dychwelyd disgrifydd ffeil ar gyfer y map;
- security_bpf_prog - yn gwirio pan fydd y cnewyllyn yn dychwelyd disgrifydd ffeil ar gyfer y rhaglen eBPF;
— security_bpf_map_alloc — yn gwirio a yw'r maes diogelwch y tu mewn i fapiau BPF wedi'i gychwyn;
- security_bpf_map_free - yn gwirio a yw'r maes diogelwch wedi'i glirio y tu mewn i fapiau BPF;
— security_bpf_prog_alloc — yn gwirio a yw'r maes diogelwch wedi'i gychwyn y tu mewn i raglenni BPF;
- security_bpf_prog_free - yn gwirio a yw'r maes diogelwch wedi'i glirio y tu mewn i raglenni BPF.
Nawr, o weld hyn i gyd, rydym yn deall: y syniad y tu ôl i atalwyr LSM BPF yw y gallant ddarparu amddiffyniad i bob gwrthrych eBPF, gan sicrhau mai dim ond y rhai sydd â'r breintiau priodol sy'n gallu cyflawni gweithrediadau ar gardiau a rhaglenni.
Crynodeb
Nid yw diogelwch yn rhywbeth y gallwch chi ei roi ar waith mewn ffordd sy'n addas i bawb ar gyfer popeth rydych chi am ei amddiffyn. Mae'n bwysig gallu diogelu systemau ar wahanol lefelau ac mewn gwahanol ffyrdd. Credwch neu beidio, y ffordd orau o sicrhau system yw trefnu gwahanol lefelau o amddiffyniad o wahanol swyddi, fel nad yw lleihau diogelwch un lefel yn caniatáu mynediad i'r system gyfan. Mae'r datblygwyr craidd wedi gwneud gwaith gwych o roi set o wahanol haenau a phwyntiau cyffwrdd i ni. Gobeithiwn ein bod wedi rhoi dealltwriaeth dda i chi o beth yw haenau a sut i ddefnyddio rhaglenni BPF i weithio gyda nhw.
Am awduron
David Calavera yw'r GTG yn Netlify. Bu’n gweithio ym maes cymorth Docker a chyfrannodd at ddatblygu offer Runc, Go a BCC, yn ogystal â phrosiectau ffynhonnell agored eraill. Yn adnabyddus am ei waith ar brosiectau Docker a datblygiad ecosystem ategyn Docker. Mae David yn angerddol iawn am graffiau fflam ac mae bob amser yn ceisio optimeiddio perfformiad.
Lorenzo Fontana yn gweithio ar y tîm ffynhonnell agored yn Sysdig, lle mae'n canolbwyntio'n bennaf ar Falco, prosiect Cloud Native Computing Foundation sy'n darparu diogelwch amser rhedeg cynhwysydd a chanfod anghysondebau trwy fodiwl cnewyllyn ac eBPF. Mae'n angerddol am systemau gwasgaredig, rhwydweithio wedi'i ddiffinio gan feddalwedd, y cnewyllyn Linux, a dadansoddi perfformiad.
» Ceir rhagor o fanylion am y llyfr yn
»
»
Ar gyfer Khabrozhiteley gostyngiad o 25% gan ddefnyddio cwpon - Linux
Ar ôl talu'r fersiwn papur o'r llyfr, anfonir llyfr electronig trwy e-bost.
Ffynhonnell: hab.com