Vietnamese (machine translation)

Lưu ý

Mục đích của file này là để độc giả tiếng Việt có thể đọc và hiểu tài liệu nhân kernel dễ dàng hơn, không phải để tạo ra một nhánh tài liệu riêng. Nếu bạn có bất kỳ nhận xét hoặc cập nhật nào cho file này, vui lòng thử cập nhật file tiếng Anh gốc trước. Nếu bạn thấy có sự khác biệt giữa bản dịch và bản gốc, hoặc có vấn đề về bản dịch, vui lòng gửi góp ý hoặc patch cho người dịch của file này, hoặc nhờ người bảo trì và người review tài liệu tiếng Việt giúp đỡ.

Bản gốc:

Memory Protection Keys

Người dịch:

Google Translate (machine translation)

Phiên bản gốc:

8541d8f725c6

Cảnh báo

Tài liệu này được dịch tự động bằng máy và chưa được review bởi người dịch. Nội dung có thể không chính xác hoặc khó hiểu ở một số chỗ. Khi có sự khác biệt với bản gốc, bản gốc luôn là chuẩn. Bản dịch chất lượng cao (được review) được đặt trong thư mục vi_VN/.

Phím bảo vệ bộ nhớ

Khóa bảo vệ bộ nhớ cung cấp cơ chế thực thi dựa trên trang các biện pháp bảo vệ mà không yêu cầu sửa đổi bảng trang khi ứng dụng thay đổi miền bảo vệ.

Không gian người dùng Pkeys (PKU) là một tính năng có thể tìm thấy trên:
  • CPU máy chủ Intel, Skylake trở lên

  • CPU máy khách Intel, Tiger Lake (Lõi thế hệ thứ 11) trở lên

  • CPU AMD trong tương lai

  • CPU arm64 triển khai Tiện ích mở rộng lớp phủ quyền (FEAT_S1POE)

x86_64

Pkey hoạt động bằng cách dành 4 bit dành riêng trước đó trong mỗi mục của bảng trang cho một “chìa khóa bảo vệ”, cung cấp 16 khóa có thể.

Các biện pháp bảo vệ cho mỗi khóa được xác định bằng một thanh ghi người dùng có thể truy cập trên mỗi CPU (PKRU). Mỗi cái trong số này là một thanh ghi 32 bit lưu trữ hai bit (Tắt truy cập và Tắt ghi) cho mỗi phím trong số 16 phím.

Là một thanh ghi CPU, PKRU vốn có tính chất luồng cục bộ, có khả năng cung cấp cho mỗi xâu chuỗi một bộ bảo vệ khác với mọi luồng khác.

Có hai hướng dẫn (RDPKRU/WRPKRU) để đọc và ghi vào đăng ký. Tính năng này chỉ khả dụng ở chế độ 64-bit, mặc dù có về mặt lý thuyết là không gian trong PAE PTE. Các quyền này được thực thi trên dữ liệu chỉ truy cập và không ảnh hưởng đến việc tìm nạp lệnh.

cánh tay64

Pkey sử dụng 3 bit trong mỗi mục trong bảng trang để mã hóa “chỉ mục khóa bảo vệ”, đưa ra 8 chìa khóa có thể.

Các biện pháp bảo vệ cho mỗi khóa được xác định bằng hệ thống người dùng có thể ghi trên mỗi CPU đăng ký (POR_EL0). Đây là mã hóa thanh ghi 64 bit đọc, ghi và thực thi quyền che phủ cho từng chỉ mục khóa bảo vệ.

Là một thanh ghi CPU, POR_EL0 vốn có tính chất luồng cục bộ, có khả năng cung cấp mỗi luồng có một bộ bảo vệ khác nhau với mọi luồng khác.

Không giống như x86_64, các quyền của khóa bảo vệ cũng áp dụng cho lệnh tìm nạp.

tòa nhà chọc trời

Có 3 lệnh gọi hệ thống tương tác trực tiếp với pkey:

int pkey_alloc(cờ dài không dấu, init_access_rights dài không dấu)

int pkey_free(int pkey); int pkey_mprotect(bắt đầu dài không dấu, size_t len,

prot dài không dấu, int pkey);

Trước khi có thể sử dụng pkey, trước tiên nó phải được cấp phát bằng pkey_alloc(). Một ứng dụng ghi trực tiếp vào kiến trúc CPU cụ thể theo thứ tự để thay đổi quyền truy cập vào bộ nhớ được bao phủ bởi một phím. Trong ví dụ này cái này được bao bọc bởi một hàm C có tên là pkey_set(). :::::::::::::::::::::::::::::::::::::::::::::::::::::::

int real_prot = PROT_READ|PROT_WRITE;

pkey = pkey_alloc(0, PKEY_DISABLE_WRITE); ptr = mmap(NULL, PAGE_SIZE, PROT_NONE, MAP_ANONYMOUS|MAP_PRIVATE, -1, 0); ret = pkey_mprotect(ptr, PAGE_SIZE, real_prot, pkey); ... application runs here

Bây giờ, nếu ứng dụng cần cập nhật dữ liệu tại ‘ptr’, nó có thể giành quyền truy cập, thực hiện cập nhật, sau đó xóa quyền ghi của nó

pkey_set(pkey, 0); // xóa PKEY_DISABLE_WRITE

*ptr = foo; // gán cái gì đó pkey_set(pkey, PKEY_DISABLE_WRITE); // đặt lại PKEY_DISABLE_WRITE

Bây giờ khi nó giải phóng bộ nhớ, nó cũng sẽ giải phóng pkey vì nó không còn được sử dụng nữa:

munmap(ptr, PAGE_SIZE);

pkey_free(pkey);

Lưu ý

pkey_set() is a wrapper around writing to the CPU register. Example implementations can be found in tools/testing/selftests/mm/pkey-{arm64,powerpc,x86}.h

Hành vi

Hạt nhân cố gắng tạo ra các khóa bảo vệ nhất quán với hành vi của một mprotect() đơn giản. Ví dụ: nếu bạn làm điều này

mprotect(ptr, kích thước, PROT_NONE);

cái gì đó(ptr);

bạn có thể mong đợi những hiệu ứng tương tự với các khóa bảo vệ khi thực hiện việc này:

pkey = pkey_alloc(0, PKEY_DISABLE_WRITE | PKEY_DISABLE_READ);

pkey_mprotect(ptr, kích thước, PROT_READ|PROT_WRITE, pkey); cái gì đó(ptr);

Điều đó đúng cho dù something() có truy cập trực tiếp vào ‘ptr’ hay không thích:

*ptr = foo;

hoặc khi kernel thực hiện quyền truy cập thay mặt ứng dụng như với một lần đọc():

đọc(fd, ptr, 1);

Hạt nhân sẽ gửi SIGSEGV trong cả hai trường hợp, nhưng si_code sẽ được đặt tới SEGV_PKERR khi vi phạm các khóa bảo vệ so với SEGV_ACCERR khi các quyền mprotect() đơn giản bị vi phạm.

Lưu ý rằng việc truy cập kernel từ kthread (chẳng hạn như io_uring) sẽ sử dụng mặc định giá trị cho thanh ghi khóa bảo vệ và do đó sẽ không nhất quán với giá trị vùng người dùng của thanh ghi hoặc mprotect().