From ba93e3c31f0e1ca51cacdd92a8127abc2a642e6c Mon Sep 17 00:00:00 2001 From: "Matsievskiy S.V" Date: Mon, 21 Nov 2022 12:10:29 +0300 Subject: [PATCH] Refactor decoder functions --- CMakeLists.txt | 4 +-- fatal.h | 6 ---- fru.c | 63 ++++++++++++++++++++++++++++++------ fru.h | 88 +++++++++++++++++++++++++++++++++++++++++++++++--- fru_reader.c | 84 ----------------------------------------------- fru_reader.h | 5 --- frugen.c | 75 +++++++++++++++++++++--------------------- 7 files changed, 176 insertions(+), 149 deletions(-) delete mode 100644 fatal.h delete mode 100644 fru_reader.c delete mode 100644 fru_reader.h diff --git a/CMakeLists.txt b/CMakeLists.txt index 078ce64..686e2ca 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -53,8 +53,8 @@ endfunction() add_executable(frugen frugen.c) add_executable(frugen-static frugen.c) -add_library(fru-static STATIC fru.c fru_reader.c) -add_library(fru-shared SHARED fru.c fru_reader.c) +add_library(fru-static STATIC fru.c) +add_library(fru-shared SHARED fru.c) find_library(JSON_LIB json-c) SET_TARGET_PROPERTIES(fru-static PROPERTIES OUTPUT_NAME fru CLEAN_DIRECT_OUTPUT 1) SET_TARGET_PROPERTIES(fru-shared PROPERTIES OUTPUT_NAME fru CLEAN_DIRECT_OUTPUT 1) diff --git a/fatal.h b/fatal.h deleted file mode 100644 index 423f7dd..0000000 --- a/fatal.h +++ /dev/null @@ -1,6 +0,0 @@ -#pragma once -#define fatal(fmt, args...) do { \ - fprintf(stderr, fmt, ##args); \ - fprintf(stderr, "\n"); \ - exit(1); \ -} while(0) diff --git a/fru.c b/fru.c index f6b592b..0871ed2 100644 --- a/fru.c +++ b/fru.c @@ -404,17 +404,9 @@ fru_field_t * fru_encode_data(int len, const uint8_t *data) return out; } -/** - * Decode data from a buffer into another buffer. - * - * For binary data use FRU_FIELDDATALEN(field->typelen) to find - * out the size of valid bytes in the returned buffer. - * - * Return false if there were errors during decoding and true otherwise. - */ bool fru_decode_data(fru_field_t *field, - typed_field_t *out, //< [out] buffer to decode into - size_t out_len) // <[in] length of output buffer + typed_field_t *out, + size_t out_len) { if (!field) return false; @@ -1225,6 +1217,57 @@ fru_t * fru_create(fru_area_t area[FRU_MAX_AREAS], size_t *size) return out; } +fru_t *find_fru_header(uint8_t *buffer, size_t size) { + if (size < 8) { + errno = ENOBUFS; + return NULL; + } + fru_t *header = (fru_t *) buffer; + if ((header->ver != FRU_VER_1) || (header->rsvd != 0) || (header->pad != 0)) { + errno = EPROTO; + return NULL; + } + if (header->hchecksum != calc_checksum(header, sizeof(fru_t) - 1)) { + errno = EPROTO; + return NULL; + } + return header; +} + +#define AREAS \ + X(chassis) \ + X(board) \ + X(product) +#define X(AREA) \ +fru_##AREA##_area_t *find_fru_##AREA##_area(uint8_t *buffer, size_t size) { \ + fru_t *header = find_fru_header(buffer, size); \ + if ((header == NULL) || (header->AREA == 0)) { \ + return NULL; \ + } \ + if ((header->AREA + 3) > size) { \ + errno = ENOBUFS; \ + return NULL; \ + } \ + fru_##AREA##_area_t *area = \ + (fru_##AREA##_area_t *)(buffer + FRU_BYTES(header->AREA)); \ + if (area->ver != 1) { \ + errno = EPROTO; \ + return NULL; \ + } \ + if (FRU_BYTES(header->AREA) + FRU_BYTES(area->blocks) > size) { \ + errno = ENOBUFS; \ + return NULL; \ + } \ + if (*(((uint8_t *)area) + FRU_BYTES(area->blocks) - 1) != \ + calc_checksum(((uint8_t *)area), FRU_BYTES(area->blocks) - 1)) { \ + errno = EPROTO; \ + return NULL; \ + } \ + return area; \ +} +AREAS +#undef X +#undef AREAS #ifdef __STANDALONE__ diff --git a/fru.h b/fru.h index e14a243..1439723 100644 --- a/fru.h +++ b/fru.h @@ -327,13 +327,93 @@ fru_mr_reclist_t * add_mr_reclist(fru_mr_reclist_t **reclist); fru_mr_area_t * fru_mr_area(fru_mr_reclist_t *reclist, size_t *total); fru_chassis_area_t * fru_encode_chassis_info(const fru_exploded_chassis_t *chassis); -bool fru_decode_chassis_info(const fru_chassis_area_t *area, fru_exploded_chassis_t *chassis_out); fru_board_area_t * fru_encode_board_info(const fru_exploded_board_t *board); -bool fru_decode_board_info(const fru_board_area_t *area, fru_exploded_board_t *board_out); fru_product_area_t * fru_encode_product_info(const fru_exploded_product_t *product); -bool fru_decode_product_info(const fru_product_area_t *area, fru_exploded_product_t *product_out); fru_field_t * fru_encode_data(int len, const uint8_t *data); -bool fru_decode_data(fru_field_t *field, typed_field_t *out, size_t out_len); fru_t * fru_create(fru_area_t area[FRU_MAX_AREAS], size_t *size); +/** + * @brief Find and validate FRU header in the byte buffer. + * + * @param[in] buffer Byte buffer. + * @param[in] size Byte buffer size. + * @return Pointer to the FRU header in the buffer. + * @retval NULL FRU header not found. + */ +fru_t *find_fru_header(uint8_t *buffer, size_t size); + +/** + * @brief Find and validate FRU chassis area in the byte buffer. + * + * @param[in] buffer Byte buffer. + * @param[in] size Byte buffer size. + * @return Pointer to the FRU chassis area in the buffer. + * @retval NULL FRU chassis area not found. + */ +fru_chassis_area_t *find_fru_chassis_area(uint8_t *buffer, size_t size); + +/** + * @brief Find and validate FRU board area in the byte buffer. + * + * @param[in] buffer Byte buffer. + * @param[in] size Byte buffer size. + * @return Pointer to the FRU board area in the buffer. + * @retval NULL FRU board area not found. + */ +fru_board_area_t *find_fru_board_area(uint8_t *buffer, size_t size); + +/** + * @brief Find and validate FRU product area in the byte buffer. + * + * @param[in] buffer Byte buffer. + * @param[in] size Byte buffer size. + * @return Pointer to the FRU product area in the buffer. + * @retval NULL FRU product area not found. + */ +fru_product_area_t *find_fru_product_area(uint8_t *buffer, size_t size); + +/** + * @brief Decode chassis area into \p fru_exploded_chassis_t. + * + * @param[in] area Encoded area. + * @param[out] chassis_out Decoded structure. + * @retval true Success. + * @retval false Failure. + */ +bool fru_decode_chassis_info(const fru_chassis_area_t *area, fru_exploded_chassis_t *chassis_out); + +/** + * @brief Decode board area into \p fru_exploded_board_t. + * + * @param[in] area Encoded area. + * @param[out] chassis_out Decoded structure. + * @retval true Success. + * @retval false Failure. + */ +bool fru_decode_board_info(const fru_board_area_t *area, fru_exploded_board_t *board_out); + +/** + * @brief Decode product area into \p fru_product_board_t. + * + * @param[in] area Encoded area. + * @param[out] chassis_out Decoded structure. + * @retval true Success. + * @retval false Failure. + */ +bool fru_decode_product_info(const fru_product_area_t *area, fru_exploded_product_t *product_out); + +/** + * Decode data from a buffer into another buffer. + * + * For binary data use FRU_FIELDDATALEN(field->typelen) to find + * out the size of valid bytes in the returned buffer. + * + * @param[in] field Encoded data field. + * @param[out] out Decoded field. + * @param[in] out_len Size of the decoded field region. + * @retval true Success. + * @retval false Failure. + */ +bool fru_decode_data(fru_field_t *field, typed_field_t *out, size_t out_len); + #endif // __FRULIB_FRU_H__ diff --git a/fru_reader.c b/fru_reader.c deleted file mode 100644 index 9acb559..0000000 --- a/fru_reader.c +++ /dev/null @@ -1,84 +0,0 @@ -#include -#include -#include "fru.h" -#include "fru_reader.h" -#include "fatal.h" - -static void safe_read(int fd, uint8_t *buffer, size_t length) { - if (!buffer) - fatal("Cannot read into NULL buffer"); - - size_t total_bytes_read = 0; - while (total_bytes_read != length) { - ssize_t bytes_read = read( - fd, buffer + total_bytes_read, length - total_bytes_read); - if (bytes_read == -1) - fatal("Error reading file"); - if (bytes_read == 0) - fatal("Reached end of file"); - - total_bytes_read += bytes_read; - } -} - -fru_t *read_fru_header(int fd) { - fru_t *fru = malloc(sizeof(fru_t)); - if (!fru) - return NULL; - safe_read(fd, (uint8_t*)fru, sizeof(fru_t)); - return fru; -} - -/** - * Allocate and read a fru_chassis_area_t from a file descriptor - */ -fru_chassis_area_t *read_fru_chassis_area(int fd) { - size_t base_len = sizeof(fru_chassis_area_t); - fru_chassis_area_t *area = malloc(base_len); - if (!area) - return NULL; - safe_read(fd, (uint8_t*)area, base_len); - size_t data_len = 8 * area->blocks; - area = realloc(area, data_len); - if (!area) - return NULL; - safe_read(fd, (uint8_t*)&area->data, data_len - base_len); - - return area; -} - -/** - * Allocate and read a fru_board_area_t from a file descriptor - */ -fru_board_area_t *read_fru_board_area(int fd) { - size_t base_len = sizeof(fru_board_area_t); - fru_board_area_t *area = malloc(base_len); - if (!area) - return NULL; - safe_read(fd, (uint8_t*)area, base_len); - size_t data_len = 8 * area->blocks; - area = realloc(area, data_len); - if (!area) - return NULL; - safe_read(fd, (uint8_t*)&area->data, data_len - base_len); - - return area; -} - -/** - * Allocate and read a fru_product_area_t from a file descriptor - */ -fru_product_area_t *read_fru_product_area(int fd) { - size_t base_len = sizeof(fru_product_area_t); - fru_product_area_t *area = malloc(base_len); - if (!area) - return NULL; - safe_read(fd, (uint8_t*)area, base_len); - size_t data_len = 8 * area->blocks; - area = realloc(area, data_len); - if (!area) - return NULL; - safe_read(fd, (uint8_t*)&area->data, data_len - base_len); - - return area; -} diff --git a/fru_reader.h b/fru_reader.h deleted file mode 100644 index 26adf1d..0000000 --- a/fru_reader.h +++ /dev/null @@ -1,5 +0,0 @@ -#include "fru.h" -fru_t *read_fru_header(int fd); -fru_chassis_area_t *read_fru_chassis_area(int fd); -fru_board_area_t *read_fru_board_area(int fd); -fru_product_area_t *read_fru_product_area(int fd); diff --git a/frugen.c b/frugen.c index d59bdc5..6e369dd 100644 --- a/frugen.c +++ b/frugen.c @@ -9,6 +9,7 @@ #endif #define COPYRIGHT_YEARS "2016-2021" +#define MAX_FILE_SIZE 1L * 1024L * 1024L #define _GNU_SOURCE #include @@ -23,14 +24,18 @@ #include #include #include "fru.h" -#include "fru_reader.h" #include "smbios.h" -#include "fatal.h" #ifdef __HAS_JSON__ #include #endif +#define fatal(fmt, args...) do { \ + fprintf(stderr, fmt, ##args); \ + fprintf(stderr, "\n"); \ + exit(1); \ +} while(0) + const char* type_names[] = { "auto", "binary", @@ -749,54 +754,48 @@ int main(int argc, char *argv[]) fatal("Failed to open file: %s", strerror(errno)); } - fru_t *raw_fru = read_fru_header(fd); - if (!raw_fru) - fatal("Failed to read fru header"); + struct stat statbuf = {0}; + if (fstat(fd, &statbuf)) { + fatal("Failed to get file properties: %s", strerror(errno)); + } + if (statbuf.st_size > MAX_FILE_SIZE) { + fatal("File too large"); + } - if (raw_fru->chassis != 0) { - if (lseek(fd, 8 * raw_fru->chassis, SEEK_SET) < 0) - fatal("Failed to seek"); + uint8_t *buffer = calloc(1, statbuf.st_size); + if (buffer == NULL) { + fatal("Cannot allocate buffer"); + } - fru_chassis_area_t *chassis_raw = - read_fru_chassis_area(fd); - bool success = fru_decode_chassis_info( - chassis_raw, &chassis); - if (!success) - fatal("Failed to decode chassis"); + if (read(fd, buffer, statbuf.st_size) != statbuf.st_size) { + fatal("Cannot read file"); + } + close(fd); - free(chassis_raw); + fru_chassis_area_t *chassis_area = + find_fru_chassis_area(buffer, statbuf.st_size); + if (chassis_area) { + if (!fru_decode_chassis_info(chassis_area, &chassis)) + fatal("Failed to decode chassis"); has_chassis = true; } - if (raw_fru->board != 0) { - if(lseek(fd, 8 * raw_fru->board, SEEK_SET) < 0) - fatal("Failed to seek"); - - fru_board_area_t *board_raw = read_fru_board_area(fd); - bool success = fru_decode_board_info(board_raw, &board); - if (!success) + fru_board_area_t *board_area = + find_fru_board_area(buffer, statbuf.st_size); + if (board_area) { + if (!fru_decode_board_info(board_area, &board)) fatal("Failed to decode board"); - - free(board_raw); has_board = true; - has_bdate = true; } - if (raw_fru->product != 0) { - if (lseek(fd, 8 * raw_fru->product, SEEK_SET) < 0) - fatal("Failed to seek"); - - fru_product_area_t *product_raw = - read_fru_product_area(fd); - bool success = - fru_decode_product_info(product_raw, &product); - if (!success) - fatal("Failed to decode product"); - free(product_raw); + fru_product_area_t *product_area = + find_fru_product_area(buffer, statbuf.st_size); + if (product_area) { + if (!fru_decode_product_info(product_area, &product)) + fatal("Failed to decode product"); has_product = true; } - free(raw_fru); - close(fd); + free(buffer); } else { fatal("The requested input file format is not supported");