From d4d80be1bf354db62239c735f736278bd67605ab Mon Sep 17 00:00:00 2001 From: DragonSlayer_14 Date: Tue, 15 Sep 2026 23:06:20 +0200 Subject: [PATCH] =?UTF-8?q?Fix:=20TOCTOU=20in=20remove=5Fpair()=20bei=20ne?= =?UTF-8?q?benl=C3=A4ufigem=20Schreiber?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Die "vorher"-Länge wurde über einen separaten, vorgelagerten load() ermittelt statt innerhalb desselben atomaren modify()-Aufrufs - zwischen beiden Aufrufen konnte ein nebenläufiger Schreiber die Paarliste ändern, was zu einem falschen PairNotFound trotz erfolgreichem Entfernen führen konnte. Der Vorher/Nachher-Vergleich läuft jetzt vollständig innerhalb des modify()-Closures. Co-Authored-By: Claude Sonnet 5 Claude-Session: https://claude.ai/code/session_01LjyzpGWECyKSBWz5DtkTGz --- src/config/pairs.rs | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/src/config/pairs.rs b/src/config/pairs.rs index a8c902d..63aa67c 100644 --- a/src/config/pairs.rs +++ b/src/config/pairs.rs @@ -31,11 +31,18 @@ pub fn update_pair(pair: DrivePair) -> Result { /// Entfernt ein Laufwerkspaar per ID. pub fn remove_pair(id: &str) -> Result { - let before_len = load()?.pairs.len(); + // Die "vorher"-Länge wird INNERHALB desselben `modify`-Aufrufs (auf der bereits frisch + // geladenen `cfg`) ermittelt statt über einen separaten, vorgelagerten `load()`-Aufruf: + // zwischen zwei getrennten Aufrufen könnte ein nebenläufiger Schreiber die Paarliste + // ändern, was hier sonst zu einem falschen `PairNotFound` trotz erfolgreichem Entfernen + // (oder umgekehrt) führen könnte. + let removed = std::cell::Cell::new(false); let updated = config_ctdra::modify::(|cfg| { + let before_len = cfg.pairs.len(); cfg.pairs.retain(|p| p.id != id); + removed.set(cfg.pairs.len() != before_len); })?; - if updated.pairs.len() == before_len { + if !removed.get() { return Err(Error::PairNotFound(id.to_string())); } Ok(updated)