Linux 7.3 kodolā binfmt_misc apakšsistēma vairs neglabās interpretatora ceļu kā nemainīgu tekstu. VFS uzturētājs Christian Brauner sagatavojis 21 ielāpa sēriju, kas ļauj binārfaila tipu atpazīt programmatiski un interpretatoru izrēķināt katrā exec izsaukumā atsevišķi. Izvēli var uzticēt BPF programmai, kura darbojas pašā kodolā.
Līdz šim binfmt_misc strādāja pēc vienkāršas shēmas. Reģistrācijas brīdī sistēmas administrators ieraksta faila paraksta baitus un interpretatora ceļu, piemēram, Wine Windows EXE failiem vai QEMU svešas arhitektūras binārfailiem. Ceļš pēc tam nemainījās līdz nākamajai reģistrācijai. Jaunā sērija šo saiti pārrauj.
Viss sākās ar Nix un $ORIGIN
Iniciatīva nāca no Nix puses. Farid Zakaria savā emuārā apraksta, ka TacoSprint 2026 laikā mēģināja panākt pārvietojamus binārfailus Nix ekosistēmā. Problēma slēpjas ELF faila PT_INTERP segmentā, kurā ierakstīts absolūts ceļš uz dinamisko ielādētāju, piemēram, uz kādu no /nix/store apakšmapēm. Pārvieto failu citur. Tas vairs nestartē.
Zakaria nosūtīja kodola sarakstam ielāpu, kas VFS līmenī atbalstītu $ORIGIN aizstājēju gan PT_INTERP, gan shebang rindā. Brauner atbildēja ar pretpriekšlikumu: visu interpretatora izvēli varētu padarīt programmējamu caur eBPF. Pirmo melnrakstu viņš uzrakstīja atvaļinājuma laikā.
Es gribēju atļaut tikai
$ORIGIN, bet programmējama izvēle ļautu darīt jebko.
Tā Zakaria apraksta savu reakciju uz Braunera piedāvājumu. Kodola sarakstā John Ericson argumentēja, ka nefiksēts PT_INTERP noder arī Buck un Bazel būvēšanas rīkiem, kuri ģenerē binārfailus ar ceļiem uz konkrētu būvēšanas koku.
Kā izskatās pati BPF programma
Programma ir struct_ops tipa un satur divas funkcijas. match pasaka, vai konkrētais fails šai apstrādei der. load uzstāda interpretatora ceļu. Zakaria piemērā match pārbauda pirmos četrus baitus ar bpf_strncmp(), tātad ķer jebkuru ELF failu. Funkcija load ar bpf_path_d_path() noskaidro paša faila atrašanās vietu failu sistēmā un no tās atvasina ielādētāja ceļu, ko nodod jaunajam palīgam bpf_binprm_set_interp().
Reģistrācija notiek divos soļos:
bpftool struct_ops register nix_origin.bpf.o /sys/fs/bpfecho ':origin:B::::nix:' > /proc/sys/fs/binfmt_misc/register
Otrā rinda ir parastais binfmt_misc reģistrācijas formāts, kas aprakstīts kodola dokumentācijā, tikai interpretatora lauka vietā stāv BPF programmas nosaukums. Kods, kas nonāk kodolā, iziet cauri verifikatoram un pēc tam tiek kompilēts uz procesora nātīvo instrukciju kopu. Verifikators atsakās ielādēt programmu ar neierobežotiem cikliem vai ar piekļuvi ārpus atļautajām struktūrām, tāpēc kļūdains apstrādātājs sistēmu neapgāž. Tas pats mehānisms jau vairākus gadus nes tīkla filtrus, novērošanas rīkus un CPU plānotājus.
Zakaria plāno NixOS moduli, kas šo reģistrē sistēmas startā. Filtrs neķers pilnīgi visus ELF failus. Tas balstīsies uz jaunu segmentu PT_INTERP_NIX, kuru binārfails nes tikai tad, ja pats to pieprasa. Vecie Nix binārfaili turpinās strādāt arī bez BPF apstrādātāja.
Vecais nodošanas modelis sabojāja procesa identitāti
Otra ielāpu sērijas daļa risina problēmu, kas binfmt_misc pieder jau gadiem. Klasiskajā režīmā reģistrētais interpretators kļūst par pašu procesu, bet fails, ko lietotājs gribēja palaist, nokļūst argumentu sarakstā. Wine un QEMU gadījumā tas ir loģiski, jo tie tiešām ir emulatori. Ielādētāja aizstāšanas gadījumā tas rada divas nepatikšanas.
argv[0]un/proc/<pid>/cmdlinerāda interpretatora izsaukumu, ne to failu, kuru lietotājs izpildīja./proc/self/exenorāda uz dinamisko saitētāju. Programmas, kas pēc šī ceļa meklē pašas sevi, atrodld.so.
Tam pievienojas divi sīkāki defekti. Binārfails, kas execveat() saņemts kā nepieejams O_CLOEXEC deskriptors, vispār nestartē. Atkļūdotājs gdb apjūk, jo AT_ENTRY un AT_PHDR vērtības nesakrīt ar exe failu.
Emulatoriem šie trūkumi nekad nav bijuši šķērslis. Wine lietotājam ir vienalga, ka ps izvadā redzams wine. Ielādētājam, kuru izvēlējusies BPF programma, tas vairs neder, jo šeit binārfails ir nātīvs un vienīgais, kas mainās, ir ceļš uz ld.so.
Divi jauni izplatīšanas režīmi
Sērija pievieno divus režīmus, kas šo plaisu aizver no pretējiem galiem.
Caurspīdīgais režīms
Interpretators ielādē binārfailu caur AT_EXECFD. Argumentu vektors paliek tieši tāds, kādu to uzbūvēja izsaucējs. Kodols mm->exe_file un comm apzīmē ar pašu binārfailu, ne ar interpretatoru. Process pēc tam izskatās tā, it kā binfmt_misc vispār nebūtu iesaistījies.
Ielādētāja aizstāšana ar karogu L
Kodols izpilda atrasto binārfailu kā galveno attēlu un vienkārši nomaina ielādētāju, kurš norādīts PT_INTERP segmentā. binfmt_misc pārstāj būt nodošanas mehānisms un kļūst par PT_INTERP pārrakstīšanu. Nekāds līgums starp kodolu un interpretatoru nav jāievēro, tāpēc nemodificēts ld.so strādā bez izmaiņām. Zakaria raksta, ka tieši šis karogs Nix vajadzībām noder visvairāk.
Ko ar to var darīt jau tagad
Zakaria jau uzrakstījis BPF programmu, kas aizstāj tradicionālo QEMU binfmt_misc reģistrācijas skriptu. $ORIGIN atbalsts shebang rindā prasa ieskatīties pirmajos 256 faila baitos, tātad arī tas ir dažu desmitu koda rindu jautājums. Tā kā interpretatoru tagad var izvēlēties pēc jebkuras faila pazīmes, tādu shēmu skaits ir atvērts jautājums.
Phoronix ziņo, ka Brauner galvenos VFS pieprasījumus nosūtīja jau pirms 7.3 apvienošanas loga atvēršanas 17. augustā. Zakaria savu NixOS moduli plāno iesniegt augšup tad, kad kods būs nonācis tagotā kodola izlaidumā.
Komentāri
Šim rakstam vēl nav komentāru. Esi pirmais, kurš dalās ar savu viedokli.