diff options
-rw-r--r-- | lib9p/9P2000.txt | 4 | ||||
-rwxr-xr-x | lib9p/9p.gen | 26 | ||||
-rw-r--r-- | lib9p/9p.generated.c | 21 |
3 files changed, 30 insertions, 21 deletions
diff --git a/lib9p/9P2000.txt b/lib9p/9P2000.txt index fa04fe0..9cdb943 100644 --- a/lib9p/9P2000.txt +++ b/lib9p/9P2000.txt @@ -133,8 +133,8 @@ bitfield o 8 107/Rerror = "ename[s]" 108/Tflush = "oldtag[2]" 109/Rflush = "" -110/Twalk = "fid[4] newfid[4] nwname[2] nwname*(wname[s])" # nwname has a maximum of 16 -111/Rwalk = "nwqid[2] nwqid*(wqid[qid])" # nwname has a maximum of 16 +110/Twalk = "fid[4] newfid[4] nwname[2,max=16] nwname*(wname[s])" +111/Rwalk = "nwqid[2,max=16] nwqid*(wqid[qid])" 112/Topen = "fid[4] mode[o]" 113/Ropen = "qid[qid] iounit[4]" 114/Tcreate = "fid[4] name[s] perm[dm] mode[o]" diff --git a/lib9p/9p.gen b/lib9p/9p.gen index f974dd1..6e01b17 100755 --- a/lib9p/9p.gen +++ b/lib9p/9p.gen @@ -90,6 +90,7 @@ class Member: cnt: str | None = None name: str typ: Atom | Bitfield | Struct + max: int | None = None ver: set[str] @property @@ -101,7 +102,7 @@ class Member: re_membername = "(?:[a-zA-Z_][a-zA-Z_0-9]*)" re_memberspec = ( - f"(?:(?P<cnt>{re_membername})\\*\\()?(?P<name>{re_membername})\\[(?P<typ>.*)\\]\\)?" + f"(?:(?P<cnt>{re_membername})\\*\\()?(?P<name>{re_membername})\\[(?P<typ>[^,]*)(?:,max=(?P<max>[0-9]+))?\\]\\)?" ) @@ -135,6 +136,11 @@ def parse_members( raise ValueError(f"list count must be an integer type: {repr(cnt)}") member.cnt = cnt + if maxstr := m.group("max"): + if (not isinstance(member.typ, Atom)) or member.cnt: + raise ValueError(f"',max=' may only be specified on a non-repeated atom") + member.max = int(maxstr) + ret += [member] return ret @@ -549,11 +555,8 @@ static ALWAYS_INLINE bool _validate_size_host(struct _validate_ctx *ctx, size_t } static ALWAYS_INLINE bool _validate_list(struct _validate_ctx *ctx, - size_t cnt, size_t max, + size_t cnt, _validate_fn_t item_fn, size_t item_host_size) { - if (max && cnt > max) - return lib9p_errorf(ctx->ctx, LINUX_EBADMSG, "list size is too large (%zu > %zu)", - cnt, max); for (size_t i = 0; i < cnt; i++) if (_validate_size_host(ctx, item_host_size) || item_fn(ctx)) return true; @@ -654,6 +657,7 @@ static ALWAYS_INLINE bool _validate_list(struct _validate_ctx *ctx, prefix0 = "\treturn " prefix1 = "\t || " + prefix2 = "\t " struct_versions = typ.members[0].ver @@ -665,14 +669,14 @@ static ALWAYS_INLINE bool _validate_list(struct _validate_ctx *ctx, ret += "( " + c_vercond(idprefix, member.ver) + " && " if member.cnt is not None: assert prev_size - maxelem = 0 - if ( - typ.name in ["Twalk", "Rwalk"] and member.name[:1] == "w" - ): # SPECIAL - maxelem = 16 - ret += f"_validate_list(ctx, decode_u{prev_size*8}le(&ctx->net_bytes[ctx->net_offset-{prev_size}]), {maxelem}, validate_{member.typ.name}, sizeof({c_typename(idprefix, member.typ)}))" + ret += f"_validate_list(ctx, decode_u{prev_size*8}le(&ctx->net_bytes[ctx->net_offset-{prev_size}]), validate_{member.typ.name}, sizeof({c_typename(idprefix, member.typ)}))" else: ret += f"validate_{member.typ.name}(ctx)" + if member.max: + ret += f"\n{prefix1}(decode_u{member.static_size*8}le(&ctx->net_bytes[ctx->net_offset-{member.static_size}]) > ({c_typename(idprefix, member.typ)})({member.max})" + ret += f'\n{prefix2}\t? lib9p_errorf(ctx->ctx, LINUX_EBADMSG, "list size is too large (%"PRIu{member.static_size*8}" > %"PRIu{member.static_size*8}")",' + ret += f"\n{prefix2}\t\tdecode_u{member.static_size*8}le(&ctx->net_bytes[ctx->net_offset-{member.static_size}]), ({c_typename(idprefix, member.typ)})({member.max}))" + ret += f"\n{prefix2}\t: false)" if member.ver != struct_versions: ret += " )" prefix = prefix1 diff --git a/lib9p/9p.generated.c b/lib9p/9p.generated.c index 387af79..0259e23 100644 --- a/lib9p/9p.generated.c +++ b/lib9p/9p.generated.c @@ -311,11 +311,8 @@ static ALWAYS_INLINE bool _validate_size_host(struct _validate_ctx *ctx, size_t } static ALWAYS_INLINE bool _validate_list(struct _validate_ctx *ctx, - size_t cnt, size_t max, + size_t cnt, _validate_fn_t item_fn, size_t item_host_size) { - if (max && cnt > max) - return lib9p_errorf(ctx->ctx, LINUX_EBADMSG, "list size is too large (%zu > %zu)", - cnt, max); for (size_t i = 0; i < cnt; i++) if (_validate_size_host(ctx, item_host_size) || item_fn(ctx)) return true; @@ -464,12 +461,20 @@ static FLATTEN bool validate_Twalk(struct _validate_ctx *ctx) { return validate_4(ctx) || validate_4(ctx) || validate_2(ctx) - || _validate_list(ctx, decode_u16le(&ctx->net_bytes[ctx->net_offset-2]), 16, validate_s, sizeof(struct lib9p_s)); + || (decode_u16le(&ctx->net_bytes[ctx->net_offset-2]) > (uint16_t)(16) + ? lib9p_errorf(ctx->ctx, LINUX_EBADMSG, "list size is too large (%"PRIu16" > %"PRIu16")", + decode_u16le(&ctx->net_bytes[ctx->net_offset-2]), (uint16_t)(16)) + : false) + || _validate_list(ctx, decode_u16le(&ctx->net_bytes[ctx->net_offset-2]), validate_s, sizeof(struct lib9p_s)); } static FLATTEN bool validate_Rwalk(struct _validate_ctx *ctx) { return validate_2(ctx) - || _validate_list(ctx, decode_u16le(&ctx->net_bytes[ctx->net_offset-2]), 16, validate_qid, sizeof(struct lib9p_qid)); + || (decode_u16le(&ctx->net_bytes[ctx->net_offset-2]) > (uint16_t)(16) + ? lib9p_errorf(ctx->ctx, LINUX_EBADMSG, "list size is too large (%"PRIu16" > %"PRIu16")", + decode_u16le(&ctx->net_bytes[ctx->net_offset-2]), (uint16_t)(16)) + : false) + || _validate_list(ctx, decode_u16le(&ctx->net_bytes[ctx->net_offset-2]), validate_qid, sizeof(struct lib9p_qid)); } static FLATTEN bool validate_Topen(struct _validate_ctx *ctx) { @@ -558,7 +563,7 @@ static FLATTEN bool validate_Rsession(struct _validate_ctx *UNUSED(ctx)) { static FLATTEN bool validate_Tsread(struct _validate_ctx *ctx) { return validate_4(ctx) || validate_2(ctx) - || _validate_list(ctx, decode_u16le(&ctx->net_bytes[ctx->net_offset-2]), 0, validate_s, sizeof(struct lib9p_s)); + || _validate_list(ctx, decode_u16le(&ctx->net_bytes[ctx->net_offset-2]), validate_s, sizeof(struct lib9p_s)); } static FLATTEN bool validate_Rsread(struct _validate_ctx *ctx) { @@ -568,7 +573,7 @@ static FLATTEN bool validate_Rsread(struct _validate_ctx *ctx) { static FLATTEN bool validate_Tswrite(struct _validate_ctx *ctx) { return validate_4(ctx) || validate_2(ctx) - || _validate_list(ctx, decode_u16le(&ctx->net_bytes[ctx->net_offset-2]), 0, validate_s, sizeof(struct lib9p_s)) + || _validate_list(ctx, decode_u16le(&ctx->net_bytes[ctx->net_offset-2]), validate_s, sizeof(struct lib9p_s)) || validate_d(ctx); } |