From 0f5deccfb63b7818509332fed2e7b96171584a6c Mon Sep 17 00:00:00 2001 From: gitlost Date: Thu, 26 Mar 2020 22:17:37 +0000 Subject: [PATCH] #181 OSS-Fuzz ZBarcode_Encode_File fix, allow for zero-length file, free buffer on error --- backend/library.c | 28 ++++++++++++----- backend/tests/test_library.c | 59 +++++++++++++++++++++++++++++++++++- 2 files changed, 79 insertions(+), 8 deletions(-) diff --git a/backend/library.c b/backend/library.c index 69c7d314..518e7584 100644 --- a/backend/library.c +++ b/backend/library.c @@ -1424,13 +1424,14 @@ int ZBarcode_Encode_and_Buffer_Vector(struct zint_symbol *symbol, unsigned char int ZBarcode_Encode_File(struct zint_symbol *symbol, char *filename) { FILE *file; unsigned char *buffer; - unsigned long fileLen; - unsigned int nRead = 0, n = 0; + long fileLen; + size_t n; + int nRead = 0; int ret; if (!strcmp(filename, "-")) { file = stdin; - fileLen = 7100; + fileLen = 7900; } else { file = fopen(filename, "rb"); if (!file) { @@ -1444,13 +1445,19 @@ int ZBarcode_Encode_File(struct zint_symbol *symbol, char *filename) { fileLen = ftell(file); fseek(file, 0, SEEK_SET); - if (fileLen > 7100) { - /* The largest amount of data that can be encoded is 7089 numeric digits in QR Code */ + if (fileLen > 7900) { + /* The largest amount of data that can be encoded is 7827 numeric digits in Han Xin Code */ strcpy(symbol->errtxt, "230: Input file too long"); error_tag(symbol->errtxt, ZINT_ERROR_INVALID_DATA); fclose(file); return ZINT_ERROR_INVALID_DATA; } + if (fileLen <= 0) { + strcpy(symbol->errtxt, "235: Input file empty or unseekable"); + error_tag(symbol->errtxt, ZINT_ERROR_INVALID_DATA); + fclose(file); + return ZINT_ERROR_INVALID_DATA; + } } /* Allocate memory */ @@ -1458,8 +1465,9 @@ int ZBarcode_Encode_File(struct zint_symbol *symbol, char *filename) { if (!buffer) { strcpy(symbol->errtxt, "231: Internal memory error"); error_tag(symbol->errtxt, ZINT_ERROR_MEMORY); - if (strcmp(filename, "-")) + if (strcmp(filename, "-")) { fclose(file); + } return ZINT_ERROR_MEMORY; } @@ -1469,12 +1477,18 @@ int ZBarcode_Encode_File(struct zint_symbol *symbol, char *filename) { n = fread(buffer + nRead, 1, fileLen - nRead, file); if (ferror(file)) { strcpy(symbol->errtxt, strerror(errno)); + if (strcmp(filename, "-")) { + fclose(file); + } + free(buffer); return ZINT_ERROR_INVALID_DATA; } nRead += n; } while (!feof(file) && (0 < n) && (nRead < fileLen)); - fclose(file); + if (strcmp(filename, "-")) { + fclose(file); + } ret = ZBarcode_Encode(symbol, buffer, nRead); free(buffer); return ret; diff --git a/backend/tests/test_library.c b/backend/tests/test_library.c index 10ba3d02..d0528f27 100644 --- a/backend/tests/test_library.c +++ b/backend/tests/test_library.c @@ -1,6 +1,6 @@ /* libzint - the open source barcode library - Copyright (C) 2008-2019 Robin Stuart + Copyright (C) 2008-2020 Robin Stuart Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions @@ -30,6 +30,9 @@ /* vim: set ts=4 sw=4 et : */ #include "testcommon.h" +#include +#include +#include static void test_checks(void) { @@ -143,10 +146,64 @@ static void test_input_mode(void) testFinish(); } +// #181 Nico Gunkel OSS-Fuzz +static void test_encode_file_zero_length(void) +{ + testStart(""); + + int ret; + char filename[] = "in.bin"; + int fd; + + struct zint_symbol* symbol = ZBarcode_Create(); + assert_nonnull(symbol, "Symbol not created\n"); + + (void)remove(filename); // In case junk hanging around + fd = creat(filename, S_IRUSR); + assert_nonzero(fd, "Input file not created\n"); + assert_zero(close(fd), "close(%s) != 0\n", filename); + + ret = ZBarcode_Encode_File(symbol, filename); + assert_equal(ret, ZINT_ERROR_INVALID_DATA, "ret %d != ZINT_ERROR_INVALID_DATA\n", ret); + + assert_zero(remove(filename), "remove(%s) != 0\n", filename); + + ZBarcode_Delete(symbol); + + testFinish(); +} + +// #181 Nico Gunkel OSS-Fuzz (buffer not freed on fread() error) Note: unable to reproduce fread() error using this method +static void test_encode_file_directory(void) +{ + testStart(""); + + int ret; + char dirname[] = "in_dir"; + int fd; + + struct zint_symbol* symbol = ZBarcode_Create(); + assert_nonnull(symbol, "Symbol not created\n"); + + (void)rmdir(dirname); // In case junk hanging around + assert_zero(mkdir(dirname, 0700), "mkdir(%s, 0700) != 0\n", dirname); + + ret = ZBarcode_Encode_File(symbol, dirname); + assert_equal(ret, ZINT_ERROR_INVALID_DATA, "ret %d != ZINT_ERROR_INVALID_DATA (%s)\n", ret, symbol->errtxt); + + assert_zero(rmdir(dirname), "rmdir(%s) != 0\n", dirname); + + ZBarcode_Delete(symbol); + + testFinish(); +} + int main() { test_checks(); test_input_mode(); + test_encode_file_zero_length(); + test_encode_file_directory(); testReport();