Farfetch’d
with a bowl because we insist on being kitchen-themed
Submission
As with previous assignments, we wil be using GitHub to distribute skeleton code and collect submissions. Please refer to our Git Workflow guide for more details. Note that we will be using multiple tags for this assignment, for each deliverable part.
Copyright By PowCoder代写 加微信 powcoder
For students on ARM Mac computers (e.g. with M1 chip): if you want your submission to be built/tested for ARM, you must create and submit a file called .armpls in the top-level directory of your repo; feel free to use the following one-liner:
You should do this first so that this file is present in all parts.
Code Style
There is a script in the skeleton code named run_checkpatch.sh . It is a wrapper over linux/scripts/checkpatch.pl , which is a Perl script that comes with the linux
kernel that checks if your code conforms to the kernel coding style.
Execute run_checkpatch.sh to see if your code conforms to the kernel style – it’ll let you know what changes you should make. You must make these changes before pushing a tag. Passing run_checkpatch.sh with no warnings and no errors is required for this assignment.
Skeleton code setup
Kernel system call stubs
In addition to the pristine Linux kernel source tree (now under linux/ ) we’ve provided a patch file which will create the syscall stubs for you. You will need to apply this patch to your repo.
The patch is under the following path:
You can use git apply to apply this patch. First, check which files will be modified by the patch:
You should also inspect what the patch is doing by reading the diffs inside. Finally,
patch/farfetch.patch
$ git apply –stat patch/farfetch.patch
cd “$(git rev-parse –show-toplevel)” && touch .armpls && git add .armpls
you can apply the patch with the following:
$ git apply patch/farfetch.patch
Now, when you run git status , you should see some files modified, as well as some .c and .h files added. After verifying that these changes worked as intended,
commit them.
Building your patched kernel
Build your kernel. Make sure you’re building with a local version that is different from your fallback ( -cs4118 ), so you don’t overwrite it; set your local version to your UNI (i.e. –
Now, when you build your kernel, you should have the farfetch() syscall stub in your kernel.
Installing kernel headers
The syscall you will implement has a cmd parameter whose possible values (defined by an enum) are unique to the syscall, and which must be known by the caller. This means that the enum definition needs to be available in both kernel and user land. You’ll need to install the farfetch header ( include/uapi/linux/farfetch.h ) from the kernel source tree to userspace.
Once you’ve built your farfetch() -stubbed kernel, run the following command:
This command will install the headers found under include/uapi/ in your Linux source tree into /usr/include/ . Now you should be able to #include
# make headers_install INSTALL_HDR_PATH=/usr
farfetch : Fetching Pages from Afar
For this assignment, you will be implementing farfetch() , a system call that allows you to manipulate the memory of a specified process. The syscall number for
farfetch() is 505, and it should be implemented as a dynamically loadable module. Behavior
The function prototype for farfetch() is the following:
farfetch() will take in five arguments:
cmd : indicates whether to read or write the remote memory by specifying
FAR_READ or FAR_WRITE , respectively (defined in the UAPI header)
addr : a pointer to the caller’s user-space buffer
target_pid : the PID of the process whose memory is to be fetched
target_addr : the starting memory address in the target process’s virtual address space
len : the maximum number of bytes to copy
Return values and error handling
On success, farfetch() should return the number of bytes copied (<= len ). If the user issuing the syscall is not root, fail with the errno value EPERM .
If cmd is not FAR_READ or FAR_WRITE , fail with the errno value EINVAL .
If the specified PID does not exist, fail with the errno value ESRCH .
If copying to/from addr fails, fail with the errno value EFAULT .
long farfetch(unsigned int cmd, void __user *addr, pid_t target_pid, unsigned long target_addr, size_t len);
If target_addr is not a valid user-space address, or is unmapped in the target virtual address space, fail with the errno value EFAULT .
Part 1: Walking the Walk
You will be implementing farfetch() in this part, but with a few simplifying limitations; most significantly, you will only be dealing with the single physical page that is associated with target_addr , so there’s no need to worry about traversing to any subsequent pages. You will copy to/from this page up until either len bytes or the end of the page (whichever comes first).
There is one restriction on your implementation for this part: you may NOT use get_user_pages_remote() / pin_user_pages_remote() , nor anything which invokes them. You may reference their implementation for performing a page walk, but note
that the relevant bits are buried in logic that deals with things you don’t need to worry about (traversing arbitrary address ranges, huge pages, special mappings, faulting in pages, etc.)—if your module contains such extraneous code, it will incur a steep deduction. Every line you write should be with purpose, so avoid haphazardly copy-pasting functions or large chunks of code.
Consequently, you will need to manually perform the 5-level page walk. Some additional simplifying limitations:
If you encounter an entry which is not present in memory, just report EFAULT . Do NOT allow writing to a non-writable PTE; in the event you are asked to do so
by FAR_WRITE , just report EFAULT .
If performing a FAR_WRITE , you should mark the modified page as dirty using
set_page_dirty_lock() .
To determine if target_addr is a valid user-space address, it is sufficient to check against the end of the target process’s virtual address space, which is evaluated by the TASK_SIZE_OF() macro; anything >= TASK_SIZE_OF() cannot be a valid user address for the task.
Our recommendation is to start with the resources linked below before looking at
kernel code, as those more directly get at what you need to implement the page walk.
Requirements
Able to copy up to a page of memory into/out of any target process.
Doesn’t allow writing to any write-protected PTE.
Does NOT (even indirectly) invoke get_user_pages_remote() / pin_user_pages_remote() .
No significantly extraneous code.
Proper error handling in all specified cases.
Test your implementation as described below.
After testing, answer the following in your written_answers.txt :
i. Observe and explain any difference in behavior when using farfetchd on the provided mmap target versus the malloc target.
Hint: try fetching a full page (i.e. 4096 bytes); how many bytes are actually fetched in each case?
Hint: man mmap .
ii. Observe and explain any difference in behavior when using farfetchd on the provided mmap target versus the fork target (in both the parent and child).
iii. Observe and explain the behavior of farfetchd on the strlit target.
iv. Try going through Session 2 without using setarch -R , which is used to disable ASLR for the process; that is, run the twecho target directly. Briefly describe what ASLR is, and explain how it affects finding the argv strings.
Hint: check where the stack is in /proc/
3) with and without setarch -R . Submission
To submit this part, push the hw7p1handin tag with the following:
Part 2: Time for Takeoff
For this part, we are lifting the main restriction of Part 1 and encouraging that you use get_user_pages_remote() . You can let the internal “GUP” logic (belonging to the get_user_pages_* family of functions) handle the details of the walk.
The use of GUP logic provides the following functionalities which were not required in Part 1:
Deal with arbitrary address ranges (potentially spanning multiple pages) Modify non-writable memory
We are the kernel. We do what we want Remember to mark any modified pages dirty (as in Part 1).
Requirements
All the functionality of Part 1.
Able to read/write arbitrary address ranges (potentially > PAGE_SIZE ). Able to write to non-writable memory (e.g. strlit target).
Invoke get_user_pages_remote() exactly once (there should be no need for repeated calls, e.g. in a loop).
$ git tag -a -m “Completed hw7 part1.” hw7p1handin
$ git push origin master
$ git push origin hw7p1handin
If get_user_pages_remote() fails, relay the errno back to the user.
If it reports less than the requested number of pages, adjust the length of
the copy (< len ).
Answer the following in your written_answers.txt :
i. Ensure that the behavior observed in Part 1 for the fork target is remedied; explain generally how the GUP logic handles this case. Feel free to reference line numbers in mm/gup.c .
Hint: there is an internal FOLL_* flag which is pertinent, see where this is set.
Submission
To submit this part, push the hw7p2handin tag with the following:
The farfetchd Hacker Utility
We’ve provided a userspace utility to test your implementation, under the following
In particular, farfetchd takes a target PID, address, and maximum length, and will execute your syscall up to two times; once to FAR_READ from the target, and then if you choose to modify any memory, once to FAR_WRITE it.
$ git tag -a -m "Completed hw7 part2." hw7p2handin
$ git push origin master
$ git push origin hw7p2handin
user/test/farfetchd/
You will need to install bvi before using farfetchd :
# apt install bvi
You will find the provided target programs useful for testing under the following path:
Though feel free to write your own for additional testing.
Linked below are some example shell sessions of testing with farfetchd , using the final Part 2 version. Note that the behavior will be different for Part 1 in some cases.
Session 1 Session 2 Session 3
Deliverables
Implement the farfetch() syscall in a kernel module using the function pointer technique from HW4.
You will find a module stub in your skeleton repo at the path user/module/farfetch/ . Implement your modularized system call here in farfetch.c .
Don’t modify the existing boilerplate code.
You should start your code in the farfetch() function.
Feel free to define and call any more functions inside your module.
You can find the farfetch cmd values ( FAR_READ / FAR_WRITE ) defined for you in the Linux kernel source tree, under include/uapi/linux/farfetch.h . Remember to install these during the setup stage so that you can include
user/test/targets/
this file from userspace.
You do not have to worry about ensuring your solution is architecture- independent. That is, we will only test your solution on your specified architecture.
Include your answers to Part 1 and Part 2 questions in written_answers.txt .
Useful Resources
Below is some online reading material that you may find helpful for this assignment:
Understanding the Linux Virtual Memory Manager: Page Table Management Stack Overflow: Details for PTE and struct page
Linux Kernel Teaching: Memory Mapping
Halo Linux: Page Table Handling
TLDP: Memory Management
For official Linux documentation on memory management:
x86_64 arm64
程序代写 CS代考 加微信: powcoder QQ: 1823890830 Email: powcoder@163.com