Showing posts with label syscalls. Show all posts
Showing posts with label syscalls. Show all posts

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!

Sunday, December 1, 2024

Wherein We Pause to Reflect: Simple ASM Review and OS Security Mechanisms

 

Hey! Corny matrix-styled dojo. Why not?


Let’s kick off today’s blog post by writing a very, very simple ASM program. Since I’m reviewing ASM stuff through pwn.college’s course, why not showcase how simple ASM can be? (In a way... math is simple too, but many would argue otherwise).

Our script will be called one-oh-one.s, and our program will be called pausing—since that’s what we’ll want at the end.

Let's start with a program that starts and ends. Simple enough, right? But for that, we need to pass execution to the OS via a syscall (remember those?). To do this, we can move the value 60 into the rax register. Here's how:






Simple enough! But if we try to assemble and link this, we’ll hit an issue:




Ah, much better. Now, our previously failing program is a success... of sorts. We made sure to run with Intel syntax, which is much cleaner (at least to my eyes). We also made the _start label globally visible so that we can indicate where our program begins.

Now no more errors, and we’re ready to tackle the rest of the program. Easy peasy.

Right! While I was trying to set up a pause in my program, I ran into an issue. The syscall I thought was the right one for pausing was actually wrong. So, since I’m working on Linux with x86_64 architecture, I checked /usr/include/asm/unistd_64.h to see which syscalls I should use.

There, I found the exit syscall (60), which needs to be loaded into rax (which we’re already doing). If we want to set an exit code, we need to load it into the rdi register. Fair enough, we can do that. As for the pause syscall, we need syscall 34. I also discovered the alarm syscall (37), which sends a SIGALRM, ending the pause syscall. Without this, we'd have to ctrl+c our way out of the program. We also learned that we need to pass a parameter through rdi. Easy peasy.

Now that we have the tools, let’s create our pausing program, assemble it, link it, and run it while checking for our exit code:




Don't know about you, but I love this!

Now, let's review other concepts. For instance, in pwn.college, you can learn how to point to a specific memory value or the contents at that memory location.

Let's say there’s a memory position 12345 holding the value 42.

If we do:


mov rdi, 12345

We're making it so that rdi will hold that number 12345.

But if we do:

mov rdi, [12345]

Now rdi will hold the value at memory position 12345, which is 42, just like the value stored at that location.

I won’t dive too much into these basics because I’m sure you either already know them or want to experiment with them yourself. Just remember that the OS will have some defenses in place that may make it difficult, if not impossible, to access specific memory locations in your binary.

You can check which defenses have been enabled with a tool called checksec:



Please take your time and check what each of these items does. Here's a quick rundown:

  • RELRO: A security feature that makes it harder to modify certain parts of a program, like its GOT (Global Offset Table), preventing attacks on function pointers.
  • STACK CANARY: A protective value placed on the stack to detect buffer overflow attacks before they overwrite important data.
  • NX: No-Execute; prevents code from running in certain areas of memory, like the stack, to stop exploits that execute malicious code.
  • PIE: Position Independent Executable; allows a program to run at random memory addresses, making it harder for attackers to predict the location of code.
  • RPATH: A runtime setting in executables that specifies directories to search for dynamic libraries before default system paths.
  • RUNPATH: Similar to RPATH, but it is used after LD_LIBRARY_PATH to specify directories for locating shared libraries at runtime.
  • Symbols: These represent function names, variable names, and other references in the program’s code, helpful for debugging or exploitation.
  • FORTIFY: A set of compiler protections that enhance the safety of certain library functions, like checking buffer sizes to prevent overflows.
  • Fortified: Refers to functions that have been modified with additional checks (from FORTIFY_SOURCE) to improve security against buffer overflows.
  • Fortifiable: Functions that can potentially be fortified using additional checks to prevent common vulnerabilities like buffer overflows.
  • FILE: Refers to the executable or object file format, containing the machine code, symbols, and metadata that the operating system uses to load and run the program.


Like I said, a quick rundown, but it’s worth spending time learning about these defenses—what they do and how to set them up to adequately inspect a binary. Also, note that this applies to ELF files.

Alrighty, another short one! Hope you had fun.






Saturday, September 21, 2024

Wherein We Create An Assembly Program: Butting Heads With The OS



When I first started learning Assembly, I wanted to write simple code, but the apparent complexity of the code I’d seen up to that point threw me off—and that might happen to you as well.


Thing is, you've probably seen ASM code that is basically a decoding of some program - the assembly level code that is the result of a partial compilation or full compilation of another program. That means this code will have a lot of overhead from function prologues, epilogues, and groundwork needed to work smoothly with different libraries and instances.

But you don't need all that to write simple ASM code. In fact you only need this:


That's right:

- you need a data section and a text section (and some detail in between).

So, having found out that that was the case, I started creating simple programs. One of the first ones was this one, a simple "Hello, World!" program (ah, the good old tradition):

See? I told you. Not too complicated.

We have a .data section, a .text section and _start, which is a label that is also where the program execution begins.
 
Yeah, ok... besides that, there's probably a lot here you've never seen before. But remember that this is not a race, it's a marathon (whatever this is). We're going to search, ask and prod for everything we don't understand. And then we're going to get some practice under our belts with these new things.

But let's clear the waters and define some of these terms and words:

db - 'define byte'. This allocates storage for a string of bytes and initializes it with a given value.

0xa - this introduces a newline character (go check 'line feed' and also look up this ASCII table, *wink, wink, nudge, nudge*)

$ is the current address in the assembler, so $ - msg  gives us the difference between that current address and the address of msg which is the address at the start of msg, then we let len be that. Smart, huh? That gives us the length of our msg string, no matter what it contains.

As for int 0x80 it's an interrupt to a syscall. We've mentioned that before. But most of today's blogpost will revolve around syscalls and registers, so we'll get right back to that after we stop babbling and create our first Assembly program.

Remember, we save our ASM script, go back to the command line and enter the following:

nasm -f elf32 -o hello_world.o hello_world.asm
ld -m elf_i386 -o hello_world hello_world.o
./hello_world

And voilĂ ! Our first Assembly 'Hello, World!' program. Newline included, free of charge.

Let's look at our code proper, inside of _start. What are those lines doing? One by one:

mov edx, len -> the sys_write syscall, which will print "Hello, World!" to the stdout expects the length of the data to be in edx. So we move that onto that register.
mov ecx, msb -> that same syscall expects the address of the msg to be in ecx.
mov ebx, 1 -> 1 is the file descriptor of stdout.
mov eax, 4 -> 4 is the call number for sys_write.
Next we do our interrupt, after everything being loaded up and ready.

And finally we do:
mov eax, 1 -> 1 is the number for the sys_exit syscall.
We do our final interrupt, and the program exits.


Let's go back to our 0x80 interrupts
Why are we doing them within our Assembly code, and why aren't we doing them when we create and compile our C programs, for example?

Well, we do, or it does quietly in the background. These syscalls are hidden within our compilation process and in particular within the libraries we do. The libraries are packaged with more than just the functions we regularly use. they also contain these syscalls which tell the OS to act in particular ways.

The function printf, for example, doesn't directly issue a system call. Instead, it goes through the C runtime, which handles formatting, buffering, and then calls a lower-level function like write() (from the C Standard Library) to send the output to stdout.
There is, in fact a system call to the kernel, but it's hidden behind several layers of abstraction.
Next time you check the Assembly code of a C program, be on the lookout for stuff like call 0x1030 <printf>. This is a syscall into the C Standard Library.

Now for something that happened to me a while ago, when I was creating a simple Assembly program to add two predefined numbers. Here’s part of the code—this version works:



Ok, like I said, this worked just fine, added '1' to '2' and returned '3'. Amazing.

Then I started thinking: 'That’s a lot of repetition. I’m constantly refreshing the register values after each interrupt. What if I just skip some of that?'

And so I did. This was one of such versions:


See? I just deleted register instructions in between interrupts.
Long story short: this version doesn't work.

And that was surprising to me at the time, and got me wondering as to why the program wasn't working. I knew that ASM wasn't preserving my register values between syscalls. But why?

After a little research I found out why: the Kernel takes control of our programs upon a syscall and it uses those same registries for its own sake. Hence, we need to always re-set our registers to the values that we want them to have after each syscall.

In fact, when the program is running normally, it’s in 'user mode,' and after a syscall is made, control is given to the Operating System. At that point, we enter 'kernel mode' until the OS finishes and returns control to the user. Here's a bad sketch to view this in action:


Good to know, right? Or at least interesting enough!

So I decided to create a (cheaty) ASM program to detect the values of the registers before and after a syscall. I wanted to actually visualize this change in two moments in time, much like the much maligned print debugging.
Here it is:



If you try to compile this program normally, it won’t work. And yeah, I’m a dirty cheater for this, but explaining all the reasons why is beyond the scope of this post. But here's a hint: see that call printf? That looks a lot like a C thing, but not so much an ASM thing.

I leave it to you to prod as to how I've cheated and what these compilation steps (which make the program work) are actually doing:

nasm -f elf32 -o register_catcher.o register_catcher.asm 
gcc -m32 -o register_catcher register_catcher.o -nostartfiles -no-pie




See? You cannot expect the registers to remain the same after an interrupt.
The OS will use and change them, often in ways you don’t expect.

Care to remake this catcher in pure ASM? Perhaps you'd like to learn more about Assembly? Then check this link. How about a Syscall Table?

The purpose of this blog is not to teach Assembly step by step, but there's a ton of resources out there for you to explore.

I hope you have learned something new. I learned a lot while playing with Assembly and when writing these blog posts.

Enjoy!





"INTs Aren't Integers and FLOATs aren't Real"

                                     I was told this is a cat-submarine. Tail = Periscope. I believe it.   Over the past few weeks, I’ve be...