Created
September 25, 2021 09:19
-
-
Save jnettlet/80f8d09d01c0dc0ffc0122f36ed78de6 to your computer and use it in GitHub Desktop.
Test for framebuffer memcpy bugs.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include <signal.h> | |
#include <stdlib.h> | |
#include <string.h> | |
#include <time.h> | |
#include <unistd.h> | |
#include <stdio.h> | |
#include <fcntl.h> | |
#include <linux/fb.h> | |
#include <sys/mman.h> | |
#include <sys/ioctl.h> | |
#define LEN 256 | |
#define PRINT_STRIDE 0x20 | |
static volatile int run = 1; | |
static void handler(int blank) { | |
run = 0; | |
} | |
int main(int argc, char **argv) { | |
int length; | |
int fixup = 0; | |
if (argc > 2) | |
fixup = atoi(argv[2]); | |
if (argc > 1) | |
length = atoi(argv[1]); | |
else | |
length = LEN; | |
unsigned char data[length]; | |
unsigned char val = 0; | |
unsigned char prev_data[length]; | |
unsigned char map_copy[length]; | |
int fbfd = 0; | |
struct fb_var_screeninfo vinfo; | |
struct fb_fix_screeninfo finfo; | |
long int screensize = 0; | |
char *fbp = 0; | |
char *fbpstart = 0; | |
unsigned long n = 0; | |
unsigned long m = 0; | |
unsigned start, end, i, len; | |
int loop = 0; | |
signal(SIGINT, handler); | |
// Open the file for reading and writing | |
fbfd = open("/dev/fb0", O_RDWR | O_DSYNC); | |
if (fbfd == -1) { | |
perror("Error: cannot open framebuffer device"); | |
exit(1); | |
} | |
printf("The framebuffer device was opened successfully.\n"); | |
// Get fixed screen information | |
if (ioctl(fbfd, FBIOGET_FSCREENINFO, &finfo) == -1) { | |
perror("Error reading fixed information"); | |
exit(2); | |
} | |
// Get variable screen information | |
if (ioctl(fbfd, FBIOGET_VSCREENINFO, &vinfo) == -1) { | |
perror("Error reading variable information"); | |
exit(3); | |
} | |
printf("%dx%d, %dbpp\n", vinfo.xres, vinfo.yres, vinfo.bits_per_pixel); | |
// Figure out the size of the screen in bytes | |
screensize = vinfo.xres * vinfo.yres * vinfo.bits_per_pixel / 8; | |
// Map the device to memory | |
fbp = (char *)mmap(0, screensize, PROT_READ | PROT_WRITE, MAP_SHARED, fbfd, 0); | |
if ((intptr_t)fbp == -1) { | |
perror("Error: failed to map framebuffer device to memory"); | |
exit(4); | |
} | |
printf("The framebuffer device was mapped to memory successfully.\n"); | |
memset(data, 0, length); | |
memset(prev_data, 0, length); | |
memset(fbp, 0, screensize); | |
fbpstart = fbp; | |
srand(time(0)); | |
fbp += (unsigned)rand() % (screensize + 1); | |
while (run) { | |
val = 0; | |
start = (unsigned)rand() % (length + 1); | |
end = (unsigned)rand() % (length + 1); | |
loop = 0; | |
if (start >= end) | |
continue; | |
len = end - start; | |
for (i = start; i < end; i++) | |
data[i] = val++; | |
if (fixup && (len > 96 && len <= 110)) { | |
m++; | |
while (len) { | |
if (len > 96) { | |
memcpy(fbp + start + (96 * loop), data + start + (96 * loop), 96); | |
len -= 96; | |
} else { | |
memcpy(fbp + start + (96 * loop), data + start + (96 * loop), len); | |
break; | |
} | |
loop++; | |
} | |
} else { | |
memcpy(fbp + start, data + start, len); | |
} | |
if (memcmp(fbp, data, length)) { | |
if (memcmp(fbp, data, length)) | |
fprintf(stderr, "second memcmp also failed!\n"); | |
if (memcmp(fbp + start, data + start, len)) | |
fprintf(stderr, "smaller region also memcmp failed!\n"); | |
unsigned j; | |
memcpy(map_copy, fbp, length); | |
fprintf(stderr, "mismatch after %lu loops!\n", n); | |
fprintf(stderr, "last copied range: 0x%x - 0x%x (0x%x)\n", start, end, (unsigned)(end - start)); | |
for (j = 0; j < length; j += PRINT_STRIDE) { | |
fprintf(stderr, "p[%03x]", j); | |
for (i = j; i < j + PRINT_STRIDE && i < length; i++) | |
fprintf(stderr, " %s%s%02x\e[0m", !(i % 4) ? " " : "", data[i] != map_copy[i] ? "\e[31m" : "", prev_data[i]); | |
fprintf(stderr, "\n"); | |
fprintf(stderr, "d[%03x]", j); | |
for (i = j; i < j + PRINT_STRIDE && i < length; i++) | |
fprintf(stderr, " %s%s%02x\e[0m", !(i % 4) ? " " : "", data[i] != map_copy[i] ? "\e[31m" : "", data[i]); | |
fprintf(stderr, "\n"); | |
fprintf(stderr, "m[%03x]", j); | |
for (i = j; i < j + PRINT_STRIDE && i < length; i++) | |
fprintf(stderr, " %s%s%02x\e[0m", !(i % 4) ? " " : "", data[i] != map_copy[i] ? "\e[31m" : "", map_copy[i]); | |
fprintf(stderr, "\n"); | |
fprintf(stderr, "f[%03x]", j); | |
for (i = j; i < j + PRINT_STRIDE && i < length; i++) | |
if (i >= (start) && i < (end)) | |
fprintf(stderr, " %s%s%02x\e[0m", !(i % 4) ? " " : "", data[i] != map_copy[i] ? "\e[31m" : "", fbp[i]); | |
else | |
fprintf(stderr, " %s%sXX\e[0m", !(i % 4) ? " " : "", "\e[41m"); | |
fprintf(stderr, "\n\n"); | |
} | |
goto exit; | |
} | |
memcpy(prev_data, data, length); | |
n++; | |
} | |
fprintf(stderr, "\nno errors after %lu loops!\n", n); | |
exit: | |
if (fixup) | |
fprintf(stderr, "matched %lu problematic loops!\n", m); | |
raise(SIGINT); | |
memset(fbpstart, 0, screensize); | |
munmap(fbpstart, screensize); | |
close(fbfd); | |
return 0; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment