Skip to content

v0.1.7

Choose a tag to compare

@github-actions github-actions released this 24 Oct 09:46
· 48 commits to main since this release
c9248b9

Added

  • publish_on_close hardening: CHANGE_NOTIFY event mapping. When
    publish_on_close is enabled on a share, the CHANGE_NOTIFY watcher now
    maps inotify events on hidden temp files (.rssmb-tmp.*) to events on
    the client-visible final name, so no temp name ever surfaces to SMB
    clients:
    • temp ADDED → FILE_ACTION_ADDED <final_name>
    • temp MODIFIED → FILE_ACTION_MODIFIED <final_name>
    • temp REMOVED → suppress (abort, delete-on-close, or publish rename)
      Also confirmed via unit tests that (a) a durable handle's close
      publishes its pending temp, (b) the startup orphan sweep runs on
      share mount (not only from the periodic sweeper), and (c) fresh temps
      survive the startup sweep.
  • publish_on_close integration tests and CI. Added a
    publish-on-close job to the interop CI workflow that runs the
    impacket two-client scenario (A creates+writes, B lists+opens during
    pending, host ls -A shows only temp, B closes → publish) and a
    rclone --inplace test with inotifywait (asserting only MOVED_TO on
    the final name). Transcripts are uploaded as CI artifacts. The nightly
    smbtorture baseline now also runs with publish_on_close ON
    (tests/live/rssmb-live-poc.toml) and compares against
    results-poc.md.

Fixed

  • publish_on_close: abort orphaning data on attach rollback. When
    an attached handle (a second CREATE on a pending name) rolled back to
    zero open_count via abort(), the temp file — carrying another
    handle's written data — was orphaned (entry removed, temp left on
    disk with no pending entry to publish it). abort() now returns
    (temp, delete_on_close) — the same shape as close() — and the
    rollback_on_err macro publishes the temp (rename → final) instead
    of orphaning it. Only a freshly-created empty temp (created_here)
    or a delete_on_close temp is unlinked.
  • publish_on_close: rename + take_destination not atomic. The
    three-step rename → take_destination → rename dance held the
    table-level write lock three separate times, leaving a window where
    both source and destination were absent from the map. Replaced with
    rename_with_replace() — one method, one write lock, one atomic
    table-level operation that does the move and collision handling
    (including discarding a displaced destination) in a single lock hold.
  • publish_on_close: close race — rename under lock. The close()
    path removed the pending entry and returned the temp path before the
    caller performed the filesystem rename, leaving a window where a
    racing resolve_or_acquire could miss the entry and create a phantom
    re-pend. Replaced with close_publish() which calls the rename
    closure under the table's write lock — the entry is removed
    atomically with the filesystem rename, so no racing acquire can
    observe the gap.
  • publish_on_close: attach race — no phantom entry. The
    pending-file probe in LocalFs::create used resolve_or_acquire
    which minted a Created entry and immediately aborted it, leaving a
    window where a racing close or resolve_or_acquire could see the
    phantom entry. Replaced with attach() which finds an existing
    pending entry and increments its count, or returns None — no mint,
    no abort, no phantom.
  • Credit window: credit_charge=0 consumed a MessageId. Per MS-SMB2
    §3.3.1.2, credit_charge=0 MUST be treated as 1 for the credit
    balance
    (available credits), but the MessageId sequence window
    must use the actual credit_charge value (0 = no MessageIds
    consumed). The server incorrectly treated credit_charge=0 as 1 for
    both, consuming MessageId M for a zero-charge WRITE and then
    rejecting a CLOSE with the same MessageId M as "already used".
    Fixed by separating the balance charge (max(charge, 1)) from the
    window charge (actual charge) in CreditManager::check_and_deduct.
    Also added a balance-availability check so a zero-charge request with
    no available credits still fails (instead of silently saturating to
    0). This fixes the impacket smb.close()/logoff() connection
    terminations that forced the publish-on-close integration test to
    work around them by dropping the TCP socket.

Changed

  • multichannel default flipped to false. SMB 3.x multichannel is
    now off by default until binding hardening lands; set multichannel = true
    in the server config to re-enable. The server still honors the capability
    when explicitly enabled.

Security

  • NTLMv2 timestamp freshness window (ntlm_max_clock_skew_secs,
    default 600).
    When ntlm_require_timestamp is true, the MsvAvTimestamp
    in the AUTHENTICATE message is now checked for freshness (±10 min by
    default) against the server clock, not just presence. A stale timestamp
    is rejected as a replay attempt. Set 0 for the old presence-only
    behavior.