GNU/Linux >> Belajar Linux >  >> Linux

Jika tumpukan diinisialisasi nol untuk keamanan, lalu mengapa tumpukan hanya diinisialisasi?

Penyimpanan yang dikembalikan oleh malloc() tidak diinisialisasi nol. Jangan pernah berasumsi demikian.

Dalam program pengujian Anda, itu hanya kebetulan:Saya rasa malloc() baru saja mendapatkan blok baru mmap() , tapi jangan mengandalkan itu juga.

Sebagai contoh, jika saya menjalankan program Anda di mesin saya dengan cara ini:

$ echo 'void __attribute__((constructor)) p(void){
    void *b = malloc(4444); memset(b, 4, 4444); free(b);
}' | cc -include stdlib.h -include string.h -xc - -shared -o pollute.so

$ LD_PRELOAD=./pollute.so ./your_program
a at 0x7ffd40d3aa60: 1256994848 21891 1256994464 21891 1087613792 32765 0 0
b at 0x55834c75d010: 67372036 67372036 67372036 67372036 67372036 67372036 67372036 67372036

Contoh kedua Anda hanya memperlihatkan artefak dari malloc implementasi di glibc; jika Anda melakukannya, ulangi malloc /free dengan buffer yang lebih besar dari 8 byte, Anda akan melihat dengan jelas bahwa hanya 8 byte pertama yang dinolkan, seperti pada kode contoh berikut.

#include <stddef.h>
#include <stdlib.h>
#include <stdio.h>

const size_t n = 4;
const size_t m = 0x10;

int main()
{
    for (size_t i = n; i; --i) {
        int *const p = malloc(m*sizeof(int));
        printf("%p ", p);
        for (size_t j = 0; j < m; ++j) {
            printf("%d:", p[j]);
            ++p[j];
            printf("%d ", p[j]);
        }
        free(p);
        printf("\n");
    }
    return 0;
}

Keluaran:

0x55be12864010 0:1 0:1 0:1 0:1 0:1 0:1 0:1 0:1 0:1 0:1 0:1 0:1 0:1 0:1 0:1 0:1 
0x55be12864010 0:1 0:1 1:2 1:2 1:2 1:2 1:2 1:2 1:2 1:2 1:2 1:2 1:2 1:2 1:2 1:2 
0x55be12864010 0:1 0:1 2:3 2:3 2:3 2:3 2:3 2:3 2:3 2:3 2:3 2:3 2:3 2:3 2:3 2:3 
0x55be12864010 0:1 0:1 3:4 3:4 3:4 3:4 3:4 3:4 3:4 3:4 3:4 3:4 3:4 3:4 3:4 3:4

Terlepas dari bagaimana tumpukan diinisialisasi, Anda tidak melihat tumpukan asli, karena pustaka C melakukan beberapa hal sebelum memanggil main , dan mereka menyentuh tumpukan.

Dengan pustaka GNU C, pada x86-64, eksekusi dimulai pada titik masuk _start, yang memanggil __libc_start_main untuk mengatur segalanya, dan yang terakhir akhirnya memanggil main . Namun sebelum memanggil main , itu memanggil sejumlah fungsi lain, yang menyebabkan berbagai potongan data ditulis ke tumpukan. Konten tumpukan tidak dihapus di antara pemanggilan fungsi, jadi saat Anda masuk ke main , tumpukan Anda berisi sisa dari pemanggilan fungsi sebelumnya.

Ini hanya menjelaskan hasil yang Anda dapatkan dari tumpukan, lihat jawaban lain terkait pendekatan dan asumsi umum Anda.


Dalam kedua kasus tersebut, Anda mendapatkan tidak diinisialisasi memori, dan Anda tidak dapat membuat asumsi apa pun tentang isinya.

Saat OS harus membagi halaman baru ke proses Anda (apakah itu untuk tumpukannya atau untuk arena yang digunakan oleh malloc() ), itu menjamin bahwa itu tidak akan mengekspos data dari proses lain; cara biasa untuk memastikannya adalah dengan mengisinya dengan nol (tetapi sama validnya untuk menimpa dengan hal lain, termasuk bahkan halaman senilai /dev/urandom - sebenarnya beberapa debugging malloc() implementasi menulis pola bukan nol, untuk menangkap asumsi yang salah seperti milik Anda).

Jika malloc() dapat memenuhi permintaan dari memori yang sudah digunakan dan dirilis oleh proses ini, isinya tidak akan dihapus (sebenarnya, kliring tidak ada hubungannya dengan malloc() dan tidak mungkin - itu harus terjadi sebelum memori dipetakan ke dalam ruang alamat Anda). Anda mungkin mendapatkan memori yang sebelumnya telah ditulis oleh proses/program Anda (misalnya sebelum main() ).

Dalam program contoh Anda, Anda melihat malloc() wilayah yang belum ditulis oleh proses ini (yaitu langsung dari halaman baru) dan tumpukan yang telah ditulis (oleh pre-main() kode dalam program Anda). Jika Anda memeriksa lebih banyak tumpukan, Anda akan menemukan bahwa tumpukan itu terisi nol lebih jauh ke bawah (ke arah pertumbuhannya).

Jika Anda benar-benar ingin memahami apa yang terjadi di tingkat OS, saya sarankan Anda melewati lapisan Perpustakaan C dan berinteraksi menggunakan panggilan sistem seperti brk() dan mmap() sebagai gantinya.


Linux
  1. Mengapa segmen .bss diperlukan?

  2. Mengapa perintah dan dmidecode gratis menunjukkan nilai yang berbeda untuk RAM?

  3. BCRYPT - Mengapa Distribusi Linux tidak menggunakannya secara default?

  1. Mengapa Server Memblokir IP Saya?

  2. Mengapa mount tidak menghargai opsi read only untuk bind mount?

  3. Mengapa menjalankan named(bind) di chroot sangat penting untuk keamanan? Atau mungkin tidak?

  1. Mengapa Ls -l Tidak Menunjukkan Waktu Dan Atau Tahun Untuk Setiap File??

  2. Mengapa Dokumen Induk Shell Di Sini Tidak Berfungsi Untuk Sub-perintah Di Dash Tapi Bash Bekerja?

  3. Mengapa Ubuntu Terbaik untuk Manajemen Server