Skip to content

Instantly share code, notes, and snippets.

@jnettlet
Created September 25, 2021 09:19
Show Gist options
  • Save jnettlet/80f8d09d01c0dc0ffc0122f36ed78de6 to your computer and use it in GitHub Desktop.
Save jnettlet/80f8d09d01c0dc0ffc0122f36ed78de6 to your computer and use it in GitHub Desktop.
Test for framebuffer memcpy bugs.
#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