Execve() adds two extra arguments - c

When I compile the following code and run strace on it, I can see that it adds two additional elements to the args[] array.
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
int main(int argc, char **argv)
{
char *args[2];
args[0] = "/bin/ls";
args[1] = "-lh";
execve(args[0], args, NULL);
return 1;
}
strace says that this is what is actually being called:
execve("/bin/ls", ["/bin/ls", "-lh", "\340\301\361\267", "\1"], NULL)

You need to add a null ptr to the last element of the argument array. Otherwise execve doesn't know where your array ends.
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
int main(int argc, char **argv)
{
char *args[3];
args[0] = "/bin/ls";
args[1] = "-lh";
args[2] = NULL;
execve(args[0], args, NULL);
return 1;
}
So basically what you are seeing is execv passing random arguments until it found a NULL in the memory you point with the array. Of course it could be crashing as well.

Related

Why does this program prints an empty line?

This program is called program.c. When I run ./program echo test, I would expect the program to print test, even if the command is run in a subshell. Why is the output an empty line? Does it have to do with filepath? When I try ./program /bin/echo test I still get an empty line output.
#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
int function(char **argv) {
execl("/bin/bash", "sh", "-c", *argv, argv, (char*)NULL);
}
int main(int argc, char **argv) {
int return2;
function(argv + 1);
}
There are two problems with your program.
The first problem is that the argument argv to execl() does not do what you think it does. The pointer argv is a pointer to a char * (i.e. a char **), and it is only permitted to pass a char * as an argument to execl(). That is, variable argument lists in C do not work how you are expecting them to.
In order to accomplish what you want, consider not using execl() and use execv() instead, passing an array of char *s which you have constructed yourself. You could do this in the following way, for example:
#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
int function(char **argv) {
// Consider passing `argc` as well to eliminate
// the need for this loop.
int len = 0;
while(argv[len]) {
len++;
}
char *new_argv[len + 3];
new_argv[0] = "sh";
new_argv[1] = "-c";
for(int i = 0; i <= len; i++) {
new_argv[i + 2] = argv[i];
}
execv("/bin/bash", new_argv);
}
int main(int argc, char **argv) {
function(argv+1);
}
However, you still have a problem: ./program echo test will still print a blank line because if you execute sh -c echo test in a terminal you just get a blank line! In order to fix this, you need to do ./program 'echo test' (corresponding to sh -c 'echo test' at the terminal), which should then work.

C in Linux - using execle() to output an environment variable?

Program 1
In program 1 I have attempted to create the sole environment variable envar putting it in the env array which is passed to the execle function for the environments creation which program 2 will be run in.
#include <stdio.h>
#include <unistd.h>
int main(int argc, char *argv[]){
int ret;
char envar[] = "Big ol' environment variable ;D";
char *env[2] = {envar, 0};
ret = execle("./exec_test1.1", "exec_test1.1", 0, env);
printf("my prog failed ret = %d", ret);
return 0;
}
Program 2
I intended this code in the same directory to retrieve the environment variable envar on execution and to print it. However I the output in its place is null "memes and dis (null)" I have searched but can't see my mistake. Program two is almost identical to another I found for the same purpose so I assume my mistake is in program one.
#include <stdio.h>
#include <stdlib.h>
int main(int argc, char *argv[]){
char *envptr = getenv("envar");
printf("memes and dis %s\n", envptr);
return 0;
}
Thanks
You have wrong envar variable format - it must be NAME=VALUE. So fixing program 1 to:
#include <stdio.h>
#include <unistd.h>
int main(int argc, char *argv[])
{
int ret;
char envar[] = "envar=Big ol' environment variable ;D";
char *env[2] = {envar, 0};
ret = execle("./exec_test1.1", "exec_test1.1", 0, env);
printf("my prog failed ret = %d", ret);
return 0;
}
should make it work.
(I also took some liberty and formatted the code to make it more readable)

getting trouble with running program in c on linux

why I am not succeed
int main(char* name,int arg0,int arg1)
{
name = "/u/e2014/Desktop/os/Prog.c";
arg0 = 0;
arg1 = 1;
char my_args[3];
my_args[0] = arg0;
my_args[1] = arg1;
my_args[2] = NULL;
execl(name,m_args);
return(0);
}
I want that my program will execute the program in the path "name".
Right now its do nothing.
I am not understand where is my mistake?
I program in C on linux, and compile it with gcc
Thanks a lot!!
gcc has 3 different signature for main function
int main(void);
int main(int argc, char* argv[]);
int main(int argc, char *argv[], char *envp[]);
Your main function doesn't match either of these. therefore compiler error.
For your case you can use the 2nd signature with a small modification.
#include <stdlib.h>
int main(int argc, char **argv)
{
char *path;
int int1, int2;
path = argv[1];
int1 = atoi(argv[2]);
int2 = atoi(argv[3]);
}
First you are passing wrong parameter in int main(). main() has at least 3 args only.
int main(int argc, char*argv[], char *envp[]);
To execute your program you should use execvp() because you passing arrey of char* not command-line arguments via a variable-argument.
difference between execl and execv?
**L vs V: whether you want to pass the parameters to the exec'ed program as
L: individual parameters in the call (variable argument list): execl(), execle(), execlp(), and execlpe()
V: as an array of char* execv(), execve(), execvp(), and execvpe()**
#include <stdio.h>
#include <unistd.h>
int main(int argc,char*argv[])
{
char *name = "/root/a.out";
char *arg0 = "0";
char *arg1 = "1";
char *my_args[4];
my_args[0] = name;
my_args[1] = arg0;
my_args[2] = arg1;
my_args[3] = NULL;
execvp(my_args[0],my_args);
return(0);
}

C: Command line arguments with string

I'm trying to write a program that takes a string as a command line argument and then runs said argument through a function (str_to_int) that takes a string as an input. However, when I try to compile the program, I get a warning saying
initializing 'char *' with an expression of type 'int' [-Wint
conversion]
char* str = atoi(argv[1]);
^ ~~~~~~~~~~~~~
And when I run the program I get a segmentation fault
I've tested the str_to_int a lot so I'm pretty sure that the issue lies with the command line program. Here's the code for it.
#include "hw3.h"
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
int main(int argc, char *argv[])
{
char* str = atoi(argv[1]);
printf("%d\n", str_to_int(str));
return 0;
}
Can anyone tell me what I'm doing wrong? Thanks.
This is all you need, though it will crash if you leave out the command-line argument.
{
printf("%d\n", str_to_int(argv[1]));
return 0;
}
This is more robust:
int main(int argc, char *argv[])
{
if (argc == 1)
printf("missing parameter.");
else
printf("%d\n", str_to_int(argv[1]));
return 0;
}
#include "hw3.h"
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
int main(int argc, char *argv[])
{
char* str = argv[1];
printf("%d\n", str_to_int(str));
return 0;
}
just remove atoi function invocation and it should work

Passing command line arguments through a C setuid wrapper to another script

I have the following c setuid wrapper:
#include <unistd.h>
#include <sys/types.h>
#include <pwd.h>
main( int argc, char ** argv ) {
struct passwd *pwd;
char user[] = "cvmfs-test";
pwd = getpwnam(user);
setuid(pwd->pw_uid);
system(argv[1]);
}
I can call my perl script with ./cwrapper perlscript.pl.
I would like to do ./cwrapper perlscript.pl --option1 --option2 --option3 and elaborate all arguments inside the perl script with GetOptions. How should I change my wrapper?
There is also a nice solution which does not need any allocation, is able to deal with arbitrary long commands and does not imply running useless processes because it does not use system. Moreover with the following solution you get the exit code of the spawned process for free.
#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <stdlib.h>
#include <string.h>
#include <pwd.h>
#define SETUIDUSER "foobar"
int main(int argc, char **argv) {
struct passwd *pwd;
char user[] = SETUIDUSER;
pwd = getpwnam(user);
// success test needed here
setuid(pwd->pw_uid);
// success test needed here
if (argc < 2)
return 1;
execvp(argv[1], &argv[1]);
return 42;
}
Here is a version dealing with a variable number of arguments. Please note that your syscalls should be tested to ensure everything is going OK.
#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <stdlib.h>
#include <string.h>
#include <pwd.h>
#define CMDMAXLGTH 4096
#define SETUIDUSER "testuser"
int main( int argc, char ** argv ) {
struct passwd *pwd;
char user[] = SETUIDUSER;
char buf[CMDMAXLGTH];
char *p = buf;
int i = 1;
pwd = getpwnam(user);
// success test needed here
setuid(pwd->pw_uid);
// success test needed here
memset (buf, 0, sizeof(buf));
while (argv[i]) {
p += sprintf(p, " %s", argv[i++]);
}
system(buf);
return 0;
}
You should use sprintf to build a character string with your options, then pass this string to system:
char command [100];
sprintf (command, "./cwrapper %s --%s --%s --%s", program_name,option1,option2,
option3);
system(command);
Update: this approach assumes a fixed number of arguments, and looking back at your question, I see that may not be the case.
Ignore the argv[0] because is the name of the c program and use all the other. You can calculate (strlen) the required memory to assemble a new string, malloc() the memory for the new string and then build your new string by concatenating all the argv (strcat). Or for a fixed length approach, follow #dan1111 answer.

Resources