Aussehen
Suche Einloggen
[c] [meta] [fefe] [erp]

/meta/ – Diskussionen über Dietchan


Antwort erstellen

(≤ 4)



[Zurück]

  • [l] Das neuste Produkt aus der Zuse KG Forschungsabteilung Zuse ## Admin Sat, 22 Nov 2025 13:53:18 GMT Nr. 160382
    PNG 448×442 1.9k
    PNG 385×489 23.5k
    So, nun ist es endlich soweit, und wir können unser neuestes Projekt vorstellen: SecMagick [0]. Ein seccomp-Kondom für ImageMagick. Längst überfällig.

    Dass ImageMagick immer wieder unter chronisches CVEs leidet, ist ja kein Geheimnis. Deshalb hatte ich schon länger vor, da mal was zu machen, und nun ist es endlich soweit. Ich habe schon in der Readme und dem zugehörigen Merge-Request in dietchan dazu geschrieben, deshalb erspare ich es mir, das alles noch mal zu wiederholen.

    SecMagick ist als Drop-In-Replacement gedacht, aber es kann naturgemäß nicht 100% kompatibel sein. Zumindest für Dietchan sollte es im Prinzip aber ohne Änderung funktionieren und lokale Tests haben das bisher auch bestätigt. Wir werden das hier in der nächsten Zeit mal hier auf dietchan.org in der Produktion testen.

    Also macht mal ruhig nen Zufallsbilderfaden oder so und testet verschiedene Dateien und Dateiformate, um zu schauen, ob irgendwas kaputt ist.

    Fände es auch spannend, was ihr allgemein davon haltet.

    Diese Daumennägel wurden ihnen prästentiert von SecMagick!

    [0] https://gitgud.io/zuse/secmagick
    [1] https://gitgud.io/zuse/dietchan/-/merge_requests/3
  • [l] Felix Sat, 22 Nov 2025 17:06:40 GMT Nr. 160387
    JPG 2048×2048 474.1k
    Sehr, sehr interessant.

    >
    identify

    >BMP, GIF, ICC (color profiles), JPEG, PNG, TGA
    Felix hat sich schon immer gefragt, ob man diese Dateiformate nicht in 3-40 Dutzend Zeilen selbst identifizieren könnte und auch Höhe/Breite sich selbst rausziehen könnte. Schließlich haben sie alle, bis auf TGA, magische Header, womit zumindest die Identifikation nur ein paar passende memcmps wäre.

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

    TGA hat statt einem magischen Header einen magischen Footer, der allerdings optional ist:
    https://en.wikipedia.org/wiki/Truevision_TGA#File_footer_(optional)

    Wobei ImageMagick bei TGA selbst Probleme hat:
    https://github.com/ImageMagick/ImageMagick/issues/834

    Was "braucht" eigentlich ein Bilderbrett an Informationen? Dateityp und Höhe/Breite?
    Klar, fürs Daumennageln braucht es mehr Informationen (u.A. Farbraum), aber das wäre dann nicht mehr identify.

    >Sidenode: Strangely, the images produced by SecMagick and regular ImageMagick are not always 100% bit-identical and tend to differ in file size by only a few bytes with no noticeable pattern. Visually, the outputs look identical at least to my eyes. I am baffed as to why that is, as in theory they should be the same. If you have any clue, let me know.
    Felix weiß auch nicht, aber Felixens Vorgehensweise wäre, möglichst einfache Testfälle (2x2 Bild mit Schwarz, Graustufen, 100% R/G/B-Farben, etc.) zu basteln, und zu schauen, ab wann die ersten Unterschiede auftauchen. Dann mit dem Debugger reinspringen und durchsteppen. Letzteres dann auch im normalen ImageMagick ebenso machen, und schauen, wann man Unterschiede in den Variablenwerten sieht. Und dann hart nachdenken, oder so. Das wäre jedenfalls Felixens Vorgehensweise, erst mal Komplexitätsreduktion vor dem Debuggen.

    >What I'm less sure about is whether the current solution will work on all x86_64 distributions or if it depends on particular linker or compiler options.
    Man kann auf Gentoo auch (die meisten Pakete) statisch linken, da wäre dann eine Grenze erreicht. :)

    Auch: Diätkanal in Fil-C wann? Schließlich lüftet djb bereits Fil-C.
  • [l] Zuse ## Admin Sat, 22 Nov 2025 18:50:58 GMT Nr. 160393
    >>160387
    Der MIME-Typ wird bereits vorher identifiziert via file (also das Unix-Programm... welches einen wirklich blöden Namen hat, absolut ungooglebar. Benutzt übrigens selbst auch eine seccomp-Sandkiste, wie restriktiv die ist, weiß ich allerdings nicht) oder, für Archivformate, unser eigenes Werkzeug (in src/archiveinfo), das auf libarchive aufbaut und ebenfalls seccomp verwendet, weil file zum Dekomprimieren sonst externe Programme aufrufen müsste, was die seccomp-Sandbox ausschaltet (ich glaube, deshalb war das notwendig). [0] (Also file könnte also beispielsweise zwar ein tar erkennen, aber kein tar.gz, ohne ein externes Programm aufzurufen.)

    Der magick identify-Befehl dient tatsächlich eigentlich nur dazu, die Dimensionen des Bildes auszulesen [1]. Wobei die gleiche Dietchan-Funktion die Informationen für alle Dateitypen parst, also auch z.B. die Länge bei Video- und Audiodateien; das Ausgabeformat der aufgerufenen Programme wird einfach entsprechend angepasst, sodass es immer gleich ist. Da identify Bestandteil von ImageMagick ist, war es naheliegend, die dort vorhandene Funktionalität zu benutzen statt die Formate auch noch selbst zu parsen. Für das reine Parsen könnte man übrigens ggf. auch wuffs nehmen [2], zumindest teilweise – es unterstützte zumindest anfangs einige Features nicht, wie z.B. progressive JPEGs, aber zumindest das wurde, glaube ich, mittlerweile nachgerüstet –, aber zum Daumennagelgenerieren braucht man ja noch weiteres: Resampler, Farbräume, Meta-Daten-Parser (Bildorientierung auslesen bei Fotos etc.) und natürlich Code, um das Ergebnis zu schreiben, was wuffs, soweit ich weiß, bisher gar nicht unterstützt, zumindest nicht für Bildformate (ich glaube, es kann JSON in CBOR umwandeln und sowas, aber keine Bildformate).

    >Felix weiß auch nicht, aber Felixens Vorgehensweise wäre, möglichst einfache Testfälle (2x2 Bild mit Schwarz, Graustufen, 100% R/G/B-Farben, etc.) zu basteln, und zu schauen, ab wann die ersten Unterschiede auftauchen.
    Ja könnte man, allerdings ist es für mich nicht wirklich so kritisch, dass ich den Aufwand investieren wollen würde, solange etwas vernünftiges herauskommt. Die Ergbenisse sind weder offensichtlich falsch noch allgemein schlechter oder besser. Manchmal sind unsere Dateien ein paar Bytes kleiner bei gleicher subjektiver Qualität, manchmal ein paar Bytes größer.

    Es ist einfach nur seltsam, weil der Code ja entweder die Funktionen von ImageMagick verwendet oder Reimplementierungen davon, die im Grunde kopierpastetet wurden und nur geringfügig angepasst und vereinfacht (z.B. sind unsere Streams immer seekable... bei ImageMagick nicht, aber effektiv müssen sie sowieso für so ziemlich alles seekable sein, weshalb es im Originalkot drölftausend Stellen gibt, an denen geprüft wird, ob ein Stream (bzw. "Blob" im IM-Lingo) seekable ist und dann ggf. seekable gemacht wird durch Anlegen einer temporären Datei. Es würde mich nicht mal wundern, wenn daher der Unterschied kommt, weil der Originalcode einfach überall verstreut und dupliziert zig Sonderfälle hat.

    Der ImageMagick-Kot ist allgemein die Hölle. Voll von Copy&Paste, so hat jedes CLI-Frontend wie convert, mogrify (was auch immer das heißen soll), identify und die drölfzig anderen Varianten im wesentlichen den identischen, tausende Zeilen langen Kot, nur um die Kommandozeilenargumente zu parsen (bzw. zu Überspringen... selbst parsen kann es sie nicht, dafür ist wieder ein anderer Teil zu ständig). Sind dabei auch noch inkonsequent, weil anscheinend immer mal wieder irgendwer hier oder da einen Bug gefixt hat, aber vergessen hat, es bei den anderen Dateien nachzupflegen. Ich hab das direkt mal vereinfacht, indem ich alle Optionen in eine Tabelle [4] gepackt habe und jetzt nur noch eine Funktion habe, die die Optionen parst. Der resultierende Kot ist kürzer als der Originalkot für auch nur eines der Frontends. Zum Vergleich, so [5] sieht das im Original aus. Und für jeden einzelnen Befehl dupliziert. m(

    Verwendet außerdem nichtssagende Beriffe wie mogrify, conjure etc., verwendet seine eigenen, komischen Begriffe Blob statt etablierten Begriffen wie Stream, hat seinen eigenen Boolean-Type, der ein Enum ist und der ganze Kot ist voll von if (x != MagickFalse), if (x == MagickTrue) etc.. Außerdem konnten sie sich nicht entscheiden, ob MagickTrue Erfolg signalisiert oder einen Fehler. Es ist bei jeder Funktion anders und es ist nicht dokumentiert. Die Kommentare lügen außerdem häufig, sind an den falschen Stellen platziert, weil zwischenzeitlich neue Funktionen eingefügt wurden...

    Der ImageMagick-Kot gehört so mit zu dem schlimmsten, den ich je gesehen habe. Was den Code für das Parsen von Optionen angeht, der sieht in etwa aus wie Bild relatiert, und wie gesagt, in mehreren Dateien dupliziert (bis auf minimale, wahrscheinlich unabsichtliche Unterschiede). Man will sich die Augen ausstechen. Man erkennt auch sofort, in welcher Ära der Kot ursprünglich geschrieben wurde, aber das ist keine Entschuldigung. Wenn man den Kot gesehen hat, wundert man sich nicht mehr darüber, dass das Ding ständig neue Sicherheitslücken hat.

    >TGA hat statt einem magischen Header einen magischen Footer, der allerdings optional ist:
    >https://en.wikipedia.org/wiki/Truevision_TGA#File_footer_(optional)
    Spaßfakt: TGA brauchen wir eigentlich nur, weil unsere Captcha-Implementierung TGA ausgibt. Genau deshalb, weil TGA so schön minimalistisch war. Aber ausliefern will man das dem Klient natürlich nicht, also wird es vorher von ImageMagick in PNG umgewandelt.

    >Auch: Diätkanal in Fil-C wann? Schließlich lüftet djb bereits Fil-C.
    Wenn du das kompiliert bekommst... kannst es ja mal probieren. Bezweifel aber, dass es funktioniert. Mit dietlibc auf jeden Fall nicht, denn dietlibc unterstützt noch nicht einmal Clang. Habe mich damit ehrlich gesagt bisher mit Fil-C noch nicht beschäftigt. Bin aber auch nicht sicher, ob das funktionieren würde, so wie unsere Datenbank funktioniert, die ja im Grunde eigentlich nur ein gemapptes Speicherabbild mit zusätzlichen Journal ist. Fil-C hat doch irgendwelche Garbage Collection oder so? Ist mir nicht klar, wie das funktionieren würde.

    >Man kann auf Gentoo auch (die meisten Pakete) statisch linken, da wäre dann eine Grenze erreicht. :)
    Ja gut, das ginge dann definitiv nicht. Wobei in diesem speziellen Fall der von Verfechtern des dynamischen Linkens angeführte Vorteil, nämlich dass man automatisch Sicherheitsupdates bekommt, ohne seinen eigenen Kot rekompilieren bzw. neu linken zu müssen, vielleicht sogar nicht ganz unberechtigt ist. Also ich installiere gefühlt jede Woche eine neue ImageMagick-Version mit Bugfixes. Ich kompiliere mein Dietchan aber nicht so oft. Und ich finde es ganz praktisch, dass ich automatisch die Updates bekomme (da die ganze Verarbeitung ja als neuer Hintergrundprozess gespawnt wird).

    Durch den Sandkasten sollten die Bugs zwar jetzt eigentlich keinen Schaden mehr anrichten können, selbst wenn sie vorhanden sind, aber man nimmt die Fixes ja trotzdem gerne mit.

    [0] https://gitgud.io/zuse/dietchan/-/blob/7e38a3ef6a740d21e3ba4689ae01c7689d87c934/src/dietchan/upload_job.c#L180
    [1] https://gitgud.io/zuse/dietchan/-/blob/7e38a3ef6a740d21e3ba4689ae01c7689d87c934/src/dietchan/upload_job.c#L455
    [2] https://blog.fefe.de/?q=wuffs
    [3] https://gitgud.io/zuse/secmagick/-/blob/master/common/options.c?ref_type=heads#L49
    [5] https://github.com/ImageMagick/ImageMagick/blob/9c0546a6e2c3512ebfdcc94f6bedfd45977bc9b3/MagickWand/mogrify.c#L56
  • [l] Copy-Paste-Fersagen Felix ## Admin Sat, 22 Nov 2025 19:36:47 GMT Nr. 160394 SÄGE
    >[5] https://github.com/ImageMagick/ImageMagick/blob/9c0546a6e2c3512ebfdcc94f6bedfd45977bc9b3/MagickWand/mogrify.c#L56
    <[5] https://github.com/ImageMagick/ImageMagick/blob/9c0546a6e2c3512ebfdcc94f6bedfd45977bc9b3/MagickWand/mogrify.c#L566
  • [l] Felix Sun, 23 Nov 2025 10:22:14 GMT Nr. 160526
    JPG 7455×7565 3.0M
    Also einen Fehler hab ich schon: Could not process Greta2.jpg
  • [l] Felix Sun, 23 Nov 2025 10:30:05 GMT Nr. 160529
    PNG 5140×3600 3.6M
    >>160526
    das hatte ich zusammen mit cockopter_downsize.jpg hochladen wollen:

    >Could not process file: >Cockopter_downsize.jpg
    >Corrupt file?

    Erst sagte es das über Greta2.jpg, nachdem ich Greta2.jpg rausgenommen habe, über Cockopter_downsize.jpg.

    Wenn ich nur Cockopter_downsize.jpg pfostieren will, bekomme ich die Fehlermeldung auch. Liegt also definitiv an Cockopter_downsize.jpg - die png-Version funktioniert, aber die ist nur 3.3MB oder so.

    Metadaten von Cockopter_downsize.jpg:
    exiftool EC/Cockopter_downsize.jpg
    ExifTool Version Number         : 13.36
    File Name                       : Cockopter_downsize.jpg
    Directory                       : EC
    File Size                       : 9.9 MB
    File Modification Date/Time     : 2024:08:01 11:39:57+02:00
    File Access Date/Time           : 2025:11:23 11:20:38+01:00
    File Inode Change Date/Time     : 2024:08:01 11:39:57+02:00
    File Permissions                : -rwxr-xr-x
    File Type                       : JPEG
    File Type Extension             : jpg
    MIME Type                       : image/jpeg
    JFIF Version                    : 1.01
    Resolution Unit                 : cm
    X Resolution                    : 236
    Y Resolution                    : 236
    Image Width                     : 22102
    Image Height                    : 15480
    Encoding Process                : Baseline DCT, Huffman coding
    Bits Per Sample                 : 8
    Color Components                : 3
    Y Cb Cr Sub Sampling            : YCbCr4:4:4 (1 1)
    Image Size                      : 22102x15480
    Megapixels                      : 342.1
    


    Eventuell hat dein Tool noch Probleme mit niedriger Auflösung? Ich würde es ja upscalen, um das zu testen, aber dann bekomme ich Probleme mit der maximalen Dateigrösse.

  • [l] Zuse ## Admin Sun, 23 Nov 2025 11:35:47 GMT Nr. 160596
    WEBM 750×500 1:02 6.6M
    >>160526
    >>160529
    Aber einzeln gehen sie, habe ich das richtig verstanden?

    Hmm, die Bilder haben beide eine recht hohe Auflösung. Vermutlich ist der RAM des Diätkanal-Servierers zu niedrig dimensioniert, um beide parallel zu verarbeiten? Diätkanal läuft auf einer Kartoffel.

    ImageMagick erzeugt manchmal ziemlichen RAM-Bloat, das ist mir früher schon aufgefallen. Mit einigen Schirmschüssen von langen Fäden gab es in der Vergangenheit auch schon Probleme. Denke daher, dass das mit normalem ImageMagick auch passiert wäre.
  • [l] Felix Sun, 23 Nov 2025 11:38:17 GMT Nr. 160597
    >>160596
    Nein, einzeln geht tatsächlich nur das Greta2.jpg, das Cockopter_diwnsized.jpg lässt sich tatsächlich auch einzeln nicht pfostieren. Es ist antürlich ein Extremfall, 9,9MB und 22k x 15k Pixel oder so. Ich bin mir nicht mal sicher, ob ImageMagick selbst damit klar kam.
  • [l] Zuse ## Admin Sun, 23 Nov 2025 11:42:37 GMT Nr. 160598
    >>160597
    >22k x 15k Pixel
    Taschenrechner sagt, das wären unkomprimiert bei 4 Farbkanälen und 8 Bit pro Kanal 1,32 GB. Das ist definitiv zu viel für den Servierer. Der Servierer hat nur 1 GB RAM insgesamt (seit kurzem sogar nur noch 950 MB... keine Ahnung, ob der Hoster uns bescheißt oder ob eine neue Kernel-Version irgendwas komisches macht) und 500 MB Swap.
  • [l] Felix Sun, 23 Nov 2025 11:46:24 GMT Nr. 160599
    >>160598
    Deshalb die Metadaten zum Debuggen in >>160529. da steht was von 3 Farbkanälen, 8 Bit je Kanal - da komme ich nur auf etwa 987 MB - sollte also locker in den RAM passen!1!
  • [l] Zuse ## Admin Sun, 23 Nov 2025 11:53:51 GMT Nr. 160600
    >>160599
    Jetzt, wo du es sagst, ich glaube, der JPEG-Codec hatte tatsächlich so ein Feature, um JPEGs mit geringerer Auflösung zu dekodieren als sie gespeichert sind, dazu diente nämlich mal das "-define jpeg:size=" hier [0]. Also entweder das ist irgendwie durch die Änderungen kaputt gegangen... oder es war schon seit längerer Zeit in ImageMagick kaputt. Müsste man mal überprüfen.

    [0] https://gitgud.io/zuse/dietchan/-/blob/master/src/dietchan/upload_job.c?ref_type=heads#L540
  • [l] Zuse ## Admin Sun, 23 Nov 2025 12:04:14 GMT Nr. 160602
    PNG 1080×1370 735.3k
    >>160599
    >>160600
    Ich habe mal kurz die Config so geändert, dass wieder das normale ImageMagick verwendet wird. Kannst du die gleichen Dateien noch mal pfostieren und schauen, ob es jetzt geht? Ist zwar kein 100%-ig exakter Test, wenn es ein OOM-Kill war, aber es wäre zumindest hilfreich als erster Indikator. Wenn das Problem im originalen ImageMagick auch besteht, dann wäre es auf jeden Fall ein WONTFIX.
  • [l] Felix Sun, 23 Nov 2025 12:54:40 GMT Nr. 160603
    JPG 367×343 16.6k
    >>160602
    Gerade probiert, geht trotzdem nicht:
    >Fehler
    >Could not process file: >Cockopter_downsize.jpg
    >Corrupt file?

    Klingt so, als ob es da einen Bugreport an Imagemagick braucht! :)
  • [l] Zuse ## Admin Sun, 23 Nov 2025 13:02:22 GMT Nr. 160604
    PNG 505×643 261.5k
    >>160603
    Puh, noch mal Glück gehabt. Ok, dann änder ich die Config jetzt wieder zurück. Danke fürs erneute Testen :)
  • [l] Zuse ## Admin Sun, 23 Nov 2025 13:19:35 GMT Nr. 160607
    JPG 977×1488 156.0k
    JPG 480×360 14.4k
    Spaßfakt: Ich habe hier gerade so ein bisschen ein Deja Vu. Ich hatte nämlich mal vor mehreren Jahren spaßeshalber versucht, Dietchan auf einem sehr schwach ausgestatteten OpenWrt-Router laufen zu lassen. Ging im Prinzip auch, bis auf genau dieses Problem mit JPEGs, die extrem viel Arbeitsspeicher verschlungen, obwohl sie es nicht hätten sollen. Mit GraphicsMagick statt ImageMagick ging es dann. Das Problem besteht also vermutlich schon länger. Deswegen hatte ich das auch noch irgendwie dunkel im Hinterkopf.

    GraphicsMagick scheint auch insgesamt weniger bloatig zu sein und deutlich weniger CVEs zu haben (allerdings bin ich mir nicht sicher, ob das einfach nur daran liegt, dass es weniger bekannt ist). Es hat gegenüber ImageMagick nur einen Haken: Es kann nicht inzu das kühle -define jpeg:extent=20kb: Genau das Feature, das mir so wichtig war, dass ich mir dafür sogar den ganzen Aufwand mit den ELF-Hooks eingebrockt habe >:(

    Du kannst nie beides haben.
  • [l] Zuse ## Admin Sun, 23 Nov 2025 14:51:20 GMT Nr. 160610
    Sehe gerade, der Durchlauf mit regulärem ImageMagick hat ein paar interessante Einträge ins Log gelegt:

    Nov 23 12:46:20 [...] Started job 120520 (file --mime-type --brief -k -r ./www/uploads/.tmpXXXXXXXXXX || file --mime-type --brief ./www/uploads/.tmpXXXXXXXXXX)
    Nov 23 12:46:20 [...] Exited job 120520
    Nov 23 12:46:20 [...] Started job 120522 ( identify -format 'width=%w\nheight=%h\n' ./www/uploads/.tmpXXXXXXXXXX)
    Nov 23 12:46:20 [...] Finalized job 120520
    Nov 23 12:46:21 [...] identify: unable to write pixel cache '/tmp/magick-DWzu3lRFYVtw4o1vt6wPt5rxJhhrrDd3': No space left on device @ error/cache.c/WritePixelCachePixels/5984.
    Nov 23 12:46:21 [...] identify: Application transferred too few scanlines `./www/uploads/.tmpXXXXXXXXXX' @ warning/jpeg.c/JPEGErrorHandler/353.
    Nov 23 12:46:21 [...] Exited job 120522
    Nov 23 12:46:21 [...] Finalized job 120522
    Nov 23 12:47:31 [...] Started job 120534 (file --mime-type --brief -k -r ./www/uploads/.tmpYYYYYYYYYY || file --mime-type --brief ./www/uploads/.tmpYYYYYYYYYY)
    Nov 23 12:47:31 [...] Exited job 120534
    Nov 23 12:47:31 [...] Started job 120536 ( identify -format 'width=%w\nheight=%h\n' ./www/uploads/.tmpYYYYYYYYYY)
    Nov 23 12:47:31 [...] Finalized job 120534
    Nov 23 12:47:32 [...] identify: unable to write pixel cache '/tmp/magick-xmgFrqR6m5uVDpaEgDvA2oBkMw9sjfBo': No space left on device @ error/cache.c/WritePixelCachePixels/5984.
    Nov 23 12:47:32 [...] identify: Application transferred too few scanlines `./www/uploads/.tmpYYYYYYYYYY' @ warning/jpeg.c/JPEGErrorHandler/353.
    


    Es ist also nicht mal der convert-Befehl, der fehlschlägt, sondern der identify-Befehl. Warum zum Fick dekodiert der das ganze Bild Pixel für Pixel in eine temporäre Datei, nur um die Höhe und die Breite festzustellen? m(
  • [l] Felix Sun, 23 Nov 2025 16:56:14 GMT Nr. 160612
    JPG 608×608 62.4k
    JPG 992×1560 255.2k
    >>160602
    >Ist zwar kein 100%-ig exakter Test, wenn es ein OOM-Kill war, aber es wäre zumindest hilfreich als erster Indikator.
    Das mit dem OOM-Kill würde für Felix etwas anderes erklären: Felix hat mal ein 10033x6858-JPEG-Bild hochladen wollen, und dann kam "Softwarefehler, kann man nichts machen.". Also dauerhaft, egal welche Seite man aufrufen wollte. Felix hat also an dem Tag den Diätkanal für alle karpott gemacht. Felix vermutet, dass der OOM-Killer etwas übereifrig war, und zuerst den Diätkanal-Prozess und dann den ImageMagick-Prozess abgeschossen hat.

    >
    /proc/<pid>/oom_score_adj

    >The lowest possible value, -1000, is equivalent to disabling OOM-killing entirely for that task, since it will always report a badness score of 0.

    NUTZFALL für einen abgeschossenen Diätkanal-Prozess??

    >>160610
    >Es ist also nicht mal der convert-Befehl, der fehlschlägt, sondern der identify-Befehl. Warum zum Fick dekodiert der das ganze Bild Pixel für Pixel in eine temporäre Datei, nur um die Höhe und die Breite festzustellen? m(
    Zuse, ich habs dir doch gesagt! Ich hab dich vor identify gewarnt! Weichwaren-Komplexität kommt immer wieder rein, nur selber schreiben macht frei. Ich habs dir gesagt!
  • [l] Zuse ## Admin Sun, 23 Nov 2025 17:24:37 GMT Nr. 160614
    JPG 250×250 16.4k
    >>160612
    >Das mit dem OOM-Kill würde für Felix etwas anderes erklären: Felix hat mal ein 10033x6858-JPEG-Bild hochladen wollen, und dann kam "Softwarefehler, kann man nichts machen.". Also dauerhaft, egal welche Seite man aufrufen wollte. Felix hat also an dem Tag den Diätkanal für alle karpott gemacht. Felix vermutet, dass der OOM-Killer etwas übereifrig war, und zuerst den Diätkanal-Prozess und dann den ImageMagick-Prozess abgeschossen hat.
    Ja, ich erinnere mich. Das ist in etwa, was passiert war, nur leicht anders: Systemd hat die merkwürdige Voreinstellung, dass es gleich den ganzen Service abschießt, wenn auch nur einer der Prozesse in seiner Gruppe einen OOM-Kill bekommt, wie ich an jenem Tag lernte.

    Die Lösung für dieses Problem ist OOMPolicy=continue:

    [Unit]
    Description=Dietchan
    
    [Service]
    ExecStart=/blabla/dietchan -l blubb
    OOMPolicy=continue
    


    Warum das nicht der Standard ist, musst du Lennart fragen.
  • [l] Felix Mon, 24 Nov 2025 16:07:04 GMT Nr. 160623
    JPG 914×963 209.3k
    >>160614
    Nochmal zu:
    >Es ist also nicht mal der convert-Befehl, der fehlschlägt, sondern der identify-Befehl. Warum zum Fick dekodiert der das ganze Bild Pixel für Pixel in eine temporäre Datei, nur um die Höhe und die Breite festzustellen? m(

    Der gleiche Felix möchte dazu noch anmerken, dass wenn man das identify selbst implementiert, man die Möglichkeit hätte, bei danach fehlschlagender Daumennagel-Generierung stattdessen ein Symbolbild "DAUMENNAGEL NICHT VERFÜGBAR" als Daumennagel zu verwenden. Damit könnte man dann Diätkanal auch problemfrei auf dem kleinsten Gurken-Rechner von Linode betreiben. (Zumindest solange, wie ffprobe und pdfinfo nicht auch noch Probleme machen.)

    Wie schwer kann es schon sein?
  • [l] Zuse ## Admin Mon, 24 Nov 2025 16:36:30 GMT Nr. 160624
    JPG 888×550 129.5k
    >>160623
    Nur zu. Selbst ist der Mann. Es ist aber auch anzumerken, dass das vor sieben Jahren, als der Kanal programmiert wurde, alles noch wunderbar funktionierte. Seitdem hat es in ImageMagick offenbar eine Regression gegeben und es wäre schön, wenn die mal behoben würde.
  • [l] Felix Mon, 24 Nov 2025 16:38:48 GMT Nr. 160625
    >>160623
    Pro-Tipp: ChatGPT kann da bei der Code-Erstellung helfen.

    Als kleiner Starter, von ChatGPT generiert:
    #include <stdio.h>
    #include <stdint.h>
    #include <string.h>
    
    void identify_png(FILE *f) {
        uint8_t header[8];
        fread(header, 1, 8, f);
        if (memcmp(header, "\x89PNG\r\n\x1a\n", 8)) {
            printf("Not a PNG\n");
            return;
        }
        fseek(f, 8, SEEK_SET); // skip signature
    
        uint8_t chunk[25]; // IHDR is 25 bytes including length/type/CRC
        fread(chunk, 1, 25, f);
        if (memcmp(chunk+4, "IHDR", 4)) {
            printf("No IHDR chunk\n");
            return;
        }
    
        uint32_t width = (chunk[8]<<24)|(chunk[9]<<16)|(chunk[10]<<8)|chunk[11];
        uint32_t height = (chunk[12]<<24)|(chunk[13]<<16)|(chunk[14]<<8)|chunk[15];
        uint8_t bit_depth = chunk[16];
        uint8_t color_type = chunk[17];
    
        printf("PNG %ux%u %u-bit color_type %u\n", width, height, bit_depth, color_type);
    }
    
    void identify_jpeg(FILE *f) {
        uint8_t buf[2];
        fread(buf, 1, 2, f);
        if (buf[0] != 0xFF || buf[1] != 0xD8) {
            printf("Not a JPEG\n");
            return;
        }
    
        while (1) {
            if (fread(buf, 1, 2, f) != 2) break;
            if (buf[0] != 0xFF) continue;
            uint8_t marker = buf[1];
    
            if (marker >= 0xC0 && marker <= 0xC3) { // SOF markers
                fseek(f, 3, SEEK_CUR);
                uint8_t dim[4];
                fread(dim, 1, 4, f);
                uint16_t height = (dim[0]<<8)|dim[1];
                uint16_t width  = (dim[2]<<8)|dim[3];
                printf("JPEG %ux%u\n", width, height);
                return;
            } else {
                uint8_t size_buf[2];
                fread(size_buf,1,2,f);
                uint16_t size = (size_buf[0]<<8)|size_buf[1];
                fseek(f, size-2, SEEK_CUR);
            }
        }
        printf("JPEG dimensions not found\n");
    }
    
    int main(int argc, char **argv) {
        if (argc < 2) {
            printf("Usage: %s <image>\n", argv[0]);
            return 1;
        }
    
        FILE *f = fopen(argv[1], "rb");
        if (!f) { perror("fopen"); return 1; }
    
        uint8_t sig[8];
        fread(sig, 1, 8, f);
        fseek(f, 0, SEEK_SET);
    
        if (!memcmp(sig, "\x89PNG\r\n\x1a\n", 8))
            identify_png(f);
        else if (sig[0]==0xFF && sig[1]==0xD8)
            identify_jpeg(f);
        else
            printf("Unsupported format\n");
    
        fclose(f);
        return 0;
    }
    


    Getestet, funktioniert - auch wenn es nicht 1:1 das Output von identify ist.
  • [l] Zuse ## Admin Mon, 24 Nov 2025 16:45:12 GMT Nr. 160626 SÄGE
    >>160625
    <Proudly made without AI
    Abgelehnt.
  • [l] Felix Mon, 24 Nov 2025 16:53:30 GMT Nr. 160627
    >>160626
    >Abgelehnt
    Och menno!

    Dabei hab ich es jetzt schon extra auf alle möglichen Bildformate und 1:1 Ausgabe wie von identify angepasst:

    #include <stdio.h>
    #include <stdint.h>
    #include <string.h>
    #include <sys/stat.h>
    
    typedef struct { uint32_t w,h; uint8_t depth; int channels; char format[16]; } ImgMeta;
    
    // --- PNG ---
    int identify_png(FILE *f, ImgMeta *meta){
        uint8_t buf[25];
        fseek(f,8,SEEK_SET);
        fread(buf,1,25,f);
        if(memcmp(buf+4,"IHDR",4)) return 0;
        meta->w = (buf[8]<<24)|(buf[9]<<16)|(buf[10]<<8)|buf[11];
        meta->h = (buf[12]<<24)|(buf[13]<<16)|(buf[14]<<8)|buf[15];
        meta->depth = buf[16];
        switch(buf[17]){
            case 0: meta->channels=1; break; // grayscale
            case 2: meta->channels=3; break; // RGB
            case 3: meta->channels=1; break; // palette
            case 4: meta->channels=2; break; // grayscale+alpha
            case 6: meta->channels=4; break; // RGBA
            default: meta->channels=3;
        }
        strcpy(meta->format,"PNG");
        return 1;
    }
    
    // --- JPEG ---
    int identify_jpeg(FILE *f, ImgMeta *meta){
        uint8_t buf[2];
        fseek(f,0,SEEK_SET);
        fread(buf,1,2,f);
        if(buf[0]!=0xFF || buf[1]!=0xD8) return 0;
        while(1){
            if(fread(buf,1,2,f)!=2) break;
            if(buf[0]!=0xFF) continue;
            uint8_t marker = buf[1];
            if(marker>=0xC0 && marker<=0xC3){
                fseek(f,3,SEEK_CUR);
                uint8_t dim[4];
                fread(dim,1,4,f);
                meta->h=(dim[0]<<8)|dim[1];
                meta->w=(dim[2]<<8)|dim[3];
                meta->depth=8;
                meta->channels=3;
                strcpy(meta->format,"JPEG");
                return 1;
            } else {
                uint8_t sz[2];
                fread(sz,1,2,f);
                uint16_t size=(sz[0]<<8)|sz[1];
                fseek(f,size-2,SEEK_CUR);
            }
        }
        return 0;
    }
    
    // --- BMP ---
    int identify_bmp(FILE *f, ImgMeta *meta){
        uint8_t hdr[26];
        fseek(f,0,SEEK_SET);
        fread(hdr,1,26,f);
        if(hdr[0]!='B'||hdr[1]!='M') return 0;
        meta->w = hdr[18]|(hdr[19]<<8)|(hdr[20]<<16)|(hdr[21]<<24);
        meta->h = hdr[22]|(hdr[23]<<8)|(hdr[24]<<16)|(hdr[25]<<24);
        meta->depth = 24;
        meta->channels = 3;
        strcpy(meta->format,"BMP");
        return 1;
    }
    
    // --- GIF ---
    int identify_gif(FILE *f, ImgMeta *meta){
        uint8_t hdr[10];
        fseek(f,0,SEEK_SET);
        fread(hdr,1,10,f);
        if(memcmp(hdr,"GIF89a",6)&&memcmp(hdr,"GIF87a",6)) return 0;
        meta->w = hdr[6]|(hdr[7]<<8);
        meta->h = hdr[8]|(hdr[9]<<8);
        meta->depth = 8;
        meta->channels = 3;
        strcpy(meta->format,"GIF");
        return 1;
    }
    
    // --- WebP ---
    int identify_webp(FILE *f, ImgMeta *meta){
        uint8_t hdr[12];
        fseek(f,0,SEEK_SET);
        fread(hdr,1,12,f);
        if(memcmp(hdr,"RIFF",4)||memcmp(hdr+8,"WEBP",4)) return 0;
        uint8_t fmt[4];
        fread(fmt,1,4,f);
        if(!memcmp(fmt,"VP8 ",4)){
            fseek(f,10,SEEK_CUR);
            uint8_t dim[4];
            fread(dim,1,4,f);
            meta->w=((dim[1]&0x3F)<<8)|dim[0];
            meta->h=((dim[3]&0x3F)<<8)|dim[2];
            meta->depth=24;
            meta->channels=3;
            strcpy(meta->format,"WebP");
            return 1;
        }
        return 0;
    }
    
    // --- Main ---
    int main(int argc,char **argv){
        if(argc<2){ printf("Usage: %s <file>\n",argv[0]); return 1; }
        FILE *f=fopen(argv[1],"rb");
        if(!f){ perror("fopen"); return 1; }
    
        ImgMeta meta={0};
        int ok= identify_png(f,&meta)||
                identify_jpeg(f,&meta)||
                identify_bmp(f,&meta)||
                identify_gif(f,&meta)||
                identify_webp(f,&meta);
    
        fclose(f);
    
        if(ok){
            struct stat st;
            stat(argv[1], &st);
            double mib = st.st_size / 1024.0 / 1024.0;
            // Ident-like output
            printf("%s %s %ux%u %ux%u+0+0 %d-bit sRGB %.5fMiB 0.000u 0:00.000\n",
                argv[1], meta.format,
                meta.w, meta.h,
                meta.w, meta.h,
                meta.depth,
                mib
            );
        } else {
            printf("Unsupported format\n");
        }
    
        return 0;
    }
    


    Ich bin mir sicher, da steckt auch nicht mehr KI drin als in ImageMagick - zumindest würde das erklären, warum da die Qualität so nachgelassen hat!

    Und wenn du es nicht 1:1 übernehmen willst, kannst du es ja zumindest als grobe Idee, wie sowas aussehen könnte, verwenden.
  • [l] Felix Mon, 24 Nov 2025 16:56:36 GMT Nr. 160628
    JPG 720×482 36.7k
    >>160627
    >Ich bin mir sicher, da steckt auch nicht mehr KI drin als in ImageMagick - zumindest würde das erklären, warum da die Qualität so nachgelassen hat!
    Die hat nicht nachgelassen, die war von Anfang an scheiße.
  • [l] Zuse ## Admin Mon, 29 Dec 2025 15:26:22 GMT Nr. 161186
    Da bislang keine Komplikationen beobachtet wurden, werten wir das mal als Erfolg. Ist nun in den Meister-Zweig verschmolzen.
  • [l] Felix Sat, 03 Jan 2026 17:49:18 GMT Nr. 161252
    Benutzt der Kot der ausführbaren Diätkanal-Binärdatei selbst eigentlich seccomp-Filter?
  • [l] Zuse ## Admin Sun, 04 Jan 2026 18:43:40 GMT Nr. 161279
    >>161252
    >Benutzt der Kot der ausführbaren Diätkanal-Binärdatei selbst eigentlich seccomp-Filter?
    Bislang nicht, gestaltet sich auch etwas schwierig, da Diätkanal ja bestimmungsgemäß andere Programme wie ImageMagick/GraphicsMagick/SecMagick, file, ffmpeg, poppler, pngquant usw. ausführen soll, wenn Dateien hochgeladen werden. Ein seccomp-Filter würde auch für alle Kind-Prozesse gelten. Außerdem müsste exec selbst natürlich erlaubt bleiben. Das alles macht es schwierig, hier sinnvoll zu filtern. Man müsste so viel zulassen, dass man es eigentlich auch gleich bleiben lassen kann.

    Wenn man das sinnvoll umsetzen wollte, dann müsste man den Diätkanal-Prozess in mehrere Unterprozesse zerteilen. Also etwa einen Unterprozess, der nur dazu da ist, andere ausführbare Prozesse zu starten, und einen, der die Webrequests verarbeitet, und letzterer kann nur über ersteren mit externen Prozessen kommunizieren und diese starten. Das würde aber erhebliche Umbaumaßnahmen erfordern.
  • [l] Felix Sun, 04 Jan 2026 19:26:30 GMT Nr. 161281
    >>161279
    >Wenn man das sinnvoll umsetzen wollte, dann müsste man den Diätkanal-Prozess in mehrere Unterprozesse zerteilen. Also etwa einen Unterprozess, der nur dazu da ist, andere ausführbare Prozesse zu starten, und einen, der die Webrequests verarbeitet, und letzterer kann nur über ersteren mit externen Prozessen kommunizieren und diese starten. Das würde aber erhebliche Umbaumaßnahmen erfordern.
    Warum machst du das dann nicht? Mach das doch mal, klingt nach Spass und Freude! Kriegst als Danke auch ein Abziebildchen von irgend einem Dödel aus dem Internet!
  • [l] Felix Mon, 05 Jan 2026 19:08:33 GMT Nr. 161311
    >>161279
    Danke, das war sehr erhellend.

    >da Diätkanal ja bestimmungsgemäß andere Programme wie ImageMagick/GraphicsMagick/SecMagick, file, ffmpeg, poppler, pngquant usw. ausführen soll, wenn Dateien hochgeladen werden.
    >Außerdem müsste exec selbst natürlich erlaubt bleiben.
    Da gäbe es die Möglichkeit, alles von dem Kram reinzukompilieren (und sei es als .so) und keine exec(ve)-Aufrufe zu machen. Wenn dabei diese Abhängigkeiten als .so vorlägen, müsste man später weiterhin nicht Diätkanal neukompilieren, wenn mal wieder in einem Monat die drölfte CVE von ImageMagick, poppler, etc. reinschneit.

    >Wenn man das sinnvoll umsetzen wollte, dann müsste man den Diätkanal-Prozess in mehrere Unterprozesse zerteilen.
    Ah, die Mikroservice-Architektur. Hielt Felix immer für einen Fehler, weil das Entkäfern enorm verkompliziert wurde, da man nun mehrere Prozesse jonglieren muss und auch noch die Kommunikation zwischen diesen Prozessen überwachen muss und permanent beim Entkäfern den Kontext wechseln muss. printf-Entkäferung einkommend.

    >Das würde aber erhebliche Umbaumaßnahmen erfordern.
    >Mach du doch.
    Absolut verständlich. Einem Kot-Autor "nur mal eben" ein paar Umbaumaßnahmen ("geht doch schnell") vorzuschlagen, hört auch dieser Felix hochgradig ungern.
    Für Mitlesende möchte Felix noch sagen, dass >>161281 nicht dieser Felix aus >>161252 ist.


[Zurück]
[c] [meta] [fefe] [erp]