simple read operating not reading any thing from char device linux - c

I have a simple code that suppose to read length sized and fetch data from character device in Linux C.
This is my code and errno is set to 9. I made sure the file exists and it does. And able to read it with cat /dev/mychardev-0 but why bad file descriptor error at time of read. I am getting this line passed int fd=open("/dev/mychardev-0",O_RDONLY); if(fd<0)
#include <fcntl.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <stdlib.h>
#include <errno.h>
int main()
{
int fd=open("/dev/mychardev-0",O_RDONLY);
if(fd<0)
{
printf("fd %d\n",fd);
exit(0);
}
int length=1024000;
int x=0;
char buffer[length-1];
while(x<length)
{
int valread=read(fd,&buffer[x],length);
if(valread==0)
{
printf("zero bytes read\n");
break;
}
if(valread<0)
{
printf("read return negative %d %d\n",valread,errno);
break;
}
x=x+valread;
}
if(x>0)
{
printf("%x",buffer);
}
else
{
printf("ops no read\n");
}
return 0;
}

char buffer[length-1];
int valread=read(fd,&buffer[x],length);
That is a very bad idea. You allocate enough space for length - 1 bytes then attempt to read length bytes into that space.
If the read gets the largest possible size, you will have a buffer overflow, well into undefined behaviour territory(1).
And, on top of that, you attempt to read length bytes even though you may have already read some in earlier iterations of the loop. You should be:
Using the correct length for the buffer; and
Adjusting the length down based on what you've already read.
And, though this may not be a problem, one meg is quite a lot of data to put on the stack (which is often limited in size by default). If that is the case, you may be better of using malloc to get a dynamic buffer, such as:
char *buffer = malloc(length);
// make sure buffer != NULL, then use it.
free(buffer);
So, something like (untested but you should hopefully get the idea):
int x = 0, length = 1024000; // with malloc if needed.
char buffer[length];
while (x < length) {
int valread = read(fd, &buffer[x], length - x);
if (valread == 0) {
printf("zero bytes read\n");
break;
}
else if (valread < 0) {
printf("read return negative %d %d\n",valread,errno);
break;
}
x += valread;
}
(1) An example of what may happen is that overflowing the buffer will affect other variables on the stack in certain ways.
For example, it may corrupt x which would mean your next read could go to some arbitrary place in memory possibly corrupting other things as a result.
Or it could corrupt fd which would make the next read likely to fail with an invalid file descriptor.You can check the actual behaviour by simply printing out those two values before any use. Given the fact you mention "bad file descriptor error", that's possibly the most likely scenario here.
But, to be honest, the best solution is probably just to avoid undefined behaviour (though it may still be educational for you to find out the effects).

Related

file system api read/write confusion

I tried to read 7 bytes from the file self_tutor.txt into the buff. But somehow the read was not successful. I have checked the syntax for read and the corresponding parameters to be used, but I am not sure where the error comes from. Also what would be the proper way of outputting value from buff if buff was successfully write with the 7 bytes of values from self_tutor.txt?
will a while loop work?
// will this work if the total number of bytes is less than I request? like there
// is only 5 bytes in the self_tutor.txt file but I request to read 7? (i.e. short-read)
while(buff!= EOF) { // will EOF work if I have short-read
printf("value of character inside the buff:%c\n ", *buff);
buff++;
}
or should it be:
while(buff!= "\n") { // so "\n" will be able to handle short-read, is it correct?
printf("value of character inside the buff:%c\n ", *buff);
buff++;
}
#include <stdio.h>
#include <fcntl.h>
#include <unistd.h>
int main()
{
printf("Hello World\n");
int f1 = open("self_tutor.txt", O_RDONLY);
char *buff;
int f2 = read(f1, buff, 7);
printf("value of f2 :%d\n ", f2); // f2 = -1, so read was not successful
// how to print all the bytes in buff from beginning of buff to end of buff
printf("value of buff:%c\n ", *buff);
return 0;
}
this is the contents of my self_tutor.txt file:
In our Y86-64 simulator. This course is pretty interesting but hard.
A related question is:
A short read may indicate end of file but does not necessarily do so.
what does it mean, does it mean if I have a short-read the following
read(f1, buff, 7);
will not necessarily produce the value 0?
i.e. read(f1, buff, 7) might equal a non-zero value?
thanks
You code never assigns any value to buff. So you are passing garbage to read. You need to make buff point to the place you want the character you read to be stored before you pass its value to read.

C strings behavior, and atoi function

I wonder why the two values of int don't validate the if condition even if it is true. printf shows both of them are equal.
Is buffer overflow able to affect the behavior of if conditions,corrupting other code sections behavior.
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
int main(void) {
srand(time(NULL));
char instring[2]; // when this increases somehow I get the right behavior
int inint;
int guess;
guess = rand() % 127;
inint = ~guess;
printf("%i\n", guess); //testing with printf()
while (guess != inint) {
printf("Guess Number\r\n");
gets(instring);
inint = atoi(instring);
printf("%i\n", inint);
if (inint > guess) {
printf("%i\n", inint);
puts("too high");
} else if (guess > inint) {
puts("too low");
} else {
puts("right");
}
}
return 0;
}
The problem is indeed here.
char instring[2];
Now let's think about this line.
gets(instring);
Let's say you type 10 and hit enter. What will go into instring is three bytes.
1
0
A terminating null.
instring can only hold two bytes, but gets will shove (at least) three in anyway. That extra byte will overflow into adjacent memory corrupting some other variable's memory causing some bizarre bug.
And that's why making instring large enough to hold the result from gets fixes the program.
To avoid this when working with strings, use functions which limit themselves to the memory available. In this case fgets.
fgets(instring, sizeof(instring), stdin);
That will limit itself to only reading as much as it can fit into instring.
In general, don't get stingy with memory to read input. A common practice is to allocate one large buffer for reading input, 1024 is good, and reuse that buffer just for reading input. The data is copied out of it to more appropriately sized memory, which atoi effectively does for you.

C: buffer overflow, changing passed variables

I'm doing some exercises regarding buffer overflows and I am currently stumped as how to proceed further with one of them. This is the program code:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <unistd.h>
#include <sys/syscall.h>
void reverb(char *msg, unsigned int len) {
unsigned char length = (unsigned char) len;
char buffer[250] = "Printed: ";
strcat(buffer + 9, msg);
if ((length > 75) || (length < 15)) {
fprintf(stderr, "Error: invalid string length");
exit(1);
}
else {
fprintf(stdout, "%s\n", buffer);
}
}
int main(int argc, char **argv) {
//argument check
if (argc != 2) {
fprintf(stderr, "Invalid arguments!\n");
return 1;
}
reverb(argv[1], strlen(argv[1]));
return 0;
}
So basically as obvious as it is, this program should just re-print the argument you gave to it. I obviously have to exploit one of the functions used, and I suspect the main culprit here is strcat. However, I'm faced with the issue of the length variable when I want to get my stack smashing done.
To be able to cause a segfault and successfully find a point for the overflow to happen, I need to pass an argument with a length of around 255+ (not sure on the current number right now but it's somewhere around that), which is not doable with my 75 char limit. Using gdb and setting a break point right after strcat, I am able to find the buffer's location in the memory (kinda easy, just the area filled with 0x41 since I spammed it with A's). length's location was kinda trickier, but here's the issue - it's located BEFORE the buffer, meaning I couldn't even overwrite it if I wanted. But, I somehow still need to overwrite it to get into the else branch, I think. And I've been stuck at that point, not seeing a way to proceed properly.
If the string is long - say 256 chars, the Length variable will be wrong. Use the suggestions in the comments to catch it.
The crash: the string copy will then copy all 256 chars onto the end of the string in buffer, which only can hold 250 bytes.
Move the strcpy() into the else.
Additional notes:
I ran this in my debugger (VS2015)
When passing in the 256 byte string and overrunning “buffer”, the variable “length” got clobbered, and its value changes from 0 to 69 (some character in my string). This caused the 75 char limit to fail and the buffer to be printed.

Unable to retain array outside the while loop

I am currently working on the C code below. I need to access the array outside the while loop, after fclose. It appears that the blackfin ADSP kernel crashes every time I run it. I will need it further to perform FFT. Please help!
#include <stdlib.h>
#include <stdio.h>
#include <flt2fr.h>
#include <fract_math.h>
#include <math_bf.h>
#include <complex.h>
#include <filter.h>
int main()
{
int n = 1024;
long int dat1[n];
FILE *file1;
fract16 *m;
int i;
// file1 open and read the values
file1 = fopen("0.dat", "r");
if (file1 == NULL) {
printf("I couldn't open 0.dat for reading.\n");
exit(0);
}
while (!feof(file1)) {
fgets(dat1, n, file1);
m = malloc(sizeof(fract16) * n);
for (i = 0; i < n; i++) {
sscanf(dat1, "%f", &m[i]); //getting error here
}
}
fclose(file1);
printf("%lf\n", m);
return 0;
}
Alright, thank you all for correcting my mistakes, but the problem is still unresolved. I am able to print all of the values inside, but outside the loop it prints just the last value of the data set, is there any precise solution for this? I googled for hours but no success yet.
The code is as follows >
#include <stdlib.h>
#include <stdio.h>
#include <flt2fr.h>
#include<fract_math.h>
#include <math_bf.h>
#include <complex.h>
#include <filter.h>
int main()
{
int n = 1024;
long int dat1[n];
FILE *file1;
fract16 *m;
file1 = fopen("0.dat", "r");
if (file1 == NULL) {
printf("I couldn't open 0.dat for reading.\n");
exit(0);
}
while( !feof(file1))
{
fgets(dat1,n,file1);
sscanf(dat1, "%f", &m);
printf("%f\n",m); //Prints all elements in the 1st column of the array, 0.dat is a nx2 matrix
}
fclose(file1);
}
You can allocate memory for the buffer before reading the file, outside the while loop. Then every time before reading into the buffer, simply use memset and set the buffer to all null characters.
Also, try using fread to read directly into the buffer rather than fgets
the variable m is defined as a pointer to and array of fract16
to fix the problem suggest:
if( 1 != sscanf(dat1, "%f", m+(sizeof(fract16)*i) )
{
perror( "sscanf failed" );
exit( EXIT_FAILURE );
}
The error is being cause because m is already a pointer and you want it to continue to be a pointer
As an aside. the code is not checking how much data was actually read in the call to fgets() so the for() may very well be reading behond the end of the actual data. And each trip through the while() loop is destroying/overlaying the pointer obtained from the prior call to malloc()
then later in the code is the statement:
printf("%lf\n", m);
But m is a pointer to an array of `fract16 objects.
and those fract16 objects might be double values, but that detail is not clear. In any case, this call to printf() will, at best, only output a single double value from the beginning of the last line in the input file. Is that what you really want to do?
Note: dat1[] is declared as an array of long int, but the call to sscanf() seems to be trying to extract float values.
I.E. the code is not consistent about the data types, nor the extraction of individual values, nor the printing.
One thing to note: with the current code there is a massive memory leak due to the pointer m being repeatedly overwritten by the calls to malloc() And due to the use of feof(), the last call to fgets() will fail, so the cotents of dat1[] will be starting with a NUL byte
Suggest allocating an array of pointers to fractl16 objects
Then for each line read, use malloc() to set the next pointer in the array of pointers, ...

Why is this Overflow Occuring?

In the following code:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int check_authentication(char *password) {
char password_buffer[16];
int auth_flag = 0;
strcpy(password_buffer, password);
if(strcmp(password_buffer, "brillig") == 0)
auth_flag = 1;
if(strcmp(password_buffer, "outgrabe") == 0)
auth_flag = 1;
return auth_flag;
}
int main (int argc, char *argv[]){
if(argc < 2){
printf("Usage: %s <password>\n", argv[0]);
exit(0);
}
if(check_authentication(argv[1])){
printf("\n-=-=-=-=-=-=-==-=-=-\n");
printf(" Access Granted\n");
printf("-=-=-=-=-=-=-==-=-=-\n");
}
else {
printf("Access Denied\n");
}
}
if I run something such as "AAAAAAAAAAAAAAAAAAAA", somehow something is overflowed and it causes the program to run as access granted. I'm confused because when I ran the gdb debugger, auth_flag was before password_buffer in the memory and it was never overflowed.
EDIT: I understand that the text doesn't fit into the buffer but I am experimenting with buffer overflows and how to exploit them in a controlled manner. Yes, we could make the array bigger but that's not the point of this
I was wondering if someone would be able to tell me why this is happening/what is being overflowed to cause this.
AAAAAAAAAAAAAAAAAAAA has size 20. You are then using strcpy to copy it to an char array of size 16. Try increasing your password_buffer size.
To avoid overflows, the size of the array pointed by destination
shall be long enough to contain the same C string as source (including
the terminating null character), and should not overlap in memory with
source.
http://www.cplusplus.com/reference/cstring/strcpy/
Because you are copying the input into a buffer that is too small (and for no reason). Your method could be implemented (without overflow) like
int check_authentication(const char *password) {
size_t len = strlen(password);
return strncmp(password, "brillig", len) == 0 ||
strncmp(password, "outgrabe", len) == 0;
}
I understand it overflows the buffet, but why would it cause access granted? (auth_flag >0)
Because auth_flag is the next int in memory after char password_buffer[16];. With some compilers (and operating systems), if you overflow password_buffer, there is a high probability that you modify auth_flag.
The memory is stored in the stack in a consecutive manner,
so there's a char[16] and an int that indicates whether the authentication passed successfully.
When you pass in a pointer to a buffer and copies it without boundary checking the local buffer, you risking overflowing your buffer and rewriting your stack variables.
When you input 'A' * 20, the first 16 'A' went into the buffer, and the remaining 4 'A's went into the int (usually sizeof(int) is 4 bytes).
So now, your int is not 0, it's:
auth = 0x41414141
since the ASCII code of 'A' is 0x41.
There's a really great article related to this -
http://insecure.org/stf/smashstack.html
It lays out the basics of stack overflows and gets a little more advanced later on.

Resources