trying hard. streaming kernel dev - https://xitter.cf/t.co/aO5X4jXGQD blogging about life, art & systems programming. non-expert work: @ableton, ex @trailofbits

berlin • he
Joined March 2011
New kernel post! This time: /proc/*/mem and how it writes to unwritable mem. Key takeaway: By walking page tables in software, the kernel can access userspace mem without directly dereferencing pointers it gets from userspace. (No WP/SMAP bits involved). offlinemark.com/2021/05/12/a…
2
137
1
491
week 140, streaming kernel dev (c++) topic: virtual memory short stream, was mostly investigating whether I can replace a memset with brace C++ object construction (as you might expect, the answer was no, the C++ rules are way too brittle/fragile here 😂) link + recap ↓
5
2
157
4,076
ERRATA: I'll revise my statement - I think it is totally possibly C++ brace object construction to replace my page table memset, but I still am unconvinced to really do it that way My confusion came from accidentally using parens () instead of braces {} in my placement new (which would replace the memset) This situation then involves a double memset because of the complex C++ construction rules Using {} works, but is brittle, somewhat error prone, and doesn't convey intent well (which were my original points against it) So I still don't know if I'd ship it in production, since memset() conveys intent very well and just works. But it is possible
1
265
learn Linux kernel exploitation from one of the best 👇
We finally got this series out. We tried to simplify Linux kernel exploitation for those interested in getting started. There are plenty of resources out there, but my impression is that they are written for experienced people, not for beginners in this complex field. In this series, we tried to do something close to real-world kernel exploitation, but much simpler, so people can use it as a first contact with Linux kernel exploitation. I hope people like it, and we will be available to help anyone who wants to reproduce all the content.
1
13
230
12,189
week 139, streaming kernel dev (c++) topic: virtual memory this was just a small refactoring stream - tweaking and refining some of my virtual memory/paging code link + recap ↓
3
4
2
57
5,393
the only thing really worth mentioning here is that I use templates pretty liberally through my VM code TBD on whether this is worth it, but it allows me to use a generic struct GenericPageTable, for operations that are in common amongst the different levels while having different struct types to represent e.g. Page table entries, from Pml4 Table entries, from Page directory entries.
8
379
everything you ever wanted to know about bitmaps
17
881
yup
9 am: i can’t wait till bedtime 10 pm: i’ve always wanted to write my own operating system
2
22
716
week 138, streaming kernel dev (c++) topic: using musl libc in kernel short prerecorded stream about how I use musl libc in my kernel. picolibc might be a better choice but this works well too link + recap ↓
1
2
73
2,411
originally I inherited hand rolled memcpy etc from JOS but I’ve been trying to reduce my first party code surface, and in general want to use third party libs when possible musl libc is pretty minimal and works ok for this purpose. I don’t actually a build a full musl since that’s a hosted libc for userspace but I’m able to extract just the routines I want and vendor them, and integrate them into the build system there is a bit of build time header generation that I needed reimplement since I’m not using the musl build system but ai was helpful for that I’m very happy with this approach and the fact that I don’t need to write my own memcpy lol
1
304
week 137, streaming kernel dev (c++) topic: preemptive multitasking Now that the timer interrupt is working, I added a basic preemptive multitasking impl. Since cooperative yields are already working, this was pretty trivial, just call yield from the interrupt handler link + recap ↓
1
4
1
118
14,668
Calling taskYield() from the timer interrupt handler was enough to implement a basic form of preemptive multitasking The task’s state is preserved at that point in the interrupt handler, and then when it gets execution again, it finishes the interrupt handler and irets back into the task The important part was just to call yield after acknowledging the interrupt, otherwise we’d schedule out and no other interrupts would happen To be clear, this isn’t the final implementation. In general it’s not good to schedule in an interrupt handler, so we might need to add some kind of “need_sched” flag and then schedule at the very end of the interrupt return path It’s also interesting to compare my implementation with @nsg650’s - after selecting a next task, he opts to overwrite the trap frame on the stack with the new task’s, and use the iret as the mechanism to switch tasks This is different from my way of context switching entirely in software using plain ret After getting it working, I used this as an opportunity to test out my in-kernel integration test framework, and wrote an integration test I created two tasks, which each receive a pointer to a bool. The first task spins, and then checks that the bool is marked true. The second task simply marks the bool as true. This checks that the second task got CPU time without the first task explicitly yielding One tricky part was adding this test without disrupting the other integration tests which aren’t designed to run with a timer interrupt. I added a hacky config mechanism for this so those tests can run without a timer interrupt, but that will need some future work
5
587
week 136, streaming kernel dev (c++) topic: LAPIC timer After getting the timer interrupt working last week, I did some refactoring. I decided to make the interrupt handlers static member functions on the LocalApic driver class link + recap ↓
1
4
37
1,961
Last week I got the timer interrupt working, but only with some hacky code I moved the timer interrupt handler functions into the LocalApic driver class to co-locate the code closer I had to make them static member functions because my interrupt dispatch code uses a function pointer table This was a little inconvenient because in the member functions, we can’t just call the eoi() method for example, but need to relocate the LocalApic driver via the Kernel reference that’s passed I thought of trying to use a regular member functions, but it’s complex ABI-wise to store pointers to those, so I didn’t go with that approach I also experimented with with an API for letting the LocalApic dynamically register its interrupt handlers in the constructor, instead of statically hardcoding them in the Idt definition But decided against that, since the dynamic flexibility isn’t currently needed, and the code is less understandable that way
3
233
week 135, streaming kernel dev (c++) topic: timer interrupt got the LAPIC timer interrupt working!! the LAPIC is a complex device, but it turns out it's not so bad to configure it for a simple timer. wired that into my interrupt subsystem and it's working =) link + screenshots ↓
4
17
1
271
31,981
last week i got the basics set up to do MMIO accesses to the LAPIC, but that was it I cleaned up the design and created an MmioWrapper abstraction for conveniently doing MMIO accesses, using templates The idea is that driver classes will take one of these on construction, meaning the responsibility for mapping the device lives outside the driver. I created a factory function to do this and construct the Local Apic driver class Then it was a matter of doing the right LAPIC configs, which were: - Spurious Interrupt Vector Register -> Write to this to enable the LAPIC in general, and also set the Spurious Interrupt Vector number (Funny how such an important enable bit is hidden in this very exotic register) - Set the divisor offset - Set the timer to periodic mode (instead of one-shot) and also register the Timer Interrupt Vector number (this is the important part!) - Set an initial count of the timer Then I registered interrupt handles for these new interrupt vectors and was able to it getting called regularly =)
1
1
8
1,350