dd auf Blockdevice schreibt/liest verfälschte Daten

Piktogramm

Admiral
Registriert
Okt. 2008
Beiträge
8.849
Soll:
Script soll Blöcke auf Laufwerk schreiben und danach lesen. Die Hashes der gelesenen Blöcke berechnen und ausgeben. Dazu wird ein 512B Zufallsblock aus urandom genutzt der zu einem 4MiB Block zusammengesetzt wird (data.bin). Diese Zufallsblock wird geschrieben und anschließend gelesen sowie gehasht. Bei Funktionierenden Laufwerken sollten alle Hashes über alle Blöcke konstant sein.

Ist:
Der "Witz" ist jedoch, dass die Blöcke beim lesen nicht die selben Hashes liefern

Code:
#!/bin/bash

#writesize in MB
writesize=4
writesize=$(( ${writesize} * 1024 * 1024))
blocksize=$((512 * 1024))
#blocksize=$(blockdev --getbsz ${1})
devsize=$((128 * 1024 * 1024))
#devsize=$(blockdev --getsize64 ${1})

cnt=$(($writesize / $blocksize))
rnd=$(dd if=/dev/urandom bs=$blocksize count=1 2>/dev/null)

rm data.bin 2>/dev/null
for ((i=1; i<=${cnt}; i++))
do
    cat <<< "$rnd" >> data.bin
done

sha256sum -b data.bin > hash.sha256

cnt=$((${devsize}/${writesize}))
for ((i=0; i<=${cnt}; i++))
do
    echo "write $i of $cnt" 1>&2
    dd if=data.bin of=${1} bs=$writesize seek=$i count=1 oflag=sync 2>/dev/null
done

sync

echo "initial hash $(cat data.bin | sha256sum -b)"
for ((i=0; i<=${cnt}; i++))
do
    echo "loop $i $(dd if=${1} bs=$writesize count=1 skip=$i oflag=sync 2>/dev/null | sha256sum -b)"
done

ergibt:
Code:
$ sudo ./checkSD.sh /dev/sdb
./checkSD.sh: line 12: warning: command substitution: ignored null byte in input
write 0 of 32
[*]
write 32 of 32
initial hash e1bcf90573d5c006def1a372a25177181f84d3df4fb942cff6d1603431540b96 *-
loop 0 6372241bc253916fa5c958b4b10709767b4836d556d02f6067b713e70a9f83e6 *-
[*]
loop 8 6372241bc253916fa5c958b4b10709767b4836d556d02f6067b713e70a9f83e6 *-
loop 9 3283f693210a0e0305d78f7ba087c770490a14da09713ecbabae83b7060532e4 *-
loop 10 5a440fb8e54242dc95d18654bb16256d5c42cd79e69b37bc5e7773dd006d58d2 *-
[*]
loop 18 5a440fb8e54242dc95d18654bb16256d5c42cd79e69b37bc5e7773dd006d58d2 *-
loop 19 b79fca8b0aae76939a4f274cc6ca6e1e64cb1020e6eb6871c0dbc61c0a52c7cf *-
loop 20 5a440fb8e54242dc95d18654bb16256d5c42cd79e69b37bc5e7773dd006d58d2 *-
loop 21 5a440fb8e54242dc95d18654bb16256d5c42cd79e69b37bc5e7773dd006d58d2 *-
loop 22 5a440fb8e54242dc95d18654bb16256d5c42cd79e69b37bc5e7773dd006d58d2 *-
loop 23 153f4d00817f520e8cbc1c6bd76963e6b8194e0bf7234bf35df0e0f673c864a9 *-
loop 24 5a440fb8e54242dc95d18654bb16256d5c42cd79e69b37bc5e7773dd006d58d2 *-
loop 25 5a440fb8e54242dc95d18654bb16256d5c42cd79e69b37bc5e7773dd006d58d2 *-
loop 26 5a440fb8e54242dc95d18654bb16256d5c42cd79e69b37bc5e7773dd006d58d2 *-
loop 27 5a440fb8e54242dc95d18654bb16256d5c42cd79e69b37bc5e7773dd006d58d2 *-
loop 28 5a440fb8e54242dc95d18654bb16256d5c42cd79e69b37bc5e7773dd006d58d2 *-
loop 29 5a440fb8e54242dc95d18654bb16256d5c42cd79e69b37bc5e7773dd006d58d2 *-
loop 30 5a440fb8e54242dc95d18654bb16256d5c42cd79e69b37bc5e7773dd006d58d2 *-
loop 31 bbcb72c59d04eeea6ab6a45832d708ac970e0099010aa26087794d81e6e0532c *-
loop 32 5a440fb8e54242dc95d18654bb16256d5c42cd79e69b37bc5e7773dd006d58d2 *-

Probleme
  1. Der Hash über data.bin passt zu keinem Hash vom Laufwerk. Beim direkten Vergleich vom hexdumb von data.bin und dd if=/dev/sdb bs=$((4 * 1024 * 1024)) count=1 | hexdump -C wird auch deutlich wieso. Der Hexdumb ist zum Ende hin je ein Anderer.
    Ich würde gern wissen, wie ich wirklich 1 zu 1 die Daten aus data.bin auf Laufwerke bekomme
  2. Die Hashes über die Blöcke des Laufwerkes bleiben im Verlauf nicht konstant, jedoch manchmal schon. Wenn da jemand eine Erklärung/ein Fix fürs Script hat wäre ich dankbar!
 
Sind das zufällig SSDs? Wenn ja, dann würde ich mir das erstmal so erklären, dass die SSDs ja immer mal Daten verschieben umd passende Blöcke frei zu halten.
Probier es doch erstmal nicht mit einem Blockdevice sondern einer Datei aus. Diese dürfte sich nicht ändern.
 
Darum ist die 'data.bin' zu kurz und der Block wird nicht vollständig geschrieben.
Man könnte als dirty fix den Block mit Nullen auffüllen:
Line 26: dd if=data.bin of=${1} bs=$writesize seek=$i count=1 conv=notrunc oflag=append 2>/dev/null

Edit: Wobei.. dann stimmen die Blöcken ja gar nicht mehr... :D
 
Zuletzt bearbeitet:
Also erst einmal mischst du hier zwei Ausgabehandles (urandom mit Bildschirmausgabe) und zweitens rechnest du integer-werte in char um und wieder zurück. Das führt dann wohl zu Interpretationsfehlern. Was willst du denn machen, nur testen ob deine Festplatte sauber arbeitet?
 
@deveth0
SD Karten, HDDs und SSDs
Wobei SSDs zwar intern Blöcke umsortieren, die addressierung nach Außen ist davon aber nicht betroffen.

@Uridium:
Das Schreiben in eine Datei funktioniert besser, wie aber schon angemerkt wurde habe ich ein Problem beim verwenden von Bashvariablen mit Binärdaten. Daher schaut es dann so aus:
Code:
initial hash cefa5bec4bbca1196634840b7c7add2933044e18216c62c3b7813e7eb100631c *-
loop 0 fad6877d546cfa8d075ec1fcc61b4f4a1f06a13e93d20d8df0f54e676c5a7f35 *-
[*]
loop 31 fad6877d546cfa8d075ec1fcc61b4f4a1f06a13e93d20d8df0f54e676c5a7f35 *-
loop 32 cefa5bec4bbca1196634840b7c7add2933044e18216c62c3b7813e7eb100631c *-
Es sind alle Hashes konstant bis auf den Letzten. Dafür ist der letzte Hash der Einzige, der zum Ausgangshash passt. Passt also soweit.
Die Diskrepanz zum Blockdevice verwirrt immer noch :/

@GrumpyCat
Danke!

@Uridium
Anstatt 0padding zu betreiben werde ich die variable einfach weglassen und das mit dd frickeln.

@froschmeister
Genau das, Laufwerk beschreiben und beim Lesen testen.
Sollte eine Fingerübung werden, offenbart aber mehr Wissenslücken als mir lieb ist.
 
Hier hast du mal ein Beispielprogramm, wie man CRC-Summen von Dateien über einen Verzeichnisbaum prüft. (Es gibt auch noch kürzere Versionen das zu tun, s.u. im Code). Ich habe es mal geschrieben um Bitflips bei Dateien zu erkennen. Es rennt durch einen gegeben Pfad und erstellt in jedem Verzeichnis eine Txt-Datei mit den CRC-Summen der zugehörigen Dateien. Dazu nutzt es "sha256sum". Gegen die CRC-Datei kann dann geprüft werden. Das Endresultat wird dann in der Wurzel protokolliert. Es ist nicht ganz perfekt und erkennt nicht alle Sonderzeichen in den Verzeichnissen. (Dem kann man aber abhelfen :-)

Code:
#!/bin/bash

# vom jeweiligen arbeitspfad aus aufrufen: "crcsum.sh set <dir>" oder  "crcsum.sh check <dir>";
# <dir> kann auch "." für aktuelles verzeichnis sein;

setfile=_crc.txt
checkfile=_crc.check.txt
rootcheckfile=_crc.check.root.txt
rootpath=$PWD

_crc_sumset ()
{
  while read line
  do
    case "$line" in
      "..") ;;
       * ) echo "current directory:" $line;
           (cd "$line"; find . -maxdepth 1 -type f -name "*" ! -name "*.txt" ! -name "*.sh" -print0 | xargs -0I {} sha256sum {} | tee $setfile)
         ;;
    esac
  done
}

_crc_sumcheck ()
{
  while read line
  do
    case "$line" in
      "..") ;;
       * ) echo "current directory:" $line;
           (cd "$line"; sha256sum -c $setfile --quiet | tee -a $rootpath/$rootcheckfile)
#           (cd "$line"; sha256sum -c $setfile --quiet | tee $checkfile | tee -a $rootpath/$rootcheckfile; echo $(date) >>$checkfile)
         ;;
    esac
  done
}

case $1 in
  "set"   ) find $2 -type d -name "*" -print | sed -e 's/\x27/\x5c\x5c\x27/g' -e 's/\x20/\x5c\x5c\x20/g' | _crc_sumset ;;
  "check" ) echo $(date) >$rootpath/$rootcheckfile; find $2 -type d -name "*" -print | sed -e 's/\x27/\x5c\x5c\x27/g' -e 's/\x20/\x5c\x5c\x20/g' | _crc_sumcheck ;;
        * ) ;;
esac
exit

# !shorter examples!
#
# find ~/Musik -type d -not -exec sh -c 'find "$0" -type f -iname \*.mp3 -or -iname \*.ogg | grep -q . ' '{}' \;  -print
#
# find -type f -exec md5sum {} \; | tee ../allfiles.txt
# md5sum --quiet -c ../allfiles.txt



Wenn es dir nur darum geht das Backup eines ganzen Stammbaums zu prüfen, dies geht in einer Codezeile mit zwei Befehlen und zwar mittels "find" und "cmp". Dazu in das Quellverzeichnis wechseln und folgendes eingeben:

Code:
find . -type f -exec cmp '{}' <zielverzeichnis>/'{}' \;

Damit habe ich letzte Woche drei Terabyte Daten gegen vier Backuplatten (WD60EZAZ, ST6000DM003, WD30EZRX und eine Toshiba) getestet. (Die letzten beiden waren 6 Jahre im Gebrauch.) Habe nicht einen Bitfehler gefunden. (Nicht mal einen halben :-)
 
Zuletzt bearbeitet von einem Moderator:
Lass den Umweg über die Variable doch einfach ganz weg und schreibe direkt mit dd in die Datei.

12: #rnd=$(dd if=/dev/urandom bs=$blocksize count=1 2>/dev/null ) 17: dd if=/dev/urandom bs=$blocksize count=1 2>/dev/null >> data.bin
 
Danke allerseits, bei Gelegenheit muss ich nochmal Hand anlegen.

Code:
#!/bin/bash

#writesize in MB
writesize=4
writesize=$(( ${writesize} * 1024 * 1024))
#blocksize=$((512 * 1024))
blocksize=$(blockdev --getbsz ${1})
#devsize=$((32 * 1024 * 1024))
devsize=$(blockdev --getsize64 ${1})

echo "block: $blocksize dev: $devsize"

cnt=$(($writesize / $blocksize))

rm data.bin
dd if=/dev/urandom of=rnd.bin bs=$blocksize count=1 2>/dev/null

for ((i=1; i<=${cnt}; i++))
do
    dd if=rnd.bin 2>/dev/null >>data.bin
done

cnt=$((${devsize}/${writesize}))
for ((i=0; i<=${cnt}; i++))
do
    echo "write $i of $cnt" 1>&2
    dd if=data.bin bs=$writesize 2</dev/null | dd bs=$writesize of=${1} seek=$i 2>/dev/null
done

sync

echo "initial hash $(cat data.bin | sha256sum -b)"
for ((i=0; i<=${cnt}; i++))
do
    echo "loop $i $(dd if=${1} bs=$writesize count=1 skip=$i oflag=sync 2>/dev/null | sha256sum -b)"
done

@froschmeister
Tests auf dem Dateisystem wollte ich vermeiden. Moderne Dateisysteme packen mir zu viel Komplexität oben drauf.
 
Als Alternative (oder Inspiration für dein Script) kann ich f3brew oder f3probe empfehlen.
Im wesentlichen macht das genau das, was du erwartest.

f3 - Fight Flash Fraud

Das Paket heißt meist einfach "f3".
 
@???
Danke, f3 ist mit bekannt und installiert. Neben dem Willen das Laufwerk zu testen ging es mir auch um die Übung. Nötig war es ja ;)
 
Zurück
Oben