Sau khi tạo ra hai chính sách điều khiển truy cập khác nhau cho hai phase, nhóm tác giả thực hiện việc so sánh số lượng các quy tắc trong cả hai chính sách này với số lượng quy tắc có sẵn trong SELinux thì thu được kết quả rất khả quan khi giảm được một lượng không nhỏ các quy tắc trong chính sách bảo mật. Khi tiến hành kiểm nghiệm với các giao thức cụ thể, kết quả được thể hiện trong bảng:
3.4. Kết luận và khuyến nghị ngƣời sử dụng
SELinux là một sản phẩm chất lượng cao do NSA phát triển nhằm nâng cao tính an toàn cho hệ thống chạy Linux bởi cơ chế bảo mật MAC. Tuy nhiên, để đảm bảo tính mềm dẻo, chi tiết trong khi thực thi, các tác giả đã phải hi sinh tính đơn giản trong cài đặt. Mỗi bộ chính sách SELinux chuẩn thông thường có khoảng 100.000 dòng. Do đó, hiện nay chỉ có tỷ lệ rất nhỏ người dùng trong giới quản trị mạng Linux sử dụng SELinux. Số người có khả năng viết thêm hoặc sửa bộ chính sách cho các ứng dụng mới còn ít hơn. Rất nhiều nghiên cứu đã được triển khai nhằm giảm bớt tính phức tạp của bộ chính sách SELinux nhằm lôi kéo nhiều người dùng hơn đến với cơ chế bảo mật rất hoàn hảo này.
Luận văn nghiên cứu việc sinh ra các chính sách của SELinux bằng Polgen, phân tích để người sử dụng hiểu rõ các chính sách đó mà không cần kiến thức chuyên sâu về SELinux, nhờ đó giúp cho việc phổ biến rộng rãi SELinux trong cộng đồng.
Ngoài ra luận văn đã thực hiện nhiệm vụ kiểm chứng lại lý thuyết chia phase do nhóm tác giả tại đại học Keio (Nhật) đề xuất. Đây là một bài toán rất khó đối với người thực hiện do đó phải hiểu sâu về kiến trúc nhân Linux để viết/biên dịch module nhân mới. Người thực hiện cũng phải có đủ hiểu biết về bộ chính sách SELinux để phân biệt chính sách nào thuộc phase nào. Tổng khối lượng công việc là rất lớn và nặng.
Chƣơng 4. TRIỂN KHAI THỬ NGHIỆM
4.1. Lập trình module nhân Linux[10]
4.1.1. Module nhân là gì?
Modules là các phần mã được lập trình, có thể được tải vào hoặc gỡ bỏ khỏi hạt nhân theo yêu cầu. Module mở rộng chức năng của hạt nhân mà không cần phải khởi động lại hệ thống. Ví dụ một loại module là device driver, cho phép hạt nhân truy cập vào phần cứng được kết nối với hệ thống.
Nếu không có module, tất cả các chức năng của hệ điều hành sẽ được biên dịch trực tiếp vào hạt nhân. Phần lớn các chức năng nằm trong bộ nhớ mà không được sử dụng, gây lãng phí bộ nhớ trong khi lại yêu cầu người dùng phải xây dựng và khởi động lại hệ thống mỗi khi muốn thêm một chức năng mới.
Module khác với chương trình (program). Một chương trình bắt đầu với một hàm main(), thực thi một loạt các lệnh và kết thúc sau khi hoàn thành các lệnh đó. Trong khi một module luôn bắt đầu với init_module hoặc một hàm được chỉ định là gọi module_init. Đây được coi là hàm khởi tạo của module. Có nhiệm vụ chỉ cho hạt nhân biết các chức năng mà module cung cấp và thiết lập hạt nhân để chạy các hàm của module khi cần. Một khi thực hiện, hàm khởi tạo sẽ gọi giá trị trả về và module sẽ không làm gì cho đến khi hạt nhân muốn làm gì đó với mã mà module cung cấp. Tất cả các module kết thúc bằng cách gọi hàm cleanup_module hoặc hàm được chỉ định là gọi module_exit. Đây coi như là chức năng thoát của module. Có tác dụng khiến mọi thứ trở về trạng thái trước khi thực hiện hàm init_module. Hàm thoát của module không đăng ký các chức năng mà init_module đã đăng ký. Yêu cầu tối thiểu cho mỗi module là phải có một hàm khởi tạo và một hàm thoát.
Các lập trình viên thường sử dụng các hàm không định nghĩa về thời gian. Ví dụ như printf(). Và sử dụng các hàm được cung cấp bởi thư viện chuẩn C. Định nghĩa cho các hàm này thực tế không khớp với chương trình khi viết cho module cho đến khi trạng thái kết nối được thiết lập, nó sẽ đảm bảo rằng mã chương trình
đã sẵn sàng và cần sửa các lệnh gọi để trỏ đến mã đó. Module không thể in ra màn hình giống như printf(), nhưng có thể ghi lại thông tin và cảnh báo.
Đây chính là điểm khác biệt của module nhân. Trong ví dụ về module ―HelloWorld‖ trong mục 4.2.2, có sử dụng hàm printk(), nhưng không cần phải cung cấp thư viện I/O. Đó là bởi vì các module là các tập tin đối tượng mà ký hiệu của chúng đã được chuyển sang khi chèn module vào hạt nhân. Các định nghĩa cho các ký hiệu đến từ chính hạt nhân đó. Do đó, khi lập trình trong module chỉ được sử dụng các thư viện được cung cấp bởi hạt nhân. Tất cả các ký hiệu được xuất ra bởi hạt nhân nằm trong /proc/kallsyms.
Một điểm cần lưu ý là sự khác biệt giữa các hàm thư viện và các hàm gọi hệ thống (system calls[10]). Các hàm thư viện ở mức độ cao hơn, chạy hoàn toàn trong không gian người dùng và cung cấp một giao diện thuận lợi cho người lập trình. Các system call chạy trong chế độ hạt nhân với tư cách người dùng và được cung cấp bởi chính hạt nhân đó. Hàm thư viện printf() có thể trông giống như một hàm in rất chung, nhưng thực tế nó định dạng dữ liệu thành các chuỗi và viết các chuỗi dữ liệu bằng cách sử dụng system call cấp thấp write(), system call này sau đó sẽ gửi dữ liệu tới đầu ra chuẩn.
Chúng ta hoàn toàn có thể viết các module thay thế các system call của nhân. Các hacker thường sử dụng cách này để tấn công hệ thống bằng backdoor hoặc Trojan. Nhưng chúng ta hoàn toàn có thể viết các module của riêng mình để thực hiện những điều mình muốn.
4.1.2. Hướng dẫn viết module nhân đơn giản[10]
4.1.2.1. Yêu cầu
Cài đặt các gói : kernel, kernel-devel để cung cấp nhân mới và cài gói gcc để biên dịch các tệp .c:
yum install kernel kernel-devel yum install gcc
Yêu cầu 3 gói kernel , kernel-devel, kernel-headers phải cùng phiên bản với nhau, câu lệnh để kiểm tra như sau:
4.1.2.2. Viết, chèn, gỡ một module khỏi nhân
Tạo 1 tệp có tên là helloworld.c (chính là module ta cần phải viết ) trong bất cứ thư mục nào
Sửa tệp helloworld.c như sau:
Hình 4.1. Tập tin helloworld.c
Tạo 1 tệp có tên là Makefile nằm trong cùng thư mục với tệp helloworld.c và sửa tệp Makefile này như sau:
Hình 4.2. Tập tin Makefile Khởi động lại máy với nhân mới
Hình 4.3. Kết quả của lệnh make
Để xem đây là loại thông tin gì sử dụng lệnh : modinfo helloworld.ko
Chèn module vừa tạo vào nhân bằng lệnh: insmod ./helloworld.ko
Các module được tải vào nhân nằm trong tệp /proc/modules
Để xóa module ra khỏi nhân: rmmod helloworld.
Vào /var/log/messages để xem các sự kiện được ghi lại Kết quả: có 2 sự kiện Hello world! và Goodbye world!
4.1.3. Biên dịch [1] và cài đặt nhân linux
Nhân Linux là cốt lõi của hệ điều hành, hoạt động như một môi trường trung gian giữa phần cứng và tất cả các tiến trình. Nhân cung cấp việc quản lý bộ nhớ, đa tác vụ, đầu ra/đầu vào, kết nối mạng và nhiều chức năng khác. Hiện nay, nhân Linux rất hiện đại vì có tính module rất cao. Rất thuận lợi cho việc cấu hình và biên dịch lại nhân cho phép người dùng có thể gỡ bỏ những phần của hạt nhân mà không cần thiết cho mục đích sử dụng của hệ thống.
Vì Linux là phần mềm mã nguồn mở, do đó việc truy cập vào mã nguồn của nhân là hoàn toàn tự do. Có nghĩa là bất cứ ai cũng hoàn toàn có thể tự do tùy chỉnh và biên dịch lại nhân cho phù hợp với nhu cầu cụ thể của họ.
Tuy nhiên khi nghĩ đến tùy biến và biên dịch lại nhân, thường người ta nghĩ rằng sẽ phải đọc hàng ngàn dòng chương trình C, nhưng hoàn toàn không phải vậy. Những module nhân không cần thiết có thể được gỡ bỏ mà không cần phải sửa lại bất kỳ một dòng chương trình nào.
Công cụ sẵn có để cấu hình và biên dịch tiến trình hiện nay đã dễ dàng hơn, nhưng đây vẫn là một quá trình khá phức tạp. Hạt nhân cũ không được sao lưu đúng cách và các lỗi trong quá trình biên dịch có thể dẫn đến một vài chức năng của hệ
thống hoạt động không đúng hay tệ hơn, khiến hệ thống không thể khởi động lên được. Vì vậy, cần phải chú ý một số yêu cầu sau:
4.1.3.3. Vì sao phải biên dịch lại nhân?
Biên dịch lại nhân để chữa lỗi của nhân: Nếu các lỗi này thuộc về lõi của nhân thì phải vá nguồn của nhân và biên dịch lại để sửa chữa các lỗi được thông báo.
Biên dịch lại nhân để nâng cao hiệu năng của nhân: Theo mặc định, các bản phân phối Linux thường kèm theo một phiên bản nhân được biên dịch với hầu hết những thành phần có sẵn để có thể đáp ứng rộng rãi cấu hình phần cứng. Lúc khởi điểm, đây đúng là một lợi thế vì rất đơn giản là người dùng không cần phải can thiệp gì cả. Tuy nhiên, sau khi đã cài thành công và nắm chắc máy có những thiết bị gì và biết rõ cần những thành phần nào cho cấu hình của máy thì không có lý do gì phải cài đặt thêm cả những thứ không cần thiết và không dùng đến.
Biên dịch lại nhân để loại bỏ những ―drivers‖ không được dùng và có thể gây lỗi hay gây hiểu lầm cho nhân, khiến hệ thống hoạt động thiếu ổn định và hay gây lỗi.
Biên dịch lại nhân để thử nghiệm một chức năng hoặc một module mình vừa tạo ra
Trường hợp này người dùng thường không hay sử dụng, nhưng lại rất có ích cho các lập trình viên muốn tham gia lập trình module.
Biên dịch lại hạt nhân cũng là cần thiết trong trường hợp một phần cứng mới được thêm vào hệ thống mà hạt nhân hiện tại không hỗ trợ.
4.1.3.3. Quy ước cấu trúc phiên bản hạt nhân
Phiên bản của nhân Linux được quy ước theo các quy tắc cụ thể, đơn giản, dễ nhớ nhưng vô cùng quan trọng khi muốn chọn một phiên bản nào đó của nhân Linux để vá và biên dịch.
Số phiên bản nhân gồm 3 số phân tách nhau bởi dấu chấm như: 2.6.38 Số đầu tiên là số hiệu phiên bản chính.
Số thứ hai là số chỉ định cho tình trạng phiên bản. Nếu số này là số chẵn, nó chỉ định cho phiên bản phát hành ổn định. Ngược lại, nếu là số lẻ, nó chỉ định cho phiên bản không ổn định, thường dùng trong môi trường đang phát triển. Các nhân
thuộc loại này thường có nhiều lỗi và không ổn định. Cộng đồng Linux thường dùng các phiên bản này để tìm lỗi và thông báo cho nhóm phát triển nhân Linux. Và do đó cũng khuyến cáo với người dùng bình thường là không nên dùng các phiên bản phát triển để chạy các ứng dụng.
Số thứ ba là chỉ định cho số hiệu phát hành của một phiên bản nhân Linux. Một phiên bản ổn định của một nhân Linux có thể có nhiều số hiệu phát hành khác nhau (cũng được coi là phiên bản vá lỗi). Chỉ khi phiên bản 2.3.x được xem là hoàn tất, mới trở thành hạt nhân 2.4.0. Các bản vá lỗi sau đó sẽ xuất hiện với phiên bản 2.4.x và công việc phát triển sẽ bắt đầu trên phiên bản 2.5.x.
4.1.3.3. Yêu cầu tối thiểu trong việc biên dịch lại nhân Linux
Để biên dịch được nhân thì cần thiết phải có đủ chỗ chứa trên đĩa. Ít nhất phải có đủ chỗ chứa cho mã nguồn cả trước và sau khi giải nén, chỗ chứa để cài nhân và các module mới sau khi biên dịch.
Yêu cầu thứ hai vô cùng quan trọng là phải có một bộ công cụ cần thiết và đúng phiên bản mới đảm bảo biên dịch thành công được.
Cần quan tâm đến cấu hình của máy, những thông tin này sẽ giúp ta lựa chọn cấu hình hạt nhân phù hợp và không phải mất quá nhiều thời gian cho việc cài đặt những lựa chọn không phù hợp.
4.1.3.3. Cấu hình hạt nhân mới:
Đầu tiên, muốn có một hạt nhân mới để thực hành, ta phải tải nhân từ trên các máy chủ, có thể tải theo liên kết sau http://www.kernel.org/ . Sau đó tùy chọn một nhân để tải về. Tập tin sau khi tải về có định dạng là linux-2.x.x.tar.bz2. Sử dụng câu lệnh tar –jxvf linux-2.x.x.tar.bz2 để giải nén vào thư mục hiện hành.
Có 3 giao diện để cấu hình nhân:
make menuconfig và make xconfig : 2 chế độ này đều cần thêm thư viện hỗ trợ đồ họa, do đó dễ sử dụng và có khả năng thực hiện lại khi cần thiết.
make config: thường chỉ dành cho những người biết rõ mình cần cài đặt những gì và không được phép chọn lại.
Người biên dịch được phép chọn lựa cách biên dịch các drivers của nhân theo dạng modules hay theo dạng biên dịch trực tiếp vào nhân. Thông thường khi
xác lập cấu hình cho nhân có ba lựa chọn: Y, M, N. Có những driver không thể biên dịch như một module vì nó phải được tải và liên kết trực tiếp ngay khi nhân khởi động. Cũng có những driver được phép chọn như một module và được tải trong và sau khi nhân được khởi động. Vấn đề quan trọng ở đây là phải hiểu rõ tại sao phải chọn M (cho module), Y (cho biên dịch trực tiếp) và N (không dùng) cho các drivers này.
Đối với nhân nguyên khối (monolithic kernel): Các drivers dù có được dùng hay không vẫn tải lên khi nhân khởi động và tất nhiên nó sẽ chiếm một phần lớn bộ nhớ. Ưu điểm của lựa chọn này là một khi drivers đã được biên dịch vào nhân thì không còn phải lo lắng đến tính xác thực của nhân và các driver nữa. Các hệ thống làm việc đòi hỏi tính bảo mật cao không dùng modules mà biên dịch thẳng vào nhân để tránh trường hợp các module không tin cậy bị cài vào nhân lúc nào đó trong quá trình hoạt động của hệ thống. Thêm một ưu điểm nữa là tính hiệu suất cao, khi cần driver thì đã có sẵn và không cần phải tải nữa.
Đối với nhân có cấu trúc module (modular kernel): Chỉ khi nào cần dùng các drivers này mới dc tải. Ưu điểm của lựa chọn này là tiết kiệm được bộ nhớ và tài nguyên của hệ thống. Với lựa chọn này, ta có thể tạo nên một nhân rất nhỏ và dễ dàng di chuyển cho nhiều mục đích khác nhau. Thêm một ưu điểm nữa là khả năng biên dịch lại chỉ một hoặc một số modules nào đó.
Như vậy, ưu điểm của nhân có cấu trúc module lại chính là nhược điểm của nhân nguyên khối và ngược lại.
4.1.3.3. Các bước thực hiện biên dịch và cài đặt
Đây là các bước thực hiện biên dịch[1] và cài đặt áp dụng cho loạt nhân 2.6.x và được thực hiện trong thư mục chứa mã nguồn:
Bước 1: make clean: dọn dẹp tất cả những objects không còn cần thiết. Bước 2: make bzImage: tạo nhân dạng nén. Đây là bước rất quan trọng, nếu xảy ra sự cố gì sẽ phải quay lại điều chỉnh cấu hình biên dịch nhân và chạy lại B1. Bước này thực hiện khá lâu và kết quả sẽ tạo ra nhân trong thư mục .arch/…/boot. Nhân đã được tạo nhưng chưa được cài.
Bước 3: make modules: biên dịch và tạo ra các modules (mà khi cấu hình ta chọn M). Các module đã được biên dịch sẽ được lưu trữ trong các thư mục tương ứng với từng nhóm drivers trong cây mã nguồn. Đây là giai đoạn lâu nhất trong cả quá trình biên dịch thực sự mã nguồn của nhân.
Bước 4: make modules_install: cài các modules vừa biên dịch vào thư mục
/lib/modules/<kernel_vesion>, bước này bắt buộc người dùng phải là root.
Bước 5: make install: thao tác các bước cần thiết để thiết lập nhân mới trên hệ thống. Bước này bao gồm quá trình lưu trữ nhân cũ, copy nhân mới, copy