cat calls open("README", 0), and in the kernel the saved a0 is 0x3fe0, the
address of the string in cat’s memory. Why can’t sys_open simply cast that number
to char * and read the name through it?
Test yourself · category 15 of 20
User pointers: copyin, copyout, arguments
How the kernel reads system-call arguments from the trapframe and copies user memory in and out by walking the process’s page table in software, page by page, so that a bad pointer becomes -1 instead of a kernel crash.
A user program passes garbage in every argument register. Which of these functions reject a bad user-supplied value themselves, by returning -1?
cat’s page table maps the trapframe page and the stack guard page, both without
PTE_U. Click the line in walkaddr that stops the kernel from copying into or out of
such pages on a user’s behalf.
Your pick: none yet (click a line in the code)
sys_open calls argstr(0, path, MAXPATH) with char path[MAXPATH] and MAXPATH =
128. What is the longest path, in characters not counting the NUL, that this call
accepts?
cat has p->sz = 0x4000, laid out as in Tour 6: System-call arguments and user pointers: code and data at 0x0000-0x1fff,
the guard page at 0x2000 (mapped, no PTE_U), and the stack page at 0x3000, which
holds "README\0" at 0x3fe0 and "cat\0" at 0x3ff0. For which of these addresses,
passed as the open path, does copyinstr return -1?
True or false: a user program can make read(fd, (char *)main, 100) overwrite its own
code with file data, because the code page has PTE_U and lies below p->sz.
Why?
sys_open fetches its path with argstr(0, path, MAXPATH); the user passed 0x3fe0.
Put these steps in the order they happen.
- fetchstr returns
strlen(path), which is 6 - copyinstr rounds the address down to its page,
va0 = 0x3000 - bytes are copied from the physical page until the NUL
walkaddrchecks the leaf PTE forPTE_VandPTE_Uand returns the physical pageargaddrcopies the saveda0(0x3fe0) out of the trapframefetchstrcallscopyinstrwithp->pagetableandp->sz
argraw returns p->trapframe->a0 and so on. Why does it read the trapframe instead of
the hart’s real a0-a5 registers?
cat is in open, and its hart is inside the byte-copying loop of copyinstr (no
lazy page is involved). What is the state of that hart?
A write system call on a pipe reaches pipewrite, which holds pi->lock and calls
copyin on a never-touched lazy sbrk page. copyin calls vmfault, which calls
kalloc. What is the hart’s state at the moment kalloc holds kmem.lock?
copyin is called with srcva = 0x1ff0 and len = 48. How many bytes does the
first iteration of its while loop copy?
sys_exec collects the user’s argv into char *argv[MAXARG], with MAXARG = 32.
What is the largest number of argument strings (not counting the terminating 0 pointer)
that exec can accept?
Match each function with what it does.
lazy_copyinstr grows the heap lazily by two pages with sbrklazy(2 * PGSIZE),
writes '/' to the last byte of the first page (p[4095]), and never touches the second
page. Then it calls open(&p[4095], O_RDONLY). The string’s NUL would be at p[4096], on
the untouched page. What happens?
fetchaddr tests addr >= p->sz || addr + sizeof(uint64) > p->sz. With
p->sz = 0x4000, which addr would pass the second test, even though it is outside the
process, so that only the first test rejects it?
A program passes copyout a buffer in heap memory it grew with lazy sbrk and has never
touched. Click the line that makes the copy succeed anyway.
Your pick: none yet (click a line in the code)
A program calls read(fd, buf, 2048) on a regular file at offset 0 whose size is at
least 2048. buf is exactly 1024 bytes below p->sz (which is page-aligned), on a page the
program has already used. Which statements are true?
True or false: walkaddr's test if (va >= MAXVA) return 0; is redundant, because
vmfault would refuse such an address anyway (it is above p->sz).
Why?
When copyin translates a user address, which page table does it walk?
walkaddr returns a physical address pa0, and copyin then calls
memmove(dst, (void *)(pa0 + (srcva - va0)), n) while the hart uses the kernel page
table. Why does using a physical address as a pointer work?
A buggy program passes 0x2f00, inside its stack guard page, as the buffer for fstat.
In copyout, walkaddr returns 0, so vmfault gets its chance. The address is below
p->sz. Why doesn’t vmfault give the program a fresh page there?
In one run, gdb shows the leaf PTE for cat’s guard page at 0x2000 as 0x21fc7407.
Decode it.
Value: 0x21fc7407
sys_open copies its path into char path[MAXPATH] on the kernel stack, but
sys_exec copies each argument string into a whole page from kalloc. Why the
difference?
A program whose file descriptor 1 is the console calls
write(1, (char *)0x80000000, 8). What does write return?