Forum: PC-Programmierung bash: was passiert da? ffmpeg?


von BOFH-i18n (Gast)


Angehängte Dateien:

Lesenswert?

ich grüsse euch Alle!

Einleitung

  ich mache seit Jahrzehnte nebenbei auch shell-Scripts auf gutem Niveau 
(aber noch nicht Guru-Level...) und habe folgenden Evolutionsschritt 
schon lange hinter mir:
1
#NAIV (1)
2
for f in  $(find . -iname '*.wma')   # verschluckt sich an Leerzeichen etc. in Datei~ u. Verzeichnisnamen
3
do
4
    :
5
done
6
7
#DEFENSIV (2)
8
find . -iname '*.wma' | while read f   # robust. Dachte ich zumindest bis heute...
9
do
10
    :
11
done


PROBLEM

TL;DR:
* <liste> | while read <var> ; do  job ; done    laesst bereits im 2. 
Schleifendurchlauf <var> leer also ""
* for <var> in "${<liste>[@]}" ; do  job ; done  funktioniert


  heute wollte ich viele, in mehreren Unterverzeichnisse verstreute, WMA 
Dateien nach OGG konvertieren und erlebte erstmals die Böse 
Überrasschung dass o.g. DEFENSIV (2) Variante versagte.

  im Anhang ist  wma.pflist  eine stark verkürzte liste von Dateien und 
wma2ogg.bash  die zusammengefasste Analyse.

  Die im script mit ##WTF## markierten Zeilen verursachen das Problem.
  Der script ist nur der Problemanalyse wegen so überstrukturiert 
(strikt prozedural), denn eigentlich ist sowas fuer mich in 99.9% der 
Fälle eine einfache ad-hoc Fingerübung am bash-Prompt, gerne auch vor 
dem ersten Kaffee...

  Es sind halt in mehreren Aufruftiefen solche ##WTF## Möglichkeiten in 
der Datei: da ist mit Verstand nat. nur an jeweils 1 Stelle aufs Mal 
solcheine Zeile umzustellen um den Fehler zu reproduzieren.


  Die Kiste hier ist ein Ubuntu 16.04.5 LTS (Linux 4.4.0-135-generic) 
auf einem aelteren Notebook (HP6730b, C2D P8800, 4GB RAM), täglich 
genutzt.
  bash: 4.3.48(1)-release
  ffmpeg: 2.8.15-0ubuntu0.16.04.1   (gcc + libs a.A.)


FRAGE

  kann mir Jemand helfen, eine Erklaerung zu finden WARUM das Problem 
auftritt um das Problem gründlich zu verstehen?

  (DIE Bitte an Forumschaoten: ein Workaround habe ich bereits gefunden, 
s. script-Datei.
Also keine andere Wege aufzeigen - es geht mir hier darum den Fehlerfall 
gründlich zu verstehen - Danke!)


HYPOTHESEN

  * Fehler in bash: Variablen anfaellig ?   (DAS wäre ein 
Glueckstreffer...)
  * Fehler in ffmpeg: verwurstelt Umgebungsvariablen ?
  * ...?

von foobar (Gast)


Lesenswert?

a) dein Problem ($pfn leer) kommt bei mir mit den Eingabedaten nicht, 
mußte allerdings etwas rumändern um es Testen zu können. Sehe auch 
nicht, wo was verkehrt sein sollte - einzig Newlines (\n) im Dateinamen 
gehen schief. Versuch mal nen minimal test case zu basteln.

b) "[ [ -v xxx ] ]" gibt es bei älteren bash-Versionen nicht.

c) "Fehler in ffmpeg: verwurstelt Umgebungsvariablen?" - sowas ist 
prinzipiell nicht möglich. Subshells (auch Funktionen in nem 
Subshell-Kontext) oder externe Programme können niemals Variablen im 
Parent ändern.

d) Variablen kreuz und quer zu definieren und zu benutzen ist nicht die 
feine Englische - gibt immer mal Probleme. Besser ist es, Parameter 
explizit an Unterprogramme zu übergeben, z.B. <do_shasum "$pfn"> und 
dort dann $1 etc benutzen.

von c-hater (Gast)


Lesenswert?

foobar schrieb:

> c) "Fehler in ffmpeg: verwurstelt Umgebungsvariablen?" - sowas ist
> prinzipiell nicht möglich. Subshells (auch Funktionen in nem
> Subshell-Kontext) oder externe Programme können niemals Variablen im
> Parent ändern.

Definitiv falsche Formulierung. Tatsächlich ist es natürlich so:

c) "Fehler in ffmpeg: verwurstelt Umgebungsvariablen?" - sowas sollte
prinzipiell nicht möglich sein. Geht aber doch, wenn Sicherheitslücken 
greifen. Dann können Subshells (auch Funktionen in nem Subshell-Kontext) 
oder externe Programme NATÜRLICH auch Variablen im Parent ändern. 
Neben vielen anderen Sachen, die dann möglich werden...

Das ist eigentlich eine Trivialität. Besonders interessant wird es erst 
durch die vielen bekannten (und vermutlich noch sehr viel zahlreicheren 
unbekannten) Sicherheitslücken in ffmpeg, die sich schlicht daraus 
ergeben, das ffmpeg ein saukomplexes Stück Software ist, was sehr 
regelmäßig mit allen Schlechtigkeiten externer Datenquellen klarkommen 
muss.

Ich würde mal davon ausgehen, dass eine genauere Untersuchung hier 
letztlich eine weitere Sicherheitslücke vom Status "bisher unbekannt" 
zum Status "bekannt" bringt und dann relativ zeitnah zum Status "fixed". 
Wenn jemand sich erbarmt, diese Untersuchung durchzuführen und die 
Ergebnisse als kompetente Fehlerbeschreibung an der richtigen Stelle im 
Netz einzuspeisen...

Der erste Schritt wäre aber natürlich, ffmpeg als Fehlerursache 
auszuschließen, indem man an der entsprechenden Stelle im Script einfach 
mal was ganz anderes, viel einfacheres macht, die betroffenen Dateien 
z.B. einfach nur stumpf umbenennt. Läuft dann das Script erwartungsgemäß 
durch, lohnt die Suche nach der ffmpeg-Lücke.

von foobar (Gast)


Lesenswert?

> Definitiv falsche Formulierung.

Quatsch. Umgebungsvariablen können von Kind-Prozessen nicht verändert 
werden. Punkt. Nicht gezielt über irgendwelche APIs oder zufällig über 
wildgewordene Programme.

Dazu kommt, dass es hier um lokale Variablen der Shell geht - davon weiß 
der Kindprozess nicht mal was.

Wenn du nun mit irgendwelchen Sicherheitslücken kommst, ist natürlich 
alles möglich. Müßig, darüber zu diskutieren ...

von BOFH-i18n (Gast)


Lesenswert?

foobar schrieb:
> d) Variablen kreuz und quer zu definieren und zu benutzen ist nicht die
> feine Englische - gibt immer mal Probleme. Besser ist es, Parameter
> explizit an Unterprogramme zu übergeben, z.B. <do_shasum "$pfn"> und
> dort dann $1 etc benutzen.

Ja klar! Da ich wie oben beschrieben solche Schlaufen häufig oft ad-hoc 
interaktiv direkt am shell-Prompt eingebe, sind normalerweise gar keine 
shell-Funktionen dazwischen.
Nun hat es mich eben kalt erwischt und ich musste irgendwie 
"Teile-und-Herrsche(-light)" anwenden: eben 'n paar simple Funktionen 
und nur mit den globalen Variablen.
Ich wollte da eben gerade nichts vergolden mit den normalen
good practices .

Die 3 Variablen (pfn/out/log) sind ja nicht kreuz und quer definiert: 
sie werden genau nur in den 2 Funktionen mit den 2 Schlaufenvarianten 
(welche nur zur EXOR-Verwendung gedacht sind) angelegt und pro 
Schlaufenduchlauf exakt nur 1x mit Werte besetzt, tiefer in der 
Aufrufverschachtelung werden sie ja nur noch gelesen.

c-hater schrieb:
> Der erste Schritt wäre aber natürlich, ffmpeg als Fehlerursache
> auszuschließen, indem man an der entsprechenden Stelle im Script einfach
> mal was ganz anderes, viel einfacheres macht, die betroffenen Dateien
> z.B. einfach nur stumpf umbenennt. Läuft dann das Script erwartungsgemäß
> durch, lohnt die Suche nach der ffmpeg-Lücke.

Zu genau diesem Zwecke ist die (Blendwerks-)Funktion do_shasum(): wird 
nur eine (beliebige) Prüfsumme berechnet anstelle von Audioformat 
umrechnen u. neue Datei anlegen so klappt es auch mit allen 
aufgefuehrten Schleifenvarianten.
Selbst das sammeln der stdout/stderr-Ausgaben in Logdateien ist nicht 
primaeres Ziel, das dient nur dazu die Ausgaben zu minimieren.

ffmpeg steht also schon im Aufmerksamkeitsfokus - ausser ich uebersehe 
eine Stein nicht, der so gross ist dass ich gar nicht darüber straucheln 
kann.

Sicherheitsluecke in ffmpeg? Ich will ja noch nicht wirklich an sowas 
glauben, stammt dies doch aus den ordinären package-repos von (L)ubuntu. 
Naja, auch diese kann's ja mal treffen...

Deswegen erst mal hier im uc.net-Forum abchecken.


Hier schon mal ein Fingerprint meines ffmpeg-Executables, das linkt aber 
noch gegen 9 libs welche dann auch noch zu untersuchen sind wenn dies 
die richtige Spur ist...
1
$ sha256sum $(which ffmpeg)
2
434c41a9b3ece7b217f475a87623996bb8a10ebe19d8dc0deadb4e427d43053a  /usr/bin/ffmpeg
3
$

In meinem Q'n'D-script fehlt auf Zeile 1 die shebang magic ,
wird also auch der richtige Interpreter angewendet?
Ich meine "JA": fuer mein Account steht /bin/bash als shell und Anlass 
der ganzen Untersuchung war ja dass der Fehler bereits beim eingeben des 
ganzen Schlaufenbefehls am Prompt passierte.
Etwas aus der Kat. simple sh o.Ä. wuerde ab den bash-ismen ( '[[', 
'-v', ...) spucken.
Das "Verpacken" in eine script-Datei ist nur ein Transporthilfsmittel 
für hierher ins Forum und um die Sache reproduzierbar zu persistieren.

Die Datenquelle  wma.pflist  habe ich vorgängig schon fluechtig mit 'cat 
-A' untersucht: damit fand ich bisher "immer" /offendingly encoded 
characters/ und hier fällt nichts auf.

von BOFH-i18n (Gast)


Lesenswert?

Immerhin: das Problem ist portabel und ich kann es exakt reproduzieren 
auf einer anderen, kleineren Maschine mit neuerer SW: Lubuntu 18.04.1 
LTS (Linux 4.15.0-34-generic, i686) [1]
bash:    4.4.19(1)-release
ffmpeg:  3.4.4-0ubuntu0.18.04.1
1
$ sha256sum $(which ffmpeg)
2
60681c501faf77e018056ae9293171d40554da32371094d571cbe6d54f55be05  /usr/bin/ffmpeg
3
$


[1] die erste maschine ist x86_64, diese Angabe fehlt im Eröffnungspost

von foobar (Gast)


Lesenswert?

Ich vermute das Problem eher vor der Tastatur ...

von foobar (Gast)


Lesenswert?

Pack in den ffmpeg-Aufruf mal nen "-nostdin" ...

von BOFH-i18n (Gast)


Lesenswert?

foobar schrieb:
> Ich vermute das Problem eher vor der Tastatur ...

Das will ich überhaupt nicht ausschliessen, genau deshalb meine Anfrage 
hier :-)

foobar schrieb:
> Pack in den ffmpeg-Aufruf mal nen "-nostdin" ...

Danke fuer diesen Hinweis: soeben ausprobiert, hilft leider nicht.

von BOFH-i18n (Gast)


Lesenswert?

BOFH-i18n schrieb:
> foobar schrieb:
>> Pack in den ffmpeg-Aufruf mal nen "-nostdin" ...
>
> Danke fuer diesen Hinweis: soeben ausprobiert, hilft leider nicht.

Kommando zurück!  -nostdin  hilft schon, so ich es richtig 
einsetzte...

> foobar schrieb:
>> Ich vermute das Problem eher vor der Tastatur ...
>
> Das will ich überhaupt nicht ausschliessen, genau deshalb meine Anfrage
> hier :-)

Q.E.D.  :-D


LÖSUNG

bei ffmpeg in scripts  -nostdin  verwenden.

Klingt komisch, ist aber so.


Danke an foobar fuer den entscheidenden Tipp: hat beim weitergoogeln 
sehr geholfen 
https://www.google.com/search?q=ffmpeg++shell+loop+variables

NB: FUBAR=FuckedUpBeyondAllRepair --> "foobar" vllt. nicht der beste 
Nick...

von foobar (Gast)


Lesenswert?

> NB: FUBAR=FuckedUpBeyondAllRepair --> "foobar" vllt. nicht der
> beste Nick...

Doch, passt schon ;-)

https://en.wikipedia.org/wiki/Foobar

 "Not to be confused with FUBAR."

von Εrnst B. (ernst)


Lesenswert?

Übrigens: Dateinamen können auch "\n" enthalten, mit Leerzeichen 
beginnen oder enden. Alles Sachen an denen sich deine 
"Defensiv"-Variante verschlucken könnte.

> touch $'Hallo\nWelt.wma'

Sicherer ist z.B.
> find ... -exec irgendwas '{}' \;
oder
> find ... -print0 | xargs -0r -n1 irgendwas


ersteres setzt die bösen Dateinamen direkt in's ARGV von irgendwas 
ein, die zweite Zeile schreibt sie NULL-Terminiert auf STDOUT, '\0x00' 
ist kein gültiger Dateinamensbestandteil, xargs -0 liest 0-terminierte 
Strings und kriegt so die original-Dateinamen.

ich persönlich mag die xargs-Variante am liebsten, da kann man mit 
"-P 16" auch ganz einfach ein paar CPU-Kerne mehr auslasten...

Was du versuchen könntest, ohne viel umzustellen:
> find ... -print0 | while read -d $'\000' f

bin mir aber nicht sicher wie portabel das ist, und ob es wirklich alle 
Fälle abdeckt.

: Bearbeitet durch User
von foobar (Gast)


Lesenswert?

Da öffnest du die berüchtigte "Can of Worms". Wenn's nach mir ginge, 
wären Steuerzeichen in Dateinamen längst verboten. Wer mehr dazu lesen 
möchte, dem empfehle ich u.a.:

  https://www.dwheeler.com/essays/fixing-unix-linux-filenames.html

von bastel_ (Gast)


Lesenswert?

Interessanter Link. Das mit dem IFS haben wir schon im Studium Ende der 
90er gelernt, ich wende schon immer
IFS="
"
an, wenn ich for Schleifen über Dateinamen machen muss, damit ging es 
dann meistens. Dachte das ist was ganz olles (ist es) und bekanntes, 
deswegen hab ich mich gar nicht getraut das hier zu erwähnen, aber im 
Artikel steht das wäre recht unbekannt. Komisch.

Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.