Hai,
Pertama, terima kasih untuk libseccomp -- kami dengan senang hati menggunakannya dalam produksi selama beberapa tahun sekarang, dan tidak mengalami masalah apa pun (sampai sekarang). Saya tidak yakin apakah ini bug dalam kode kami, kesalahpahaman dokumentasi, atau sesuatu yang lain -- tetapi saya telah menghabiskan sebulan terakhir mencoba melacak ini tetapi tidak berhasil.
Kami baru-baru ini memutakhirkan paket dalam wadah Docker kami, yang mencakup peningkatan dari libseccomp 2.3.3 (versi dalam repo stabil Debian) ke 2.4.3. Ada paket sistem lain yang juga ditingkatkan, tetapi saya tidak merekamnya. Kernel kami tidak ditingkatkan, dan merupakan versi 4.19.0-8-amd64.
Kami menggunakan SCMP_ACT_TRACE
, dan membuat filter yang hanya terdiri dari aturan SCMP_ACT_ALLOW
yang ditambahkan menggunakan nomor syscall asli, bukan nomor semu libseccomp. Kami memotong proses helper 64-bit yang membangun dan memuat filter seccomp sebelum exec
-ing biner 64-bit lainnya.
Sebagai referensi, ini adalah keseluruhan dari rutinitas inisialisasi seccomp kami, menggunakan pemeriksaan kesalahan yang serupa dengan halaman manual seccomp_rule_add
.
Namun, panggilan kami ke seccomp_load
telah mulai mengembalikan -EINVAL
, pada urutan besarnya 1 / 100.000 inisialisasi proses. (Tidak dapat mereproduksi secara andal, hal ini membuat proses debug menjadi membosankan.) Tidak ada perubahan kode pada aplikasi kita selama ini. Panggilan sys yang ditambahkan ke filter identik di semua proses.
Adakah gagasan tentang apa yang salah (atau bahkan bagaimana menggali lebih jauh apa yang salah), atau apakah ini diharapkan dalam beberapa cara? Tidak banyak bagian yang bergerak dinamis, dan saya tidak dapat menemukan apa pun dalam dokumentasi tentang mengapa ini bisa terjadi.
Hai @Xyene ,
Tidak banyak tempat yang mengembalikan -EINVAL di jalur kode seccomp_load() . Berdasarkan pemeriksaan cepat terhadap kode libseccomp v2.4.3, sepertinya ini disebabkan oleh scmp_filter_ctx
tidak valid atau kernel yang mengeluh tentang panggilan prctl(...)
yang memuat filter.
Mengingat v2.4.3 umumnya berfungsi, dan Anda belum mengubah kernel Anda, tampaknya meragukan bahwa panggilan prctl(...)
adalah penyebab yang membawa kita ke konteks filter yang tidak valid. Pernahkah Anda memperhatikan perilaku aneh lainnya dalam program Anda sejak peningkatan? Saya ingin tahu apakah ada masalah kerusakan memori di tempat lain yang menyebabkan masalah.
Meskipun kesalahan selalu ada pada libseccomp, kami menjalankan setiap rilis melalui serangkaian pemeriksaan yang mencakup valgrind run untuk semua uji regresi kami serta analisis statis menggunakan dentang dan Coverity.
Selain itu, meskipun ini tidak membantu untuk v2.4.3, salah satu peningkatan yang kami targetkan untuk rilis v2.5.0 yang hampir siap adalah peningkatan dokumentasi dan penanganan kode kesalahan.
Kami baru-baru ini memutakhirkan paket dalam wadah Docker kami, yang mencakup peningkatan dari libseccomp 2.3.3 (versi dalam repo stabil Debian) ke 2.4.3. Ada paket sistem lain yang juga ditingkatkan, tetapi saya tidak merekamnya. Kernel kami tidak ditingkatkan, dan merupakan versi 4.19.0-8-amd64.
Terima kasih telah memverifikasi bahwa kode Anda dan kernel yang mendasarinya tidak berubah. Itu akan membantu melacak masalahnya.
Untuk referensi, ini adalah keseluruhan dari rutinitas inisialisasi seccomp kami, menggunakan pemeriksaan kesalahan yang serupa dengan halaman manual
seccomp_rule_add
.
Filter Anda terlihat masuk akal bagi saya.
Adakah gagasan tentang apa yang salah (atau bahkan bagaimana menggali lebih jauh apa yang salah), atau apakah ini diharapkan dalam beberapa cara? Tidak banyak bagian yang bergerak dinamis, dan saya tidak dapat menemukan apa pun dalam dokumentasi tentang mengapa ini bisa terjadi.
Saya melihat melalui kode v2.4.3 seccomp_load()
, dan saya pikir hanya ada dua tempat di mana libseccomp menghasilkan kode pengembalian -EINVAL
:
seccomp_load()
pada saluran 283_gen_bpf_build_bpf()
pada baris 1657Kedua kesalahan di atas secara efektif disebabkan oleh filter yang tidak valid. Itu sepertinya tidak mungkin bagi saya berdasarkan kode filter Anda.
Perlu dicatat bahwa nilai pengembalian default kernel di seccomp_set_mode_filter()
adalah -EINVAL
, jadi mungkin ada hal lain pada sistem yang berubah, yang membuat kita jatuh ke jalur itu. Anda menyebutkan bahwa Anda menjalankan di Docker; apakah Anda menonaktifkan filter seccomp Docker default?
Saya akan tergoda untuk menambahkan beberapa debug lagi ke kode Anda di dalam if setelah seccomp_load()
gagal. Misalnya, kita dapat menampilkan PFC dan/atau BPF dari filter itu sendiri untuk memverifikasi bahwa filter tersebut terlihat masuk akal. Lihat seccomp_export_pfc()
dan seccomp_export_bpf()
.
Saya melihat melalui kode v2.4.3
seccomp_load()
, dan saya pikir hanya ada dua tempat di mana libseccomp menghasilkan kode pengembalian-EINVAL
:
seccomp_load()
pada saluran 283_gen_bpf_build_bpf()
pada baris 1657
Ingatlah bahwa setiap kegagalan yang ditemukan di gen_bpf_generate(...)
, atau di bawahnya, secara efektif digabungkan menjadi -ENOMEM oleh sys_filter_load(...)
pada src/system.c:267 .
Aku benci jatuh kembali ke "korupsi memori!" begitu cepat, tapi sepertinya itu yang terjadi di sini.
Terima kasih atas balasan yang cepat dan terperinci! Mereka telah menghasilkan beberapa jalan eksplorasi :slightly_smiling_face:
Pernahkah Anda memperhatikan perilaku aneh lainnya dalam program Anda sejak peningkatan? Saya ingin tahu apakah ada masalah kerusakan memori di tempat lain yang menyebabkan masalah.
Tidak, hanya ini. Tes unit dan integrasi kami terus lulus, dan selain dari EINVAL
sangat langka ini, tidak ada kesalahan yang dicatat dalam prod. Hal ini tentu membuatnya membingungkan; Saya juga mencurigai kerusakan memori, tetapi belum dapat menemukan bukti untuk mendukungnya :slightly_frowning_face:
Untuk sedikit lebih banyak konteks:
seccomp_init
dll.Saat mengetik ini, saya punya ide: Saya telah mendengar cerita horor tentang malloc
tidak aman untuk digunakan setelah forking, dan kami memiliki beberapa di dalam libseccomp itu sendiri. Aplikasi Python itu sendiri _is_ multithreaded, tetapi kami selalu memegang GIL saat dalam kode asli jadi ini harus aman (?). Saya hanya mendengar tentang kebuntuan yang terjadi melalui malloc-after-fork. (Saya kira ini membuat urutan bisnis berikutnya bergerak seccomp_init
et al. sebelum fork, hanya memanggil seccomp_load
post-fork, dan melihat apakah kesalahan terus terjadi.)
Saya akan tergoda untuk menambahkan beberapa debug lagi ke kode Anda di dalam if after seccomp_load() gagal.
Terima kasih untuk sarannya! Saya telah menambahkan panggilan ke seccomp_export_pfc
, serta membuang konten input ke filter ( config->syscall_whitelist
). Saya akan menindaklanjuti saat ini gagal.
Hai @Xyene - karena sudah sekitar seminggu, saya hanya ingin memeriksa dan melihat apakah ada sesuatu yang baru yang Anda temukan?
Belum, sayangnya. Setelah menambahkan tambalan ke seccomp_export_pfc
, itu diam. Kemarin saya mendorong tambalan itu ke semua VM kami (bukan hanya satu uji coba) dengan harapan dapat menangkap masalah ketika itu akhirnya terjadi.
Saya menemukan keheningan itu aneh, tetapi untuk saat ini saya menganggapnya sebagai kebetulan karena semua logika debugging/ekspor terjadi _after_ gagal seccomp_load
, jadi itu seharusnya tidak mempengaruhi kegagalan itu sendiri.
Kemajuan!
Ternyata alasannya diam adalah karena seccomp_export_bpf
adalah segfaulting (haruskah, jika dipanggil setelah seccomp_load
?), dan itu dilaporkan di tempat lain dan bukan di tempat saya mencari kegagalan seccomp. Lebih penting lagi, saya mengalami kasus di mana saya dapat dengan andal mereproduksi masalah dalam ~ 150 permintaan, jadi dengan beberapa pekerjaan pipa saya harus dapat mengekstrak beberapa dump inti.
Baiklah, saya mengeluarkan coredump, dan ini adalah jejaknya: https://Gist.github.com/Xyene/920f1cb098784a031f53c66a2f49d167
Ini agak mencurigakan, karena crash di dalam rutinitas realloc
jemalloc. Selain itu, menggunakan glibc malloc sebagai gantinya menyelesaikan masalah (sayangnya, ini bukan opsi jangka panjang dalam kasus ini karena masalah fragmentasi).
Selanjutnya, saya menarik jemalloc, mengkompilasinya dengan simbol -O0
dan debugging, dan memutar ulang reproduksi. Kali ini crash di seccomp_load
, bukan setelahnya! Saya telah mengunggah jejak itu di sini: https://Gist.github.com/Xyene/5da56168bcea337da85b2cd30704d12e
Cuplikan jejak itu:
#9 0x00007ff962698495 in free (ptr=0x5a5a5a5a5a5a5a5a) at src/jemalloc.c:2867
No locals.
#10 0x00007ff96062d087 in _program_free (prg=prg@entry=0x7ff95e963010) at gen_bpf.c:511
No locals.
#11 0x00007ff96062f605 in gen_bpf_release (program=program@entry=0x7ff95e963010) at gen_bpf.c:1986
No locals.
#12 0x00007ff96062c04f in sys_filter_load (col=col@entry=0x7ff95e9a5000) at system.c:293
rc = -1
prgm = 0x7ff95e963010
#13 0x00007ff96062b666 in seccomp_load (ctx=ctx@entry=0x7ff95e9a5000) at api.c:286
col = 0x7ff95e9a5000
Mencari jemalloc, sepertinya 0x5a
digunakan untuk menandai byte gratis sebagai free , dengan maksud khusus untuk merusak kode yang mencoba membebaskan sesuatu yang sudah dibebaskan.
gen_bpf.c:511
di v2.4.3 adalah: https://github.com/seccomp/libseccomp/blob/1dde9d94e0848e12da20602ca38032b91d521427/src/gen_bpf.c#L505 -L513
Tapi, ini tidak masuk akal karena masa pakai program hanyalah tubuh sys_filter_load
:
Saya pikir saya telah melihat setidaknya satu masalah. Dalam gen_bpf_generate
;
state.bpf = prgm
selama zmalloc
tidak gagal. Selanjutnya, _gen_bpf_build_bpf
dipanggil, dan berdasarkan rc
, state.bpf
diatur ke NULL
.
Mempertimbangkan kasus di mana rc != 0
, state.bpf
masih disetel ke prgm
pada saat panggilan ke _state_release
. Ini akan menyebabkan memori yang ditunjuk oleh prgm
dibebaskan.
Selanjutnya, gen_bpf_generate
akan return prgm
, yang meskipun telah dibebaskan, masih merupakan penunjuk bukan nol.
Kembali di sys_filter_load
, gen_bpf_generate
kembali, dan prgm
tidak- NULL
jadi itu berlanjut.
Akhirnya, di akhir sys_filter_load
, gen_bpf_release
dipanggil pada prgm
.
Ini tidak mengatasi kekhawatiran mengapa _gen_bpf_build_bpf
akan gagal sejak awal, tetapi sepertinya sesuatu yang buruk dapat terjadi jika itu gagal.
Sunting: sebenarnya, ini sepertinya telah diperbaiki sebagai efek samping dari https://github.com/seccomp/libseccomp/commit/3a1d1c977065f204b96293cccfe7d3e5aa0d7ace.
Mempertimbangkan kasus di mana rc != 0, state.bpf masih disetel ke prgm pada saat panggilan ke _state_release. Ini akan menyebabkan memori yang ditunjuk oleh prgm dibebaskan.
Ah! Tangkapan bagus @Xyene!
Saya pikir kita perlu memperbaiki ini di luar 3a1d1c977065f204b96293cccfe7d3e5aa0d7ace, izinkan saya memikirkan ini sebentar ... Saya tidak berpikir perbaikannya akan terlalu sulit ... dan lihat apakah saya bisa membuat PR.
Saya pikir kita perlu memperbaiki ini di luar 3a1d1c9, izinkan saya memikirkan ini sebentar ... Saya tidak berpikir perbaikannya akan terlalu sulit ... dan lihat apakah saya bisa membuat PR.
Ups, saya sedang melihat kode lama ketika saya menulis itu; ya, saya percaya bahwa 3a1d1c9 memang memperbaiki ini untuk kami, tetapi kami akan membutuhkan tambalan untuk cabang rilis-2.4. Saya akan mengerjakannya sekarang.
_(Meta: Saya akan terus memperbarui pesan ini dengan temuan saya saat saya melanjutkan, jadi saya punya tempat untuk menuliskannya tanpa mengirim email spam ke kalian :)_
Baiklah, kembali ke 2.4.3 dengan tambalan diterapkan, saya sudah bisa mengeluarkan filter yang gagal: link .
Penyebab yang dilaporkan sekarang adalah ENOMEM
bukannya EINVAL
, yang saya kira diharapkan mengingat _gen_bpf_build_bpf
gagal dan mengembalikan program NULL
. PFC mencetak dengan baik. Memodifikasi kode seccomp untuk melaporkan nilai kembalian _gen_bpf_build_bpf
menunjukkan EFAULT
sebagai penyebabnya.
Sebagai peretasan cepat, saya menjalankan :%s/return -EFAULT/abort()
lebih dari src/gen_bpf.c
, dan dapat mengekstrak jejak tumpukan ini:
Jejak tumpukan EFAULT
(gdb) bt full
#0 __GI_raise (sig=sig@entry=6) at ../sysdeps/unix/sysv/linux/raise.c:50
set = {__val = {0, 140084028365964, 140083248439464, 140083248438968, 140083248431088, 140084028368143, 28659884033, 140083965300736,
140083248439464, 140083248438968, 140083248431088, 140084028351031, 140084019988760, 140083248439624, 140083248431200, 140084028372597}}
pid = <optimized out>
tid = <optimized out>
ret = <optimized out>
#1 0x00007f67daa4d55b in __GI_abort () at abort.c:79
save_stage = 1
act = {__sigaction_handler = {sa_handler = 0x7f67d6f3eec0, sa_sigaction = 0x7f67d6f3eec0}, sa_mask = {__val = {140083965300736,
140083965300736, 0, 0, 140083248438968, 140083248438968, 140083248439464, 140083248431504, 140084028417173, 140083964793344,
140083965300736, 140083248431552, 140083994791895, 140083248431552, 140083994787642, 140083965300736}}, sa_flags = -1404894496,
sa_restorer = 0x0}
sigs = {__val = {32, 0 <repeats 15 times>}}
#2 0x00007f67d8bfd455 in _gen_bpf_build_bpf (state=0x7f67ac4302e0, col=0x7f67d6f63040) at gen_bpf.c:1943
rc = 0
iter = 1
h_val = 1425818561
res_cnt = 0
jmp_len = 0
arch_x86_64 = 0
arch_x32 = -1
instr = {op = 32, jt = {tgt = {imm_j = 0 '\000', imm_k = 0, hash = 0, db = 0x0, blk = 0x0, nxt = 0}, type = TGT_NONE}, jf = {tgt = {
imm_j = 0 '\000', imm_k = 0, hash = 0, db = 0x0, blk = 0x0, nxt = 0}, type = TGT_NONE}, k = {tgt = {imm_j = 4 '\004', imm_k = 4,
hash = 4, db = 0x4, blk = 0x4, nxt = 4}, type = TGT_K}}
i_iter = 0x7f67d6fdcb60
b_badarch = 0x7f67d6fd9000
b_default = 0x7f67d6fd9060
b_head = 0x7f67d6fda1a0
b_tail = 0x7f67d6fd9000
b_iter = 0x0
b_new = 0x7f67d6fe3300
b_jmp = 0x0
db_secondary = 0x0
pseudo_arch = {token = 0, token_bpf = 0, size = ARCH_SIZE_UNSPEC, endian = ARCH_ENDIAN_LITTLE, syscall_resolve_name = 0x0,
syscall_resolve_num = 0x0, syscall_rewrite = 0x0, rule_add = 0x0}
#3 0x00007f67d8bfd560 in gen_bpf_generate (col=0x7f67d6f63040) at gen_bpf.c:1971
rc = 0
state = {htbl = {0x0 <repeats 256 times>}, attr = 0x7f67d6f63044, bad_arch_hsh = 889798935, def_hsh = 742199527, arch = 0x7f67ac4301e0,
bpf = 0x7f67d6f64010}
prgm = 0x7f67d6f64010
#4 0x00007f67d8bf64a7 in sys_filter_load (col=0x7f67d6f63040) at system.c:265
rc = 32615
prgm = 0x0
#5 0x00007f67d8bf4f10 in seccomp_load (ctx=0x7f67d6f63040) at api.c:287
col = 0x7f67d6f63040
Itu sesuai dengan baris 1943:
Mengingat sifat penggantinya, saya pikir kita dapat mengecualikan EFAULT
apa pun dalam fungsi pembantu apa pun, karena itu akan dibatalkan terlebih dahulu.
Setelah ini, saya mencoba mereproduksi hal yang sama dengan HEAD -- itu masih terjadi. Selanjutnya, %s:/goto build_bpf_free_blks/abort()
dan ulangi. Penyebabnya adalah:
Untungnya fungsi ini pendek, dan hanya memiliki beberapa titik kegagalan. Putaran lain dari penyisipan abort
nanti;
Jejak
(gdb) bt full
#0 __GI_raise (sig=sig@entry=6) at ../sysdeps/unix/sysv/linux/raise.c:50
set = {__val = {0, 140050183343588, 0, 448, 140049402494880, 140049402509040, 140049402494832, 140050183342988, 140049402495088,
140049402509040, 140049402494896, 140050183343588, 4294967296, 140049402509040, 140049402509040, 140049402509040}}
pid = <optimized out>
tid = <optimized out>
ret = <optimized out>
#1 0x00007f5ff953055b in __GI_abort () at abort.c:79
save_stage = 1
act = {__sigaction_handler = {sa_handler = 0x7f5ff595d260, sa_sigaction = 0x7f5ff595d260}, sa_mask = {__val = {139642271694862,
140050119389792, 0, 0, 140049402502840, 0, 140049402503336, 140049402502888, 140049402502840, 112, 384, 140049402502840, 140050149861504,
140049402495328, 140050149857273, 392}}, sa_flags = 448, sa_restorer = 0x7f5ff595d240}
sigs = {__val = {32, 0 <repeats 15 times>}}
#2 0x00007f5ff76edee5 in _bpf_append_blk (prg=0x7f5ff5964010, blk=0x7f5ff59df1a0) at gen_bpf.c:452
rc = -12
i_new = 0x0
i_iter = 0x7f5ff59fa178
old_cnt = 48
iter = 1
#3 0x00007f5ff76f3716 in _gen_bpf_build_bpf (state=0x7f5fcae302d0, col=0x7f5ff59c5000) at gen_bpf.c:2223
rc = 0
iter = 1
h_val = 1425818561
res_cnt = 0
jmp_len = 0
arch_x86_64 = 0
arch_x32 = -1
instr = {op = 32, jt = {tgt = {imm_j = 0 '\000', imm_k = 0, hash = 0, db = 0x0, blk = 0x0, nxt = 0}, type = TGT_NONE}, jf = {tgt = {
imm_j = 0 '\000', imm_k = 0, hash = 0, db = 0x0, blk = 0x0, nxt = 0}, type = TGT_NONE}, k = {tgt = {imm_j = 4 '\004', imm_k = 4,
hash = 4, db = 0x4, blk = 0x4, nxt = 4}, type = TGT_K}}
i_iter = 0x7f5ff59e1b60
b_badarch = 0x7f5ff59de000
b_default = 0x7f5ff59de060
b_head = 0x7f5ff59df1a0
b_tail = 0x7f5ff59de000
b_iter = 0x7f5ff59df1a0
b_new = 0x7f5ff59e8300
b_jmp = 0x7f5ff59df0e0
db_secondary = 0x0
pseudo_arch = {token = 0, token_bpf = 0, size = ARCH_SIZE_UNSPEC, endian = ARCH_ENDIAN_LITTLE, syscall_resolve_name = 0x0,
syscall_resolve_num = 0x0, syscall_rewrite = 0x0, rule_add = 0x0}
#4 0x00007f5ff76f3874 in gen_bpf_generate (col=0x7f5ff59c5000, prgm_ptr=0x7f5fcae30b40) at gen_bpf.c:2270
rc = 0
state = {htbl = {0x0, 0x7f5ff593ef80, 0x7f5ff593efe0, 0x7f5ff593efc0, 0x0, 0x7f5ff595d000, 0x7f5ff593ef60, 0x7f5ff593ef00,
0x0 <repeats 248 times>}, attr = 0x7f5ff59c5004, bad_arch_hsh = 889798935, def_hsh = 742199527, bpf = 0x7f5ff5964010,
arch = 0x7f5fcae301c0, b_head = 0x7f5ff59e8300, b_tail = 0x7f5ff59de120, b_new = 0x7f5ff59e8300}
prgm = <optimized out>
#5 0x00007f5ff76eb275 in sys_filter_load (col=0x7f5ff59c5000, rawrc=false) at system.c:307
rc = 0
prgm = 0x0
#6 0x00007f5ff76e9505 in seccomp_load (ctx=0x7f5ff59c5000) at api.c:386
col = 0x7f5ff59c5000
rawrc = false
Jadi realloc
gagal lagi, dan _bpf_append_blk
mengembalikan -ENOMEM
yang ditutupi oleh _gen_bpf_build_bpf
dan berubah menjadi -EFAULT
. Ini bukan masalah besar, tetapi karena Anda mengatakan pelaporan kesalahan yang lebih baik adalah target 2,5, saya pikir saya akan menyebutkannya karena ini terlihat dalam cakupan :slightly_smiling_face:
Beberapa menyodok dengan GDB:
(gdb) f 2
#2 0x00007f5ff76edee5 in _bpf_append_blk (prg=0x7f5ff5964010, blk=0x7f5ff59df1a0) at gen_bpf.c:452
452 abort();
(gdb) info args
prg = 0x7f5ff5964010
blk = 0x7f5ff59df1a0
(gdb) print prg->blks
$4 = (bpf_instr_raw *) 0x7f5ff59fa000
(gdb) x/32bx &prg->blks
0x7f5ff5964018: 0x00 0xa0 0x9f 0xf5 0x5f 0x7f 0x00 0x00
0x7f5ff5964020: 0x5a 0x5a 0x5a 0x5a 0x5a 0x5a 0x5a 0x5a
0x7f5ff5964028: 0x5a 0x5a 0x5a 0x5a 0x5a 0x5a 0x5a 0x5a
0x7f5ff5964030: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00
(gdb) print ((prg)->blk_cnt * sizeof(*((prg)->blks)))
$5 = 392
(gdb) print prg->blk_cnt
$6 = 49
Yang ini benar-benar mulai terlihat seperti kegagalan pengalokasi ...
Aha, cerita ini akhirnya mencapai kesimpulan _thrilling_ — Saya telah mengetahui apa yang terjadi, dan memverifikasi perbaikannya :slightly_smiling_face:
Karena itu mungkin membuat cerita yang menarik, ini dia:
Proses utama yang memotong pekerja biasanya berada di ~80mb RSS. Setelah bercabang, ia membatasi penggunaan memori melalui rlimit
, terkadang hingga 64mb. Ini menempatkannya pada posisi di mana penggunaan memori saat ini melebihi batasnya, tetapi ini diizinkan oleh rlimit
. _Sebagian besar_ waktu, pengalokasi memori akan memiliki cukup memori bebas yang tersedia untuk melayani rutinitas inisialisasi libseccomp tanpa meminta lebih banyak dari kernel. Tetapi ketika _tidak_, dan perlu meminta ruang untuk arena tambahan atau sesuatu, kernel tidak akan menyediakannya karena prosesnya sudah melewati batasnya.
Di 2.4.3, kegagalan untuk mendapatkan memori ini diwujudkan dalam EINVAL
dan double-free. Di master post- https://github.com/seccomp/libseccomp/commit/3a1d1c977065f204b96293cccfe7d3e5aa0d7ace , EFAULT
dilaporkan sebagai gantinya. Dengan https://github.com/seccomp/libseccomp/pull/257 diterapkan, ENOMEM
dilaporkan dengan benar.
Alasan mengapa hal ini jarang terjadi kemudian menjadi jelas: sepenuhnya bergantung pada apakah pengalokasi memiliki cukup memori untuk membangun program BPF tanpa meminta lebih banyak dari kernel. pengalokasi glibc lebih longgar tentang memungkinkan fragmentasi untuk membangun, jadi ini tidak pernah terjadi dengan itu di tempat. jemalloc menempatkan batas yang lebih ketat, dan mengarah pada peningkatan kemungkinan perlunya meminta memori selama seccomp_load
— cukup untuk melihat kegagalan yang dihasilkan, tetapi masih menyebalkan untuk dilacak.
Maka, cara mengatasinya adalah dengan memindahkan semua panggilan setrlimit
ke _after_ seccomp_load
. Dengan demikian, realloc
tidak lagi gagal dalam _bpf_append_blk
, dan filter berhasil dimuat. Ini berarti bahwa filter harus mengizinkan setrlimit
, tetapi dalam kasus saya ini dapat diterima. Secara lebih umum, saya pikir masalah ini akan diselesaikan dengan sesuatu seperti https://github.com/seccomp/libseccomp/issues/123 .
@pcmoore , @drakenclimber -- sekali lagi terima kasih atas semua bantuan Anda dalam
Bug ini diperbaiki dengan komit https://github.com/seccomp/libseccomp/commit/c0a6e6fd15f74c429a0b74e0dfd4de5a29aabebd
Komentar yang paling membantu
Belum, sayangnya. Setelah menambahkan tambalan ke
seccomp_export_pfc
, itu diam. Kemarin saya mendorong tambalan itu ke semua VM kami (bukan hanya satu uji coba) dengan harapan dapat menangkap masalah ketika itu akhirnya terjadi.Saya menemukan keheningan itu aneh, tetapi untuk saat ini saya menganggapnya sebagai kebetulan karena semua logika debugging/ekspor terjadi _after_ gagal
seccomp_load
, jadi itu seharusnya tidak mempengaruhi kegagalan itu sendiri.