TerminateProcess with GetCurrentProcess() handle and with GetCurrentProcessId() handle - c

I'm studying Windows Internals. In fact, there's no similar _exit system call like in *nix.
The process should terminate itself with TerminateProcess/NtTerminateProcess.
ExitProcess/RtlExitUserProcess API doing some cleanup before self-terminate.
TerminateProcess/NtTerminateProcess work with GetCurrentProcess/NtCurrentProcess/(HANDLE)-1.
But when I try it with GetCurrentProcessId/gs:[0x40] it didn't work.
#include <windows.h>
int main(void)
{
TerminateProcess(GetCurrentProcess(), 0); // work
TerminateProcess(GetCurrentProcessId(), 0); // didn't work
}
mov rcx, -1
xor edx, edx
call TerminateProcess
; this one is working
call GetCurrentProcessId
mov ecx, eax
xor edx, edx
call TerminateProcess
; this one didn't work
Why Windows processes must self terminate itself with GetCurrentProcess and can't work with GetCurrentProcessId ?

The documentation for TerminateProcess() clearly says that it takes a process handle, whereas GetCurrentProcessID() returns a process ID instead. Why would you expect that ID to work?
One comment of yours seems to suggest that you think a process HANDLE is the same as a process ID. Clearly that is not true, otherwise GetCurrentProcess() and GetCurrentProcessID() would not exist as separate APIs.
In fact, GetCurrentProcess() actually returns 0xffffffff.
The docs say:
The return value is a pseudo handle to the current process.

Okay, like the other said, TerminateProcess accept process handle, and not process id.
I should take the handle from OpenProcess(PROCESS_TERMINATE, false, GetCurrentProcessId()).
Sorry for the misinformation.

Related

How to get the full returned value of a child process?

I need to catch the returned value of a child process..
The problem is: with using the waitpid() function I can catch only 8 bits of the returned value
WEXITSTATUS(wstatus)
returns the exit status of the child. This consists of the
least significant 8 bits of the status argument that the child
specified in a call to exit(3) or _exit(2) or as the argument
for a return statement in main(). This macro should be
employed only if WIFEXITED returned true.
How can I catch the full int value that is returned from main() ?
EDIT: Stackoverflow forced me to edit the question as it linked another answered question but it has nothing to do with mine!
POSIX requires that the full exit value be passed in the si_status member of the siginfo_t structure passed to the SIGCHLD handler, if it is appropriately established via a call to sigaction with SA_SIGINFO specified in the flags:
If si_code is equal to CLD_EXITED, then si_status holds the exit value of the process; otherwise, it is equal to the signal that caused the process to change state. The exit value in si_status shall be equal to the full exit value (that is, the value passed to _exit(), _Exit(), or exit(), or returned from main()); it shall not be limited to the least significant eight bits of the value.
(Emphasis mine).
Note that upon testing, it appears that Linux does not honour this requirement and returns only the lower 8 bits of the exit code in the si_status member. Other operating systems may correctly return the full status; FreeBSD does. See test program here.
Be wary, though, that is not completely clear that you will receive an individual SIGCHLD signal for every child process termination (multiple pending instances of a signal can be merged), so this technique is not completely infallible. It is probably better to find another way to communicate a value between processes if you need more than 8 bits.
The short answer is that you pretty much can't. Traditionally, the exit status of a process under Unix/Linux is propagated as an 8-bit value. You can return any integer from main that you like, you can call exit with any integer that you like, but only the low-order 8 bits are available to the parent via any of the wait functions.
The reason WEXITSTATUSis documented as returning only the low-order 8 bits of the status is that those are the only bits that there are.
If you're trying to pass arbitrary data from a subprocess back to its parent, the exit status is not the way to do it. Me, I normally print data to the standard output, and have the caller capture it using popen or the equivalent.
Addendum: I thought the kernel didn't even record the full int-sized exit status, and that it was therefore impossible to retrieve it by any means, but as davmac explains in another answer, you might be able to get your hands on it in a SIGCHLD handler.
I believe the only ways you can get it is by straceing the process and looking for the exit system calls, which now seem to be exit_group, by debugging, or possibly by using some ugly hacks like LD_PRELOAD. I.e. nothing unintrusive.
For zombie processes the exit code can be found in the last column of /proc/<pid>/stat but it is already & 0xFF.

Why can the execve system call run "/bin/sh" without any argv arguments, but not "/bin/ls"?

I am confused with the syscall of __NR_execve. When I learn linux system call. The correct way that I know to use execve is like this:
char *sc[2];
sc[0]="/bin/sh";
sc[1]= NULL;
execve(sc[0],sc,NULL);
Then the function execve will call syscall() to get into system kernel with putting the arguments on Registers EAX, EBX, ECX and EDX. However, It still succeed if I use
execve("/bin/sh",NULL,NULL);
But if I replace "/bin/sh" with "/bin/ls",it fail with:
A NULL argv[0] was passed through an exec system call.
I wonder why "/bin/sh" can be executed successfully without enough parameters while "/bin/ls" fail?
This is not a kernel issue. The kernel will run with the filename arg of execve regardless of whether argv and envp are NULL or not. It is just a Unix convention that argv[0] points to the program name.
And what you saw is just normal, i.e. nothing is wrong. Because ls is part of GNU's coreutils, and all programs in the coreutils package call set_program_name to do some setup work. You can see this in the source: it checks whether argv[0] is NULL, and it will call abort when it is.
On the other hand, /bin/sh is apparently a program that does not belong to coreutils, and does not check against argv[0]. That's why it runs without the problem.
Refer to the source code:
http://git.savannah.gnu.org/cgit/coreutils.git/tree/src/ls.c#n1285
http://git.savannah.gnu.org/cgit/gnulib.git/tree/lib/progname.c#n51

Why can't stdout from calling c library printf in asm be piped to other programs?

I have written a simple NASM program:
printtest.asm
section .data
str_out db "val = %d",10,0
section .text
global main
extern printf
main:
PUSH 5
PUSH DWORD str_out
CALL printf
ADD ESP, 8
MOV EAX, 1
INT 80h
I am linking and creating an executable with the following commands:
nasm -f elf -l printtest.lst printtest.asm
gcc -o printtest printtest.o
When linked and executed, this prints "val = 5" to the console no problem. As far as I'm aware, calling printf by default writes on stdout. So why when I try and pipe this to another program does the other program seem to receive no input?
E.g
./printtest | cat
Seems to do nothing
I am sure I am fundamentally misunderstanding something here.
C stdio functions may be buffered by default, so writing to stdout with printf doesn't always actually output anything -- sometimes it just writes to the buffer, awaiting a subsequent flush. Often times, whether a given stdio stream is buffered or not depends on whether it is connected to a terminal or a pipe or a file or something else.
When you call the exit system call (as you do), any data still in buffers will be lost. If you instead call the C library exit function, it will flush all buffers before actually exiting.

Fork and returning twice

I am working on a project that requires implementation of a fork() in unix. I read freeBSD and openBSD source code but it is really hard to understand. Can someone please Explain the returning twice concept? I understand that one return is pid of a child, and that gets returned to parent and other one is zero and it gets returned to a child process. But I cannot wrap my head around how to implement this notion of returning twice... how can I return twice? Thanks everyone in advance.
When you call fork, it returns "twice" in that the fork spawns two processes, which each return.
So, if you're implementing fork, you have to create a second process without ending the first. Then the return-twice behavior will happen naturally: each of the two distinct processes will continue execution, only differing in the value they return (the child giving zero, and the parent giving the child's PID).
When you think of a function returning, you have your usual code flow in mind, which starts at the entry point (usually main) and then executes line by line, in a strictly deterministic and linear fashion.
However, in a real-world system, it is possible to have multiple execution contexts which each have their own control flow (and the new C++ standard actually includes that notion). Each separate process is an execution context that starts at main, but you can also create a new execution context from within an existing one (in fact, all operating systems must be able to do that!). fork is one way to create a new execution context, and the entry point of the new context is the point where fork returns. However, the original context also continues running, and it continues as usual after the fork call. The new context is a separate process, and thus fork returns (once) in both contexts.
There are other ways of creating new execution contexts; one is to create a new thread (within the same process) by instantiating a std::thread object or by using a platform-specific function; another is Linux's clone() function, which underlies both the Posix thread implementation and fork in Linux (by creating a new execution path for the kernel's scheduler, and either copying all virtual memory (new process) or not (new thread).
Following I will try to explain how to return twice from a function.
I'm warning you from the start that this is all a hack.
But there are plenty of places that use these sort of hacks.
First let's say we have the following C program.
#include <stdio.h>
uint64_t saved_ret;
int main(int argc, char *argv[])
{
if (saveesp()) {
printf("here! esp = %llX\n", saved_ret);
jmpback();
} else {
printf("there! esp = %llX\n", saved_ret);
}
return 0;
}
Now we want to saveesp() to return twice so that we can reach both printf's.
So here's how saveesp() is implemented:
#define _ENTRY(x) \
.text; .globl x; .type x,#function; x:
#define NENTRY(y) _ENTRY(y)
NENTRY(saveesp)
movq (%rsp), %rax
movq %rax, saved_ret
movl $1, %eax
ret
NENTRY(jmpback)
xorq %rax, %rax
pushq saved_ret
ret
This is in no way portable code. But you can write similar assembly stubs for all the platforms you want to support.
What saveesp() does is, it takes the return address stored on the stack and saves it to a local variable. Afterwards it returns 1. Which is a non-zero return, which takes us to the first printf.
After the printf() we call jmpback(). Which is the actual hack. This function makes it so that it appears that saveesp() returns a second time.
It does this by pushing the saved return address down the stack and doing a ret. The ret will pop the address from the stack and jump to it. The return code is set to zero this time around. So when we 'reach' back to our C routine it appears we've just came back from saveesp() with zero return value. Thus the second printf is reached.
If you're interested in this sort of hacks you should read a bit more about setjmp and longjmp from the C standard that are used to implement exception handling.
Also, we actually use this inside the OpenBSD kernel on the suspend/resume codepath.
Have a look here at lines 231 and 250 it's pretty much the same C code as above. And then have a look at the assembly code here at line 542 is the savecpu function that returns the first time on suspend and at line 375 is where we return the second time around when we come back on resume.

Fork implementation

How is fork system call code written . I want to know some details how a function can return two different values and that to two different processes . In short want to know how fork system call is implemented?
Carl's answer was great. I'd like to add that in many operating systems return values are passed in one of the registers. In x86 architecture this register might be eax, In ARM architecture this register might be R0, etc.
Each process also have a Process Control Block (PCB), which store values of registers at the time some interrupt, syscall, or exception happened and control was passed to the OS. The next time the process scheduled, the values of the registers are restored from PCB.
Now, when fork() happens, OS can do:
child_process->PCB[return_value_register] = 0;
parrent_process->PCB[return_value_register] = child_pid;
So, when the processes are rescheduled, each of them see a different return value.
As an example, you can see xv6's implementation of fork. In there, the parent process is still in running state, so it returns parent's return value using simple return statement. But it sets value of EAX register for child process to 0, so when child process is scheduled it sees 0 as return value:
// Clear %eax so that fork returns 0 in the child.
np->tf->eax = 0;
Note that return 0 will also compile to something like "mov eax, 0".
Update: I just implemented fork() for a hobby OS I am doing. You can see the source code here.
You've pretty much explained it by saying that it's a system call. It's the operating system's job to do all that work, and the operating system can pretty much do whatever it wants outside of the context of your program or the rules of whatever language you're implementing it in. Here's a simple example of how it might happen:
Program calls fork() system call
Kernel fork system call duplicates the process running the program
The kernel sets the return value for the system call for the original program and for the duplicate (PID of the duplicate and 0, respectively)
The kernel puts both processes in the scheduler queue
As each process is scheduled, the kernel 'returns' to each of the two programs.
There is a comment in the Unix V6 source code booklet for universities which was annotated by Ken Thompson and Dennis Ritchie themselves describing how the double return actually works. The comment ends with following sentence:
You are not expected to understand this.
In easy way for example process is cloned in fork() function with Moving IP/EIP/RIP register to skip some instruction in functions that can look like:
return pid;
return 0;
First process will execute first instruction and pop function from stack, second process will start but from second instruction returning 0.

Resources