Trong loạt bài này, tôi sẽ viết thêm (và học thêm) về các chi tiết kỹ thuật của sự tràn bộ đệm và các cách phòng chống. Một phần của loạt bài này tôi viết đã lâu, nhưng chưa bao giờ tìm ra thời gian viết tiếp. Nay nhân vụ Cisco chọi Michael Lynn [1], khi lỗi trong IOS của Cisco là lỗi tràn bộ đệm kinh điển, tôi nghĩ vẫn có nhu cầu cần phổ cập hóa kiến thức về cái bug này. (Xem thêm bài trình bày của Michael Lynn [2] do một bạn đọc gửi.)
2. Căn bản về buffer overflow với ngôn ngữ C
Lỗi buffer overflow (hay overrun) khá phổ biến trong các chương trình viết bằng C, vì C không cung cấp cấu trúc dữ liệu mảng (array) kèm kích thước và sự kiểm tra kích thước mảng trước khi dùng. Đây là một trong những cái giá phải trả cho sự hiệu quả (efficiency) của C, ngôn ngữ thông dụng nhất cho lập trình hệ thống.
Với mục tiêu minh họa, C là ngôn ngữ lý tưởng cho các thao tác liên quan đến bộ nhớ, stack, heap, …
Hãy xét một chương trình C nho nhỏ và “vô tội” sau:
/* ---------------------------------------------------------------------
* Vi' du. 1:
* ---------------------------------------------------------------------
*/
#include
void foo() {
unsigned char buffer[20]; int i=0; int c;
while ((c = getc(stdin)) != EOF) {
buffer[i++] = (unsigned char) c;
}
buffer[i] = '\0';
printf("You entered %s\n", buffer);
}
int main() {
foo();
return 0;
}
Ta dĩ nhiên có thể dùng stdin làm input cho chương trình. Tuy vậy, để làm ví dụ ta tạo một file dữ liệu làm input cho chương trình này. Tạo một file tên là data với nội dung chỉ có một dòng:
01234567890123456789012345678901234567
Sau khi dịch, bạn thử chạy chương trình:
hqn@hanoi (~/BO/Examples) % e1 < data
You entered 01234567890123456789012345678901234567
Không có vấn đề gì hết. Chương trình làm cái nó được thiết kết để làm. Thử cái khác nhé. Làm cho data dài hơn một byte:
hqn@hanoi (~/BO/Examples) % more data
01234567890123456789012345678901234567*
hqn@hanoi (~/BO/Examples) % e1 < data
You entered 01234567890123456789012345678901234567*
Segmentation fault
hqn@hanoi (~/BO/Examples) %
Tôi chỉ thêm vào data một byte (dấu *) và chương trình đã bị lỗi phân đoạn (segmentation fault [3]). Dễ thấy rằng segmentation fault là do ta đọc vào nhiều bytes hơn là ta đã dành cho buffer (20 bytes). Đây chính là nội dung cơ bản của sự tràn bộ đệm.
Segmentation fault thường xuất hiện khi ta truy cập phần bộ nhớ không thuộc về process hiện hành. Thế nhưng tại sao data file đầu tiên có đến 38 bytes thì vẫn chưa bị tràn mà 39 bytes thì lại bị, trong khi ta chỉ có 20 bytes cho buffer? Ta sẽ trả lời câu hỏi này sau.
Cũng cần chú ý rằng tôi đang dùng gcc phiên bản 3.2. Với gcc phiên bản khác và cấu hình máy khác thì con số 38, 39 có thể khác do stack alignment [4] khác nhau (xem thêm về data alignment [5] trên MSDN). Tuy vậy nguyên tắc overflow này không đổi. Nếu 38 không phải là con số của bạn thì bạn có thể thí nghiệm tăng từ từ kể tử 21 lên đến con số cần thiết cho overflow.
Có thể thấy từ một ví dụ đơn giản này rằng một chương trình nào đó của hệ thống (httpd chẳng hạn), nếu lập trình cẩu thả là đã có thể bị phá hoại dễ dàng. Trong trường hợp này, ít nhất ta có thể làm nó ngưng chạy bằng cách cung cấp nhiều dữ liệu hơn dự tính.
Bạn có thể nghĩ rằng đọc từng byte từng byte một có vẻ không thực tế lắm. Không hẳn thế! Nhiều network protocols dùng các ký tự đặc biệt như '\n' hay '\r' để đánh dấu kết thúc một field nào đó trong packet header. Các TCP sockets cũng chỉ là file descriptors, và ta thường phải kiểm tra từng byte cho đến khi thấy ký tự giới hạn.
Article printed from Blog Khoa Học Máy Tính: http://www.procul.org/blog
URL to article: http://www.procul.org/blog/2005/08/15/l%e1%bb%97i-tran-b%e1%bb%99-o%e1%bb%87m-2/
URLs in this post:
[1] Cisco chọi Michael Lynn: http://nqh.blogspot.com/2005/07/cisco-v-michael-lynn-bn-v-phe-ai.html
[2] bài trình bày của Michael Lynn: http://cryptome.quintessenz.org/mirror/lynn-cisco.pdf
[3] segmentation fault: http://en.wikipedia.org/wiki/Segmentation_fault
[4] stack alignment: http://www.fftw.org/fftw3_doc/Stack-alignment-on-x86.html
[5] data alignment: http://msdn.microsoft.com/library/default.asp?url=/library/en-us/dv_vstechart/html/vcconwindowsdataalignmentonipfx86x86-64.asp