2012-05-09 48 views
8

Tôi biết rằng các chức năng copy_to_user/copy_from_user, get_user/put_user là dành cho mục đích này.Làm thế nào để truy cập bộ nhớ không gian người dùng từ hạt nhân Linux?

Câu hỏi của tôi là, được cung cấp địa chỉ/con trỏ của không gian người dùng, làm cách nào tôi có thể truy cập vào dữ liệu được trỏ tới bởi địa chỉ từ hạt nhân nói chung?

Tôi có thể tưởng tượng rằng trước tiên tôi phải đảm bảo trang chứa phải nằm trong bộ nhớ vật lý (thay vì trong đĩa).

Bước tiếp theo là gì? Tôi có thể sử dụng *p, trong đó p là con trỏ trỏ tới dữ liệu không gian người dùng nào đó, trực tiếp để tham chiếu đến dữ liệu không?

Hoặc trước tiên tôi phải gọi kmap để ánh xạ khung trang vật lý có chứa vào không gian địa chỉ ảo hạt nhân? Tại sao?

Trả lời

4

Chỉ riêng con trỏ không đủ! Bạn cần phải biết quá trình mà con trỏ "thuộc về".

Khi quá trình này được đặt trước, con trỏ trỏ vào không gian địa chỉ của một quy trình khác. Địa chỉ có thể không được ánh xạ nữa, yadda yadda,

Nếu quá trình đó sẽ là quy trình hiện tại khi bạn truy cập dữ liệu, thì bạn nên sử dụng các hàm copy_to_user/copy_from_user.

Nếu quá trình này có thể được lên lịch, bạn có thể thử mlock() trang trong RAM và tìm ra địa chỉ ram vật lý của trang. Bất cứ khi nào bạn muốn truy cập nó, bạn ánh xạ trang vật lý đó vào một địa chỉ ảo hạt nhân.

LƯU Ý:

  • Một quá trình độc hại có thể munlock() trang và lừa bạn truy cập vào một trang RAM sai.
  • Tôi không chắc chắn ngữ nghĩa() ngữ nghĩa yêu cầu trang RAM gạch dưới KHÔNG PHẢI thay đổi.
  • hạt nhân sẽ có thể khóa một trang vào RAM, tôi không quen thuộc với hệ thống con mm.
3

Ứng dụng không gian người dùng khác nhau có bảng trang khác nhau. 1) bạn cần nhận pid chương trình không gian người dùng. 2) addree tìm kiếm trong bảng trang của pid.

Dưới đây là mã mẫu để dịch địa chỉ ảo của không gian người dùng thành địa chỉ thực. Nó hoạt động ở nền tảng x86.

taskpid = find_get_pid(curpid); 
task = pid_task(taskpid, PIDTYPE_PID); 
mm = get_task_mm(task); 
down_read(&mm->mmap_sem); 

start_vaddr = vaddr; 
end_vaddr = 0xC0000000; 

while(start_vaddr < end_vaddr){ 
    u32 end; 

    end = ((start_vaddr + PMD_SIZE) & PMD_MASK); 

    if(end < start_vaddr || end > end_vaddr) 
     end = end_vaddr; 

    ret = walk_pgd(start_vaddr, end, mm); 
    if(ret != 0){ 
     printk("ret: %08x \n", ret); 
     break; 
    } 

    start_vaddr = end; 

} 

up_read(&mm->mmap_sem); 

paddr = ret; 
kaddr = __va(paddr); 
mmput(mm); 
+0

Điểm tốt và logic mã là tốt đẹp. Nhưng tôi đoán có một số bảng băm hoặc cấu trúc dữ liệu tương tự, với một địa chỉ ảo, giúp bạn xác định vị trí trang vật lý một cách nhanh chóng. Có một lỗ hổng: kaddr = __va (paddr); Dòng này chỉ hoạt động khi paddr nằm trong bộ nhớ thấp, phải không? – Infinite

+0

paddr có nghĩa là địa chỉ vật lý, vì vậy, luôn luôn tồn tại trong bộ nhớ. kaddr nghĩa là địa chỉ hạt nhân. Trong định nghĩa hạt nhân Linux là '#define __va (x) ((void *) ((unsigned long) (x) + PAGE_OFFSET))'. Ánh xạ bộ nhớ địa chỉ hạt nhân không phức tạp, chỉ là PAGE_OFFSET. (Nên là 0xC0000000 ở chế độ x86). Có cách khác để lấy địa chỉ. Ứng dụng không gian người dùng có thể truy cập địa chỉ hạt nhân bằng/proc//sơ đồ trang để nhận thông tin trang. Nếu có thể nhận được PFN, nó cũng có thể lấy địa chỉ hạt nhân. – richliu

0

Bạn sẽ cần phải follow một địa chỉ để có được một page struct tương ứng (xem follow_page cho ví dụ). Tiếp theo, nhận cấu trúc page bạn sẽ cần ánh xạ tới không gian địa chỉ của hạt nhân qua kmap hoặc kmap_atomic.

3

Bạn có thể thấy điều này hữu ích.

Hãy để chúng tôi lặp lại đối số buff cho phương pháp đọc và viết là con trỏ không gian người dùng. Do đó, nó không thể bị hủy bỏ trực tiếp bởi mã số hạt nhân .Có một vài lý do để hạn chế này:

  • Tùy thuộc vào kiến ​​trúc lái xe của bạn đang chạy trên, và làm thế nào hạt nhân đã được cấu hình, con trỏ sử dụng không gian có thể không có giá trị trong khi chạy trong kernel mode tại tất cả các. Có thể không có ánh xạ cho địa chỉ hoặc nó có thể trỏ đến một số dữ liệu ngẫu nhiên khác.

  • Ngay cả khi con trỏ không có nghĩa là điều tương tự trong không gian hạt nhân, bộ nhớ không gian người dùng được phân trang và bộ nhớ được đề cập có thể không phải là trong RAM khi thực hiện cuộc gọi hệ thống. Cố gắng tham chiếu bộ nhớ không gian người dùng trực tiếp có thể tạo ra lỗi trang, là điều gì đó mà mã hạt nhân không được phép thực hiện. Kết quả sẽ là một "oops", điều này sẽ dẫn đến cái chết của quá trình thực hiện cuộc gọi hệ thống .

  • Con trỏ được đề cập đã được chương trình người dùng cung cấp, trong đó có thể bị lỗi hoặc độc hại. Nếu trình điều khiển của bạn bao giờ bị mờ một cách mù quáng một con trỏ do người dùng cung cấp, nó cung cấp một cửa mở cho phép chương trình không gian người dùng truy cập hoặc ghi đè bộ nhớ ở bất kỳ đâu trong hệ thống . Nếu bạn không muốn chịu trách nhiệm về việc xâm phạm bảo mật của hệ thống người dùng của mình, bạn không bao giờ có thể coi trọng trực tiếp con trỏ không gian người dùng .

Nguồn: http://www.makelinux.net/ldd3/chp-3-sect-7

Điều đó nói rằng, tôi là chính tôi tò mò muốn biết những gì sẽ xảy ra nếu địa chỉ sử dụng không gian là thực sự có giá trị, và không ai trong số các điều kiện trên được áp dụng ...

Các vấn đề liên quan