Showing posts with label hardware. Show all posts
Showing posts with label hardware. Show all posts

Sunday, September 6, 2026

SUDO INIT 6: Rebooting Your C Journey

 

                                                    Yeah, let's do just that. So grab some popcorn and lean back.

 

I've said it again and again: To teach is to lie.

 

I'll simplify things. A lot.

Not that the details aren't interesting, but if I start throwing around PTEs, PFNs, page faults, kernel internals and CPU privileges from the beginning, nobody is going to read this.

Worry slightly, though. I'll throw some stuff your way. End of warning.

 

I Wanted a C project


I've been learning C for a while and I genuinely like it. I like it a lot. But I don't like the "just build a project!" approach to learning.

Build an app.

A website.

A to-do list.

A game or something that simplifies your life.

 

Just do a project = me dead inside

 

Yeah, that's not me. I'm not a programmer. I don't want to build an app and spend months adding features, fixing bugs and maintaining it. That's not me. To me, these kinds of projects are mood-killers.
 

What I do enjoy is understanding what the machine is actually doing. I want to use C to ask questions about the stuff I really want to understand.

And I've been having some success learning C and Assembly while also playing around with microcontrollers and lower-level concepts: memory, pointers, addresses, system calls, how OSes work, and so on. 

 

A Memorable Idea?

 

 I knew that a process doesn't deal directly with physical RAM addresses. It works with virtual addresses.

 

The CPU and OS cooperate to translate those virtual addresses into physical addresses. The OS sets up the mappings; the CPU's memory-management hardware uses them.

The details are considerably more interesting, but let's keep this mental picture for now:

Process --> Virtual Address --> Translation --> Physical Address 

 

I also knew that, under certain conditions, the relationship between virtual and physical addresses could change.

The same virtual address could end up referring to a different physical page.

So, could I force those conditions? Can I make one of those addresses change?

Hey, isn't this a project of sorts?

 

I was hyped. And that's a good sign. If you are ecstatic about doing something that is useful for what you're studying, something you actually want to become good at, that's a good sign. 

 

The Plan

 

 I started by asking myself some questions and starting small:

- Can I get the PID of a process? Of course, easy.

- Can I allocate a page? Probably.

- Can I print the virtual address? Sure. 

- Can I figure out which page that address belongs to?

- Can I find the corresponding physical page?

- Do I have enough privileges for anything related to the physical address?

 

And finally, when I know I can access all of this and print it to stdout:

- Can I make the relationship change while the process is still alive? 

 

Oh, but for context mmap() in ASM was the touchstone that made me trip into this rabbit hole. I even considered building my whole project in ASM, but then briefly considered how much pain I was willing to accept. So C it was!

mmap()


If you haven't used it before, mmap() is a Linux/POSIX interface that lets a program create mappings in its virtual address space.

 

For my first experiment, I used it to create a mapping for a single 4096-byte page of memory. Remember that 4096 bytes in decimal is 0x1000 in hexadecimal. 

 

This was important because 4096 bytes is also the page size I'm working with here.

A 4096-byte page needs 12 bits to identify any byte within it, because:

4096 = 2¹²

So, the lowest 12 bits of a virtual address tell us the offset within the page. 

Everything above those 12 bits gives us the virtual page number.


Once we have the virtual page number, we can find the corresponding entry in pagemap. 

There is one 64-bit entry in pagemap for each virtual page. So, to find the entry for our virtual page, we multiply the virtual page number by 8. 

 

A pagemap entry consists of several pieces of information. I care here about the Page Frame Number (PFN), which tells me which physical page is backing the virtual page. 

Then I wrote a value into that memory:

42 

 

So far, nothing particularly exciting. Just moving along and gathering our LEGO bricks.

 

But now we had our program, a process, a virtual address, a page, and a value stored at that address.

I made the program request the user to press the Enter key. This way, it was kept alive.

 

But where is that page actually sitting in physical memory? 

Linux provides an interesting interface for this:

/proc/<PID>/pagemap

 

This is a kernel-provided interface that lets a userspace program inspect information about a process's page mappings.

In particular, a pagemap entry can contain the PFN, corresponding to a virtual page.

And, from here, the physical address is fairly straightforward:

Physical Address = PFN x page size + page offset

  

So, now I had all the bricks that I needed.

I also learned that you needed the appropriate privileges to actually access the pagemap. 

Root isn't necessarily equivalent to having every Linux capability. On my system, I needed the privileges associated with CAP_SYS_ADMIN to obtain the PFN information from pagemap.

And that gave me another little rabbit hole: being root and having a particular Linux capability aren't quite the same thing.


 

 

 

 

 

 

 

 

  

 

 

 

 

 


Experiment A (first steps) or, as  Ilike to call it: To Sudo or Not to Sudo 

 

The Experiments

 

I called these the experiments. Gathering all the tools I needed was Experiment A. I now wanted to jump into Experiment B, where I'd try to change the physical address.

I knew one cheaty way to do it.

I knew about Copy-On-Write (COW). I'd recently been reading about COW in another context, including some security research involving COW-related behaviour.

So this seemed like a natural place to start.

 

The basic idea behind COW is pretty simple to understand:

Suppose a process has a page containing some data. Now we create a child process with fork() - see here.
The child gets its own process and its own virtual address space. 

But, for the moment, the kernel has no need to immediately make a complete physical copy of every page.

Instead, parent and child can initially refer to the same physical page.

The mappings are made effectively read-only (this is important) and the system keeps track of the fact that the page can be copied if someone tries to modify it.

  

Experiment B

 

 

 Why 666? Because Gilfoyle is my spirit animal

 

Now, my child process did the following:

*(int *)addr = 666;


The CPU detects that the attempted write isn't permitted by the current page-table entry and raises a page fault.

Now, before you start thinking segfault, nope. 

A page fault does not automatically mean something has gone wrong.

A page fault is a mechanism, and the kernel can handle it.

In this case, it recognizes that this is a legitimate COW situation, creates a new physical page for the child, copies the contents, changes the child's mapping, and allows the write to continue.

 

And, voilà! Same virtual address in two processes, different physical addresses.

So, slight cheating, but not entirely.

 

Also, see the weird thing up there? Maybe you don't. Compare that image of experiment B against my running that exact same program a second time:

 

 See it now? Both processes are writing to stdout and we cannot predict which one will print which line first. 

 

For a moment, I was baffled by this, but then I remembered what fork() actually does. It's not instructing the child to run after the parent runs. It means:

There are now two concurrent processes capable of running. Run them.

The scheduler decides when each gets CPU time.

So, voilà! An accidental demonstration of concurrency. You're welcome. It wasn't planned.

As for concurrency, that's another rabbit hole. Rabbit holes everywhere you look. Reminds me of math classes and the Real line. My professor used to draw rabbit holes there all the time. Fun, fun, fun.


 Experiment C

 

 Single process, same physical page, two different virtual addresses.

I now wanted to remove fork() from the equation. 

 This required a different approach, and I used a POSIX shared-memory object and mapped it twice into the same process.


Think of the shared-memory object as the thing being mapped. The mapping itself isn't the memory.

I asked Linux to map the same object twice.

So, now Linux could give me two different virtual addresses while both mappings referred to the same physical page. 

 

  

 

 

 

 

 

 

 



Note: it is not a given that the two addresses will be adjacent. 

 

I could inspect both virtual pages through /proc/<PID>/pagemap, once more and check that the PFN was the same and, therefore, the same physical page.

 

The Issue

 

I had technically answered part of my original question, but I had used fork(). What if I didn't?

Could I get a single process, keep the same virtual address, and somehow make Linux replace the physical page underneath it?

That became the next question. 

And this is where the project is currently sitting.

I already received a very interesting suggestion for how to approach it, involving madvise() and memory pressure.

 

I haven't properly investigated it yet, so I'm not going to pretend I understand it well enough to explain that here.

That's the next rabbit hole, and one you might want to trip into yourself. All quite accidentally, of course.

 

 

 

 

 

 

 

 

  Yup, I'm a cute little sunrise.  

 

 

 

 

 

 

 

I started this little field trip because I wanted to learn C and understand virtual memory better. And, along the way, I got to touch on:

- mmap()

- pointers and pointer casts

- virtual pages and page offsets

- PFNs

- /proc/<PID>/pagemap

- Linux capabilities

- COW

- page faults

- shared memory

- multiple virtual mappings

- process IDs

- scheduling and concurrent processes

- ... 

 

If anyone reads this and is interested in its innards, here's my Github. Mind the step, not the mess.

 

The code is deliberately small, and certainly not a production-quality memory inspection tool.

It's an experiment. Or a series of them, actually.

Something you can compile yourself, run, modify, break, and have fun with. 

 

One last thing:

The little snippets of these experiments that I posted on LinkedIn were well received. People have suggested alternative experiments, pointed out things I wasn't considering, asked interesting questions which themselves gave me ideas of stuff to try.

That's been rather nice.

I don't pretend to be an expert in any of these things. Quite the contrary. So I'm humbled and grateful when those that know more than I do chime in and give their input.

 

I was going to say keep digging, but that's not necessary. Just accidentally trip into any of the rabbit holes that are all around us. And be perpetually amazed as you fall deeper and deeper. 

 

 

Tuesday, May 27, 2025

Why Won’t You Power Off?

                       

        "Beneath this mask there is more than flesh. Beneath this mask there is an idea, Mr. Creedy."

 

 I recently purchased an old-school Lenovo ThinkPad x260 - a beautiful little tank of a machine. It was in tip top shape: clean chassis, no keyboard shine, and great battery health. So, first things first: wipe Windows off the face of the earth and install Linux (not Arch, btw).

Everything was great ... except for this teeny tiny issue:

Even after shutdown, the laptop stayed warm. 

This typically means the system isn’t reaching a full ACPI S5 (soft off) or G3 (mechanical off) state.

 ...I didn't expect it to have any temperature issues, but I decided to play it safe, and installed lm-sensors, just to be sure. No worries there! The temperature was low, even after running some tests and forcing the CPU to do some work. So, the issue wasn't that it was overheating... perhaps it just wasn't shutting down properly?
After some testing, I confirmed that hypothesis: USB ports were still feeding power. The fan wasn't spinning, and there was no noise or visible lights, but something was still alive in there and refusing to go to sleep.

 

I tried to issue clean shutdown commands, with shutdown -P now, oldschool init 0, the desktop shutdown button, etc. You name it. Nothing forced the computer to turn off and the battery was still sipping away slowly. Plugging  a phone to the USB would charge the phone. You get the picture.


 

Step 1: Blame the BIOS

I quickly checked the BIOS setup (on this ThinkPad F1 does the trick) and went through the tabs:

- Disabled "Wake on LAN"

- Checked "Intel SpeedStep" and thermal profiles

- Ensured USB always-on charging was off

Note: this did not stop phone charging through USB.

- Even poked at virtualization, secure boot, and power-on behaviors

 

No luck. I all looked fine an dandy. And yet, the x260 continued to undead itself.

There was a slight mystery in that the power button worked 'strangely'. And by strangely I mean that the computer didn't connect directly when pressing the power button. But the reason was quite obvious. Since the computer was not properly shut down, I couldn't turn it on by just pressing the power button. I had to first keep the power button pressed for long enough to force a hard shut down. Only then did the computer shut down and allowed me to turn it on by pressing the power button.


 

Step 2: Linux Kernel Parameters, ACPI... huh, no?

So, I guessed I might as well go up a couple of layers and check the OS itself. Maybe the Kernel wasn't handling ACPI (Advanced Configuration and Power Interface) properly.

This led me to go and modify GRUB entries:

# In /etc/default/grub, change the following line:
GRUB_CMDLINE_LINUX_DEFAULT="quiet splash acpi=force reboot=pci"

# Then update GRUB (Debian/Ubuntu):
sudo update-grub

...And reboot=hard, reboot=efi

( `acpi=force` forces the kernel to enable ACPI even if it thinks the BIOS doesn’t support it, and `reboot=pci`, `reboot=efi`, ... tell the kernel which reboot/shutdown method to try — in some buggy firmware cases, different paths behave differently

Also, please please and pretty please make sure to back up your current GRUB configuration before modifying it. Bad kernel parameters can sometimes prevent boot. You have been warned)

I also tested power off sequences with systemctl poweroff, shutdown -h now, and halt.

Same result every time: "Bye bye, mate. I'm going into zombie mode." 

I found the emergency reset button in the back of the x260, which cleared the battery state - cute. But not the fix either.

 

 



Step 3: It's elementary TPM,  my dear Watson Reader. 

Eventually, buried in a forum post, someone suggested disabling the security chip - also known as TPM (Trusted Platform Module) - in the BIOS.

Interesting. Why would a security chip interfere with system shutdown?

But hey! Let's try it.  And try I did. BIOS > Security > Security Chip, and I set it to disabled.

There was the option to switch between intel PTT (Intel's firmware-based implementation of TPM) and discrete TPM.

Boom! Disabling both solved the problem.

No... really. No more zombies in my machine.

 

 So, erm. What was all that about?


 

Step 4: Read up

TPM and ACPI can be tightly coupled, especially on systems originally designed to work with Windows. 

Firmware behavior is often not standardized across vendors, and ACPI implementations are notoriously inconsistent. 

When Windows is installed, in this case, it plays nicely with proprietary firmware handling of secure state transitions (shutdowns/hibernation). But Linux? That OS expects firmware to follow spec, not to have it silently ignore part of the validation process. 

By disabling the TPM, we cut off whatever interaction was confusing the firmware - and Linux finally does get a say in controlling the power sequence.

 

 Anecdote du jour: did you know that Torvalds once said something nice about ACPI?

 "ACPI is a complete design disaster in every way. But we're kind of stuck with it. If any Intel people are listening to this and you had anything to do with ACPI, shoot yourself now, before you reproduce."

 

It must have been a Monday.

 

Should you, dear reader, disable TPM on your old machine?

Well, if you don't use full-disk encryption tied to TPM, yes I guess.

If you're using Linux and notice a behavior such as this, then certainly try it.

But if you do rely on TPM for encryption (why do you need to do that nowadays is beyond me) then be careful. TPM often stores or seals encryption keys. Disabling it can make your system unable to decrypt the disk unless you’ve backed up your recovery keys elsewhere.

 If you’re still facing power-off issues after all this, check if your BIOS firmware is outdated (I admit that this was my F plan, after all else didn't work... but I can be lazy like that). Lenovo occasionally issues updates that patch quirky ACPI or EC bugs, especially for Linux users.


 

Alright, that's it for today! I finally am getting my life-work-zen states figured out and aligned, so I'm getting a bit more time to do research and to document my work, which is totally awesome. So I hope to start posting a bit more frequently.

 

As always, enjoy the ride!

Thursday, February 20, 2025

Insert Here Joke About The 'S' In IoT: ___________

                    ─ Anne Rice

            "One moment the world is as it is. The next, it is something entirely different. Something it has never been before."


忍耐 (Nintai) – Endurance & Patience

Life has its twists, turns, tugs, and takes, right?

Lately, I’ve been (kind of) ‘forced’ to plunge into radio waves—5GHz, 2.4GHz, channel allocations, and even how certain countries restrict radio some frequencies.

"Woah, so new job and you got more free time to explore stuff?"

No. Not really.

If anything, I have less free time than ever. Firewalls, network congestion, MAC virtualization, plus remembering things I learned over a year ago, while picking up new tricks along the way. But here’s the thing—I get to manage my time better (to a point). 

Not because the workload is lighter, far from it.

The difference? I’m not buried neck-deep under tickets every minute of my working day. Instead of having problems chase me around nonstop, I carve out specific windows to troubleshoot, test, and develop strategies─tackling issues before they spiral out of control. And when the odd danger moment does come up, I can devote my time and energy to it.

A three-hour troubleshoot session? No problem. An endless stream of tickets for three hours? That drains the life out of you.

Drop by drop.


So, I decided to get my hands dirty and learn a bit about IoT hacking. Why the hell not?

I didn't get the luxury of studying computer science or electrical (or-anything-very-technical-really) engineering for 3 years in college─on the other hand, that gave me the privilege of carving out my own study program, and avoiding dumb, mandatory courses.

I started with this Defcon32 talk, which was surprisingly accessible, straight to the point, and fun. After that, I picked a target, got some basic tools, and started tinkering.

                "Nice IoT you got there, friend. T'would be a shame if something happened to it..."

It's not about going uber deep on this, it's about understanding a bit more about the field, getting our hands dirty and seeing if anything clicks. Also, you never know when any of this might come in useful.

Never in my life have I ever wanted to become a DB engineer, or backend mantainer, but I don't know how many times it has been extremely useful to know how to query a DB or create a View.

And always: The journey is the fun part.

Meanwhile, I've been chipping away at Practical Malware Analysis (yikes, he likes books!) but I'm saving that for later. I'll need some time to organize my notes and scribblings into something half-decent, before that becomes a blog post.


Honestly, I kind of envy the people who seem to have all the time in the world to write massive, in-depth blog posts. How do they do it? I guess, like anything else, it comes down to practice—it gets easier the more you do it.

I'm lucky if I manage to put out one of these out every so often.

But hey─if you're deep into your own projects, I hope you're having fun.



SUDO INIT 6: Rebooting Your C Journey

                                                                  Yeah, let's do just that. So grab some popcorn and lean back.   I'...