Does anyone tell me how to block some specific system calls within a program, please? I am building a system which takes a piece of C source code, compiles it with gcc and runs it. For security reasons, I need to prevent the compiled program from calling some system calls. Is there any way to do it, from the source code level (e.g. stripping the header files of gcc, detecting malicious external calls, ...) to the executable level?
Edited #1: Add details about malicious calls.
Edited #2: My system is a GNU/Linux one.
Edited #3:
I have tried some methods within a few days and here are the conclusions I've got so far:
Scanning the source code does not solve the main problem since one can always obsfucate his/her C source file quite well.
"Overriding C symbol" works well for libraries, but for system calls I have not achieved what I wanted. This idea is not dead, however, doing this would definitely cause me a lot of time hacking (gcc and/or ld).
Permission deescalation works like a charm. I could use fakeroot or a "guest" user to do it. This method is also the easiest to implement.
The other one is native client which I have not tried yet but I definitely would in near future due to the common between the project and my work.
As others have noted, it's impossible for a program to avoid making system calls, they permate the C library all over the place.
However you might be able to make some headway with careful use of the LD_PRELOAD mechanism, if your platform supports it (e.g. Linux): you write a shared library with the same symbol names as those in the C library, which are called instead of the intended libc functions. (For example, Electric Fence is built as a shared library on Debian-based systems and intercepts calls to malloc, free et al.)
I suspect you could use this mechanism to trap or argument-check calls to any libc functions you don't like, and perhaps to note those which you consider unconditionally safe. It might then be reasonable to scan the compiled executable for the code corresponding to INT 0x80 to trap out any attempts to make raw syscalls (0xcd 0x80 - though beware of false positives). However I have only give this a few moments of thought, I could easily have missed something or this might turn out to be impractical...
You could run the compiled program by forking it from a wrapper and use the Linux ptrace(2) facility to intercept and inspect all system calls invoked by the program.
The following example code shows a wrapper that runs the /usr/bin/w command, prints each system call invoked by the command, and terminates the command if it tries to invoke the write(2) system call.
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/ptrace.h>
#include <sys/wait.h>
#include <sys/syscall.h>
#include <sys/reg.h>
#define BAD_SYSCALL __NR_write
int main(int argc, char *argv)
{
pid_t child;
int status, syscall_nr;
child = fork();
if (child == 0) {
/* In child. */
ptrace(PTRACE_TRACEME, 0, NULL, NULL);
execl("/usr/bin/w", NULL, NULL);
// not reached
}
/* In parent. */
while (1) {
wait(&status);
/* Abort loop if child has exited. */
if (WIFEXITED(status) || WIFSIGNALED(status))
break;
/* Obtain syscall number from the child's process context. */
syscall_nr = ptrace(PTRACE_PEEKUSER, child, 4 * ORIG_EAX, NULL);
printf("Child wants to execute system call %d: ", syscall_nr);
if (syscall_nr != BAD_SYSCALL) {
/* Allow system call. */
printf("allowed.\n");
ptrace(PTRACE_SYSCALL, child, NULL, NULL);
} else {
/* Terminate child. */
printf("not allowed. Terminating child.\n");
ptrace(PTRACE_KILL, child, NULL, NULL);
}
}
exit(EXIT_SUCCESS);
}
You can do much more powerful things using ptrace, such as inspect and change a process' address space (e.g., to obtain and modify the parameters passed to a system call).
A good introduction can be found in this Linux Journal Article and its follow-up.
You can't.
Even this program:
#include <stdio.h>
int main()
{
printf("Hello, World\n");
return 0;
}
makes at least one system call (to send the string "Hello, World\n" to standard out). System calls are the only way for a program to interact with the outside World. Use the operating system's security model for security.
Edited for this comment:
I meant not all system calls but malicious system calls, e.g. execv() could be used to execute a BASH script which wipes out my data on the disk.
Your operating system already includes mechanisms to stop that sort of thing happening. For instance, in order for a bash script to wipe out your data, the process must already have write access to that data. That means it must have been started by you or root. Your only real option is not to install untrustworthy software.
By the way, depending on your platform, execv is not necessarily a system call. On Linux, it's a C library wrapper for the real system call (execve).
Just to illustrate that this is not possible, the following program:
int main() {
return 0;
}
makes over 20 system calls as reported using strace. The calls include open (twice) which is one of the calls you seem to want to block.
Well, if you just want to block specific calls, why not just do a grep through the source code before attempting to compile it ? And reject programs which use the insecure system calls.
Some project have similar idea you can take a look at nacl: http://code.google.com/p/nativeclient/
Related
This question already has answers here:
syscall wrapper asm C
(2 answers)
Closed 2 years ago.
Can a system call happen in a C program?
Consider this:
int main()
{
int f = open("/tmp/test.txt", O_CREAT | O_RDWR, 0666);
write(f, "hello world", 11);
close(f);
return 0;
}
In this sample code, open, write, and close are library functions. During my searches I conclude that they are functions not system calls. Each of these functions (open, write, and close) make a system call.
Questions
Are my conclusions above all correct?
Can system calls happen in C programs?
If system calls can happen in C programs, when do they happen? Please give an example.
Can the use of a library function versus directly making a system call be controlled by compile options? For example, is it possible that can we compile the above program with some options so that the write and read system calls are made directly, and if we compile it with different options, it calls library functions instead?
System call background
A system call, according to Wikipedia, is a "programmatic way in which a computer program requests a service from the kernel of the operating system on which it is executed".
Another way of understanding a system call is as a user space program making a request to the operating system kernel to perform some task on behalf of the user space program. The full set of system calls provided by the kernel is analogous (in some ways) to an API provided by the kernel to user space.
As system calls are a low level interface to the kernel, correctly providing their arguments can be error prone or even dangerous. For these reasons, C library authors provide simpler and safer wrapper functions for a significant portion of a kernel's set of system calls.
These wrapper functions take a simplified argument set and then derive the appropriate values to pass on to the kernel so the system call can be executed.
Example
Note: This example is based on compiling and running a C program with gcc on Linux. The system calls, library functions, and output may differ on other POSIX or non-POSIX operating systems.
I will attempt to show how to see when system calls are being made with a simple example.
#include <stdio.h>
int main() {
write(1, "Hello world!\n", 13);
}
Above we have a very simple C program that writes the string Hello world!\n to stdout. If we compile and then execute this program with strace, we see the following (note the output may look different on other computers):
$ strace ./hello > /dev/null
execve("./hello", ["./hello"], 0x7fff083a0630 /* 58 vars */) = 0
<a bunch of output we aren't interested in>
write(1, "Hello world!\n", 13) = 13
exit_group(0) = ?
+++ exited with 0 +++
strace is a Linux program that intercepts and displays all system calls made by a program, as well as the arguments provided to the system calls and their return values.
We can see here that, as expected, the write system call was made with the expected arguments. Nothing strange yet.
Another Linux tracing program is ltrace, which intercepts dynamic library calls made by a program, and displays their arguments and return values.
If we run the same program with ltrace, we see this:
$ ltrace ./hello > /dev/null
write(1, "Hello world!\n", 13) = 13
+++ exited (status 0) +++
This tells us that the write library function was executed. This means that the C code first called the write library function, which then in turn called the write system call.
Suppose now that we want to explicitly make a write system call without calling the write library function. (This is inadvisable in normal use, but useful for illustration.)
Here is the new code:
#include <stdio.h>
#include <unistd.h>
#include <sys/syscall.h>
int main() {
syscall(SYS_write, 1, "Hello world!\n", 13);
}
Here we directly call the syscall library function, telling it we want to execute the write system call.
After recompiling, here is the output of strace:
$ strace ./hello > /dev/null
execve("./hello", ["./hello"], 0x7ffe3790a660 /* 58 vars */) = 0
<a bunch of output we aren't interested in>
write(1, "Hello world!\n", 13) = 13
exit_group(0) = ?
+++ exited with 0 +++
We can see the write system call is made as before as expected.
If we run ltrace we see the following:
$ ltrace ./hello > /dev/null
syscall(1, 1, 0x560b30e4d704, 13) = 13
+++ exited (status 0) +++
So the write library function is no longer being called, but we are still making a library function call. Now we are making a call to the syscall library function instead of the write library function.
There may be a way to directly make a system call from a user space C program without calling any library functions, and if there is a way I believe it would be very advanced.
Detecting when a C program makes system calls
In general, nearly every non-trivial C program makes at least one system call. This is because user space does not have direct access to kernel memory or to the computer's hardware. User space programs have indirect access to kernel memory and the hardware through system calls.
To identify if a compiled C program (or any other program on Linux) makes a system call, and to identify which system calls it makes, simply use strace.
Are there compiler options to prevent calling the library wrapper functions for system calls?
You can compile your C program (assuming you are using gcc) with the -nostdlib option. This will prevent linking the C standard library as part of producing your executable. However, then you would need to write your own code to make system calls.
"In computing, a system call is a programmatic way in which a computer program requests a service from the kernel of the operating system on which it is executed. This may include hardware-related services (for example, accessing a hard disk drive), creation and execution of new processes, and communication with integral kernel services such as process scheduling. System calls provide an essential interface between a process and the operating system." - Wikipedia
The close system call is a system call used to close a file descriptor by the kernel. For most file systems, a program terminates access to a file in a filesystem using the close system call.
int close(int fd);
close() closes a file descriptor, so that it no longer refers to any file and may be reused.
so as you see, syscall is used when you need to access something in kernel space and this is possible only syscalls.
In the below program, I've used system library function to execute "pkill" command. Is there any system call available for pkill(Because PID is unknown). I don't want to use "system" library function. Please let me know how to do it
#include <stdio.h>
int main()
{
char test[1024] = "pkill -15 radio";
system(test);
return 0;
}
The system call for sending signals to processes is kill; however, you need the process id for. If you intend to launch the program to be killed from within your application, too, use fork together with one of the exec-functions and you have it. Otherwise, you will most likely have to iterate over the /proc/* subdirectories.
I have a long-running C program which opens a file in the beginning, writes out "interesting" stuff during execution, and closes the file just before it finishes. The code, compiled with gcc -o test test.c (gcc version 5.3.1.) looks like as follows:
//contents of test.c
#include<stdio.h>
FILE * filept;
int main() {
filept = fopen("test.txt","w");
unsigned long i;
for (i = 0; i < 1152921504606846976; ++i) {
if (i == 0) {//This case is interesting!
fprintf(filept, "Hello world\n");
}
}
fclose(filept);
return 0;
}
The problem is that since this is a scientific computation (think of searching for primes, or whatever is your favourite hard-to-crack stuff) it could really run for a very long time. Since I determined that I am not patient enough, I would like to abort the current computation, but I would like to do this in an intelligent way by somehow forcing the program by external means to flush out all the data that is currently in the OS buffer/disk cache, wherever.
Here is what I have tried (for this bogus program above, and of course not for the real deal which is currently still running):
pressing ctrl+C; or
sending kill -6 <PID> (and also kill -3 <PID>) -- as suggested by #BartekBanachewicz,
but after either of these approaches the file test.txt created in the very beginning of the program remains empty. This means, that the contents of fprintf() were left in some intermediate buffer during the computation, waiting for some OS/hardware/software flush signal, but since no such a signal was obtained, the contents disappeared. This also means, that the comment made by #EJP
Your question is based on a fallacy. 'Stuff that is in the OS
buffer/disk cache' won't be lost.
does not seem to apply here. Experience shows, that stuff indeed get lost.
I am using Ubuntu 16.04 and I am willing to attach a debugger to this process if it is possible, and if it is safe to retrieve the data this way. Since I never done such a thing before, I would appreciate if someone would provide me a detailed answer how to get the contents flushed into the disk safely and surely. Or I am open to other methods as well. There is no room for error here, as I am not going to rerun the program again.
Note: Sure I could have opened and closed a file inside the if branch, but that is extremely inefficient once you have many things to be written. Recompiling the program is not possible, as it is still in the middle of some computation.
Note2: the original question was asked the same question in a slightly more abstract way related to C++, and was tagged as such (that is why people in the comments suggesting std::flush(), which wouldn't help even if this was a C++ question). Well, I guess I made a major edit then.
Somewhat related: Will data written via write() be flushed to disk if a process is killed?
Can I just add some clarity? Obviously months have passed, and I imagine your program isn't running any more ... but there's some confusion here about buffering which still isn't clear.
As soon as you use the stdio library and FILE *, you will by default have a fairly small (implementation dependent, but typically some KB) buffer inside your program which is accumulating what you write, and flushing it to the OS when it's full, (or on file close). When you kill your process, it is this buffer that gets lost.
If the data has been flushed to the OS, then it is kept in a unix file buffer until the OS decides to persist it to disk (usually fairly soon), or someone runs the sync command. If you kill the power on your computer, then this buffer gets lost as well. You probably don't care about this scenario, because you probably aren't planning to yank the power! But this is what #EJP was talking about (re Stuff that is in the OS buffer/disk cache' won't be lost): your problem is the stdio cache, not the OS.
In an ideal world, you'd write your app so it fflushed (or std::flush()) at key points. In your example, you'd say:
if (i == 0) {//This case is interesting!
fprintf(filept, "Hello world\n");
fflush(filept);
}
which would cause the stdio buffer to flush to the OS. I imagine your real writer is more complex, and in that situation I would try to make the fflush happen "often but not too often". Too rare, and you lose data when you kill the process, too often and you lose the performance benefits of buffering if you are writing a lot.
In your described situation, where the program is already running and can't be stopped and rewritten, then your only hope, as you say, is to stop it in a debugger. The details of what you need to do depend on the implementation of the std lib, but you can usually look inside the FILE *filept object and start following pointers, messy though. #ivan_pozdeev's comment about executing std::flush() or fflush() within the debugger is helpful.
By default, the response to the signal SIGTERM is to shut down the application immediately. However, you can add your own custom signal handler to override this behaviour, like this:
#include <unistd.h>
#include <signal.h>
#include <atomic>
...
std::atomic_bool shouldStop;
...
void signalHandler(int sig)
{
//code for clean shutdown goes here: MUST be async-signal safe, such as:
shouldStop = true;
}
...
int main()
{
...
signal(SIGTERM, signalHandler); //this tells the OS to use your signal handler instead of default
signal(SIGINT, signalHandler); //can do it for other signals too
...
//main work logic, which could be of form:
while(!shouldStop) {
...
if(someTerminatingCondition) break;
...
}
//cleanup including flushing
...
}
Be aware that if take this approach, you must make sure that your program does actually terminate after your custom handler is run (it is under no obligation to do so immediately, and can run clean-up logic as it sees fit). If it doesn't shut down, linux will not shut it down either so the SIGTERM will be 'ignored' from an outside perspective.
Note that by default the linux kill command sends a SIGTERM, invoking the behaviour above. If your program is running in the foreground and Ctrl-C is pressed, a SIGINT is sent instead, which is why you might want to handle that as well as per above.
Note also, the implementation suggested above takes care to be safe, in that no async logic is performed in the signal handler other than setting an atomic flag. This is important, as pointed out in the comments below. See the Async-signal safe section of this page for details of what is and isn't allowed.
I have a pretty unique case where I am calling a 3rd party library (which I cannot modify) from a higher-level C program.
This code has a clean-up routine that calls exit() - which terminates the whole application.
However, I do not want to terminate the whole application at this time, as there is still some work that must be done by the main application.
So to solve this, I tried to 'trick' this 3rd party library by temporarily 'aliasing' the exit() function call to a dummy function using dlsym - and then later restoring exit() to its normal state.
This solution almost works - using LD_PRELOAD to point to the dummy exit wrapper I can see this dummy exit function being called - however, imminently after this I get a segmentation fault when this function goes out of scope.
I suspect this has to do with the fact that gcc by default puts an attribute called noreturn on this function.
Is there a way to remove this noreturn attribite, or better still another way of preventing this 3rd party library from calling exit()?
Any and all suggestions would be most appreciated.
Ignoring the fact that this may be a bad idea and that this is an old question and it seams to be answered in the comments.
There is an alternative solution to this if using gcc on Linux (maybe other systems to, I wouldn't know).
/* compile with "gcc -Wl,-wrap,exit -o test wrap_exit.c" */
/* check exit status with "echo $?" */
#include <stdio.h>
#include <stdlib.h>
void __real_exit(int status);
void __wrap_exit(int status)
{
int stat = 2;
printf("trying to exit with status %d\n", status);
printf("now exiting for real with status %d\n", stat);
__real_exit(stat);
}
int main(void)
{
exit(1);
return 0;
}
There is question about using exit in C++. The answer discusses that it is not good idea mainly because of RAII, e.g., if exit is called somewhere in code, destructors of objects will not be called, hence, if for example a destructor was meant to write data to file, this will not happen, because the destructor was not called.
I was interested how is this situation in C. Are similar issues applicable also in C? I thought since in C we don't use constructors/destructors, situation might be different in C. So is it ok to use exit in C? For example I have seen following functions sometimes used in C:
void die(const char *message)
{
if(errno) {
perror(message);
} else {
printf("ERROR: %s\n", message);
}
exit(1);
}
Rather than abort(), the exit() function in C is considered to be a "graceful" exit.
From C11 (N1570) 7.22.4.4/p2 The exit function (emphasis mine):
The exit function causes normal program termination to occur.
The Standard also says in 7.22.4.4/p4 that:
Next, all open streams with unwritten buffered data are flushed, all
open streams are closed, and all files created by the tmpfile function
are removed.
It is also worth looking at 7.21.3/p5 Files:
If the main function returns to its original caller, or if the exit
function is called, all open files are closed (hence all output
streams are flushed) before program termination. Other paths to
program termination, such as calling the abort function, need not
close all files properly.
However, as mentioned in comments below you can't assume that it will cover every other resource, so you may need to resort to atexit() and define callbacks for their release individually. In fact it is exactly what atexit() is intended to do, as it says in 7.22.4.2/p2 The atexit function:
The atexit function registers the function pointed to by func, to be
called without arguments at normal program termination.
Notably, the C standard does not say precisely what should happen to objects of allocated storage duration (i.e. malloc()), thus requiring you be aware of how it is done on particular implementation. For modern, host-oriented OS it is likely that the system will take care of it, but still you might want to handle this by yourself in order to silence memory debuggers such as Valgrind.
Yes, it is ok to use exit in C.
To ensure all buffers and graceful orderly shutdown, it would be recommended to use this function atexit, more information on this here
An example code would be like this:
void cleanup(void){
/* example of closing file pointer and free up memory */
if (fp) fclose(fp);
if (ptr) free(ptr);
}
int main(int argc, char **argv){
/* ... */
atexit(cleanup);
/* ... */
return 0;
}
Now, whenever exit is called, the function cleanup will get executed, which can house graceful shutdown, clean up of buffers, memory etc.
You don't have constructors and destructors but you could have resources (e.g. files, streams, sockets) and it is important to close them correctly. A buffer could not be written synchronously, so exiting from the program without correctly closing the resource first, could lead to corruption.
Using exit() is OK
Two major aspects of code design that have not yet been mentioned are 'threading' and 'libraries'.
In a single-threaded program, in the code you're writing to implement that program, using exit() is fine. My programs use it routinely when something has gone wrong and the code isn't going to recover.
But…
However, calling exit() is a unilateral action that can't be undone. That's why both 'threading' and 'libraries' require careful thought.
Threaded programs
If a program is multi-threaded, then using exit() is a dramatic action which terminates all the threads. It will probably be inappropriate to exit the entire program. It may be appropriate to exit the thread, reporting an error. If you're cognizant of the design of the program, then maybe that unilateral exit is permissible, but in general, it will not be acceptable.
Library code
And that 'cognizant of the design of the program' clause applies to code in libraries, too. It is very seldom correct for a general purpose library function to call exit(). You'd be justifiably upset if one of the standard C library functions failed to return just because of an error. (Obviously, functions like exit(), _Exit(), quick_exit(), abort() are intended not to return; that's different.) The functions in the C library therefore either "can't fail" or return an error indication somehow. If you're writing code to go into a general purpose library, you need to consider the error handling strategy for your code carefully. It should fit in with the error handling strategies of the programs with which it is intended to be used, or the error handling may be made configurable.
I have a series of library functions (in a package with header "stderr.h", a name which treads on thin ice) that are intended to exit as they're used for error reporting. Those functions exit by design. There are a related series of functions in the same package that report errors and do not exit. The exiting functions are implemented in terms of the non-exiting functions, of course, but that's an internal implementation detail.
I have many other library functions, and a good many of them rely on the "stderr.h" code for error reporting. That's a design decision I made and is one that I'm OK with. But when the errors are reported with the functions that exit, it limits the general usefulness the library code. If the code calls the error reporting functions that do not exit, then the main code paths in the function have to deal with error returns sanely — detect them and relay an error indication to the calling code.
The code for my error reporting package is available in my SOQ (Stack Overflow Questions) repository on GitHub as files stderr.c and stderr.h in the src/libsoq sub-directory.
One reason to avoid exit in functions other than main() is the possibility that your code might be taken out of context. Remember, exit is a type of non local control flow. Like uncatchable exceptions.
For example, you might write some storage management functions that exit on a critical disk error. Then someone decides to move them into a library. Exiting from a library is something that will cause the calling program to exit in an inconsitent state which it may not be prepared for.
Or you might run it on an embedded system. There is nowhere to exit to, the whole thing runs in a while(1) loop in main(). It might not even be defined in the standard library.
Depending on what you are doing, exit may be the most logical way out of a program in C. I know it's very useful for checking to make sure chains of callbacks work correctly. Take this example callback I used recently:
unsigned char cbShowDataThenExit( unsigned char *data, unsigned short dataSz,unsigned char status)
{
printf("cbShowDataThenExit with status %X (dataSz %d)\n", status, dataSz);
printf("status:%d\n",status);
printArray(data,dataSz);
cleanUp();
exit(0);
}
In the main loop, I set everything up for this system and then wait in a while(1) loop. It is possible to make a global flag to exit the while loop instead, but this is simple and does what it needs to do. If you are dealing with any open buffers like files and devices you should clean them up before close for consistency.
It is terrible in a big project when any code can exit except for coredump. Trace is very import to maintain a online server.