I was exploring around with C regarding strncpy since most people says that it is safer than strcpy (Additional parameter, length, to avoid buffer overflows). I also wanted to find out the effects of non-null terminated strings on a program. This is a snippet of the code that I have.
char password[5]="1234\0"; //Global variable
int main(int argc, char* argv[])
{
int length = 5;
char temp[5];
strncpy(temp, argv[1], length); //Possible problems?
/* Safer alternative */
//strncpy(temp, argv[1], length-1);
//temp[4] = '\0';
if(strncmp(password, temp, length) == 0) {
printf("Success! \n");
}
else {
printf("Error! Password is incorrect: %s\n", temp);
}
return 0;
}
As you can see, strncpy copies 5 characters and this will lead to non-null termination of variable temp if len(argv[1]) >= 5. I'm looking to see if I can use this property to read other memory regions such as the global variable password.
I've read up on strncpy being problematic causing the adjacent buffers to be affected if the string is not null-terminated, causing the next buffer to be read when it is referenced.
Exploring Adjacent Memory: http://www.securiteam.com/securityreviews/5PP030KEUM.html
The line
printf("Error! Password is incorrect: %s\n", temp);
will be a problem when temp is not null terminated. It will lead to undefined behavior since the format %s expects a null terminated string.
Use of
strncpy(temp, argv[1], length-1);
temp[4] = '\0';
will lead to erroneous outcome. The test will succeed if the user provides any password that starts with "1234".
Related
This subprogram takes three user inputs: a text string, a path to a file, and a 1 digit flag. It loads the file into a buffer, then appends both the flag and the file buffer, in that order, to a char array that serves as a payload. It returns the payload and the original user string.
I received a bug where some of my string operations on the file buffer, flag, and payload appeared to corrupt the memory that the user_string was located in. I fixed the bug by swapping strcat(flag, buffer) to strcpy(payload, flag), (which is what I intended to write originally), but I'm still perplexed as to what caused this bug.
My guess from reading the documentation (https://www.gnu.org/software/libc/manual/html_node/Concatenating-Strings.html , https://www.gnu.org/software/libc/manual/html_node/Concatenating-Strings.html) is that strcat extends the to string strlen(to) bytes into unprotected memory, which the file contents loaded into the buffer copied over in a buffer overflow.
My questions are:
Is my guess correct?
Is there a way to reliably prevent this from occurring? Catching this sort of thing with an if(){} check is kind of unreliable, as it doesn't consistently return something obviously wrong; you expect a string of length filelength+1 and get a string of filelength+1.
bonus/unrelated: is there any computational cost/drawbacks/effects with calling a variable without operating on it?
/*
user inputs:
argv[0] = tendigitaa/four
argv[1] = ~/Desktop/helloworld.txt
argv[2] = 1
helloworld.txt is a text file containing (no quotes) : "Hello World"
*/
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <unistd.h>
#include <string.h>
int main (int argc, char **argv) {
char user_string[100] = "0";
char file_path[100] = "0";
char flag[1] = "0";
strcpy(user_string, argv[1]);
strcpy(file_path, argv[2]);
strcpy(flag, argv[3]);
/*
at this point printfs of the three declared variables return the same as the user inputs.
======
======
a bunch of other stuff happens...
======
======
and then this point printfs of the three declared variables return the same as the user inputs.
*/
FILE *file;
char * buffer = 0;
long filelength;
file = fopen(file_path, "r");
if (file) {
fseek(file, 0, SEEK_END);
filelength = ftell(file);
fseek(file, 0, SEEK_SET);
buffer = malloc(filelength);
printf("stringcheck1: %s \n", user_string);
if (buffer) {
fread(buffer, 1, filelength, file);
}
}
long payloadlen = filelength + 1;
char payload[payloadlen];
printf("stringcheck2: %s \n", user_string);
strcpy(payload, flag);
printf("stringcheck3: %s \n", user_string);
strcat(flag, buffer);
printf("stringcheck4: %s \n", user_string); //bug here
free(buffer);
printf("stringcheck5: %s \n", user_string);
payload; user_string; //bonus question: does this line have any effect on the program or computational cost?
return 0;
}
/*
printf output:
stringcheck1: tendigitaa/four
stringcheck2: tendigitaa/four
stringcheck3: tendigitaa/four
stringcheck4: lo World
stringcheck5: lo World
*/
note: taking this section out of the main program caused stringcheck 4 to segfault instead of returning "lo World". The behavior was otherwise equivalent.
strcat does exactly what documentation says:
char *strcat(char *restrict s1, const char *restrict s2); The
strcat() function shall append a copy of the string pointed to by s2
(including the terminating null byte) to the end of the string pointed
to by s1. The initial byte of s2 overwrites the null byte at the end
of s1. If copying takes place between objects that overlap, the
behavior is undefined.
s1 has to have enough memory allocated to accommodate both strings plus the terminating nul
The linked article is about programming own string concatenating functions. How to write such a function depends on the application - which is stated there. There are many ways.
In your program the destination char array is not big enough and the result is an Undefined Behaviour and it is not even big enough to accommodate a single character string.
I strongly advice to learn some C strings basics.
If you want safer strcat you can write your own one for example:
char *mystrcat(const char *str1, const char *str2)
{
char *dest = NULL;
size_t str1_length, str2_length;
if(str1 && str2)
{
dest = malloc((str1_length = strlen(str1)) + (str2_length = strlen(str2)) + 1);
if(dest)
{
memcpy(dest, str1, str1_length);
memcpy(dest + str1_length, str2, str2_length);
}
}
return dest;
}
But for the safety we always pay the price - the code is longer and less efficient. C language was designed to be as efficient as possible sacrificing the safety and introducing the idea if the Undefined Behaviour.
You can't store a non-empty string in a 1-character array. A string needs room for the string contents and a null terminator.
So when you declare
char flag[1] = "1";
you've only allocated one byte, which contains the character 1. There's no null terminator.
Using this with any string functions will result in undefined behavior, because they look for the null terminator to find the end of the string.
strcat(flag, buffer) will search for the null terminator, which will be outside the array, and then append buffer after that. So this clearly causes a buffer overflow when writing.
strcpy(payload, flag) is also wrong. It will look for a null terminator after the flag bytes to know when to stop copying to payload, so it will copy more than just flag (unless there happens to be a null byte after it).
You can resolve the strcpy() problem by increasing the size:
char flag[2] = "1";
You can also leave the size empty, the compiler will make it large enough to hold the string that initializes it, including the null byte:
char flag[] = "1";
The line that causes the problem is because strcat() is trying to cram buffer into flag which is only one character long and you haven't allocated any more space to fit buffer.
If you want to put buffer into flag, I recommend using realloc() to increase the length of flag to include the length of buffer.
Also the only thing you ever print is user_string. I'm not sure if you're trying to print the other string you're working with.
I'm writing a status function but nothing except for the "Tracked:" is printing out. Can anyone see why? I'm assuming that the '.index' file is just a line by line list of file names.
int git_status() {
FILE *check = fopen(".git/.index", "r");
int count = 0;
char *pointer;
printf("Tracked:\n\n");
while(fgets(pointer, sizeof(pointer), check)){
strtok(pointer, "\n");
printf("%s\n", pointer);
count++;
}
printf("\n%d is the number of files", count);
fclose(check);
}
In C you need to allocate the memory you want for strings. In your case you need to declare either a array of characters with fixed length or dynamically reserve enough memory to contain the characters you are about to read.
For instance, the following is not very safe because p does not point to any memory, it is just an uninitialized address:
char* p;
strcpy(p, "This is a string");
If your lucky your compiler should warn you when you try to do things like the above (you might need to enable warnings, -Wall on gcc).
A better approach might be
char chArray[20];
strcpy(chArray, "This is a string");
or
char *p = malloc(20);
strcpy(p, "This is a string");
free(p);
As for char *fgets(char *s, int size, FILE *stream) you probably want to do something like:
#define BUFFER 128
char buf[BUFFER];
while (fgets(buf, BUFFER, fp) != NULL) { /* TODO */ }
To get your program running you will also probably need to look at how strtok works:
The strtok() function breaks a string into a sequence of zero or
more
nonempty tokens. On the first call to strtok() the string to be parsed
should be specified in str. In each subsequent call that should parse
the same string, str must be NULL.
This is just a small program I wrote to find a problem with a larger one. Everything changes when I add the line with scanf. I know it is not safe, I read other threads concerning printf errors that suggest other functions. Anything but cin is fine. Btw, I didn't choose the type definitions of the 'messages', that came from my teachers, so I cannot change them.
#include <stdio.h>
#include <string.h>
char message1 [] = "amfdalkfaklmdklfamd.";
char message2 [] = "fnmakajkkjlkjs.";
char initializer [] = ".";
char* com;
char* word;
int main()
{
com = initializer;
int i = 1;
while (i !=4)
{
printf ("%s \n", com);
scanf("%s",word);
i++;
};
return 0;
}
The problem: after a single iteration the program exits, nothing is printed.
The reason the scanf will crash is buffer is not initialized: word has not been assigned a value, so it is pointing nowhere.
You can fix it by allocating some memory to your buffer, and limiting scanf to a certain number of characters, like this:
char word[20];
...
scanf("%19s", word);
Note that the number between % and s, which signifies the maximum number of characters in a string, is less by 1 than the length of the actual buffer. This is because of null terminator, which is required for C strings.
com is a pointer whose value is the address of the literal string initializer. Literal strings are contained within read-only memory areas, but the scanf function will attempt to write into the address given to it, this is an access-violation and causes the OS to kill your process, hence the crash you're seeing.
Change your scanf code to resemble this, note the addition of width limit in the %s placeholder, as well as the use of the scanf_s version to ensure there is no buffer overflow.
static int const BufferLength = 2048; // 2KiB should be sufficient
char* buffer = calloc( BufferLength , 1 );
if( buffer == null ) exit(1);
int fieldCount = scanf_s("%2047s", buffer, BufferLength );
if( fieldCount == 1 ) {
// do stuff with `buffer`
}
free( buffer );
Note that calloc zeroes memory before returning, which means that buffer can serve as a null-terminated string directly, whereas a string allocated with malloc cannot (unless you zero it yourself).
word has no memory associated with it.
char* word;
scanf("%s",word);
Could use
char word[100];
word[0] = '\0';
scanf("%99s",word);
If available, use getline().
Although not standard C, getline() will dynamicaly allocate memory for arbitrarily long user input.
char *line = NULL;
size_t len = 0;
ssize_t read;
while ((read = getline(&line, &len, stdin)) != -1) {
printf("%s", line);
}
free(line);
Linux Programmer's Manual GETLINE(3)
In the code below, I hope you can see that I have a char* variable and that I want to read in a string from a file. I then want to pass this string back from the function. I'm rather confused by pointers so I'm not too sure what I'm supposed to do really.
The purpose of this is to then pass the array to another function to be searched for a name.
Unfortunately the program crashes as a result and I've no idea why.
char* ObtainName(FILE *fp)
{
char* temp;
int i = 0;
temp = fgetc(fp);
while(temp != '\n')
{
temp = fgetc(fp);
i++;
}
printf("%s", temp);
return temp;
}
Any help would be vastly appreciated.
fgetc returns an int, not a char*. This int is a character from the stream, or EOF if you reach the end of the file.
You're implicitly casting the int to a char*, i.e., interpreting it as an address (turn your warnings on.) When you call printf it reads that address and continues to read a character at a time looking for the null terminator which ends the string, but that address is almost certainly invalid. This is undefined behavior.
I've taken some liberties with what you wanted to accomplish. Rather that deal with pointers, you can just use a fixed sized array as long as you can set a maximum length. I've also included several checks so that you don't run off the end of the buffer or the end of the file. Also important is to make sure that you have a null termination '\0' at the end of the string.
#define MAX_LEN 100
char* ObtainName(FILE *fp)
{
static char temp[MAX_LEN];
int i = 0;
while(i < MAX_LEN-1)
{
if (feof(fp))
{
break;
}
temp[i] = fgetc(fp);
if (temp[i] == '\n')
{
break;
}
i++;
}
temp[i] = '\0';
printf("%s", temp);
return temp;
}
So, there are several problems here:
You're not setting aside any storage for the string contents;
You're not storing the string contents correctly;
You're attempting to read memory that doesn't belong to you;
The way you're attempting to return the string is going to give you heartburn.
1. You're not setting aside storage for the string contents
The line
char *temp;
declares temp as a pointer to char; its value will be the address of a single character value. Since it's declared at local scope without the static keyword, its initial value will be indeterminate, and that value may not correspond to a valid memory address.
It does not set aside any storage for the string contents read from fp; that would have to be done as a separate step, which I'll get to below.
2. You're not storing the string contents correctly
The line
temp = fgetc(fp);
reads the next character from fp and assigns it to temp. First of all, this means you're only storing the last character read from the stream, not the whole string. Secondly, and more importantly, you're assigning the result of fgetc() (which returns a value of type int) to an object of type char * (which is treated as an address). You're basically saying "I want to treat the letter 'a' as an address into memory." This brings us to...
3. You're attempting to read memory that doesn't belong to you
In the line
printf("%s", temp);
you're attempting to print out the string beginning at the address stored in temp. Since the last thing you wrote to temp was most likely a character whose value is < 127, you're telling printf to start at a very low and most likely not accessible address, hence the crash.
4. The way you're attempting to return the string is guaranteed to give you heartburn
Since you've defined the function to return a char *, you're going to need to do one of the following:
Allocate memory dynamically to store the string contents, and then pass the responsibility of freeing that memory on to the function calling this one;
Declare an array with the static keyword so that the array doesn't "go away" after the function exits; however, this approach has serious drawbacks;
Change the function definition;
Allocate memory dynamically
You could use dynamic memory allocation routines to set aside a region of storage for the string contents, like so:
char *temp = malloc( MAX_STRING_LENGTH * sizeof *temp );
or
char *temp = calloc( MAX_STRING_LENGTH, sizeof *temp );
and then return temp as you've written.
Both malloc and calloc set aside the number of bytes you specify; calloc will initialize all those bytes to 0, which takes a little more time, but can save your bacon, especially when dealing with text.
The problem is that somebody has to deallocate this memory when its no longer needed; since you return the pointer, whoever calls this function now has the responsibility to call free() when it's done with that string, something like:
void Caller( FILE *fp )
{
...
char *name = ObtainName( fo );
...
free( name );
...
}
This spreads the responsibility for memory management around the program, increasing the chances that somebody will forget to release that memory, leading to memory leaks. Ideally, you'd like to have the same function that allocates the memory free it.
Use a static array
You could declare temp as an array of char and use the static keyword:
static char temp[MAX_STRING_SIZE];
This will set aside MAX_STRING_SIZE characters in the array when the program starts up, and it will be preserved between calls to ObtainName. No need to call free when you're done.
The problem with this approach is that by creating a static buffer, the code is not re-entrant; if ObtainName called another function which in turn called ObtainName again, that new call will clobber whatever was in the buffer before.
Why not just declare temp as
char temp[MAX_STRING_SIZE];
without the static keyword? The problem is that when ObtainName exits, the temp array ceases to exist (or rather, the memory it was using is available for someone else to use). That pointer you return is no longer valid, and the contents of the array may be overwritten before you can access it again.
Change the function definition
Ideally, you'd like for ObtainName to not have to worry about the memory it has to write to. The best way to achieve that is for the caller to pass target buffer as a parameter, along with the buffer's size:
int ObtainName( FILE *fp, char *buffer, size_t bufferSize )
{
...
}
This way, ObtainName writes data into the location that the caller specifies (useful if you want to obtain multiple names for different purposes). The function will return an integer value, which can be a simple success or failure, or an error code indicating why the function failed, etc.
Note that if you're reading text, you don't have to read character by character; you can use functions like fgets() or fscanf() to read an entire string at a time.
Use fscanf if you want to read whitespace-delimited strings (i.e., if the input file contains "This is a test", fscanf( fp, "%s", temp); will only read "This"). If you want to read an entire line (delimited by a newline character), use fgets().
Assuming you want to read an individual string at a time, you'd use something like the following (assumes C99):
#define FMT_SIZE 20
...
int ObtainName( FILE *fp, char *buffer, size_t bufsize )
{
int result = 1; // assume success
int scanfResult = 0;
char fmt[FMT_SIZE];
sprintf( fmt, "%%%zus", bufsize - 1 );
scanfResult = fscanf( fp, fmt, buffer );
if ( scanfResult == EOF )
{
// hit end-of-file before reading any text
result = 0;
}
else if ( scanfResult == 0 )
{
// did not read anything from input stream
result = 0;
}
else
{
result = 1;
}
return result;
}
So what's this noise
char fmt[FMT_SIZE];
sprintf( fmt, "%%%zus", bufsize - 1 );
about? There is a very nasty security hole in fscanf() when you use the %s or %[ conversion specifiers without a maximum length specifier. The %s conversion specifier tells fscanf to read characters until it sees a whitespace character; if there are more non-whitespace characters in the stream than the buffer is sized to hold, fscanf will store those extra characters past the end of the buffer, clobbering whatever memory is following it. This is a common malware exploit. So we want to specify a maximum length for the input; for example, %20s says to read no more than 20 characters from the stream and store them to the buffer.
Unfortunately, since the buffer length is passed in as an argument, we can't write something like %20s, and fscanf doesn't give us a way to specify the length as an argument the way fprintf does. So we have to create a separate format string, which we store in fmt. If the input buffer length is 10, then the format string will be %10s. If the input buffer length is 1000, then the format string will be %1000s.
The following code expands on that in your question, and returns the string in allocated storage:
char* ObtainName(FILE *fp)
{
int temp;
int i = 1;
char *string = malloc(i);
if(NULL == string)
{
fprintf(stderr, "malloc() failed\n");
goto CLEANUP;
}
*string = '\0';
temp = fgetc(fp);
while(temp != '\n')
{
char *newMem;
++i;
newMem=realloc(string, i);
if(NULL==newMem)
{
fprintf(stderr, "realloc() failed.\n");
goto CLEANUP;
}
string=newMem;
string[i-1] = temp;
string[i] = '\0';
temp = fgetc(fp);
}
CLEANUP:
printf("%s", string);
return(string);
}
Take care to 'free()' the string returned by this function, or a memory leak will occur.
I am getting "Bus Error" trying to read stdin into a char* variable.
I just want to read whole stuff coming over stdin and put it first into a variable, then continue working on the variable.
My Code is as follows:
char* content;
char* c;
while( scanf( "%c", c)) {
strcat( content, c);
}
fprintf( stdout, "Size: %d", strlen( content));
But somehow I always get "Bus error" returned by calling cat test.txt | myapp, where myapp is the compiled code above.
My question is how do i read stdin until EOF into a variable? As you see in the code, I just want to print the size of input coming over stdin, in this case it should be equal to the size of the file test.txt.
I thought just using scanf would be enough, maybe buffered way to read stdin?
First, you're passing uninitialized pointers, which means scanf and strcat will write memory you don't own. Second, strcat expects two null-terminated strings, while c is just a character. This will again cause it to read memory you don't own. You don't need scanf, because you're not doing any real processing. Finally, reading one character at a time is needlessly slow. Here's the beginning of a solution, using a resizable buffer for the final string, and a fixed buffer for the fgets call
#define BUF_SIZE 1024
char buffer[BUF_SIZE];
size_t contentSize = 1; // includes NULL
/* Preallocate space. We could just allocate one char here,
but that wouldn't be efficient. */
char *content = malloc(sizeof(char) * BUF_SIZE);
if(content == NULL)
{
perror("Failed to allocate content");
exit(1);
}
content[0] = '\0'; // make null-terminated
while(fgets(buffer, BUF_SIZE, stdin))
{
char *old = content;
contentSize += strlen(buffer);
content = realloc(content, contentSize);
if(content == NULL)
{
perror("Failed to reallocate content");
free(old);
exit(2);
}
strcat(content, buffer);
}
if(ferror(stdin))
{
free(content);
perror("Error reading from stdin.");
exit(3);
}
EDIT: As Wolfer alluded to, a NULL in your input will cause the string to be terminated prematurely when using fgets. getline is a better choice if available, since it handles memory allocation and does not have issues with NUL input.
Since you don't care about the actual content, why bother building a string? I'd also use getchar():
int c;
size_t s = 0;
while ((c = getchar()) != EOF)
{
s++;
}
printf("Size: %z\n", s);
This code will correctly handle cases where your file has '\0' characters in it.
Your problem is that you've never allocated c and content, so they're not pointing anywhere defined -- they're likely pointing to some unallocated memory, or something that doesn't exist at all. And then you're putting data into them. You need to allocate them first. (That's what a bus error typically means; you've tried to do a memory access that's not valid.)
(Alternately, since c is always holding just a single character, you can declare it as char c and pass &c to scanf. No need to declare a string of characters when one will do.)
Once you do that, you'll run into the issue of making sure that content is long enough to hold all the input. Either you need to have a guess of how much input you expect and allocate it at least that long (and then error out if you exceed that), or you need a strategy to reallocate it in a larger size if it's not long enough.
Oh, and you'll also run into the problem that strcat expects a string, not a single character. Even if you leave c as a char*, the scanf call doesn't make it a string. A single-character string is (in memory) a character followed by a null character to indicate the end of the string. scanf, when scanning for a single character, isn't going to put in the null character after it. As a result, strcpy isn't going to know where the end of the string is, and will go wandering off through memory looking for the null character.
The problem here is that you are referencing a pointer variable that no memory allocated via malloc, hence the results would be undefined, and not alone that, by using strcat on a undefined pointer that could be pointing to anything, you ended up with a bus error!
This would be the fixed code required....
char* content = malloc (100 * sizeof(char));
char c;
if (content != NULL){
content[0] = '\0'; // Thanks David!
while ((c = getchar()) != EOF)
{
if (strlen(content) < 100){
strcat(content, c);
content[strlen(content)-1] = '\0';
}
}
}
/* When done with the variable */
free(content);
The code highlights the programmer's responsibility to manage the memory - for every malloc there's a free if not, you have a memory leak!
Edit: Thanks to David Gelhar for his point-out at my glitch! I have fixed up the code above to reflect the fixes...of course in a real-life situation, perhaps the fixed value of 100 could be changed to perhaps a #define to make it easy to expand the buffer by doubling over the amount of memory via realloc and trim it to size...
Assuming that you want to get (shorter than MAXL-1 chars) strings and not to process your file char by char, I did as follows:
#include <stdio.h>
#include <string.h>
#define MAXL 256
main(){
char s[MAXL];
s[0]=0;
scanf("%s",s);
while(strlen(s)>0){
printf("Size of %s : %d\n",s,strlen(s));
s[0]=0;
scanf("%s",s);
};
}