I know that use the command "chroot" in linux need some files or directories such as usr, bin and so on. But when I use the function chroot() in C, do I need these files?
Here is my code, which "hw.out" is a binary file which just print "Hello, world". I compiled it and run it as root, but it was failed to print "Hello, world". What else should I do? Thank you!
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
int main(int argc, char *argv[])
{
int result = chroot(".");
if(result == 0)
printf("Chroot Succese.\n");
char *arrays[]={"./hw.out",NULL};
execvp("./hw.out", arrays);
return 0;
}
execvp is most likely failing, probably with ENOENT: no such file or directory, if hw.out is a dynamically linked executable.
For that to work, all the libraries required by hw.out need to be findable in the chrooted environment.
Try linking hw.out statically, and it should work. (And add error checking after execvp to see what errno is set to after the call if it returns.)
Please test that your hw.out works with command line chroot.
Perhaps hw.out is dynamically linked and is missing some libraries or ld-linux.so in the chroot directory.
Nitpicks 1, what's the point of return 0 after execvp? it never gets executed unless there is an error. I would rather have perror("can't exec"); return 1;
Nitpick 2, chroot() doesn't change working directory, although it works in your case, as you are chrooting to ".", it won't work as you expect if you later change it to chroot("somedir").
Make sure that hw.out is in the correct direct. Perhaps it is easier to have it statically linked if it is using libraries. Otherwise need to enable after chroot that it can access the dynamic libraries.
Related
I am currently learning C, using CLion on Windows, and as so I am starting off with a very simple program using cURL.
I have finally successfully included the library in my code using CMake as performed in this question:
How do I link dynamically built cmake files on Windows?
The code now builds without error.
The issue is, as soon as I write the curl_easy_init(), the program outputs with an unusual exit code not referenced in the cURL docs and print functions fail to output like normal.
#include <stdio.h>
#include <curl/curl.h>
int main(void) {
printf("Hello world!\n");
CURL *curl;
CURLcode res;
curl = curl_easy_init(); // Line that changes program
return 0;
}
Whenever that dreadful line is written, the program no longer outputs a happy old "Hello World!" with an exit code of zero, and instead, outputs this:
Process finished with exit code -1073741515 (0xC0000135)
What even is that exit code??
Any information is much appreciated.
0xC0000135 is "application not correctly initialized", which generally indicates that the loader cannot find a dll required by your application. Most probably you linked the libcurl import library, but the corresponding dll (libcurl.dll) cannot be found in the same directory of the executable and isn't in the global dll search paths. Make sure the dll is available when you launch your application, or link libcurl statically.
I'm trying to learn File I/O concepts in C programming language. I'm using GNU / Linux ( Ubuntu 16.04 LTS ) and my IDE is eclipse 3.8. when I try to write in a file through fprintf() method, it doesn't create any files or if the file is even created, it doesn't write in it. I tried to fix the problem by using fflush() or setbuf(file_pointer, NULL) methods as is suggested here but still no change. I guess I'm writing the address of the file in a wrong way.
Here is the code:
#include <stdio.h>
int main(void){
FILE *file_pointer;
file_pointer=fopen("~/.textsfiless/test.txt","w+");
setbuf(file_pointer,NULL);
fprintf(file_pointer,"Testing...\n");
fclose(file_pointer);
return EXIT_SUCCESS;
}
Can someone explain what's wrong here?
On Linux, the ~ in ~/.textsfiless/test.txt is not expanded by the C library fopen... When you use ~ on the command line, it is expanded by your shell (but not by the program using it, started by the shell doing some execve(2)...) into your home directory; the expansion is called globbing. Read glob(7). You are very unlikely to have a directory named ~.
You should read Advanced Linux Programming
So you should check if fopen failed (it is very likely that it did fail). If you want to get a file in the home directory, you'll better use getenv(3) with "HOME" (or perhaps getpwuid(3) & getuid(2)...). See environ(7)
Perhaps a better code might be:
char*homedir = getenv("HOME");
if (!homedir) { perror("getenv HOME"); exit(EXIT_FAILURE); };
char pathbuf[512]; /// or perhaps PATH_MAX instead of 512
snprintf(pathbuf, sizeof(pathbuf),
"%s/.textsfiless/test.txt", homedir);
FILE *file_pointer = fopen(pathbuf, "r");
if (!file_pointer) { perror(pathbuf); exit(EXIT_FAILURE); };
and so on.
Notice that you should check against failures most C standard library (& POSIX) functions. The perror(3) function is useful to report errors to the user on stderr.
(pedantically, we should even test that snprintf(3) returns a length below sizeof(pathbuf) or use and test against failure asprintf(3) instead; I leave that test as an exercise to the reader)
More generally, read the documentation of every external function that you are using.
Beware of undefined behavior (your code is probably having some, e.g. fprintf to a NULL stream). Compile your code with all warnings & debug info (so gcc -Wall -g) and use the gdb debugger. Read What every C programmer should know about undefined behavior.
BTW, look into strace(1) and try it on your original (faulty) program. You'll learn a lot about the system calls used in it.
Most likely your call to fopen() fails. You don't have any checking in your program to ensure fopen even worked. It may not have, and this could be due to a variety of things, like you spelling the path wrong, wrong file or process permissions, etc.
To see what really happened, you should check fopen's return value:
#include <stdio.h>
int main(void){
FILE *file_pointer;
file_pointer=fopen("~/.textsfiless/test.txt","w+");
if (file_pointer == NULL) {
printf("Opening the file failed.");
return EXIT_FAILURE;
}
setbuf(file_pointer,NULL);
fprintf(file_pointer,"Testing...\n");
fclose(file_pointer);
return EXIT_SUCCESS;
}
Edit: Since your comment, you getting the path wrong is most certainly what happened. If you're executing your program from the current directory, and your file is in a folder called "textfiless" in your current directory and your file is called "test.txt", then you'd call fopen like this:
file_pointer=fopen("/textsfiless/test.txt","w+");
I'm trying to make a program which runs an executable in its folder on my Mac.
Considering that my program is compiled in the same folder as the source (/Users/Marcello/Documents/C/Test/Test/Test.c), the program would look something like this:
int main(int argc, const char * argv[])
{
printf("Hello, world!\n");
if(execl("/Users/Marcello/Documents/C/Test/Test/HelloWorld", "HelloWorld", NULL))
printf("ERROR\n");
return 0;
}
Everything works fine if I give the absolute path, but it won't work anymore when I try to pass the relative path to the folder (passing "HelloWorld" instead of "/Users/Marcello/Documents/C/Test/Test/HelloWorld").
I noticed this happens because, without other indications, the program will try to search for HelloWorld in the shell's folder instead of the project's folder. This happens as well with functions such as fopen(), so I tried thinking of solutions; the problem is, I want to get this code into a program that everybody could download and install wherever they like, an I would like it to be cross-platform too, but all the solutions I found, such as chdir(), somehow reference to the absolute path of the program, which I shouldn't know in advance.
Can anybody help me find a long-term solution?
The first element of argv contain the relative to path to your program.
I have a problem with the execution of shell commands inside a chroot jail. Here is an exemple:
#include <stdio.h>
#include <unistd.h>
#include <errno.h>
#include <string.h>
#include <sys/types.h>
int main()
{
if (geteuid() == 0) // check root privileges
{
chroot("/bin");
chdir("/");
execl("/ls", "ls", "-l", (char *) NULL); // "/ls" should be equivalent to "/bin/ls"
perror(strerror(errno));
}
else
printf("Permission denied\n");
return 0;
}
The problem is the exec: according to errno, the error is "No such file or directory".
The same error appears if I use exec("/bin/ls", ...)
I think that "ls" cannot use the shared libraries he needs, because of chroot jail.
Any suggestion to solve this problem?
You're probably right regarding shared libraries being inaccessible. Setting up a chroot jail typically involves copying parts of /bin, /usr/bin, /lib, and /usr/lib into a parallel directory structure.
A simpler alternative is to use only statically linked executables. On many linux systems there will be a statically linked executable called busybox that provides the base functionality of many Unix commands including ls. Invoking it like busybox ls -l provides similar output to the regular ls program without needed to access addition shared libraries outside the chroot jail.
I am executing a program say A from another by first fork-ing followed by execve(). Now the problem is I would want A to use my library that I would generaly do by using LD_PRELOAD. How do I do it within execve().
Thanks
you can pass the LD_PRELOAD in envp execve's argument:
the program that gets execved, named "run":
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
int main(int argc, char **argv)
{
printf("%s\n",getenv("LD_PRELOAD"));
}
the program that does the execve, named "ex":
#include <stdio.h>
#include <unistd.h>
int main(int argc, char **argv)
{
char *const args[] = {"./run",NULL};
char *const envs[] = {"LD_PRELOAD=caca",NULL};
execve("./run",args,envs);
}
running it:
root#pinkpony:~# ./ex
ERROR: ld.so: object 'caca' from LD_PRELOAD cannot be preloaded: ignored.
caca
EDIT:
the error shown gets thrown because "caca" lib can't be preloaded for run, so it works. (I skipped the fork() part for clarity but the usage is the same)
EDIT:
doing something like:
LD_PRELOAD=caca ./ex
will not automagically preload caca lib when execve()-ing run if you're not passing it via envp execve()'s argument
If you want to use LD_PRELOAD just for program A (and not for its parent) you could load it via the shell; pass to the shell the name of the program to execute and add LD_PRELOAD to the environment.
Update
After reading the added info from the question, I'm guessing that you might have to specify a complete path, or set LD_LIBRARY_PATH as well? Since the loader is acknowledging the fact that the preload is ordered.
Otherwise, I can imagine there being a security restriction (allthough it would have to be tied to being run invoked from a login shell, which seems quite brittle to detect). Nonetheless, you may wish to try running as root (use sudo -E to keep your environment)
It would appear from this earlier question that such behaviour is the default
LD_PRELOAD affects new child even after unsetenv("LD_PRELOAD")
Have you tested it?