zeek/spicy

`skip` fields trims too much data in `&size`-constrained unit

Closed this issue · 0 comments

The following grammar fails to parse since field S.b consumes all available input:

module skip;

type S = unit(size: uint64) {
    a       : bytes &size=2;
    b       : skip bytes &size=1;
    c       : bytes &size=1;
    d       : skip bytes &eod;

    on %done {
        print self;
    }
} &size=size;


public type X = unit {
    : S(6);
};
$ printf "\x01\x02\x03\x04\x05\x06" | HILTI_DEBUG=spicy-verbose spicy-driver -d skip.spicy
[spicy-verbose] - state: type=skip::X input="\\x01\\x02\\x03\\x04\\x05\\x06" stream=0x6000000842b8 offsets=0/0/0/6 chunks=1 frozen=yes mode=default trim=yes lah=n/a lah_token="n/a" recovering=no
[spicy-verbose] - parsing production: Unit: skip__X -> Resolved_3
[spicy-verbose]   - state: type=skip::X input="\\x01\\x02\\x03\\x04\\x05\\x06" stream=0x6000000842b8 offsets=0/0/0/6 chunks=1 frozen=yes mode=default trim=yes lah=n/a lah_token="n/a" recovering=no
[spicy-verbose]   - parsing production: Unit: skip__S_2 -> a_2 b_2 c_2 d_2 (field '_anon', id n/a, parser/composer, args: (6))
[spicy-verbose]     - state: type=skip::S input="\\x01\\x02" stream=0x6000000842b8 offsets=0/0/0/6 chunks=1 frozen=yes mode=default trim=yes lah=n/a lah_token="n/a" recovering=no
[spicy-verbose]     - parsing production: Variable: a   -> bytes
[spicy-verbose]       - trimming input
[spicy-verbose]     - setting field 'a' to '\\x01\\x02'
[spicy-verbose]     - state: type=skip::S input="\\x03\\x04\\x05\\x06" stream=0x6000000842b8 offsets=2/0/2/6 chunks=1 frozen=yes mode=default trim=yes lah=n/a lah_token="n/a" recovering=no
[spicy-verbose]     - parsing production: Skip: b   -> skip: b
[spicy-verbose]       - trimming input
[spicy-verbose]       - skipped 1 bytes (0 left to skip)
[spicy-verbose]     - state: type=skip::S input="" stream=0x6000000842b8 offsets=3/0/6/6 chunks=1 frozen=yes mode=default trim=yes lah=n/a lah_token="n/a" recovering=no
[spicy-verbose]     - parsing production: Variable: c   -> bytes
[spicy-verbose]       - trimming input
[error] terminating with uncaught exception of type spicy::rt::ParseError: &size amount not consumed: expected 1 bytes, but got 0 bytes (skip.spicy:6:14-6:20)

This is due to the following code which incorrectly updates the limited view (from &size) of the unit with a position pointing after the unit (i.e., parsing the skip field consumes all available data).

if ( state().ncur ) {
builder()->addAssign(state().cur, *state().ncur);
state().ncur = {};
}

This has been broken since at least the introduction of this skip syntax in e134dc4, i.e., likely since the skip feature came about.

This was originally reported privately by @Mohan-Dhawan.