I ran a code analysis on my embedded C code with SonarCube with sonar.cxx plugin.
I also parse with sonarcube the XML generated with Rough Auditing Tool for Security (RATS) and i get this error:
This function does not properly handle non-NULL terminated strings. This does not result in exploitable code, but can lead to access violations.
This is the code that generates the above error:
if( (machineMarket == NULL) || (strlen(machineMarket) > VALUE_MARKET_MAX_LEN) )
Which is the best practise to handle the non NULL terminated string?
The auditing tool is warning that the call to strlen will keep reading bytes until it finds a zero byte. If the contents of machineMarket do not contain a zero, it is possible that strlen will keep reading right off the end of legal memory and cause an access violation.
You say you are declaring the variable like this
char machineMarket[VALUE_MARKET_MAX_LEN + 1];
So you can either use the strnlen function to ensure you never read too far, or use #Zan Lynx's method of forcibly inserting a 0 at the end.
With either method, you'll probably need to handle the case where the original string is/was not terminated.
The way that I handle it is whenever I get a string from outside my module, from a network read or a call into my library, I set a 0 on the end of it. Now, no matter what, it is a valid C string.
So if my library function accepts int func(char *output, size_t output_len) then right up front before I use it for anything I always validate with if( !output || !output_len) return; and then output[output_len-1] = 0;
Then even if they passed me complete garbage, it is at least a valid string.
If the contiguous block of memory that you own starting from machineMarket does not have a \0 then the behaviour of your code is undefined.
Use strnlen instead, passing something of the order VALUE_MARKET_MAX_LEN as the parameter and then refactor your >.
Related
I am absolutely new to C programming. Currently I am preparing for my new course of studies IT Security. In a slightly older exam I found a task where I have no approach how to solve it. The task is in German. In principle it is about finding critical errors.
It is not written how the passed parameters look like.
1) I have come to the point that you should not use strcpy because it has no bounds checking.
2) Also char[10] should not be used if you want to store 10 characters (\0). It should be char[11].
Is it possible to read Adresses or write sth due the printf(argv[1]) command ?
I would like to mention again that you help me here personally and do not help to collect bonus points in the university.
#include <stdio.h>
int main(int argc, char *argv[])
{
char code[10];
if(argc != 2) return 1;
printf(argv[1]);
strcpy(code, "9999999999");
for(int i = 0; i < 10; ++i){
code[i] -= argv[1][i] % 10;
}
printf(", %s\n", code);
return 0;
}
See
related.
you should not use strcpy() because it has no bounds checking
Nothing in C has bounds checking unless either
the compiler writer put it there, or
you put it there.
Few compiler writers incorporate bounds checking into their products, because it usually causes the resulting code to be bigger and slower. Some tools exist (e.g.
Valgrind,
Electric Fence)
to provide bounds-checking-related debugging assistance, but they are not commonly incorporated into delivered software because of limitations they impose.
You absolutely should use strcpy() if
you know your source is a NUL-terminated array of characters, a.k.a. "a string", and
you know your destination is large enough to hold all of the source array including the terminating NUL
because the compiler writer is permitted to use behind-the-scenes tricks unavailable to compiler users to ensure strcpy() has the best possible performance while still providing the behaviour guaranteed by the standard.
char[10] should not be used if you want to store 10 characters (\0)
Correct.
To store 10 characters and the terminating NUL ('\0'), you must have at least 11 characters of space available.
Is it possible to read Adresses or write sth due the printf(argv[1]) command ?
In principle: maybe.
The first argument to printf() is a format string which is interpreted by printf() to determine what further arguments have been provided. If the format string contains any format specifications (e.g. "%d" or "%n") then printf() will try to retrieve corresponding arguments.
If they were not in fact passed to it, then it invokes Undefined Behaviour which is Bad.
An attacker could run your program giving it a command-line argument containing format specifiers, which would lead to such UB.
The right way to print an arbitrary string like this with printf() is printf("%s", argv[1]);
I have been using this code:
char options_string[96];
sprintf(options_string,"%s_G%u", options_string, options.allowed_nucleotide_gap_between_CpN);
which is just writing unsigned integers to a string mixed with some letters.
but with the new version 9 of GCC that I just started using, is warning me:
warning: passing argument 1 to restrict-qualified parameter aliases
with argument 3 [-Wrestrict] 1012 |
sprintf(options_string,"%s_G%u", options_string,
options.allowed_nucleotide_gap_between_CpN);
| ^~~~~~~~~~~~~~ ~~~~~~~~~~~~~~
I've read that the best way to make a string like this is to use sprintf, as I have: How to convert an int to string in C?
I've re-checked the code, and I'm not using any restrict keywords.
How can I write to this string without the warning?
The code causes undefined behaviour because the same part of a char buffer is used as both input and output for sprintf. The warning is useful information in this case. To be correct you must change the code so there is no overlap between inputs and outputs.
For example you could find the end of the current string and start writing from there. Also it would be wise to guard against buffer overflows in the length of output.
Possible code:
char options_string[96];
// ...assume you omitted some code that writes some valid string
size_t upto = strlen(options_string);
int written = snprintf(options_string + upto, sizeof options_string - upto,
"_G%u", options.allowed_nucleotide_gap_between_CpN);
if ( written < 0 || written + upto >= sizeof options_string )
{
// ...what you want to do if the options don't fit in the buffer
}
A conforming implementation of sprintf could start by writing a zero byte to the destination, then replacing that byte with the first byte of output (if any) and writing a zero after that, then replacing that second zero byte with the next byte of output and writing a third zero, etc. Such an approach would avoid the need to have it take any particular action (such as writing a terminating zero) after processing the last byte. An attempt to use your code with such an implementation, however, would fail since options_string would effectively get cleared before code could read it.
The warning you're receiving is thus an indication that your code may not work as written.
In your case it is better to use the strcat function instead of sprintf, due to the fact that you want to concatenate a string.
Being new to C, I just came across the C11 addition getenv_s. Here is what I'm actually trying to do:
Handling POST data sent by html form in CGI C
I'm trying to sanitize, both CONTENT_LENGTH and message-body(stdin) in my case. That is the objective here.
So in order to limit the upper-bounds (against malformed CONTENT_LENGTH, trying to cause overflow), I tried using an array instead of pointer, like this:
char some[512];
some = getenv("CONTENT_LENGTH");
It naturally threw an error (incompatible types when assigning to type char[512] from type char *). So I assume,
Q1. getenv is already a string?
Then I came across "getenv_s"
http://en.cppreference.com/w/c/program/getenv
Q2. Can anyone tell me a safe-as-rocksolid way of using this? To avoid underflow, overflow, etc.
First off, do not use any of the _s functions. They are an optional feature of C11 which, to my knowledge, has never been fully implemented by anyone, not even Microsoft, which invented them, and it has been proposed to remove them again; even more importantly, they do not actually solve the problems they purport to address. (The intention was to have a bunch of drop-in replacements for dangerous string-related functions, but it turns out that that doesn't work; fixing string-related security bugs in C programs requires actual redesign with thought put into it. The functions that genuinely could not be used safely already had portable replacements, e.g. fgets instead of gets, snprintf instead of sprintf, strsep instead of strtok -- sometimes the replacement is not in ISO C but it's usually widespread enough not to worry about, or you can get a shim implementation from gnulib.)
getenv is guaranteed to return a valid NUL-terminated C string (or a null pointer), but the string could be arbitrarily long. In the context of a CGI program written in C, the correct way to "sanitize" the value of the CONTENT_LENGTH environment variable is to feed it to strtol and carefully check for errors:
/* Returns a valid content_length, or -1 on error. */
long get_content_length(void)
{
char *content_length, *endp;
long rv;
content_length = getenv("CONTENT_LENGTH");
if (!content_length) return -1;
errno = 0;
rv = strtol(content_length, &endp, 10);
if (endp == content_length || *endp || errno || rv <= 0)
return -1;
return rv;
}
Each of the four clauses in the if statement after the strtol call checks for a different class of ill-formed input. You have to clear errno explicitly before the call, because the value strtol returns when it reports an overflow is also a value it can return when there was no overflow, so the only way to distinguish is to look at errno, but errno could have a stale nonzero value from some earlier operation.
Note that even if CONTENT_LENGTH is syntactically valid, it might not be trustworthy. That is, the actual amount of POST data available to you might be either less or more than CONTENT_LENGTH. Make sure to pay attention to the numbers returned by read as well. (This is an example of how swapping out string functions for "hardened" ones doesn't solve all your problems.)
What's considered best practice for handling what's meant to be a string as
an argument to a function ie
int use_the_force(const char *dark_side_file_name) {
char *safe_force_it_is = Yoda(dark_side_file_name);
return useTheForceYouCan(safe_force_it_is);
}
Assuming the caller is Darth Vader, what would Yoda do in order to ensure that when we use things like strlen/strnlen or memchr on "safe_force_it_is" that there's a NULL terminator and that we're not running off into the dark side when we use what we're expecting to be a valid string?
It's not reasonable to take a string of unknown length and try to figure out if it is null terminated or not. If it's not, how would you know when to stop?
There may be a handful of crazy, non-portable ideas, but none of them is required in a sane program. You need to know that the input is null-terminated, or else you need to know its maximum length.
I have written a simple program to calculate length of string in this way.
I know that there are other ways too. But I just want to know why this program is giving this output.
#include <stdio.h>
int main()
{
char str[1];
printf( "%d", printf("%s", gets(str)));
return 0;
}
OUTPUT :
(null)6
Unless you always pass empty strings from the standard input, you are invoking undefined behavior, so the output could be pretty much anything, and it could crash as well. str cannot be a well-formed C string of more than zero characters.
char str[1] allocates storage room for one single character, but that character needs to be the NUL character to satisfy C string constraints. You need to create a character array large enough to hold the string that you're writing with gets.
"(null)6" as the output could mean that gets returned NULL because it failed for some reason or that the stack was corrupted in such a way that the return value was overwritten with zeroes (per the undefined behavior explanation). 6 following "(null)" is expected, as the return value of printf is the number of characters that were printed, and "(null)" is six characters long.
There's several issues with your program.
First off, you're defining a char buffer way too short, a 1 char buffer for a string can only hold one string, the empty one. This is because you need a null at the end of the string to terminate it.
Next, you're using the gets function which is very unsafe, (as your compiler almost certainly warned you about), as it just blindly takes input and copies it into a buffer. As your buffer is 0+terminator characters long, you're going to be automatically overwriting the end of your string into other areas of memory which could and probably does contain important information, such as your rsp (your return pointer). This is the classic method of smashing the stack.
Third, you're passing the output of a printf function to another printf. printf isn't designed for formating strings and returning strings, there are other functions for that. Generally the one you will want to use is sprintf and pass it in a string.
Please read the documentation on this sort of thing, and if you're unsure about any specific thing read up on it before just trying to program it in. You seem confused on the basic usage of many important C functions.
It invokes undefined behavior. In this case you may get any thing. At least str should be of 2 bytes if you are not passing a empty string.
When you declare a variable some space is reserved to store the value.
The reserved space can be a space that was previously used by some other
code and has values. When the variable goes out of scope or is freed
the value is not erased (or it may be, anything goes.) only the programs access
to that variable is revoked.
When you read from an unitialised location you can get anything.
This is undefined behaviour and you are doing that,
Output on gcc (Ubuntu/Linaro 4.6.3-1ubuntu5) 4.6.3 is 0
For above program your input is "(null)", So you are getting "(null)6". Here "6" is the output from printf (number of characters successfully printed).