Pirtûka "BPF ji bo Çavdêriya Linux"

Pirtûka "BPF ji bo Çavdêriya Linux"Silav, niştecîhên Xabro! Makîneya virtual BPF yek ji hêmanên herî girîng ên kernel Linux e. Bikaranîna wê ya rast dê destûrê bide endezyarên pergalê ku xeletiyan bibînin û pirsgirêkên herî tevlihev jî çareser bikin. Hûn ê fêr bibin ka meriv çawa bernameyên ku çavdêrîkirin û guheztina tevgerê kernelê dike, çawa bi ewlehî kodê ji bo şopandina bûyerên di kernelê de bicîh dikin, û hêj bêtir binivîsin. David Calavera û Lorenzo Fontana dê ji we re bibin alîkar ku hûn hêza BPF vekin. Zanîna xwe ya xweşbîniya performansê, torê, ewlehiyê berfireh bikin. - BPF-ê bikar bînin da ku tevgerê kernel Linux bişopînin û biguhezînin. - Kodê derzînin da ku bi ewlehî bûyerên kernelê bişopînin bêyî ku hûn kernel ji nû ve berhev bikin an pergalê ji nû ve bidin destpêkirin. - Di C, Go an Python de mînakên kodên hêsan bikar bînin. - Bi xwedîkirina çerxa jiyanê ya bernameya BPF ve kontrol bikin.

Ewlekariya Kernel Linux, Taybetmendiyên Wê û Seccomp

BPF rêgezek hêzdar peyda dike ku kernel bê qurbankirina aramî, ewlehî, an leza xwe dirêj bike. Ji ber vê yekê, pêşdebirên kernel fikirîn ku ew ê ramanek baş be ku meriv pirrengiya wê bikar bîne da ku veqetandina pêvajoyê li Seccomp bi sepandina fîlterên Seccomp ên ku ji hêla bernameyên BPF ve têne piştgirî kirin, ku wekî Seccomp BPF jî tê zanîn, baştir bikin. Di vê beşê de em ê rave bikin ka Seccomp çi ye û çawa tê bikar anîn. Dûv re hûn ê fêr bibin ka meriv çawa fîlterên Seccomp bi karanîna bernameyên BPF dinivîse. Piştî wê, em ê li çengên BPF-ya çêkirî yên ku di nav kernelê de ji bo modulên ewlehiya Linux-ê ve girêdayî ne binêrin.

Modulên Ewlekariya Linux (LSM) çarçoveyek e ku komek fonksiyonan peyda dike ku dikare were bikar anîn da ku modelên ewlehiyê yên cihêreng bi rengek standardkirî bicîh bîne. LSM dikare rasterast di dara çavkaniya kernelê de, wekî Apparmor, SELinux û Tomoyo, were bikar anîn.

Ka em bi nîqaşkirina kapasîteyên Linux-ê dest pê bikin.

Taybetmendiyên

Esasê kapasîteyên Linux ev e ku hûn hewce ne ku destûrek pêvajoyek bêdestûr bidin da ku karek diyar bike, lê bêyî ku suid ji bo wê armancê bikar bîne, an wekî din pêvajoyê îmtiyaz bike, îhtîmala êrîşê kêm bike û destûrê bide pêvajoyê ku hin karan pêk bîne. Mînakî, heke serîlêdana we pêdivî ye ku portek îmtiyaz veke, bêje 80, li şûna ku pêvajoyê wekî root bimeşîne, hûn dikarin bi hêsanî jê re kapasîteya CAP_NET_BIND_SERVICE bidin.

Bernameyek Go bi navê main.go bifikirin:

package main
import (
            "net/http"
            "log"
)
func main() {
     log.Fatalf("%v", http.ListenAndServe(":80", nil))
}

Ev bername serverek HTTP-ê li porta 80-ê (ev portek îmtiyaz e) re xizmet dike. Bi gelemperî em wê tavilê piştî berhevkirinê dimeşînin:

$ go build -o capabilities main.go
$ ./capabilities

Lêbelê, ji ber ku em îmtiyazên root nadin, ev kod dê di girêdana portê de xeletiyek bavêje:

2019/04/25 23:17:06 listen tcp :80: bind: permission denied
exit status 1

capsh (rêveberê şêlê) amûrek e ku şêlê bi komek kapasîteyên taybetî dimeşîne.

Di vê rewşê de, wekî ku berê jî behs kir, li şûna ku hûn mafên root ên bêkêmasî bidin, hûn dikarin girêdana portê ya îmtiyazê bi peydakirina kapasîteya cap_net_bind_service digel her tiştê ku berê di bernameyê de heye çalak bikin. Ji bo kirina vê yekê, em dikarin bernameya xwe bi capsh vekin:

# 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"

Werin em hinekî vê tîmê fam bikin.

  • capsh - capsh wekî şêlê bikar bînin.
  • —caps='cap_net_bind_service+eip cap_setpcap,cap_setuid,cap_setgid+ep' - ji ber ku em hewce ne ku bikarhêner biguherînin (em naxwazin wekî root bixebitin), em ê cap_net_bind_service û şiyana ku em bi rastî nasnameya bikarhênerê biguhezînin diyar bikin. root ji kesî re, ango cap_setuid û cap_setgid.
  • —keep=1 — em dixwazin dema ku ji hesabê root veguherînin kapasîteyên sazkirî biparêzin.
  • —user="tu kes" - bikarhênerê dawî yê ku bernameyê dimeşîne dê kes nebe.
  • —addamb=cap_net_bind_service - piştî guheztina ji moda root paqijkirina kapasîteyên têkildar saz bikin.
  • - -c "./kapasîteyên" - tenê bernameyê bimeşînin.

Kapasîteyên pêvekirî celebek taybetî ya kapasîteyê ne ku ji hêla bernameyên zarokan ve têne mîras kirin dema ku bernameya heyî wan bi karanîna execve() dimeşîne. Tenê kapasîteyên ku destûr têne girêdan, an bi gotinek din, wekî kapasîteyên hawirdorê, dikarin werin mîras kirin.

Bê guman hûn meraq dikin ku +eip piştî ku kapasîteyê di vebijarka --caps de diyar dike tê çi wateyê. Van alayan ji bo destnîşankirina kapasîteyê têne bikar anîn:

-divê were aktîfkirin (p);

-ji bo bikaranînê heye (e);

-dikare ji hêla pêvajoyên zarokan ve were mîras kirin (i).

Ji ber ku em dixwazin cap_net_bind_service bikar bînin, divê em vê yekê bi ala e-yê bikin. Dûv re em ê di fermanê de dest bi şêlê bikin. Ev ê kapasîteyên binary bimeşîne û pêdivî ye ku em wê bi ala i nîşan bikin. Di dawiyê de, em dixwazin ku taybetmendî were çalak kirin (me vê yekê bêyî guhertina UID-ê kir) bi p. Ew mîna cap_net_bind_service+eip xuya dike.

Hûn dikarin encamê bi karanîna ss kontrol bikin. Werin em derketinê hinekî kurt bikin da ku li ser rûpelê cîh bigrin, lê ew ê porta têkildar û ID bikarhênerê ji bilî 0, di vê rewşê de 65 nîşan bide:

# ss -tulpn -e -H | cut -d' ' -f17-
128 *:80 *:*
users:(("capabilities",pid=30040,fd=3)) uid:65534 ino:11311579 sk:2c v6only:0

Di vê nimûneyê de me capsh bikar anî, lê hûn dikarin bi karanîna libcap şêlê binivîsin. Ji bo bêtir agahdarî, meriv 3 libcap bibînin.

Dema ku bernameyan dinivîsin, pir caran pêşdebir bi hemî taybetmendiyên ku bernameyê di dema xebitandinê de hewce dike ji pêş de nizane; Wekî din, dibe ku ev taybetmendî di guhertoyên nû de biguhezin.

Ji bo ku hûn kapasîteyên bernameya xwe baştir fam bikin, em dikarin amûra jêhatî ya BCC, ku kprobe ji bo fonksiyona kernel cap_capable saz dike, bigirin:

/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

Em dikarin heman tiştî bi karanîna bpftrace bi kprobeya yek-liner di fonksiyona kernelê ya cap_capable de bi dest bixin:

bpftrace -e 
   'kprobe:cap_capable {
      time("%H:%M:%S ");
      printf("%-6d %-6d %-16s %-4d %dn", uid, pid, comm, arg2, arg3);
    }' 
    | grep -i capabilities

Ger kapasîteyên bernameya me piştî kprobe werin çalak kirin dê tiştek mîna jêrîn derxe:

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

Stûna pêncemîn kapasîteyên ku pêvajo hewce dike ne, û ji ber ku ev encam bûyerên ne-kontrolkirî dihewîne, em hemî kontrolên ne-kontrolkirî û di dawiyê de kapasîteya hewce bi ala kontrolê (di encam de ya dawîn de) wekî 1 dibînin. yeka ku em jê re eleqedar in CAP_NET_BIND_SERVICE e, ew di koda çavkaniya kernelê de wekî domdarek di pelê de tê pênase kirin ku têde/uapi/linux/ability.h bi nasnav 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">

Kapasîteyên bi gelemperî di dema xebitandinê de ji bo konteynerên wekî runC an Docker têne çalak kirin da ku rê bidin wan ku di moda nedesthilatdar de bixebitin, lê ew tenê destûr didin kapasîteyên ku ji bo xebitandina pir serlêdanan hewce ne. Dema ku serîlêdanek hin kapasîteyên hewce dike, Docker dikare wan bi karanîna --cap-add peyda bike:

docker run -it --rm --cap-add=NET_ADMIN ubuntu ip link add dummy0 type dummy

Ev ferman dê kapasîteya CAP_NET_ADMIN bide konteynerê, bihêle ku ew girêdanek torê mîheng bike da ku pêwendiya dummy0 zêde bike.

Beşa din nîşan dide ka meriv çawa taybetmendiyên wekî fîlterkirin bikar tîne, lê teknîkek cûda bikar tîne ku destûrê dide me ku em bi bernameyî fîlterên xwe bicîh bikin.

Seccomp

Seccomp wekî Secure Computing radiweste û qatek ewlehiyê ye ku di kernel Linux de hatî bicîh kirin ku dihêle pêşdebiran hin bangên pergalê fîlter bikin. Her çend Seccomp di kapasîteyên Linux-ê de berawirdî ye jî, jêhatiya wê ya birêvebirina hin bangên pergalê wê li gorî wan pir maqûltir dike.

Taybetmendiyên Seccomp û Linux ji hev veqetandî ne û bi gelemperî bi hev re têne bikar anîn da ku ji her du nêzîkatiyan sûd werbigirin. Mînakî, dibe ku hûn bixwazin pêvajoyek kapasîteya CAP_NET_ADMIN bidin lê nehêlin ku ew girêdanên soketê qebûl bike, bangên pergalê qebûl bike û qebûl bike4 asteng bike.

Rêbaza parzûna Seccomp li ser fîlterên BPF-ê yên ku di moda SECCOMP_MODE_FILTER de dixebitin ve girêdayî ye, û fîlterkirina banga pergalê bi heman awayê ku ji bo pakêtan tête kirin.

Parzûnên Seccomp bi karanîna prctl bi operasyona PR_SET_SECCOMP têne barkirin. Van parzûnan forma bernameyek BPF-ê digirin ku ji bo her pakêtek Seccomp-ê ku ji hêla avahiya seccomp_data ve hatî destnîşan kirin ve têne darve kirin. Ev avahî mîmariya referansê, nîşanek rêwerzên pêvajoyê di dema banga pergalê de, û herî zêde şeş argumanên banga pergalê, ku wekî uint64 têne diyar kirin, vedihewîne.

Ev e ku avahiya seccomp_data ji koda çavkaniya kernelê ya di pelê linux/seccomp.h de xuya dike:

struct seccomp_data {
int nr;
      __u32 arch;
      __u64 instruction_pointer;
      __u64 args[6];
};

Wekî ku hûn ji vê strukturê dibînin, em dikarin ji hêla banga pergalê, argumanên wê, an jî tevliheviya her duyan ve fîlter bikin.

Piştî wergirtina her pakêtek Seccomp, parzûn divê pêvajoyê pêk bîne da ku biryara dawîn bide û ji kernelê re bêje ka paşê çi bike. Biryara dawîn ji hêla yek ji nirxên vegerandinê (kodên statûyê) ve tête diyar kirin.

- SECCOMP_RET_KILL_PROCESS - piştî fîlterkirina bangek pergalê ya ku ji ber vê yekê nayê darve kirin, tavilê pêvajoyê dikuje.

- SECCOMP_RET_KILL_THREAD - piştî fîlterkirina bangek pergalê ya ku ji ber vê yekê nayê darve kirin, tavilê mijara heyî bi dawî dike.

- SECCOMP_RET_KILL - navekî ji bo SECCOMP_RET_KILL_THREAD, ji bo lihevhatina paşverû hiştin.

- SECCOMP_RET_TRAP - banga pergalê qedexe ye, û sînyala SIGSYS (Banga Sîstema Xirab) ji peywira ku jê re tê gotin tê şandin.

- SECCOMP_RET_ERRNO - Banga pergalê nayê pêkanîn, û beşek ji nirxa vegerê ya parzûna SECCOMP_RET_DATA wekî nirxa xeletî ji cîhê bikarhêner re derbas dibe. Bi sedema xeletiyê ve girêdayî, nirxên cûda yên xelet têne vegerandin. Di beşa pêş de navnîşek hejmarên xeletiyê tê pêşkêş kirin.

- SECCOMP_RET_TRACE - Ji bo agahdarkirina şopgerê ptrace bi kar tê bikar anîn - PTRACE_O_TRACESECCOMP ji bo ku gava bangek pergalê tê darve kirin da ku wê pêvajoyê bibîne û kontrol bike. Ger şopgerek neyê girêdan, xeletiyek tê vegerandin, errno li -ENOSYS tê danîn, û banga pergalê nayê kirin.

- SECCOMP_RET_LOG - banga pergalê tê çareser kirin û têketin.

- SECCOMP_RET_ALLOW - banga pergalê bi hêsanî tê destûr kirin.

ptrace bangek pergalê ye ji bo pêkanîna mekanîzmayên şopandinê di pêvajoyek bi navê tracee de, bi şiyana şopandin û kontrolkirina pêkanîna pêvajoyê. Bernameya şopandinê dikare bi bandor li ser darvekirinê bandor bike û tomarên bîranîna tracee biguhezîne. Di çarçoveya Seccomp de, ptrace dema ku ji hêla koda statûya SECCOMP_RET_TRACE ve tê destnîşan kirin tê bikar anîn, ji ber vê yekê şopger dikare pêşî li pêkanîna banga pergalê bigire û mantiqa xwe bicîh bîne.

Çewtiyên Seccomp

Dem bi dem, dema ku bi Seccomp re dixebitin, hûn ê bi xeletiyên cihêreng re rû bi rû bimînin, ku ji hêla nirxek vegerê ya celebê SECCOMP_RET_ERRNO ve têne nas kirin. Ji bo raporkirina xeletiyek, banga pergala seccomp dê li şûna 1-ê -0 vegere.

Çewtiyên jêrîn mimkun in:

- BÊKIRIN - Destûr nayê dayîn ku bangker bangek pergalê bike. Ev bi gelemperî diqewime ji ber ku ew ne xwediyê mafên CAP_SYS_ADMIN ne an jî no_new_privs bi karanîna prctl nayê danîn (em ê paşê li ser vê biaxivin);

- EFAULT - argumanên derbasbûyî (args di avahiya seccomp_data de) navnîşek derbasdar nînin;

- EINVAL - Li vir çar sedem hene:

-Operasyona tê xwestin nenas e an ji hêla kernelê ve di veavakirina heyî de nayê piştgirî kirin;

-alên diyarkirî ji bo operasyona daxwazkirî ne derbasdar in;

-xebata BPF_ABS-ê dihewîne, lê di navberê de pirsgirêk hene, ku dibe ku ji mezinahiya avahiya seccomp_data derbas bibe;

-hejmara talîmatên ku ji parzûnê re derbas dibin ji herî zêde derbas dibe;

- ENOMEM - ne bes bîra ji bo pêkanîna bernameyê;

- EOPNOTSUPP - operasyonê destnîşan kir ku bi SECCOMP_GET_ACTION_AVAIL çalakî berdest bû, lê kernel vegerên di argumanan de piştgirî nake;

- ESRCH - pirsgirêkek di dema hevdengkirina çemek din de derket;

- ENOSYS - Ti şopgerek bi çalakiya SECCOMP_RET_TRACE ve girêdayî nîne.

prctl bangek pergalê ye ku destûrê dide bernameyek cîhê bikarhêner ku aliyên taybetî yên pêvajoyek, wek endannessiya byte, navên mijarê, moda hesabkirina ewledar (Seccomp), îmtiyaz, bûyerên Perf, hwd, manîpule bike (saz bike û bistîne).

Dibe ku Seccomp ji we re wekî teknolojiyek sandbox xuya bike, lê ew ne wusa ye. Seccomp amûrek e ku destûrê dide bikarhêneran ku mekanîzmayek sandbox pêşve bibin. Naha em binihêrin ka bernameyên danûstendina bikarhêner çawa bi karanîna parzûnek ku rasterast ji hêla banga pergala Seccomp ve tê gotin têne afirandin.

Mînaka Parzûna BPF Seccomp

Li vir em ê destnîşan bikin ka meriv çawa her du kiryarên ku berê hatine nîqaş kirin, bi navgîniyê ve tê hev kirin:

- em ê bernameyek Seccomp BPF binivîsin, ku li gorî biryarên hatine girtin dê wekî parzûnek bi kodên vegerê yên cihêreng were bikar anîn;

- Parzûnê bi karanîna prctl bar bikin.

Pêşî hûn hewceyê sernivîsên ji pirtûkxaneya standard û kernel 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>

Berî ku em vê nimûneyê biceribînin, divê em piştrast bikin ku kernel bi CONFIG_SECCOMP û CONFIG_SECCOMP_FILTER li ser y hatîye berhev kirin. Li ser makîneyek xebitandinê hûn dikarin vî rengî kontrol bikin:

cat /proc/config.gz| zcat | grep -i CONFIG_SECCOMP

Koda mayî fonksiyonek install_filtera du-beşî ye. Beşa yekem navnîşa me ya rêwerzên fîlterkirina BPF-ê vedihewîne:

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),
  };

Rêbername bi karanîna makroyên BPF_STMT û BPF_JUMP yên ku di pelê linux/filter.h de hatine destnîşankirin têne danîn.
Werin em bi rêwerzan derbas bibin.

- BPF_STMT(BPF_LD + BPF_W + BPF_ABS (offsetof (struct seccomp_data, arch))) - Pergal ji BPF_LD di forma peyva BPF_W de bar dike û berhev dike, daneya pakêtê li cîhek nermalava BPF_ABS-ê ye.

- BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, arch, 0, 3) - bi karanîna BPF_JEQ kontrol dike ka nirxa mîmarî ya di berdewamiya berhevkarê BPF_K de bi kemerê re wekhev e. Ger wusa be, ji 0-ê berbi talîmata din ve diçe, wekî din li ser 3-yê (di vê rewşê de) dikeve da ku xeletiyek bavêje ji ber ku arşîv li hev nayê.

- BPF_STMT(BPF_LD + BPF_W + BPF_ABS (offsetof(struct seccomp_data, nr))) - Ji BPF_LD di forma peyva BPF_W de, ku jimareya banga pergalê ye ku di navberdana sabît a BPF_ABS de tê de, tê barkirin û berhev dibe.

— BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, nr, 0, 1) — jimareya banga pergalê bi nirxa guhêrbara nr re dide ber hev. Ger ew wekhev bin, berbi talîmata din ve diçe û banga pergalê asteng dike, wekî din destûr dide banga pergalê bi SECCOMP_RET_ALLOW.

- BPF_STMT(BPF_RET + BPF_K, SECCOMP_RET_ERRNO | (çewtî & SECCOMP_RET_DATA)) - bernameyê bi BPF_RET diqedîne û di encamê de xeletiyek SECCOMP_RET_ERRNO bi hejmara ji guhêrbara xeletiyê re çêdike.

- BPF_STMT(BPF_RET + BPF_K, SECCOMP_RET_ALLOW) - bernameyê bi BPF_RET diqedîne û dihêle ku banga pergalê bi karanîna SECCOMP_RET_ALLOW were darve kirin.

SECCOMP CBPF e
Dibe ku hûn meraq bikin ka çima navnîşek rêwerzan li şûna objektek ELF-ya berhevkirî an bernameyek C-ya berhevkirî ya JIT-ê tê bikar anîn.

Du sedemên vê yekê hene.

• Pêşîn, Seccomp cBPF (BPF klasîk) û ne eBPF bikar tîne, yanî: qeydên wê tune, lê tenê berhevkarek e ku encama hesabê paşîn hilîne, wekî ku di nimûneyê de tê dîtin.

• Ya duyemîn, Seccomp nîşanek ji rêzek rêwerzên BPF rasterast qebûl dike û ne tiştek din. Makroyên ku me bikar anîne bi hêsanî arîkariya diyarkirina van rêwerzan bi awayek bernamenûs-dostane dikin.

Heke hûn ji bo têgihîştina vê civînê bêtir arîkariyê hewce dikin, pseudokoda ku heman tiştî dike bifikirin:

if (arch != AUDIT_ARCH_X86_64) {
    return SECCOMP_RET_ALLOW;
}
if (nr == __NR_write) {
    return SECCOMP_RET_ERRNO;
}
return SECCOMP_RET_ALLOW;

Piştî diyarkirina koda parzûnê di avahiya socket_filter de, hûn hewce ne ku sock_fprog ku kod û dirêjahiya hesabkirî ya parzûnê vedihewîne destnîşan bikin. Ev avahiya daneyê wekî argûmanek hewce ye ku pêvajo paşê were meşandin:

struct sock_fprog prog = {
   .len = (unsigned short)(sizeof(filter) / sizeof(filter[0])),
   .filter = filter,
};

Di fonksiyona install_filter de tenê tiştek maye ku meriv bike - bernameyê bixwe bar bike! Ji bo kirina vê yekê, em prctl bikar tînin, PR_SET_SECCOMP wekî vebijarkek digirin da ku têkevin moda hesabkirina ewledar. Dûv re em ji modê re dibêjin ku parzûnê bi karanîna SECCOMP_MODE_FILTER, ku di guhêrbara prog ya celebê sock_fprog de heye, bar bike:

  if (prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, &prog)) {
    perror("prctl(PR_SET_SECCOMP)");
    return 1;
  }
  return 0;
}

Di dawiyê de, em dikarin fonksiyona xweya install_filter bikar bînin, lê pêşî divê em prctl bikar bînin da ku PR_SET_NO_NEW_PRIVS ji bo darvekirina heyî saz bikin û bi vî rengî ji rewşa ku pêvajoyên zarok ji dêûbavên xwe bêtir îmtiyazan werdigirin dûr bixin. Bi vê yekê, em dikarin di fonksiyona install_filter de bangên prctl yên jêrîn bêyî ku mafên root bin bikin.

Naha em dikarin bangî fonksiyona install_filter bikin. Werin em hemî bangên pergala nivîsandinê yên girêdayî mîmariya X86-64 asteng bikin û bi tenê destûrek bidin ku hemî hewldanan asteng dike. Piştî sazkirina parzûnê, em bi argumana yekem ve darvekirinê didomînin:

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]);
 }

Werin em dest pê bikin. Ji bo berhevkirina bernameya xwe em dikarin clang an gcc bikar bînin, bi her awayî ew tenê pelê main.c bêyî vebijarkên taybetî berhev dike:

clang main.c -o filter-write

Wekî ku hate destnîşan kirin, me hemî têketinên bernameyê asteng kirine. Ji bo ceribandina vê yekê hûn hewceyê bernameyek ku tiştek derdixe - ls wekî berendamek baş xuya dike. Bi gelemperî ew çawa tevdigere:

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

Pirxweş! Li vir bi karanîna bernameya meya wrapperê dixuye: Em bi tenê bernameya ku em dixwazin wekî argumana yekem biceribînin derbas dikin:

./filter-write "ls -la"

Dema ku ev bername were darve kirin, ev bername bi tevahî vala derdixe. Lêbelê, em dikarin strace bikar bînin ku bibînin ka çi diqewime:

strace -f ./filter-write "ls -la"

Encama xebatê pir tê kurt kirin, lê beşa wê ya têkildar destnîşan dike ku tomar bi xeletiya EPERM-ê têne asteng kirin - ya ku me mîheng kiriye. Ev tê vê wateyê ku bername tiştek dernakeve ji ber ku ew nikare bigihîje banga pergala nivîsandinê:

[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)

Naha hûn fêm dikin ka Seccomp BPF çawa dixebite û ramanek baş heye ku hûn dikarin bi wê çi bikin. Lê ma hûn naxwazin bi eBPF-ê li şûna cBPF-ê heman tiştî bi dest bixin da ku hêza xwe ya tevahî bikar bînin?

Dema ku li ser bernameyên eBPF difikirin, pir kes difikirin ku ew bi tenê wan dinivîsin û wan bi îmtiyazên rêveberê bar dikin. Dema ku ev gotin bi gelemperî rast e, kernel komek mekanîzmayan pêk tîne da ku tiştên eBPF di astên cihêreng de biparêze. Ji van mekanîzmayan re xefikên BPF LSM têne gotin.

xefikên BPF LSM

Ji bo peydakirina çavdêriya serbixwe-mîmarî ya bûyerên pergalê, LSM têgeha xefikan pêk tîne. Bangek hook ji hêla teknîkî ve mîna bangek pergalê ye, lê pergalek serbixwe ye û bi binesaziyê re yekgirtî ye. LSM têgehek nû peyda dike ku tê de qatek abstraksiyonê dikare ji pirsgirêkên ku dema ku bi bangên pergalê re li ser mîmariyên cihêreng mijûl dibin re rû bi rû nehêle.

Di dema nivîsandinê de, kernel heft hook hene ku bi bernameyên BPF ve girêdayî ne, û SELinux tenê LSM-ya çêkirî ye ku wan bicîh tîne.

Koda çavkaniyê ya xefikan di dara kernelê ya pelê de ye 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);

Her yek ji wan dê di qonaxên cûda yên darvekirinê de were gotin:

- ewlekarî_bpf - kontrolek destpêkê ya bangên pergala BPF-ê yên darvekirî pêk tîne;

- security_bpf_map - kontrol dike dema ku kernel ji bo nexşeyê ravekerek pelê vedigerîne;

- security_bpf_prog - kontrol dike dema ku kernel ji bo bernameya eBPF ravekerek pelê vedigerîne;

- security_bpf_map_alloc - kontrol dike ka qada ewlehiyê di hundurê nexşeyên BPF de hatî destpêkirin an na;

- security_bpf_map_free - kontrol dike ka qada ewlehiyê di hundurê nexşeyên BPF de paqij e;

- security_bpf_prog_alloc - kontrol dike ka qada ewlehiyê di hundurê bernameyên BPF de hatî destpêkirin;

- security_bpf_prog_free - kontrol dike ka qada ewlehiyê di hundurê bernameyên BPF de paqij e.

Naha, em van hemîyan dibînin, em fam dikin: ramana li pişt navdêrên LSM BPF ev e ku ew dikarin parastinê ji her tiştê eBPF re peyda bikin, dabîn bikin ku tenê yên xwedî îmtiyazên guncan dikarin li ser kart û bernameyan operasyonan bikin.

Nîqaş

Ewlekarî ne tiştek e ku hûn dikarin ji bo her tiştê ku hûn dixwazin biparêzin bi rengek yek-pîvan-hemû bicîh bikin. Girîng e ku meriv bikaribe pergalên di astên cûda û bi awayên cûda de biparêze. Bawer bikin an na, baştirîn rê ji bo ewlekirina pergalek organîzekirina astên cûda yên parastinê ji cihên cihê ye, da ku kêmkirina ewlehiya yek astê rê nede gihîştina tevaya pergalê. Pêşdebirên bingehîn karekî hêja kirine ku ji me re komek qat û nuqteyên cihêreng dane. Em hêvî dikin ku me têgihiştinek baş daye we ka çi qat in û meriv çawa bernameyên BPF bikar tîne da ku bi wan re bixebite.

Li ser nivîskaran

David Calavera li Netlify CTO ye. Wî di piştgiriya Docker de xebitî û beşdarî pêşkeftina amûrên Runc, Go û BCC, û her weha projeyên din ên çavkaniya vekirî bû. Ji bo xebata xwe ya li ser projeyên Docker û pêşkeftina ekosîstema pêveka Docker tê zanîn. David di derbarê grafikên şewatê de pir dilşewat e û her gav li xweşbînkirina performansê digere.

Lorenzo Fontana li ser tîmê çavkaniya vekirî li Sysdig dixebite, li wir ew di serî de balê dikişîne ser Falco, projeyek Weqfa Cloud Native Computing ku ewlehiya dema konteynerê û tespîtkirina anomalî bi navgînek kernel û eBPF peyda dike. Ew ji pergalên belavkirî, tora pênasekirî ya nermalavê, kernel Linux, û analîza performansê dilşewat e.

» Agahiyên bêtir li ser pirtûkê dikarin li vir bibînin malpera weşanger
» Table of Contents
» Jêkirin

Ji bo Khabrozhiteley 25% erzanî bi karanîna kupon - Linux

Li ser dayîna guhertoya kaxezê ya pirtûkê, dê pirtûkek elektronîkî bi e-nameyê were şandin.

Source: www.habr.com

Add a comment