Skip to content

OpenSyn's Shm extension changed encoding between 1.9.0 and 1.10.0 while VERSION and PatchType::CURRENT stayed the same #2772

Description

@temporaryfix

Raising this as a versioning question rather than a bug report, since the right fix is yours to pick. It is not a vulnerability, and there is no split-brain.

What changed

transport::open::ext::Shm is zextz64!(0x2, false) in 1.9.0 and zextzbuf!(0x2, false) in 1.10.0. VERSION is 0x09 in both, and PatchType::CURRENT is 1 in both.

Extension dispatch matches on iext::eid(header), which is header & !FLAG_Z and therefore keeps the ENC bits, while ext::Shm::ID has ENC baked in. Each version consequently sees the other's OPEN Shm extension as an unknown non-mandatory extension and skips it. The rest of the OpenSyn decodes normally.

Why it is reachable rather than theoretical

The INIT stage is unchanged between the two releases: InitSyn { alice_segment } and InitAck { alice_challenge, bob_segment } are identical, and INIT's Shm extension is zextzbuf in both. A mixed 1.9/1.10 pair therefore negotiates SHM all the way through INIT, both sides allocate and open each other's auth segments, and only then is the OPEN extension dropped.

Both versions' recv_open_syn return Ok(()) when the extension is absent, and the skip is logged at debug!, so the visible outcome is shared memory quietly not being used. Neither side can conclude SHM is on by itself, so both settle on off.

Reproducer

One script, two small crates, no daemon needed:

https://gist.github.com/temporaryfix/0a9c66a733e8c68419417dc0dace7ada

The first two cases are positive controls. If either reports ABSENT then shared-memory is disabled somewhere and the cross-version results below mean nothing.

[1.10.0] Shm::ID = 0x42   VERSION = 0x09   PatchType::CURRENT = 1
[1.9.0]  Shm::ID = 0x22   VERSION = 0x09   PatchType::CURRENT = 1

1.9.0  encodes -> 1.9.0  decodes   ext_shm = PRESENT   (positive control)
1.10.0 encodes -> 1.10.0 decodes   ext_shm = PRESENT   (positive control)
1.10.0 encodes -> 1.9.0  decodes   decoded OK, ext_shm = ABSENT
1.9.0  encodes -> 1.10.0 decodes   decoded OK, ext_shm = ABSENT

The whole difference is one header byte: 0x42 (ENC_ZBUF | 0x2) against 0x22 (ENC_Z64 | 0x2).

Where this lives

what where
pub type Shm = zextz64!(0x2, false) zenoh-protocol-1.9.0/src/transport/open.rs:111
pub type Shm = zextzbuf!(0x2, false) zenoh-protocol-1.10.0/src/transport/open.rs:111
INIT's Shm is zextzbuf in both src/transport/init.rs:150
VERSION = 0x09 in both src/lib.rs:31
PatchType::CURRENT = Self(1) in both src/transport/mod.rs:326
eid(header) = header & !FLAG_Z, so ENC is part of the match key src/common/extension.rs:68
the ext::Shm::ID dispatch arm zenoh-codec/src/transport/open.rs:175
unknown and non-mandatory, so skipped with a debug! zenoh-codec/src/common/extension.rs:33-41
a missing extension returns Ok(()) zenoh-transport-1.9.0/src/unicast/establishment/ext/shm.rs:481
the same in 1.10.0 zenoh-transport-1.10.0/src/unicast/establishment/ext/shm/auth.rs:544

The question

What should a decoder do when a known extension id arrives with an unexpected ENC? Today it is indistinguishable from an unknown extension, so any future ENC change on any id degrades silently between peers that have agreed on both VERSION and PatchType::CURRENT.

If the intended rule is to bump PatchType::CURRENT whenever an extension's encoding changes, that seems worth writing down somewhere a later change will run into it.

Not tested

I have not run two daemons against each other. The reproducer works at the codec level, which is where the dispatch happens. Happy to do the daemon version if that would be more useful.

Written with AI assistance. Every claim above was checked against the sources named and by running the reproducer.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions