1c63f63a2SAndrew Jeffery #ifndef PLDM_MSGBUF_H 2c63f63a2SAndrew Jeffery #define PLDM_MSGBUF_H 3c63f63a2SAndrew Jeffery 4c63f63a2SAndrew Jeffery #ifdef __cplusplus 5c63f63a2SAndrew Jeffery extern "C" { 6c63f63a2SAndrew Jeffery #endif 7c63f63a2SAndrew Jeffery 8c63f63a2SAndrew Jeffery #include "base.h" 9c63f63a2SAndrew Jeffery #include "pldm_types.h" 10c63f63a2SAndrew Jeffery 11c63f63a2SAndrew Jeffery #include <assert.h> 12c63f63a2SAndrew Jeffery #include <endian.h> 13c63f63a2SAndrew Jeffery #include <limits.h> 14c63f63a2SAndrew Jeffery #include <stdbool.h> 15c63f63a2SAndrew Jeffery #include <string.h> 16c63f63a2SAndrew Jeffery #include <sys/types.h> 17c63f63a2SAndrew Jeffery 18c63f63a2SAndrew Jeffery struct pldm_msgbuf { 19c63f63a2SAndrew Jeffery const uint8_t *cursor; 20c63f63a2SAndrew Jeffery ssize_t remaining; 21c63f63a2SAndrew Jeffery }; 22c63f63a2SAndrew Jeffery 23c63f63a2SAndrew Jeffery /** 24c63f63a2SAndrew Jeffery * @brief Initialize pldm buf struct for buf extractor 25c63f63a2SAndrew Jeffery * 26c63f63a2SAndrew Jeffery * @param[out] ctx - pldm_msgbuf context for extractor 27c63f63a2SAndrew Jeffery * @param[in] minsize - The minimum required length of buffer `buf` 28c63f63a2SAndrew Jeffery * @param[in] buf - buffer to be extracted 29c63f63a2SAndrew Jeffery * @param[in] len - size of buffer 30c63f63a2SAndrew Jeffery * 31c63f63a2SAndrew Jeffery * @return PLDM_SUCCESS if all buffer accesses were in-bounds, 32c63f63a2SAndrew Jeffery * PLDM_ERROR_INVALID_DATA if pointer parameters are invalid, or 33c63f63a2SAndrew Jeffery * PLDM_ERROR_INVALID_LENGTH if length constraints are violated. 34c63f63a2SAndrew Jeffery */ 355646f23bSAndrew Jeffery __attribute__((no_sanitize("pointer-overflow"))) static inline int 365646f23bSAndrew Jeffery pldm_msgbuf_init(struct pldm_msgbuf *ctx, size_t minsize, const void *buf, 375646f23bSAndrew Jeffery size_t len) 38c63f63a2SAndrew Jeffery { 39c63f63a2SAndrew Jeffery uint8_t *end; 40c63f63a2SAndrew Jeffery 41c63f63a2SAndrew Jeffery if (!ctx || !buf) { 42c63f63a2SAndrew Jeffery return PLDM_ERROR_INVALID_DATA; 43c63f63a2SAndrew Jeffery } 44c63f63a2SAndrew Jeffery 45c63f63a2SAndrew Jeffery if ((minsize > len) || (len > SSIZE_MAX)) { 46c63f63a2SAndrew Jeffery return PLDM_ERROR_INVALID_LENGTH; 47c63f63a2SAndrew Jeffery } 48c63f63a2SAndrew Jeffery 49c63f63a2SAndrew Jeffery end = (uint8_t *)buf + len; 50c63f63a2SAndrew Jeffery if (end && end < (uint8_t *)buf) { 51c63f63a2SAndrew Jeffery return PLDM_ERROR_INVALID_LENGTH; 52c63f63a2SAndrew Jeffery } 53c63f63a2SAndrew Jeffery 54c63f63a2SAndrew Jeffery ctx->cursor = (uint8_t *)buf; 55c63f63a2SAndrew Jeffery ctx->remaining = (ssize_t)len; 56c63f63a2SAndrew Jeffery 57c63f63a2SAndrew Jeffery return PLDM_SUCCESS; 58c63f63a2SAndrew Jeffery } 59c63f63a2SAndrew Jeffery 60c63f63a2SAndrew Jeffery /** 61c63f63a2SAndrew Jeffery * @brief Validate buffer overflow state 62c63f63a2SAndrew Jeffery * 63c63f63a2SAndrew Jeffery * @param[in] ctx - pldm_msgbuf context for extractor 64c63f63a2SAndrew Jeffery * 65c63f63a2SAndrew Jeffery * @return PLDM_SUCCESS if there are zero or more bytes of data that remain 66c63f63a2SAndrew Jeffery * unread from the buffer. Otherwise, PLDM_ERROR_INVALID_LENGTH indicates that a 67c63f63a2SAndrew Jeffery * prior accesses would have occurred beyond the bounds of the buffer, and 68c63f63a2SAndrew Jeffery * PLDM_ERROR_INVALID_DATA indicates that the provided context was not a valid 69c63f63a2SAndrew Jeffery * pointer. 70c63f63a2SAndrew Jeffery */ 71c63f63a2SAndrew Jeffery static inline int pldm_msgbuf_validate(struct pldm_msgbuf *ctx) 72c63f63a2SAndrew Jeffery { 73c63f63a2SAndrew Jeffery if (!ctx) { 74c63f63a2SAndrew Jeffery return PLDM_ERROR_INVALID_DATA; 75c63f63a2SAndrew Jeffery } 76c63f63a2SAndrew Jeffery 77c63f63a2SAndrew Jeffery return ctx->remaining >= 0 ? PLDM_SUCCESS : PLDM_ERROR_INVALID_LENGTH; 78c63f63a2SAndrew Jeffery } 79c63f63a2SAndrew Jeffery 80c63f63a2SAndrew Jeffery /** 81c63f63a2SAndrew Jeffery * @brief Destroy the pldm buf 82c63f63a2SAndrew Jeffery * 83c63f63a2SAndrew Jeffery * @param[in] ctx - pldm_msgbuf context for extractor 84c63f63a2SAndrew Jeffery * 85c63f63a2SAndrew Jeffery * @return PLDM_SUCCESS if all buffer accesses were in-bounds, 86c63f63a2SAndrew Jeffery * PLDM_ERROR_INVALID_DATA if the ctx parameter is invalid, or 87c63f63a2SAndrew Jeffery * PLDM_ERROR_INVALID_LENGTH if prior accesses would have occurred beyond the 88c63f63a2SAndrew Jeffery * bounds of the buffer. 89c63f63a2SAndrew Jeffery */ 90c63f63a2SAndrew Jeffery static inline int pldm_msgbuf_destroy(struct pldm_msgbuf *ctx) 91c63f63a2SAndrew Jeffery { 92c63f63a2SAndrew Jeffery int valid; 93c63f63a2SAndrew Jeffery 94c63f63a2SAndrew Jeffery if (!ctx) { 95c63f63a2SAndrew Jeffery return PLDM_ERROR_INVALID_DATA; 96c63f63a2SAndrew Jeffery } 97c63f63a2SAndrew Jeffery 98c63f63a2SAndrew Jeffery valid = pldm_msgbuf_validate(ctx); 99c63f63a2SAndrew Jeffery 100c63f63a2SAndrew Jeffery ctx->cursor = NULL; 101c63f63a2SAndrew Jeffery ctx->remaining = 0; 102c63f63a2SAndrew Jeffery 103c63f63a2SAndrew Jeffery return valid; 104c63f63a2SAndrew Jeffery } 105c63f63a2SAndrew Jeffery 106c63f63a2SAndrew Jeffery /** 107c63f63a2SAndrew Jeffery * @brief pldm_msgbuf extractor for a uint8_t 108c63f63a2SAndrew Jeffery * 109c63f63a2SAndrew Jeffery * @param[inout] ctx - pldm_msgbuf context for extractor 110c63f63a2SAndrew Jeffery * @param[out] dst - destination of extracted value 111c63f63a2SAndrew Jeffery * 112c63f63a2SAndrew Jeffery * @return PLDM_SUCCESS if buffer accesses were in-bounds, 113c63f63a2SAndrew Jeffery * PLDM_ERROR_INVALID_LENGTH otherwise. 114c63f63a2SAndrew Jeffery * PLDM_ERROR_INVALID_DATA if input a invalid ctx 115c63f63a2SAndrew Jeffery */ 116c63f63a2SAndrew Jeffery static inline int pldm_msgbuf_extract_uint8(struct pldm_msgbuf *ctx, 117c63f63a2SAndrew Jeffery uint8_t *dst) 118c63f63a2SAndrew Jeffery { 119c63f63a2SAndrew Jeffery if (!ctx || !ctx->cursor || !dst) { 120c63f63a2SAndrew Jeffery return PLDM_ERROR_INVALID_DATA; 121c63f63a2SAndrew Jeffery } 122c63f63a2SAndrew Jeffery 123c63f63a2SAndrew Jeffery ctx->remaining -= sizeof(*dst); 124c63f63a2SAndrew Jeffery assert(ctx->remaining >= 0); 125c63f63a2SAndrew Jeffery if (ctx->remaining < 0) { 126c63f63a2SAndrew Jeffery return PLDM_ERROR_INVALID_LENGTH; 127c63f63a2SAndrew Jeffery } 128c63f63a2SAndrew Jeffery 129c63f63a2SAndrew Jeffery *dst = *((uint8_t *)(ctx->cursor)); 130c63f63a2SAndrew Jeffery ctx->cursor++; 131c63f63a2SAndrew Jeffery return PLDM_SUCCESS; 132c63f63a2SAndrew Jeffery } 133c63f63a2SAndrew Jeffery 134c63f63a2SAndrew Jeffery static inline int pldm_msgbuf_extract_int8(struct pldm_msgbuf *ctx, int8_t *dst) 135c63f63a2SAndrew Jeffery { 136c63f63a2SAndrew Jeffery if (!ctx || !ctx->cursor || !dst) { 137c63f63a2SAndrew Jeffery return PLDM_ERROR_INVALID_DATA; 138c63f63a2SAndrew Jeffery } 139c63f63a2SAndrew Jeffery 140c63f63a2SAndrew Jeffery ctx->remaining -= sizeof(*dst); 141c63f63a2SAndrew Jeffery assert(ctx->remaining >= 0); 142c63f63a2SAndrew Jeffery if (ctx->remaining < 0) { 143c63f63a2SAndrew Jeffery return PLDM_ERROR_INVALID_LENGTH; 144c63f63a2SAndrew Jeffery } 145c63f63a2SAndrew Jeffery 146c63f63a2SAndrew Jeffery *dst = *((int8_t *)(ctx->cursor)); 147c63f63a2SAndrew Jeffery ctx->cursor++; 148c63f63a2SAndrew Jeffery return PLDM_SUCCESS; 149c63f63a2SAndrew Jeffery } 150c63f63a2SAndrew Jeffery 151c63f63a2SAndrew Jeffery static inline int pldm_msgbuf_extract_uint16(struct pldm_msgbuf *ctx, 152c63f63a2SAndrew Jeffery uint16_t *dst) 153c63f63a2SAndrew Jeffery { 154c63f63a2SAndrew Jeffery uint16_t ldst; 155c63f63a2SAndrew Jeffery 156c63f63a2SAndrew Jeffery if (!ctx || !ctx->cursor || !dst) { 157c63f63a2SAndrew Jeffery return PLDM_ERROR_INVALID_DATA; 158c63f63a2SAndrew Jeffery } 159c63f63a2SAndrew Jeffery 160c63f63a2SAndrew Jeffery // Check for buffer overflow. If we overflow, account for the request as 161c63f63a2SAndrew Jeffery // negative values in ctx->remaining. This way we can debug how far 162c63f63a2SAndrew Jeffery // we've overflowed. 163c63f63a2SAndrew Jeffery ctx->remaining -= sizeof(ldst); 164c63f63a2SAndrew Jeffery 165c63f63a2SAndrew Jeffery // Prevent the access if it would overflow. First, assert so we blow up 166c63f63a2SAndrew Jeffery // the test suite right at the point of failure. However, cater to 167c63f63a2SAndrew Jeffery // -DNDEBUG by explicitly testing that the access is valid. 168c63f63a2SAndrew Jeffery assert(ctx->remaining >= 0); 169c63f63a2SAndrew Jeffery if (ctx->remaining < 0) { 170c63f63a2SAndrew Jeffery return PLDM_ERROR_INVALID_LENGTH; 171c63f63a2SAndrew Jeffery } 172c63f63a2SAndrew Jeffery 173c63f63a2SAndrew Jeffery // Use memcpy() to have the compiler deal with any alignment 174c63f63a2SAndrew Jeffery // issues on the target architecture 175c63f63a2SAndrew Jeffery memcpy(&ldst, ctx->cursor, sizeof(ldst)); 176c63f63a2SAndrew Jeffery 177c63f63a2SAndrew Jeffery // Only assign the target value once it's correctly decoded 178c63f63a2SAndrew Jeffery *dst = le16toh(ldst); 179c63f63a2SAndrew Jeffery ctx->cursor += sizeof(ldst); 180c63f63a2SAndrew Jeffery 181c63f63a2SAndrew Jeffery return PLDM_SUCCESS; 182c63f63a2SAndrew Jeffery } 183c63f63a2SAndrew Jeffery 184c63f63a2SAndrew Jeffery static inline int pldm_msgbuf_extract_int16(struct pldm_msgbuf *ctx, 185c63f63a2SAndrew Jeffery int16_t *dst) 186c63f63a2SAndrew Jeffery { 187c63f63a2SAndrew Jeffery int16_t ldst; 188c63f63a2SAndrew Jeffery 189c63f63a2SAndrew Jeffery if (!ctx || !ctx->cursor || !dst) { 190c63f63a2SAndrew Jeffery return PLDM_ERROR_INVALID_DATA; 191c63f63a2SAndrew Jeffery } 192c63f63a2SAndrew Jeffery 193c63f63a2SAndrew Jeffery ctx->remaining -= sizeof(ldst); 194c63f63a2SAndrew Jeffery assert(ctx->remaining >= 0); 195c63f63a2SAndrew Jeffery if (ctx->remaining < 0) { 196c63f63a2SAndrew Jeffery return PLDM_ERROR_INVALID_LENGTH; 197c63f63a2SAndrew Jeffery } 198c63f63a2SAndrew Jeffery 199c63f63a2SAndrew Jeffery memcpy(&ldst, ctx->cursor, sizeof(ldst)); 200c63f63a2SAndrew Jeffery 201c63f63a2SAndrew Jeffery *dst = le16toh(ldst); 202c63f63a2SAndrew Jeffery ctx->cursor += sizeof(ldst); 203c63f63a2SAndrew Jeffery 204c63f63a2SAndrew Jeffery return PLDM_SUCCESS; 205c63f63a2SAndrew Jeffery } 206c63f63a2SAndrew Jeffery 207c63f63a2SAndrew Jeffery static inline int pldm_msgbuf_extract_uint32(struct pldm_msgbuf *ctx, 208c63f63a2SAndrew Jeffery uint32_t *dst) 209c63f63a2SAndrew Jeffery { 210c63f63a2SAndrew Jeffery uint32_t ldst; 211c63f63a2SAndrew Jeffery 212c63f63a2SAndrew Jeffery if (!ctx || !ctx->cursor || !dst) { 213c63f63a2SAndrew Jeffery return PLDM_ERROR_INVALID_DATA; 214c63f63a2SAndrew Jeffery } 215c63f63a2SAndrew Jeffery 216c63f63a2SAndrew Jeffery ctx->remaining -= sizeof(ldst); 217c63f63a2SAndrew Jeffery assert(ctx->remaining >= 0); 218c63f63a2SAndrew Jeffery if (ctx->remaining < 0) { 219c63f63a2SAndrew Jeffery return PLDM_ERROR_INVALID_LENGTH; 220c63f63a2SAndrew Jeffery } 221c63f63a2SAndrew Jeffery 222c63f63a2SAndrew Jeffery memcpy(&ldst, ctx->cursor, sizeof(ldst)); 223c63f63a2SAndrew Jeffery 224c63f63a2SAndrew Jeffery *dst = le32toh(ldst); 225c63f63a2SAndrew Jeffery ctx->cursor += sizeof(ldst); 226c63f63a2SAndrew Jeffery 227c63f63a2SAndrew Jeffery return PLDM_SUCCESS; 228c63f63a2SAndrew Jeffery } 229c63f63a2SAndrew Jeffery 230c63f63a2SAndrew Jeffery static inline int pldm_msgbuf_extract_int32(struct pldm_msgbuf *ctx, 231c63f63a2SAndrew Jeffery int32_t *dst) 232c63f63a2SAndrew Jeffery { 233c63f63a2SAndrew Jeffery int32_t ldst; 234c63f63a2SAndrew Jeffery 235c63f63a2SAndrew Jeffery if (!ctx || !ctx->cursor || !dst) { 236c63f63a2SAndrew Jeffery return PLDM_ERROR_INVALID_DATA; 237c63f63a2SAndrew Jeffery } 238c63f63a2SAndrew Jeffery 239c63f63a2SAndrew Jeffery ctx->remaining -= sizeof(ldst); 240c63f63a2SAndrew Jeffery assert(ctx->remaining >= 0); 241c63f63a2SAndrew Jeffery if (ctx->remaining < 0) { 242c63f63a2SAndrew Jeffery return PLDM_ERROR_INVALID_LENGTH; 243c63f63a2SAndrew Jeffery } 244c63f63a2SAndrew Jeffery 245c63f63a2SAndrew Jeffery memcpy(&ldst, ctx->cursor, sizeof(ldst)); 246c63f63a2SAndrew Jeffery 247c63f63a2SAndrew Jeffery *dst = le32toh(ldst); 248c63f63a2SAndrew Jeffery ctx->cursor += sizeof(ldst); 249c63f63a2SAndrew Jeffery 250c63f63a2SAndrew Jeffery return PLDM_SUCCESS; 251c63f63a2SAndrew Jeffery } 252c63f63a2SAndrew Jeffery 253c63f63a2SAndrew Jeffery static inline int pldm_msgbuf_extract_real32(struct pldm_msgbuf *ctx, 254c63f63a2SAndrew Jeffery real32_t *dst) 255c63f63a2SAndrew Jeffery { 256c63f63a2SAndrew Jeffery uint32_t ldst; 257c63f63a2SAndrew Jeffery 258c63f63a2SAndrew Jeffery if (!ctx || !ctx->cursor || !dst) { 259c63f63a2SAndrew Jeffery return PLDM_ERROR_INVALID_DATA; 260c63f63a2SAndrew Jeffery } 261c63f63a2SAndrew Jeffery 262c63f63a2SAndrew Jeffery ctx->remaining -= sizeof(ldst); 263c63f63a2SAndrew Jeffery assert(ctx->remaining >= 0); 264c63f63a2SAndrew Jeffery if (ctx->remaining < 0) { 265c63f63a2SAndrew Jeffery return PLDM_ERROR_INVALID_LENGTH; 266c63f63a2SAndrew Jeffery } 267c63f63a2SAndrew Jeffery 268c63f63a2SAndrew Jeffery _Static_assert(sizeof(*dst) == sizeof(ldst), 269c63f63a2SAndrew Jeffery "Mismatched type sizes for dst and ldst"); 270c63f63a2SAndrew Jeffery memcpy(&ldst, ctx->cursor, sizeof(ldst)); 271c63f63a2SAndrew Jeffery ldst = le32toh(ldst); 272c63f63a2SAndrew Jeffery memcpy(dst, &ldst, sizeof(*dst)); 273c63f63a2SAndrew Jeffery ctx->cursor += sizeof(*dst); 274c63f63a2SAndrew Jeffery 275c63f63a2SAndrew Jeffery return PLDM_SUCCESS; 276c63f63a2SAndrew Jeffery } 277c63f63a2SAndrew Jeffery 278c63f63a2SAndrew Jeffery #define pldm_msgbuf_extract(ctx, dst) \ 279c63f63a2SAndrew Jeffery _Generic((*(dst)), uint8_t \ 280c63f63a2SAndrew Jeffery : pldm_msgbuf_extract_uint8, int8_t \ 281c63f63a2SAndrew Jeffery : pldm_msgbuf_extract_int8, uint16_t \ 282c63f63a2SAndrew Jeffery : pldm_msgbuf_extract_uint16, int16_t \ 283c63f63a2SAndrew Jeffery : pldm_msgbuf_extract_int16, uint32_t \ 284c63f63a2SAndrew Jeffery : pldm_msgbuf_extract_uint32, int32_t \ 285c63f63a2SAndrew Jeffery : pldm_msgbuf_extract_int32, real32_t \ 286c63f63a2SAndrew Jeffery : pldm_msgbuf_extract_real32)(ctx, dst) 287c63f63a2SAndrew Jeffery 288*369b121aSAndrew Jeffery static inline int pldm_msgbuf_extract_array_uint8(struct pldm_msgbuf *ctx, 289*369b121aSAndrew Jeffery uint8_t *dst, size_t count) 290*369b121aSAndrew Jeffery { 291*369b121aSAndrew Jeffery size_t len; 292*369b121aSAndrew Jeffery 293*369b121aSAndrew Jeffery if (!ctx || !ctx->cursor || !dst) { 294*369b121aSAndrew Jeffery return PLDM_ERROR_INVALID_DATA; 295*369b121aSAndrew Jeffery } 296*369b121aSAndrew Jeffery 297*369b121aSAndrew Jeffery if (!count) { 298*369b121aSAndrew Jeffery return PLDM_SUCCESS; 299*369b121aSAndrew Jeffery } 300*369b121aSAndrew Jeffery 301*369b121aSAndrew Jeffery len = sizeof(*dst) * count; 302*369b121aSAndrew Jeffery if (len > SSIZE_MAX) { 303*369b121aSAndrew Jeffery return PLDM_ERROR_INVALID_LENGTH; 304*369b121aSAndrew Jeffery } 305*369b121aSAndrew Jeffery 306*369b121aSAndrew Jeffery ctx->remaining -= (ssize_t)len; 307*369b121aSAndrew Jeffery assert(ctx->remaining >= 0); 308*369b121aSAndrew Jeffery if (ctx->remaining < 0) { 309*369b121aSAndrew Jeffery return PLDM_ERROR_INVALID_LENGTH; 310*369b121aSAndrew Jeffery } 311*369b121aSAndrew Jeffery 312*369b121aSAndrew Jeffery memcpy(dst, ctx->cursor, len); 313*369b121aSAndrew Jeffery ctx->cursor += len; 314*369b121aSAndrew Jeffery 315*369b121aSAndrew Jeffery return PLDM_SUCCESS; 316*369b121aSAndrew Jeffery } 317*369b121aSAndrew Jeffery 318*369b121aSAndrew Jeffery #define pldm_msgbuf_extract_array(ctx, dst, count) \ 319*369b121aSAndrew Jeffery _Generic((*(dst)), uint8_t \ 320*369b121aSAndrew Jeffery : pldm_msgbuf_extract_array_uint8)(ctx, dst, count) 321*369b121aSAndrew Jeffery 322c63f63a2SAndrew Jeffery #ifdef __cplusplus 323c63f63a2SAndrew Jeffery } 324c63f63a2SAndrew Jeffery #endif 325c63f63a2SAndrew Jeffery 326c63f63a2SAndrew Jeffery #endif /* BUF_H */ 327