Bug pada Keyring Facilities di Kernel Linux

Pada akhir tahun 2015, tim Perception Point menemukan bug pada fasilitas keyring di kernel linux versi 4.4.1 dan sebelumnya. Bug ini, yang mendapatkan identitas CVE-2016-0728, pada saat dibuka ke publik, diperkirakan mempengaruhi sekitar puluhan juta PC dan server dengan sistem operasi Linux, dan 66% perangkat Android. CVE-2016-0728 adalah bug yang disebabkan oleh reference leak pada fasilitas keyring.

Penyebab Terjadinya Bug

Fasilitas keyring (keyring facilities) adalah metode yang disediakan kernel untuk driver-driver men-cache data keamanan, kunci otentikasi, kunci enkripsi dan data lainnya. Antarmuka system call (syscall) keyctl disediakan agar program-program pada userspace dapat mengelola keyring ini dan menggunakan fasilitas untuk tujuannya masing-masing.

Setiap proses dapat membuat keyring pada sesi berjalan (session keyring) menggunakan syscall keyctl(KEYCTL_JOIN_SESSION_KEYRING, name) dan dapat memberikan nama pada keyring tersebut, atau memberi nilai NULL pada bagian nama. Obyek keyring dapat digunakan bersama oleh beberapa proses yang menggunakan nama keyring yang sama.

Apabila suatu proses sudah memiliki session keyring, syscall yang sama akan menimpa keyring sebelumnya dengan yang baru. Apabila suatu obyek keyring digunakan bersama oleh beberapa proses, nilai internal refcount milik obyek tersebut yang tersimpan pada field bernama usage ditambah satu.

‘Kebocoran’ terjadi pada saat suatu proses mencoba untuk menimpa session keyring yang sedang digunakan dengan keyring yang itu juga.  Hal ini terjadi karena pada fungsi join_session_keyring, fungsi tersebut menyimpar reference ke keyring yang diminta. Namun apabila keyring yang sama sedang digunakan oleh proses yang memanggil syscall tersebut, kernel tidak mengurangi nilai internal refcount pada field usage, sehingga memory yang digunakan oleh keyring menjadi lebih besar dari yang digunakan (memory leak).

Uji Coba pada Server

Bug di ujicoba pada Ubuntu Server yang terinstall pada server kuliah el5228-05 menggunakan source code berikut (https://gist.github.com/PerceptionPointTeam/3864cf0c2a77f7ebd1dd#file-leak-c , diakses 9/2/2016):

/* $ gcc leak.c -o leak -lkeyutils -Wall */
/* $ ./leak */
/* $ cat /proc/keys */

#include 
#include 
#include <sys/types.h>
#include 

int main(int argc, const char *argv[])
{
    int i = 0;
    key_serial_t serial;

    serial = keyctl(KEYCTL_JOIN_SESSION_KEYRING, "leaked-keyring");
    if (serial < 0) {
        perror("keyctl");
        return -1;
    }

    if (keyctl(KEYCTL_SETPERM, serial, KEY_POS_ALL | KEY_USR_ALL) < 0) {
        perror("keyctl");
        return -1;
    }

    for (i = 0; i < 100; i++) {
        serial = keyctl(KEYCTL_JOIN_SESSION_KEYRING, "leaked-keyring");
        if (serial < 0) {
            perror("keyctl");
            return -1;
        }
    }

    return 0;
}

Source code membutukan librari libkeyutils-dev dan compiler gcc, sehingga kedua paket ini harus diinstal dulu di server. Setelah gcc dan libkeyutils-dev terinstall, source code di-compile dengan perintah:

gcc leak.c -o leak -lkeyutils -Wall

Berikut adalah screenshot keyrings sebelum dan sesudah program “leak“ dijalankan.

aaaa
Sebelum program dijalankan
bbbb
Setelah program dijalankan

Setelah program dijalankan, akan terlihat bahwa keyring bernama leaked-keyring seakan-akan digunakan oleh 100 proses, walaupun sebenarnya leaked-keyring hanya digunakan oleh satu proses milik satu program diatas. Namun karena program diatas memanggil syscall keyctl pada loop hingga 100 kali, nilai usage tidak dikurangi dan akibatnya, kernel mengira keyring tersebut sedang digunakan 100 proses.

Konsekuensi Terjadinya Bug

Seperti yang diperlihatkan diatas, bug ini dapat menyebabkan memory leak. Namun ada konsekuensi lain. Nilai reference count pada kolom usage diatas dapat mengalami integer overflow. Tidak ada pengecekan yang dilakukan untuk menghindari terjadinya overflow pada kolom usage ini.

Apabila suatu proses dapat membuat kernel mengalami leak referensi ke 0x100000000 (maksimum integer + 1) pada proses yang sama, ini dapat menyebabkan kernel mengira bahwa obyek tidak lagi direferensi dan membebaskan memori yang digunakan obyek tersebut, men-dealokasi, atau me-realokasi memori, yang sebenarnya masih digunakan. Hal ini akan menyebabkan munculnya kelemahan use-after-free: suatu program menggunakan suatu pointer ke alamat memori yang sebenarnya sudah dibebaskan oleh kernel, sehingga bisa terjadi perilaku yang tidak didefinisikan oleh program.

Penyerang dapat memanfaatkan kelemahan user-after-free yang terjadi dengan membuat program yang melakukan hal berikut:

  1. Membuat referensi yang benar ke suatu obyek keyring
  2. Overflow nilai usage keyring tersebut
  3. Perintahkan kernel untuk membebaskan obyek keyring tersebut
  4. Alokasikan obyek kernel yang berbeda dari userspace, dengan konten yang dikendalikan pengguna (arbitrary code), pada alamat memory yang sebelumnya digunakan oleh obyek keyring yang dibebaskan.
  5. Gunakan referensi ke obyek keyring yang sudah dibebaskan tersebut sehingga memicu eksekusi kode.

Pada exploit yang digunakan oleh tim Perception Point sebagai contoh, exploit dijalankan pada kernel versi 3.18 64-bit dan memakan waktu hingga 30 menit pada Intel Core i7-5500. Hasil yang didapatkan tim Perception Point, exploit dapat memberikan akses root pada shell.

cve_2016_0728
Hak akses root didapatkan

Mitigasi

Karena bug ini hanya mempengaruhi kernel linux versi 4.4.1, mengupgrade ke versi yang lebih baru akan menutup kelemahan yang disebabkan bug. Selain itu, Supervisor Mode Execution Program atau SMEP (suatu fitur keamanan pada beberapa CPU Intel) dan SELinux pada perangkat Android akan mempersulit berjalankan exploit pada komputer target.

Artikel ini dibuat oleh Agung Utama Putra (23215061) sebagai tugas 1 mata kuliah EL5228 Keamanan Sistem Operasi di program studi S2 Sekolah Teknik Elektro dan Informatika, Institut Teknologi Bandung.

Referensi

Leave a Reply

Your email address will not be published. Required fields are marked *