Files
rdb/doc/review.md
T
wkh 9f6c450492 Sicherheit: report/screen maskieren Shell-Eingaben, Sperren privat und atomar
report setzt Zellwerte in <!befehl!> maskiert ein, screen verlangt gültige
Variablennamen, lock/unlock nutzen /tmp/rdb-locks-<UID> mit flock, vilock
sperrt per Hardlink. EDITOR darf Argumente haben. Doku und Tests ergänzt.
2026-10-30 09:45:18 +01:00

5.7 KiB

Code-Review: Schwachstellen, Fehler, Verbesserungspotential

Stand: 2026-10-30, Version 0.7.0. Die 114 Tests und der Handbuch-Test liefen grün. „Bestätigt“ heißt: nachgestellt. Alles andere stammt aus dem Lesen des Codes.

Schwachstellen (alle vier behoben, siehe CHANGELOG)

  1. Befehlseinschleusung über Tabellendaten in report (bestätigt). lib/rdb/cmd/report.rb:11-12: Bei <!cmd <Spalte>!> werden Zellwerte ungefiltert in einen Backtick-Aufruf eingesetzt. Eine Zelle mit touch PWNED hat die Datei angelegt. Abhilfe: Shellwords.escape, oder in der Doku als „nur vertrauenswürdige Daten“ kennzeichnen. Behoben: Werte werden mit Shellwords.escape eingesetzt.
  2. screen erzeugt Shell-Code aus Spaltennamen (report.rb:50-70). Namen stehen unquotiert in read NAME und echo "$NAME"; Leerzeichen, ; oder $(…) brechen das Skript oder führen Code aus. Werte werden ebenfalls nicht maskiert. Behoben: Spaltennamen müssen gültige Shell-Variablennamen sein.
  3. Lock-Dateien in /tmp (access.rb:121). Vorhersagbare Namen, andere Benutzer können sie anlegen oder löschen. lock liest und hängt an, ohne flock (Race). Keine Prüfung, ob die PID noch lebt; nach einem Absturz bleibt das Schloss. Behoben: privates Verzeichnis /tmp/rdb-locks-<UID> (0700) und flock. Offen: verwaiste Schlösser nach Absturz (eine PID-Prüfung bricht Tests und Handbuch, die erfundene PIDs nutzen).
  4. vilock nicht atomar (access.rb:134). Race zwischen File.exist? und rename; nach kill -9 bleibt LOCK… liegen. Behoben: atomare Sperre über File.link. Offen: nach kill -9 bleibt LOCK… liegen.

Fehler

  1. Umlaute in Spaltennamen (bestätigt). to_awk erkennt nur [A-Za-z_#] und ASCII-\w. row 'Über > 3' scheitert mit awk-Fehler. Relevant für die DE/AT/CH-Tarife.
  2. Nicht-UTF-8-Daten (bestätigt). Latin-1-Datei führt zu invalid byte sequence in UTF-8 mit Stacktrace (table.rb:28). Abhilfe: binär lesen und scrub/ force_encoding, oder Kodierungsoption.
  3. Kein Fehlerfang auf oberster Ebene (bestätigt). Stacktraces statt Meldungen bei ungültiger Regex (update.rdb mit /[, access.rb:277; sale, act.rb:345), Date::Error in to_julian, Errno::*. Abhilfe: rescue StandardError in bin/rdb/Rdb.run.
  4. EDITOR mit Argumenten (bestätigt, behoben). system(ENV['EDITOR'], datei) in vilock und edit_cells (access.rb:138, access.rb:150) behandelt "nvim -f" als einen Programmnamen. Der Editor startet nie, update.rdb meldet trotzdem „record replaced“. Abhilfe: Shellwords.split, Rückgabewert prüfen.
  5. Datenverlust-Risiko bei update.rdb e (access.rb:289). Der Satz wird vor dem Editieren geleert; bei Abbruch ist er weg. Erst nach erfolgreichem Editieren schreiben.
  6. Tab/Zeilenumbruch in Werten ungeprüft (bestätigt für Tab). append, enter, replace, ve schreiben Zellen unverändert; ein Tab erzeugte eine Zeile mit 3 statt 2 Spalten (check.rdb meldet es).
  7. Nicht atomares Schreiben. splice, build, substitute überschreiben direkt, ohne temporäre Datei plus rename, ohne flock.
  8. Inkonsistente Vergleiche bei -mb/-mi (nur im Code gesehen). Index sortiert mit to_s, Suche vergleicht mit strip; führende Leerzeichen und -x ohne Teilsuche können falsch ausfallen.
  9. Kleinigkeiten. sorttable -r kehrt gleiche Schlüssel um (reverse! nach stabiler Sortierung); -nrf gilt global für alle Spalten; jointable -n wird ignoriert; total/mean lehnen 1e3 ab; eine Zeile aus lauter leeren Zellen gilt als gelöscht (fast.rb:21).

Verbesserungspotential

  1. Indexe sind nicht schnell. Jede Suche liest Tabelle und Indexdatei komplett (fast.rb:151, fast.rb:171, Data.new pro Schlüssel in delete/update.rdb): O(n) pro Schlüssel. Abhilfe: mit seek/pread direkt an der Fixbreiten-Position lesen.
  2. Schlechte Hash-Funktion (fast.rb:68): bytes.sum % slots. Bestätigt: 3000 fünfstellige Nummern landen in 30 Slots, größter Bucket 223. Abhilfe: FNV-1a o. Ä., Primzahl-Slotzahl.
  3. Geld in Float (act.rb:11, to_f im /act-Teil und in total). Abhilfe: BigDecimal oder ganzzahlige Rappen.
  4. awk-Brücke (env.rb:119-138): ganze Tabelle als String durch capture3, kein Streaming; handgeschriebener Parser erkennt Strings und Regexe heuristisch (prev) und hängt vom awk-Dialekt ab.
  5. Globale Methoden auf Object (fast_opts, lock_file, num, money, ask, need, show_record …). In ein Modul kapseln und in Env einbinden.
  6. Doppelter Code. awk/awk_text; Schlüsseltabellen-Parsing in fast_opts/ key_columns; von Hand gebaute Kopf-/Strichzeilen trotz Table.dash_row.
  7. Tests. Laufzeit ca. 66 s wegen eines Ruby-Prozesses pro Test. Fehlerfälle (Encoding, Tab in Wert, Locks, Editor) nicht abgedeckt; Tests direkt gegen Rdb.run im Prozess wären schneller.
  8. Repo. demo/fact.pl, fact_lc.pl, rule.pl sind ungetrackt; demo/testall.old (1187 Zeilen) wäre als Golden-File-Test besser gepflegt.

Empfohlene Reihenfolge

Die Schwachstellen sind erledigt. Weiter mit: Umlaute (Fehler 1), Encoding (2), Top-Level-Rescue (3), report-Einschleusung (Schwachstelle 1); danach Hash-Funktion und Index-Lesezugriffe.