strtol resulting in a segmentation fault on the raspberry pi 3 b+ - c

I have this problem that strtol doesn't work and results in my C program crashing. I am using a Raspberry Pi 3 b+ but that probably doesn't matter.
My program (which is a command line tool to control shift registers) uses strtol for parsing through the command line arguments the program gets.
Here's the output I get: fish: Job 2, “./a.out -p 16 -w 0xff” terminated by signal SIGSEGV (Addroundary error)
And here's the output on gdp:
Program received signal SIGSEGV, Segmentation fault.
__GI_____strtol_l_internal (
nptr=0x76f72968 <_nl_C_LC_CTYPE_toupper+512> "",
nptr#entry=0x7efff6e9 "16", endptr=0x7efff6e9,
base=<optimized out>, group=group#entry=0,
loc=0x76fa1c70 <_nl_global_locale>) at strtol_l.c:484
484 strtol_l.c: No such file or directory.
The following is the code:
else if(!strcmp(argv[arg], "-p") || !strcmp(argv[arg], "-pins")) {
if(argc <= arg+1)
return 1;
pins = strtol(argv[++arg], endptr, 0);
}
The command line argument parsing happens like so:
uint8_t arg, pins;
char **endptr;
uint64_t writeValue;
bool valueGiven; // The other bools that I define are irrelevant
for(arg = 1; arg < argc; arg++) {
if(!strcmp(argv[arg], "-w") || !strcmp(argv[arg], "-write")) {
if(argc <= arg+1)
return 1;
writeValue = strtol(argv[++arg], endptr, 0); // error happens here too
valueGiven = true;
}
else if(!strcmp(argv[arg], "-p") || !strcmp(argv[arg], "-pins")) {
if(argc <= arg+1)
return 1;
pins = strtol(argv[++arg], endptr, 0);
}
// There are more arguments but those are irrelevant
}
And I run the program like this: ./a.out -p 16 -w 0xFF
This error is very odd for the exact same thing worked before, could this be a case of data corruption?

Your char **endptr is uninitialized. It needs to point to a char * where the address of the first unconverted character will be stored. Instead, yours points nowhere, so strtol is going to try to write to whatever bogus memory location it points to, and very likely crash.
GCC and clang should both issue warnings about the uninitialized variable if you enable -Wall. Example. Always use compiler warnings, and don't ignore them!
Normally you would declare a char * variable and pass its address:
char *end;
strtol(argv[++arg], &end, 0);

Related

How to exploit a buffer overflow to execute instructions on the stack

I'm starting to tinker with buffer overflows, and wrote the following program:
#include <unistd.h>
void g() {
execve("/bin/sh", NULL, NULL);
}
void f() {
long *return_address;
char instructions[] = "\xb8\x01\x00\x00\x00\xcd\x80"; // exit(1)
return_address = (long*) (&return_address + 2);
*return_address = (long)&g; // or (long)instructions
}
int main() {
f();
}
It does what I expect it to do : return_address overwrite the return address of f with the address of g, which opens a shell. However, if I set the return address to instructions, I got a segmentation fault, and none of the instructions in instructions is executed.
I compile with GCC, using -fno-stack-protector.
How could I prevent this segmentation fault occurring ?
At least one problem isn't related to the buffer overflow.
execve("/bin/sh", NULL, NULL);
That first NULL becomes the argv of the process you're starting. argv must be an array of strings that is terminated with a NULL. So a segfault may happen when /bin/sh starts up, tries to read argv[0], and dereferences NULL.
void g(void) {
char *argv[] = { "/bin/sh", NULL };
execve(argv[0], argv, NULL);
}
You might also add -z execstack to the gcc command line, which will tell the linker to permit an executable stack. You should also verify that the instructions you have there are what exit(1) compiles to on your system if you got them from a tutorial somewhere.

C: IF statement not firing when expected

I have the following function. The executable runs fine. At the prompt, after the program is run, I enter \x0037337331, the value of B is set as B: 0x31333337
Any advice on how I'd trigger to open log.txt
int play() {
int a;
int b;
char buffer[010];
a = 0x41414141;
b = 0x42424242;
if (write(STDOUT_FILENO, "For a moment, nothing happened. Then, after a second or so, nothing continued to happen.\n> ", 91) < 0) {
perror("write");
}
if (read(STDIN_FILENO, &buffer, 0xC) < 0) {
perror("read");
}
if (a == 31337) {
system(buffer);
}
else if (b == 1337) {
readfile("log.txt");
}
else {
printf("B: 0x%08x\n", b);
}
}
You have two mistakes:
Line:
char buffer[010]; // This is octal i.e. 8!
should be
char buffer[0xc];
Also
read(STDIN_FILENO, &buffer, 0xC)
should be
read(STDIN_FILENO, buffer, 0xC)
As you need the pointer to the start of the buffer.
EDIT
Also you need to add the null character to buffer before system.
since 1337 in decimal is 539 in hex, so just run following command in bash.
$ printf 'xxxxxxxx\x39\x05\x00\x00' | ./a.out
buffer has size of 010 which is 8 byte, so it will be filled with xxxxxxxx, and since b is allocated next to buffer in the stack, reading 0xC bytes into buffer will leak into b and it will fill with 0x39050000. Since most of the architecture is little endian, the value of b will be 0x00000539 which is 1337 in decimal.
Maybe how local variable is allocated in stack depends on compiler, architecture, or OS, but this seems the behavior of gcc-compiled binary on Linux OS x86 since 10 years ago.
Adding to the answer given by #ymonad
As it has to be done remotely, he has to netcat into port 1984. So this should be required answer.
printf 'xxxxxxxx\x39\x05\x00\x00' | netcat serverip 1984

Compare string literal command line parameters in C

I need my program to run this way ./src c 2345 or ./src s 345, whereby the first character hs to be either c or s and second an integer. The program should throw an usage error if there's any less parameters and also any charcter other than c or s. Here's my code
int main(int argc, char **argv) {
int num_of_connections = 0, client_sockfd;
int max_sockfd, master_socket;
fd_set socket_collection, read_collection;
// Check validity of the user input
if(argc < 3) {
if((strcmp(argv[2], "s") != 0) || (strcmp(argv[2], "c") != 0)){
fprintf(stderr, "Usage: ./src <s/c> <port>\n");
exit(EXIT_FAILURE);
}
}
When I enter one argument I get a segmentation fault. Also it doesnt identify the C or S parameter. Any help will be appreciated.
Notice that main has a very specific convention: the argv array has argc+1 members, with the last being NULL and the others being non-null distinct pointers to zero-terminated strings.
So if argc is 1 (e.g. if your run ./src alone) or 2, argv[2] is NULL and you cannot pass it to  strcmp
You can call strcmp(argv[2],"s") only when argc>=3
BTW, I would suggest to use getopt(3) or preferably (on Linux only) getopt_long and to accept the --help and --version arguments, per GNU conventions.
Also, compile with all warnings and debug info (gcc -Wall -g) and use the gdb debugger. It would be faster for you to use gdb than to ask here and wait for replies.
if(argc < 3) { does not make sense if you want exactly two parameters. In the inner if block you are confusion || (logical or) with && (logical and).
In your invocation example ./src s 345 the character is the first argument, so probably argv[2] should read argv[1].
if ((argc != 3) || ((strcmp(argv[1], "s") != 0) &&
(strcmp(argv[1], "c") != 0))) {
fprintf(…);
return EXIT_FAILURE;
}
Note: all parentheses in this if (…) condition are optional, because of C's operator precedence. I put them for readability.

GCC 4.7.0 run time issue - receiving signal 11 (SigSegv)

The following is a code snippet from my read from pipe function. This executes properly and verified that the data is got into buffer .
int readFrom(char *buffer)
{
int nread;
if((nread = read(readfd,buffer,100)) < 0)
{
printf("\nerror in reading data from FIFO\n");
return(-1);
}
buffer[nread]='\0';
return(0);
}
In the above example nread is less than 100 . I am using GCC-4.7.0.
We had an abstraction layer for the above function like below :
int pipe_input(char *parmPtr, int size)
{
char readMsg[100];
if( readFrom((char *)&readMsg) == -1)
return ERROR;
if (strlen(readMsg) < 1)
{
printf("Incorrect Input\n");
return ERROR;
}
strncpy(parmPtr, readMsg, ((size < 100)?size:100));
return 0;
}
In the above function as well it was verified that read message is proper and parmptr is properly loaded with the value. But in the function Where i am trying to call pipe_input I am getting a sigsegv. This happens with GCC-4.7.0 but the same code compiled with GCC-4.2.4 executes fine. I verified the warnings, but there are no warning for the above. Any pointers would be highly helpful.
Below code snippet for calling pipe_input :
int Calling_func(void)
{
char alpha[100] ;
pipe_input(alpha,100);
printf("alpha value is %s \r\n",alpha);
}
getting sigsegv at the print statement.
You have off-by-one errors in your code. Your array has 100 elements, but you're not taking NULL-termination into account:
strncpy(parmPtr, readMsg, ((size < 100)?size:100));
and:
buffer[nread]='\0';
The last element is buffer[99] (since array indices start from 0, not 1,) but you can write to buffer[100]. This can result in a segfault.
You should probably declare all arrays with a size of 101 instead and see if it helps. If you're on Linux, you should also run your program in Valgrind; it can tell you exactly how the segfault occurred.

Unix tail program in C using an implemented function

I have implemented my own dynamic-memory version of getline function:
char * fgetline(FILE * f)
Starts with 30 character buffer and when the buffer is full allocate a new one copy the contents and free the old buffer. When we get EOF or \n we return from the function.
I want to use this function to implement a version of the program tail. Input comes from stdin, output goes to stdout. If the first argument begins with -, everything after the - is the number of lines to print. The default number of lines to print is 10, when no argument is given.
I have thought until now that I should use the function:
int atoi (const char *s)
from stdlib.h and have an array of pointers to lines but I don't know exactly how to do this.
Any ideas?
Declare your main function as
int main (int argc, char**argv) {
}
If you compile your program to myprog executable, and invoke it as myprog -20 somefile anotherfile then you have:
argc == 4
&& strcmp(argv[0], "myprog") == 0
&& strcmp(argv[1], "-20") == 0
&& strcmp(argv[2], "somefile") == 0
&& strcmp(argv[3], "anotherfile") == 0
&& argv[4] == NULL
in other words, you might want to have your program containing
int nblines = 10;
int main(int argc, char**argv) {
int argix = 1;
if (argc>1) {
if (argv[1][0]=='-')
{
nblines = atoi(argv[1]+1);
argix = 2;
}
for (; argix < argc; argix++)
tail (argv[argix]);
}
return 0;
}
It is up to you to implement your void tail(char*filename); function appropriately. Don't forget to compile with all warnings & debugging info, e.g. with gcc -Wall -g on Linux. Use your debugger (gdb on Linux) to debug your program. Take into account that fopen can fail, and use errno to display an appropriate error message.
Notice that you don't need your fgetline function. The getline(3)
function is standard (in Posix 2008) and is dynamically allocating the line buffer.

Resources