3.2.1 Bảo vệ bộ nhớ qua đặc quyền
Với chức năng quản lý bộ nhớ của hệ điều hành, không gian nhớ của các tiến trình cần được cách lý với nhau sao cho mỗi tiến trình chỉ có thể truy nhập được không gian nhớ của riêng mình. Các không gian nhớ của các tiến trình phải được cách biệt với nhau và với phần nhân của hệ điều hành. Việc này ngăn chặn lỗi hay phần mềm xấu bên trong
39 tiến trình không ảnh hưởng tới các tiến trình khác và bản thân hệ điều hành. Việc cố truy nhập bộ nhớ không phải của tiến trình sẽ gây ra lỗi phần cứng, như là lỗi xâm phạm ô nhớ được bảo vệ, và làm cho tiến trình vi phạm phải chấm dứt hoạt động.
Các tiến trình sử dụng địa chỉ bộ nhớ lô-gíc thay vì địa chỉ bộ nhớ vật lý mà bộ xử lý kết nối tới thông qua buýt hệ thống. Như vậy, cần phải thực hiện việc chuyển đổi (ánh xạ) từ địa chỉ lô-gíc của chương trình thành địa chỉ vật lý thực sự trước khi thao tác đọc/ghi bộ nhớ được diễn ra.
Kiến trúc x86 sử dụng phương pháp phân đoạn để quản lý không gian nhớ chương trình nhờ vào việc tách biệt các chức năng của không gian nhớ (đoạn mã, đoạn dữ liệu, đoạn ngăn xếp) cũng như việc chia sẻ. Các đoạn chức năng được truy nhập nhờ vào các thanh ghi đoạn như thanh ghi đoạn lệnh CS hay đoạn dữ liệu DS. Các thông tin quản lý
của các thanh ghi đoạn được lưu trong thẻ mô tả thanh ghi đoạn (segment descriptor).
Hình 3-3. Thẻ mô tả đoạn
Địa chỉ cơ sở (base) sử dụng cấu trúc tuyến tính 32 bít cho biết vị trí bắt đầu của
đoạn và giới hạn (limit) cho biết độ lớn của đoạn. DPL là mức đặc quyền của đoạn: 0 ứng
với nhiều đặc quyền nhất; 3 ít đặc quyền nhất và kiểm soát việc truy nhập tới đoạn. Các thẻ mô tả đoạn được lưu trong hai bảng: bảng mô tả toàn cục GDT (Global
Descriptor Table) và bảng mô tả cục bộ LDT (Local Descriptor Table). Để chọn đoạn,
chương trình cần sử dụng thẻ chọn đoạn (segment selector) có cấu trúc như dưới đây.
Hình 3-4. Thẻ chọn đoạn
Bít TI giúp phân biệt GDT (TI=0) và LDT (TI=1) còn RPL mô tả mức đặc quyền cần thiết khi truy nhập vào đoạn tương ứng. Thông thường cần 1 bảng GDT để truy nhập trực tiếp vào không gian nhớ phẳng. Vị trí đầu tiên của bảng GDT được lưu trong thanh ghi
40
Hình 3-5. Truy nhập bộ nhớ qua GDT
Nếu chương trình người dùng có khả năng sửa đổi thông tin trong bảng GDT thì tự bản thân chương trình này có khả năng thay đổi đặc quyền của mình. Như vậy, hệ điều hành cần phải lưu bảng này trong phần bộ nhớ dành cho nhân và không thể truy nhập trực tiếp từ chương trình người dùng. Nói cách khác, các thông tin này cần được lưu vào không gian nhớ được bảo vệ.
Hình 3-6 dưới đây minh họa cấu trúc không gian nhớ của chương trình với bảng mô tả toàn cục GDT. Ngoài không gian thông thường như dữ liệu và đoạn mã, bảng GDT cung cấp thông tin về các đoạn mã được bảo vệ (protected code) và các cổng gọi hàm (call gate) giúp chương trình truy nhập tới bộ nhớ được bảo vệ. Khi việc bảo vệ truy nhập bộ nhớ thông qua việc kiểm soát đặc quyền được kích hoạt, toàn bộ việc kiểm tra được thực hiện thông qua phần cứng nên chống lại can thiệp vào cơ chế kiểm tra từ chương trình người dùng.
41
Hình 3-6. Cấu trúc không gian nhớ của tiến trình và thông tin quản lý bộ nhớ
Như trong hình mô tả đặc quyền (Hình 3-7), khi đoạn dữ liệu được nạp việc kiểm tra được diễn ra theo các bước như sau. Mức độ bảo vệ của đoạn bộ nhớ được yêu cầu truy nhập DPL được so sánh với CPL và RPL. Nếu giá trị DPL mà nhỏ hơn thì việc truy nhập là hợp lệ. Nếu không khi này sẽ phát sinh lỗi truy nhập bộ nhớ được bảo vệ. Việc sử dụng RPL cho phép đoạn mã nhân nạp đoạn bộ nhớ dùng mức đặc quyền thấp hơn. Riêng với đoạn ngăn xếp, cả ba mức CPL, RPL và DPL phải giống nhau hoàn toàn.
42 Thực tế, việc bảo vệ đoạn bộ nhớ không quá quan trọng bởi các nhân của hệ điều hành hiện đại sử dụng không gian địa chỉ phẳng còn chương trình người dùng truy nhập toàn bộ không gian địa chỉ tuyến tính (ảo). Cơ chế bảo vệ bộ nhớ hữu ích được thực hiện tại bộ phận quản lý trang khi thực hiện việc chuyển đổi địa chỉ phẳng thành địa chỉ vật lý. Mỗi trang nhớ được mô tả bởi khoản mục bảng trang PTE (page table entry) chứa hai
trường phục vụ cho việc bảo vệ là cờ giám sát (supervisor) và đọc/ghi. Cờ giám sát cho
phép bảo vệ không gián nhớ của nhân. Khi cờ này bật lên, trang nhớ tương ứng sẽ không truy nhập được từ mức người dùng (mức đặc quyền 3). Cờ đọc/ghi không thực sự quan trọng với việc thực thi đặc quyền. Khi tiến trình được nạp vào bộ nhớ, trang chứa mã được bật cờ chỉ đọc. Như vậy các thao tác ghi lên trang nhớ này sẽ bị báo lỗi và từ chối thực hiện.
3.2.2 Cấm thực thi dữ liệu
Tấn công tràn bộ đệm là một trong những kỹ thuật khai thác lỗ hổng trong việc tổ
chức và quản lý không gian nhớ của chương trình. Ngăn chặn thực thi dữ liệu DEP (Data
Execution Prevention) là kỹ thuật bảo vệ bộ nhớ ở mức hệ thống được tích hợp vào hệ
điều hành. Về cơ bản, DEP cho phép hệ thống đánh dấu một hay nhiều trang bộ nhớ là không thực thi được. Như vậy đoạn mã tại vùng nhớ này sẽ không được thực thi và tạo thêm rào cản cho việc khai thác tràn bộ đệm.
Kiến trúc x86 hỗ trợ cơ chế này thông qua bit cấm chạy (execute-disable hay no-
execute) đặt tại trang nhớ. Khi chương trình cố thực thi đoạn mã từ trang nhớ có bít cấm
chạy được bật sẽ gây ra lỗi trang. Ở mức độ hệ điều hành nếu lỗi này không được xử lý thì chương trình đang chạy sẽ bị chấm dứt việc thực thi. Cơ chế cấm chạy có thể được kích hoạt bằng bít cấm chạy tại bất kỳ mức nào trong cấu trúc trang. Khi cơ chế bảo vệ này không được kích hoạt, trang nhớ có thể được dùng lẫn giữa mã và dữ liệu.
Mặt khác, DEP có thể được thực hiện ở mức hệ điều hành như trong Windows XP nhằm ngăn chặn mã độc lợi dụng cơ chế xử lý lỗi (exception) trong Windows. DEP từ phần mềm có thể hoạt động trên bất kỳ bộ xử lý bất kể bộ xử lý có hỗ trợ DEP từ phần cứng hay không. Tuy nhiên, DEP bằng phần mềm chỉ giới hạn bảo vệ các file nhị phân của hệ thống