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