거북이의 쉼터

(2022.02.03) User Memory Access 가이드라인 본문

코딩 삽질/KAIST PINTOS (CS330)

(2022.02.03) User Memory Access 가이드라인

onlim 2022. 2. 3. 14:22

음... 이번 매뉴얼은 뭔가 짧다.

To implement syscalls, you need to provide ways to read and write data in user virtual address space. You don't need this ability when getting the arguments. However, when you read the data from the pointer provided as the system call's argument, you should proxied through this functionallity. This can be a bit tricky: what if the user provides an invalid pointer, a pointer into kernel memory, or a block partially in one of those regions? You should handle these cases by terminating the user process.

 

User Program이 syscall을 통해 메모리에 접근하려고 할 때, 비정상적인 접근은 모두 막아야 한다는 내용이다. 비정상적인 주소, 커널 주소 등 접근해서는 안되는 영역에 접근하려고 할 때는 모두 User Process를 강제 종료시키라는 것이다. 이를 검증하는 방법을 고안하라는 것이 해당 subtask의 목적일 것이다. 하지만 여기까지만 보면 너무 막연하다. 그래서 다른 곳에 설명이 더 있나 해서 찾아보았다. Introduction에 관련 내용이 더 있었다.

There are at least two reasonable ways to do this correctly. The first method is to verify the validity of a user-provided pointer, then dereference it. If you choose this route, you'll want to look at the functions in thread/mmu.c and in include/threads/vaddr.h. This is the simplest way to handle user memory access.

The second method is to check only that a user pointer points below KERN_BASE, then dereference it. An invalid user pointer will cause a "page fault" that you can handle by modifying the code for page_fault() in userprog/exception.c. This technique is normally faster because it takes advantage of the processor's MMU, so it tends to be used in real kernels (including Linux).

 

첫 번째 방법은 syscall이 호출될 때 우선 포인터에 대한 검증을 모두 마친 뒤, 안전하다고 판단이 되면 syscall을 실행하는 방법이다. 두 번째는 포인터가 KERN_BASE 아래에 있는지만 확인한 뒤, 오류가 있다면 page fault를 이용해서 잡아내는 방법이다. 두 번째 방법을 사용하기 위해서는 page_fault 함수도 수정해야 할 필요가 있어서 난 첫 번째 방식으로 진행을 하려고 한다.

 

이제 방향성을 정했으니 구체적으로 유저 포인터의 제약 조건을 생각해보자.

 

  • invalid pointer -> NULL 등 mapping 되지 않은 주소
  • kernel pointer -> KERN_BASE 상위 주소
  • block partially in one of those regions -> 영역의 일부가 비정상적인 블록?

마지막 것은 조금 애매하긴 한데... 아마 read / write 같이 특정 포인터 주소 뿐만이 아닌 메모리의 일정 역역을 사용하는 syscall에서 사용하는 메모리의 일부가 invalid / kernel 영역일 경우 강제 종료하라는 뜻으로 해석했다. 지금까지의 내용을 종합하면 subtask를 위해서 2가지 정도 함수를 구현해야 할 것으로 보인다.

 

  • 주어진 유저 포인터 (uaddr)이 유효한 주소인지 검사하는 함수
  • 주어진 영역 (uaddr + 범위)가 유효한지 검사하는 함수

이제 어느 정도 해석이 됐다. 다음 포스팅에서는 실제로 해당 내용을 구현해보도록 하겠다.

Comments