GNU/Linux >> Belajar Linux >  >> Linux

Linux – Bagaimana Cara Memastikan Bahwa Pustaka Bersama Akan Memiliki Halaman Memori yang Dibagikan Oleh Beberapa Proses?

Izinkan saya menjelaskan terlebih dahulu apa yang ingin saya lakukan, diikuti dengan apa yang berhasil saya lakukan, dan terakhir masalah saya.

Tujuan:menerapkan serangan cache flush+flush di C

Saya mencoba menerapkan dalam C serangan cache flush+flush (https://gruss.cc/files/flushflush.pdf). Pada dasarnya, ini mengeksploitasi fakta bahwa dua proses berbeda mungkin berbagi halaman memori yang sama saat menggunakan pustaka bersama. Ini menghasilkan "penggunaan bersama" dari cache.

Mari kita asumsikan bahwa kita memiliki proses korban, terus berjalan dan terkadang menjalankan fungsi func diimpor dari perpustakaan bersama.

Secara paralel, kami berasumsi bahwa kami memiliki proses mata-mata, berjalan di komputer yang sama dengan korban, yang tujuannya adalah untuk memata-matai ketika korban memanggil func . Mata-mata juga memiliki akses ke perpustakaan bersama yang sama. Pseudo-code proses mata-mata adalah sebagai berikut:

i=0;
for (i = 0; i < trace_length ; i++)
{
    trace[i] = flush_time( address of function "func");
    i++;
}

di mana flush_time( <address> ) adalah fungsi yang mengembalikan waktu yang diperlukan CPU untuk mengosongkan memori yang ditunjukkan oleh address dari semua level cache. Pada prosesor Intel, ini dapat dicapai melalui instruksi perakitan clflush . Seseorang dapat mengamati bahwa eksekusi clflush lebih cepat ketika alamat tidak ada dalam cache. Akibatnya, waktu yang diperlukan untuk menghapus alamat memori dapat langsung diterjemahkan dengan kehadirannya (atau tidak) di dalam cache.

Proses mata-mata mengembalikan vektor jejak yang berisi hasil flush_time dari waktu ke waktu. Dari pengamatan sebelumnya, jejak ini akan menunjukkan waktu yang lebih tinggi ketika korban juga memanggil fungsi func . Mata-mata dengan demikian akan memotong ketika korban memanggil func .

Apa yang berhasil saya lakukan:membuat serangan berhasil terhadap pustaka bersama GSL

Saya menerapkan serangan yang disebutkan di atas, di mana perpustakaan bersama adalah GSL. Secara sewenang-wenang, saya memilih gsl_stats_mean (didefinisikan dalam gsl_statistics_double ) untuk bertindak sebagai fungsi func Saya bersedia untuk memata-matai.

Dalam hal ini, mata-mata bekerja dengan sempurna karena saya dapat dengan jelas melihat perbedaan waktu ketika program korban membuat panggilan ke gsl_stats_mean

Masalah saya:serangan tidak berhasil pada perpustakaan bersama buatan sendiri

Saya sekarang ingin membuat perpustakaan bersama saya sendiri dan menggunakannya untuk tes mata-mata/korban. Mari kita asumsikan . menunjukkan folder tempat spy.c saya dan victim.c file adalah. Saya membuat dua file myl.c dan myl.h dalam folder ./src/myl , yang masing-masing berisi deskripsi func dan itu adalah deklarasi. Seperti sebelumnya, tujuan mata-mata saya adalah untuk mendeteksi penggunaan func dari korban.

Keduanya spy.c dan victim.c berisi baris include:

 #include "src/myl/myl.h"

Pembuatan perpustakaan bersama dilakukan dengan menggunakan perintah berikut:

gcc -c -fPIC src/myl/myl.c -o bin/shared/myl.o  #creation of object in ./bin/shared
gcc -shared bin/shared/myl.o -o bin/shared/libmyl.so #creation of the shared library in ./bin/shared
gcc -c spy.c -o spy.o #creation of spy's process object file
gcc -c victim.c -o victim.o #creation of victim's process object file
gcc spy.o -Lbin/shared -lmyl -o spy #creation of spy's executable
gcc victim.o -Lbin/shared -lmyl -o victim #creation of victim's executable

Saya kemudian meluncurkan korban dan mata-mata saya menggunakan baris berikut:

LD_LIBRARY_PATH=$(pwd)/bin/shared ./victim
LD_LIBRARY_PATH=$(pwd)/bin/shared ./spy

Namun, berbeda dengan kasus di mana saya menggunakan fungsi GSL, saya tidak dapat melihat aktivitas apa pun di cache lagi. Saya kira ini berarti bahwa proses mata-mata dan korban saya tidak berbagi halaman memori yang sama untuk perpustakaan bersama saya (namun, itu terjadi ketika menggunakan GSL). Perhatikan bahwa saat mengompilasi dengan cara ini, mata-mata masih berfungsi saat menargetkan fungsi GSL.

Pertanyaan utama saya adalah sebagai berikut:bagaimana memastikan bahwa perpustakaan bersama yang dikompilasi buatan sendiri akan memiliki paging memori yang dibagikan ketika dijalankan oleh beberapa proses pada saat yang bersamaan? Tampaknya demikian halnya dengan pustaka "tepat" yang saya instal, seperti GSL, gmp, pustaka asli, dll…. Tapi tidak untuk yang saya buat sendiri.

Terima kasih sebelumnya, dan saya minta maaf jika jawabannya langsung.

EDIT:keluaran LD_DEBUG=libs dan files untuk mata-mata dan korban.
CATATAN:korban disebut pg2 dan mata-mata disebut pg1 (maaf soal itu)

Pertama, libs untuk korban, diikuti oleh file untuk korban (pg2 ). Kemudian, lib untuk mata-mata, diikuti oleh file untuk mata-mata (pg1 ):

LD_DEBUG=libs LD_LIBRARY_PATH=$(pwd)/bin/shared ./pg2
 31714: find library=libmyl.so [0]; searching
 31714:  search path=/home/romain/Documents/work/test/page_sharing/bin/shared/tls/x86_64:/home/romain/Documents/work/test/page_sharing/bin/shared/tls:/home/romain/Documents/work/test/page_sharing/bin/shared/x86_64:/home/romain/Documents/work/test/page_sharing/bin/shared      (LD_LIBRARY_PATH)
 31714:   trying file=/home/romain/Documents/work/test/page_sharing/bin/shared/tls/x86_64/libmyl.so
 31714:   trying file=/home/romain/Documents/work/test/page_sharing/bin/shared/tls/libmyl.so
 31714:   trying file=/home/romain/Documents/work/test/page_sharing/bin/shared/x86_64/libmyl.so
 31714:   trying file=/home/romain/Documents/work/test/page_sharing/bin/shared/libmyl.so
 31714: 
 31714: find library=libc.so.6 [0]; searching
 31714:  search path=/home/romain/Documents/work/test/page_sharing/bin/shared       (LD_LIBRARY_PATH)
 31714:   trying file=/home/romain/Documents/work/test/page_sharing/bin/shared/libc.so.6
 31714:  search cache=/etc/ld.so.cache
 31714:   trying file=/lib/x86_64-linux-gnu/libc.so.6
 31714: 
 31714: 
 31714: calling init: /lib/x86_64-linux-gnu/libc.so.6
 31714: 
 31714: 
 31714: calling init: /home/romain/Documents/work/test/page_sharing/bin/shared/libmyl.so
 31714: 
 31714: 
 31714: initialize program: ./pg2
 31714: 
 31714: 
 31714: transferring control: ./pg2
 31714: 



LD_DEBUG=files LD_LIBRARY_PATH=$(pwd)/bin/shared ./pg2
 31901: 
 31901: file=libmyl.so [0];  needed by ./pg2 [0]
 31901: file=libmyl.so [0];  generating link map
 31901:   dynamic: 0x00007f5a3b34be48  base: 0x00007f5a3b14b000   size: 0x0000000000201028
 31901:     entry: 0x00007f5a3b14b580  phdr: 0x00007f5a3b14b040  phnum:                  7
 31901: 
 31901: 
 31901: file=libc.so.6 [0];  needed by ./pg2 [0]
 31901: file=libc.so.6 [0];  generating link map
 31901:   dynamic: 0x00007f5a3b144ba0  base: 0x00007f5a3ad81000   size: 0x00000000003c99a0
 31901:     entry: 0x00007f5a3ada1950  phdr: 0x00007f5a3ad81040  phnum:                 10
 31901: 
 31901: 
 31901: calling init: /lib/x86_64-linux-gnu/libc.so.6
 31901: 
 31901: 
 31901: calling init: /home/romain/Documents/work/test/page_sharing/bin/shared/libmyl.so
 31901: 
 31901: 
 31901: initialize program: ./pg2
 31901: 
 31901: 
 31901: transferring control: ./pg2
 31901: 


LD_DEBUG=libs LD_LIBRARY_PATH=$(pwd)/bin/shared ./pg1
 31938: find library=libmyl.so [0]; searching
 31938:  search path=/home/romain/Documents/work/test/page_sharing/bin/shared/tls/x86_64:/home/romain/Documents/work/test/page_sharing/bin/shared/tls:/home/romain/Documents/work/test/page_sharing/bin/shared/x86_64:/home/romain/Documents/work/test/page_sharing/bin/shared      (LD_LIBRARY_PATH)
 31938:   trying file=/home/romain/Documents/work/test/page_sharing/bin/shared/tls/x86_64/libmyl.so
 31938:   trying file=/home/romain/Documents/work/test/page_sharing/bin/shared/tls/libmyl.so
 31938:   trying file=/home/romain/Documents/work/test/page_sharing/bin/shared/x86_64/libmyl.so
 31938:   trying file=/home/romain/Documents/work/test/page_sharing/bin/shared/libmyl.so
 31938: 
 31938: find library=libgsl.so.23 [0]; searching
 31938:  search path=/home/romain/Documents/work/test/page_sharing/bin/shared       (LD_LIBRARY_PATH)
 31938:   trying file=/home/romain/Documents/work/test/page_sharing/bin/shared/libgsl.so.23
 31938:  search cache=/etc/ld.so.cache
 31938:   trying file=/usr/local/lib/libgsl.so.23
 31938: 
 31938: find library=libgslcblas.so.0 [0]; searching
 31938:  search path=/home/romain/Documents/work/test/page_sharing/bin/shared       (LD_LIBRARY_PATH)
 31938:   trying file=/home/romain/Documents/work/test/page_sharing/bin/shared/libgslcblas.so.0
 31938:  search cache=/etc/ld.so.cache
 31938:   trying file=/usr/local/lib/libgslcblas.so.0
 31938: 
 31938: find library=libc.so.6 [0]; searching
 31938:  search path=/home/romain/Documents/work/test/page_sharing/bin/shared       (LD_LIBRARY_PATH)
 31938:   trying file=/home/romain/Documents/work/test/page_sharing/bin/shared/libc.so.6
 31938:  search cache=/etc/ld.so.cache
 31938:   trying file=/lib/x86_64-linux-gnu/libc.so.6
 31938: 
 31938: find library=libm.so.6 [0]; searching
 31938:  search path=/home/romain/Documents/work/test/page_sharing/bin/shared       (LD_LIBRARY_PATH)
 31938:   trying file=/home/romain/Documents/work/test/page_sharing/bin/shared/libm.so.6
 31938:  search cache=/etc/ld.so.cache
 31938:   trying file=/lib/x86_64-linux-gnu/libm.so.6
 31938: 
 31938: 
 31938: calling init: /lib/x86_64-linux-gnu/libc.so.6
 31938: 
 31938: 
 31938: calling init: /lib/x86_64-linux-gnu/libm.so.6
 31938: 
 31938: 
 31938: calling init: /usr/local/lib/libgslcblas.so.0
 31938: 
 31938: 
 31938: calling init: /usr/local/lib/libgsl.so.23
 31938: 
 31938: 
 31938: calling init: /home/romain/Documents/work/test/page_sharing/bin/shared/libmyl.so
 31938: 
 31938: 
 31938: initialize program: ./pg1
 31938: 
 31938: 
 31938: transferring control: ./pg1
 31938: 
0: 322 # just some output of my spying program
1: 323 # just some output of my spying program
 31938: 
 31938: calling fini: ./pg1 [0]
 31938: 
 31938: 
 31938: calling fini: /home/romain/Documents/work/test/page_sharing/bin/shared/libmyl.so [0]
 31938: 
 31938: 
 31938: calling fini: /usr/local/lib/libgsl.so.23 [0]
 31938: 
 31938: 
 31938: calling fini: /usr/local/lib/libgslcblas.so.0 [0]
 31938: 
 31938: 
 31938: calling fini: /lib/x86_64-linux-gnu/libm.so.6 [0]
 31938: 




LD_DEBUG=files LD_LIBRARY_PATH=$(pwd)/bin/shared ./pg1
 31940: 
 31940: file=libmyl.so [0];  needed by ./pg1 [0]
 31940: file=libmyl.so [0];  generating link map
 31940:   dynamic: 0x00007fb3d8794e48  base: 0x00007fb3d8594000   size: 0x0000000000201028
 31940:     entry: 0x00007fb3d8594580  phdr: 0x00007fb3d8594040  phnum:                  7
 31940: 
 31940: 
 31940: file=libgsl.so.23 [0];  needed by ./pg1 [0]
 31940: file=libgsl.so.23 [0];  generating link map
 31940:   dynamic: 0x00007fb3d8582ac8  base: 0x00007fb3d8126000   size: 0x000000000046da60
 31940:     entry: 0x00007fb3d8180e30  phdr: 0x00007fb3d8126040  phnum:                  7
 31940: 
 31940: 
 31940: file=libgslcblas.so.0 [0];  needed by ./pg1 [0]
 31940: file=libgslcblas.so.0 [0];  generating link map
 31940:   dynamic: 0x00007fb3d8124df0  base: 0x00007fb3d7ee8000   size: 0x000000000023d050
 31940:     entry: 0x00007fb3d7eea120  phdr: 0x00007fb3d7ee8040  phnum:                  7
 31940: 
 31940: 
 31940: file=libc.so.6 [0];  needed by ./pg1 [0]
 31940: file=libc.so.6 [0];  generating link map
 31940:   dynamic: 0x00007fb3d7ee1ba0  base: 0x00007fb3d7b1e000   size: 0x00000000003c99a0
 31940:     entry: 0x00007fb3d7b3e950  phdr: 0x00007fb3d7b1e040  phnum:                 10
 31940: 
 31940: 
 31940: file=libm.so.6 [0];  needed by /usr/local/lib/libgsl.so.23 [0]
 31940: file=libm.so.6 [0];  generating link map
 31940:   dynamic: 0x00007fb3d7b1cd88  base: 0x00007fb3d7815000   size: 0x00000000003080f8
 31940:     entry: 0x00007fb3d781a600  phdr: 0x00007fb3d7815040  phnum:                  7
 31940: 
 31940: 
 31940: calling init: /lib/x86_64-linux-gnu/libc.so.6
 31940: 
 31940: 
 31940: calling init: /lib/x86_64-linux-gnu/libm.so.6
 31940: 
 31940: 
 31940: calling init: /usr/local/lib/libgslcblas.so.0
 31940: 
 31940: 
 31940: calling init: /usr/local/lib/libgsl.so.23
 31940: 
 31940: 
 31940: calling init: /home/romain/Documents/work/test/page_sharing/bin/shared/libmyl.so
 31940: 
 31940: 
 31940: initialize program: ./pg1
 31940: 
 31940: 
 31940: transferring control: ./pg1
 31940: 
0: 325 # just some output of my spying program
1: 327 # just some output of my spying program
 31940: 
 31940: calling fini: ./pg1 [0]
 31940: 
 31940: 
 31940: calling fini: /home/romain/Documents/work/test/page_sharing/bin/shared/libmyl.so [0]
 31940: 
 31940: 
 31940: calling fini: /usr/local/lib/libgsl.so.23 [0]
 31940: 
 31940: 
 31940: calling fini: /usr/local/lib/libgslcblas.so.0 [0]
 31940: 
 31940: 
 31940: calling fini: /lib/x86_64-linux-gnu/libm.so.6 [0]
 31940: 

Jawaban yang Diterima:

Karena keluaran debug dari ld penaut/pemuat dinamis mengonfirmasi bahwa kedua victim dan spy program memuat file input yang benar, langkah selanjutnya adalah memverifikasi apakah kernel benar-benar telah menyiapkan halaman fisik di mana libmyl.so dimuat dalam memori untuk dibagikan di antara victim dan spy .

Di Linux ini dimungkinkan untuk memverifikasi sejak kernel versi 2.6.25 melalui pagemap antarmuka di kernel yang memungkinkan program ruang pengguna untuk memeriksa tabel halaman dan informasi terkait dengan membaca file di /proc .

Prosedur umum untuk menggunakan peta halaman untuk mengetahui apakah dua proses berbagi memori berjalan seperti ini:

  1. Baca/proc/<pid>/maps untuk kedua proses untuk menentukan bagian mana dari ruang memori yang dipetakan ke objek mana.
  2. Pilih peta yang Anda minati, dalam hal ini halaman tempat libmyl.so dipetakan.
  3. Buka /proc/<pid>/pagemap . pagemap terdiri dari deskriptor peta halaman 64-bit, satu per halaman. Pemetaan antara alamat halaman dan alamat deskriptornya di pagemap adalah alamat halaman / ukuran halaman * ukuran deskriptor . Carilah deskriptor halaman yang ingin Anda periksa.
  4. Baca deskriptor 64-bit sebagai bilangan bulat yang tidak ditandatangani untuk setiap halaman dari pagemap .
  5. Bandingkan nomor bingkai halaman (PFN) dalam bit 0-54 dari deskriptor halaman antara libmyl.so halaman untuk victim dan spy . Jika PFN cocok, kedua proses berbagi halaman fisik yang sama.
Terkait:Windows – Bagaimana Windows TIDAK merusak sistem file Linux saat mengacaukan skema partisi?

Contoh kode berikut mengilustrasikan bagaimana pagemap dapat diakses dan dicetak dari dalam proses. Ini menggunakan dl_iterate_phdr() untuk menentukan alamat virtual dari setiap pustaka bersama yang dimuat ke dalam ruang memori proses, kemudian mencari dan mencetak pagemap yang sesuai dari /proc/<pid>/pagemap .

#define _GNU_SOURCE
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <inttypes.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <link.h>
#include <errno.h>
#include <error.h>

#define E_CANNOT_OPEN_PAGEMAP 1
#define E_CANNOT_READ_PAGEMAP 2

typedef struct __attribute__ ((__packed__)) {
    union {
        uint64_t pmd;
        uint64_t page_frame_number : 55;
        struct {
            uint64_t swap_type: 5;
            uint64_t swap_offset: 50;
            uint64_t soft_dirty: 1;
            uint64_t exclusive: 1;
            uint64_t zero: 4;
            uint64_t file_page: 1;
            uint64_t swapped: 1;
            uint64_t present: 1;
        };
    };
} pmd_t;


static int print_pagemap_for_phdr(struct dl_phdr_info *info,
                                  size_t size, void *data)
{
    struct stat statbuf;

    size_t pagesize = sysconf(_SC_PAGESIZE);

    char pagemap_path[BUFSIZ];
    int pagemap;

    uint64_t start_addr, end_addr;

    if (!strcmp(info->dlpi_name, "")) {
        return 0;
    }

    stat(info->dlpi_name, &statbuf);

    start_addr = info->dlpi_addr;
    end_addr = (info->dlpi_addr + statbuf.st_size + pagesize) & ~(pagesize-1);

     printf("n%10p-%10p %snn",
            (void *)start_addr,
            (void *)end_addr,
            info->dlpi_name);

     snprintf(pagemap_path, sizeof pagemap_path, "/proc/%d/pagemap", getpid());

     if ((pagemap = open(pagemap_path, O_RDONLY)) < 0) {
         error(E_CANNOT_OPEN_PAGEMAP, errno, 
               "cannot open pagemap: %s", pagemap_path);
     }

     printf("%10s %8s %7s %5s %8s %7s %7sn",
            "", "", "soft-", "", "file /", "", "");
     printf("%10s %8s %7s %5s %11s %7s %7sn",
            "address", "pfn", "dirty", "excl.",
            "shared anon", "swapped", "present");

     for (unsigned long i = start_addr; i < end_addr; i += pagesize) {
          pmd_t pmd;

          if (pread(pagemap, &pmd.pmd, sizeof pmd.pmd, (i / pagesize) * sizeof pmd) != sizeof pmd) {
              error(E_CANNOT_READ_PAGEMAP, errno,
                    "cannot read pagemap: %s", pagemap_path);
          }

          if (pmd.pmd != 0) {
              printf("0x%10" PRIx64 " %06" PRIx64 " %3d %5d %8d %9d %7dn", i,
                     (unsigned long)pmd.page_frame_number,
                     pmd.soft_dirty,
                     pmd.exclusive,
                     pmd.file_page,
                     pmd.swapped,
                     pmd.present);
          }
    }

    close(pagemap);

    return 0;
}

int main()
{
    dl_iterate_phdr(print_pagemap_for_phdr, NULL);

    exit(EXIT_SUCCESS);
}

Output dari program akan terlihat seperti berikut:

$ sudo ./a.out

0x7f935408d000-0x7f9354256000 /lib/x86_64-linux-gnu/libc.so.6

                      soft-         file /                
   address      pfn   dirty excl. shared anon swapped present
0x7f935408d000 424416   1     0        1         0       1
0x7f935408e000 424417   1     0        1         0       1
0x7f935408f000 422878   1     0        1         0       1
0x7f9354090000 422879   1     0        1         0       1
0x7f9354091000 43e879   1     0        1         0       1
0x7f9354092000 43e87a   1     0        1         0       1
0x7f9354093000 424790   1     0        1         0       1
...

dimana:

  • address adalah alamat virtual halaman
  • pfn adalah nomor bingkai halaman halaman
  • soft-dirty menunjukkan jika bit kotor lunak diatur di halaman Entri Tabel Halaman (PTE).
  • excl. menunjukkan apakah halaman dipetakan secara eksklusif (yaitu halaman hanya dipetakan untuk proses ini).
  • file / shared anon menunjukkan apakah halaman tersebut adalah halaman file atau halaman anonim bersama.
  • swapped menunjukkan jika halaman saat ini ditukar (menyiratkan present adalah nol).
  • present menunjukkan jika halaman saat ini ada dalam proses tetap set (menyiratkan swapped adalah nol).
Terkait:linux dasar (1) Lembar Cheat

(Catatan:Saya menjalankan program contoh dengan sudo karena sejak Linux 4.0 hanya pengguna dengan CAP_SYS_ADMIN kapabilitas bisa mendapatkan PFN dari /proc/<pid>/pagemap . Mulai dari Linux 4.2, bidang PFN di-nolkan jika pengguna tidak memiliki CAP_SYS_ADMIN . Alasan perubahan ini adalah untuk mempersulit eksploitasi kerentanan terkait memori lainnya, serangan Rowhammer, menggunakan informasi pada pemetaan virtual-ke-fisik yang diekspos oleh PFN.)

Jika Anda menjalankan program contoh beberapa kali, Anda akan melihat bahwa alamat virtual halaman harus berubah (karena ASLR), tetapi PFN untuk pustaka bersama yang digunakan oleh proses lain harus tetap sama.

Jika PFN untuk libmyl.so kecocokan antara victim dan spy program, saya akan mulai mencari alasan mengapa serangan itu gagal dalam kode serangan itu sendiri. Jika PFN tidak cocok, bit tambahan mungkin memberikan beberapa petunjuk mengapa halaman tidak diatur untuk dibagikan. pagemap bit menunjukkan hal berikut:

present file exclusive state:
   0      0     0      non-present
   1      1     0      file page mapped somewhere else
   1      1     1      file page mapped only here
   1      0     0      anonymous non-copy-on-write page (shared with parent/child)
   1      0     1      anonymous copy-on-write page (or never forked)

Salin halaman tulis di (MAP_FILE | MAP_PRIVATE) area anonim dalam konteks ini.

Bonus: Untuk mendapatkan berapa kali halaman telah dipetakan, PFN dapat digunakan untuk mencari halaman di /proc/kpagecount . File ini berisi 64-bit hitungan berapa kali setiap halaman dipetakan, diindeks oleh PFN.


Linux
  1. Cara Membunuh Proses yang Berjalan di Linux

  2. Bagaimana cara melihat daftar fungsi yang diekspor oleh perpustakaan bersama Linux?

  3. Bagaimana pustaka bersama (.so) memanggil fungsi yang diimplementasikan dalam program pemuatannya?

  1. Bagaimana cara membaca halaman manual Linux?

  2. Cara membuat penundaan perpustakaan bersama dimuat di Linux

  3. Bagaimana kesalahan memori bit tunggal memengaruhi Linux?

  1. Cara Memasang Pustaka Ncurses Di Linux

  2. Cara Menghapus Cache Memori di Linux

  3. Apakah Linux akan mulai mematikan proses saya tanpa bertanya apakah memori saya pendek?