diff options
Diffstat (limited to 'lib9p/9p.c')
-rw-r--r-- | lib9p/9p.c | 20 |
1 files changed, 14 insertions, 6 deletions
@@ -45,9 +45,9 @@ int lib9p_errorf(struct lib9p_ctx *ctx, uint32_t linux_errno, char const *fmt, . return -1; } -ssize_t lib9p_unmarshal_size(struct lib9p_ctx *ctx, uint8_t *net_bytes) { +ssize_t lib9p_validate(struct lib9p_ctx *ctx, uint8_t *net_bytes) { /* Header */ - struct _checksize_ctx subctx = { + struct _validate_ctx subctx = { .ctx = ctx, .net_size = decode_u32le(net_bytes), .net_bytes = net_bytes, @@ -61,13 +61,21 @@ ssize_t lib9p_unmarshal_size(struct lib9p_ctx *ctx, uint8_t *net_bytes) { /* Body */ struct _vtable_msg vtable = _lib9p_vtables[ctx->version].msgs[typ]; - if (!vtable.unmarshal_extrasize) + if (!vtable.validate) return lib9p_errorf(ctx, LINUX_EOPNOTSUPP, "unknown message type %s", lib9p_msg_type_str(typ)); - if (vtable.unmarshal_extrasize(&subctx)) + if (vtable.validate(&subctx)) return -1; + assert(subctx.net_offset <= subctx.net_size); + if (subctx.net_offset < subctx.net_size) + return lib9p_error(ctx, LINUX_EBADMSG, "message has %"PRIu32" extra bytes", + subctx.net_size - subctx.net_offset); - return (ssize_t)(vtable.unmarshal_basesize + subctx.host_extra); + ssize_t ret; + if (__builtin_add_overflow(vtable.basesize, subctx.host_extra, &ret)) + return lib9p_error(ctx, LINUX_EMSGSIZE, "unmarshalled payload overflows SSIZE_MAX"); + + return ret; } void lib9p_unmarshal(struct lib9p_ctx *ctx, uint8_t *net_bytes, @@ -98,7 +106,7 @@ bool lib9p_marshal(struct lib9p_ctx *ctx, enum lib9p_msg_type typ, uint16_t tag, }; ret_bytes[4] = typ; encode_u16le(tag, &ret_bytes[5]); - + /* Body */ struct _vtable_msg vtable = _lib9p_vtables[ctx->version].msgs[typ]; if (vtable.marshal(&subctx, body)) |