no_new_privs Membuat Peningkatan Privilege Saat Eksekusi Bersifat Irreversibel

Sebuah layanan Linux dapat dengan sengaja mengeksekusi program yang memiliki bit set-user-ID atau file capabilities sambil bermaksud tetap berada pada tingkat privilege yang sudah dimilikinya. Tanpa batas eksekusi eksplisit, execve() dapat menjadi transisi privilege: metadata pada executable dapat mengubah kredensial efektif atau menyumbangkan capability kepada program baru.

Atribut task no_new_privs mengubah transisi tersebut. Setelah aktif, execve() yang berhasil tidak dapat memberikan privilege yang sebelumnya tidak dapat digunakan task sebelum pemanggilan itu. Atribut ini diwariskan kepada turunan, bertahan melewati eksekusi, dan tidak dapat dinonaktifkan. Sifat tersebut menjadikannya constraint satu arah pada garis keturunan proses, bukan opsi sementara untuk satu executable.

Batas melekat pada execve

Linux secara normal mengevaluasi beberapa mekanisme privilege ketika mengganti image proses. Bit mode set-user-ID dan set-group-ID dapat mengubah ID efektif, sedangkan file capabilities dapat menyumbangkan capability sesuai aturan transformasi capability.

Saat no_new_privs aktif, mekanisme pada file executable tersebut tidak dapat menaikkan privilege task melalui execve(). Dokumentasi kernel juga menyatakan bahwa Linux Security Modules tidak melonggarkan constraint setelah eksekusi dalam mode ini.

Operasi ini umumnya ditetapkan dengan prctl():

if (prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0) == -1) {
    /* handle error */
}

Pemanggilan tersebut mengubah atribut thread pemanggil. Nilai selain pengaturan yang didukung bukan permintaan untuk mode reversibel; tidak ada operasi yang mematikan bit itu setelah aktif.

Karena itu, posisi pemanggilan memiliki konsekuensi. Launcher yang mengaktifkan atribut sebelum mengeksekusi workload tidak tepercaya membuat thread tersebut beserta garis eksekusi berikutnya terikat pada semantik transisi yang dibatasi.

Pewarisan mengubah keputusan lokal menjadi kebijakan garis proses

Atribut diwariskan melalui fork() dan clone() serta dipertahankan melalui execve(). Child tidak dapat memulihkan transisi privilege normal saat eksekusi hanya dengan mengganti image prosesnya.

launcher
  |
  +-- set no_new_privs
  |
  +-- fork
       |
       +-- execve helper
            |
            +-- execve program lain

semua turunan mempertahankan atribut

Persistensi ini berguna bagi sandbox launcher karena kebijakan tidak bergantung pada setiap executable berikutnya untuk mengulangi pemanggilan setup. Konsekuensinya, keputusan tersebut juga dapat memengaruhi perangkat lunak beberapa tahap eksekusi setelah komponen yang pertama kali mengaktifkannya.

Kernel mengekspos status melalui field NoNewPrivs pada /proc/<pid>/status di kernel yang menyediakan field tersebut. Status itu melaporkan atribut task; nilainya tidak menggambarkan seluruh mekanisme confinement lain yang mungkin berlaku pada proses.

Mekanisme ini bukan privilege drop umum

Namanya dapat memberi kesan jaminan yang lebih luas daripada kontrak interface. Constraint berpusat pada privilege yang diperoleh melalui execve(). Mekanisme ini sendiri tidak menghapus kredensial, menutup file descriptor, mencabut capability yang sudah dimiliki, membatasi akses filesystem, atau memfilter system call.

Task yang sudah memiliki otoritas sebelum bit diaktifkan dapat mempertahankan otoritas itu sesudahnya. Sebagai contoh, file descriptor yang sudah terbuka tetap mengikuti semantik descriptor dan permission objek biasa. Demikian pula, proses dengan privilege yang sesuai dapat menjalankan operasi yang tidak bergantung pada peningkatan saat eksekusi.

Perbedaan ini memisahkan dua operasi keamanan:

no_new_privs       -> memblokir peningkatan privilege akibat execve
privilege dropping -> menghapus otoritas yang sudah dimiliki task

Launcher yang kuat mungkin memerlukan keduanya beserta kontrol isolasi terpisah. Menganggap bit ini sebagai sandbox lengkap akan membiarkan kanal otoritas lain tetap tidak tersentuh.

Seccomp memakai batas ini untuk mencegah pewarisan filter ke program berprivilege

Mode filter seccomp dapat mempertahankan filter melewati execve() ketika eksekusi diizinkan oleh filter. Persistensi tersebut menimbulkan masalah keamanan jika task tanpa privilege dapat memasang filter arbitrer lalu mengeksekusi program yang memperoleh privilege.

Karena itu, Linux mewajibkan thread tanpa privilege mengaktifkan no_new_privs sebelum memasang filter seccomp, kecuali thread memiliki CAP_SYS_ADMIN dalam user namespace miliknya. Kondisi tersebut mencegah thread menyusun perilaku syscall pilihan penyerang lalu membawa perilaku itu ke executable yang baru memperoleh privilege.

Hubungan keduanya bersifat struktural, bukan identik. no_new_privs mengontrol transisi privilege; seccomp mengontrol perilaku system call terpilih. Mengaktifkan yang pertama tidak memasang filter syscall, dan pemasangan filter tidak membuat batas pertama menjadi berlebihan pada jalur setup tanpa privilege.

Transisi security module memerlukan peninjauan sesuai deployment

Batas exec juga berinteraksi dengan Linux Security Modules. Dokumentasi kernel mencatat bahwa dalam mode no_new_privs, LSM dapat dicegah melonggarkan constraint melalui eksekusi, tetapi mekanisme yang sama juga dapat mengganggu transisi LSM yang seharusnya memperketat confinement.

Konsekuensi ini relevan bagi launcher layanan generik. Mengaktifkan bit secara global dapat mengubah kebijakan eksekusi yang mengharapkan transisi domain pada execve(). Pertanyaan deployment bukan hanya apakah peningkatan privilege perlu diblokir, tetapi juga apakah kebijakan LSM di sekitarnya mengharapkan perubahan label atau domain saat eksekusi.

Ini merupakan batas implementasi dan kebijakan, bukan alasan untuk menghindari atribut tersebut. Launcher dan security module yang aktif perlu memiliki semantik transisi yang selaras.

Irreversibilitas mengurangi ambiguitas kebijakan berikutnya

Flag proses yang reversibel dapat dimatikan tepat sebelum eksekusi sensitif, sehingga keputusan trust berpindah ke komponen mana pun yang masih memiliki izin untuk mematikannya. no_new_privs sengaja tidak memiliki bentuk seperti itu. Setelah aktif, kode berikutnya tidak dapat memulihkan peningkatan privilege normal saat eksekusi bagi garis proses tersebut.

Hasilnya adalah properti monotonik: eksekusi dapat berlanjut, image proses dapat berubah, dan child dapat dibuat, tetapi kemampuan memperoleh privilege tambahan dari metadata executable tidak kembali. Properti ini lebih sempit daripada sandboxing, namun lebih kuat daripada konvensi yang mengandalkan setiap child untuk secara sukarela menghindari executable berprivilege.

Bagi supervisor proses, batas praktisnya presisi. Aktifkan atribut hanya setelah transisi eksekusi berprivilege yang memang diperlukan telah selesai, lalu sebelum kontrol diserahkan kepada kode yang turunannya tidak boleh mendapatkan kembali transisi tersebut. Efek keamanan berasal dari kernel yang mempertahankan status satu arah itu melewati batas eksekusi.