dd conv=sync,noerror
(ou conv=noerror,sync
) corrompt vos données.
En fonction de l'erreur d'E/S rencontrée et de la taille de bloc utilisée (plus grande que la taille du secteur physique ?), les adresses d'entrée et de sortie ne restent pas réellement synchronisées mais finissent par se retrouver aux mauvais décalages, ce qui rend la copie inutile pour les images de systèmes de fichiers et autres choses où les décalages importent.
De nombreux endroits recommandent d'utiliser conv=noerror,sync
lors de la manipulation de disques endommagés. J'avais l'habitude de faire la même recommandation moi-même. Cela a fonctionné pour moi, lorsque j'ai dû récupérer un disque endommagé il y a quelque temps.
Cependant, des tests suggèrent que cela n'est en fait pas fiable de quelque manière que ce soit.
Utilisez losetup
et dmsetup
pour créer un périphérique A erreur B
:
truncate -s 1M a.img b.img
A=$(losetup --find --show a.img)
B=$(losetup --find --show b.img)
i=0 ; while printf "A%06d\n" $i ; do i=$((i+1)) ; done > $A
i=0 ; while printf "B%06d\n" $i ; do i=$((i+1)) ; done > $B
Les périphériques en boucle A, B ressemblent à ceci :
# head -n 3 $A $B
==> /dev/loop0 <==
A000000
A000001
A000002
==> /dev/loop1 <==
B000000
B000001
B000002
Donc c'est A, B avec des numéros croissants qui nous aideront à vérifier les décalages plus tard.
Maintenant, pour mettre une erreur de lecture entre les deux, grâce au gestionnaire de périphériques Linux :
# dmsetup create AerrorB << EOF
0 2000 linéaire $A 0
2000 96 erreur
2096 2000 linéaire $B 48
EOF
Cet exemple crée AerrorB
comme 2000
secteurs de A
, suivis de 2*48
secteurs d'erreur, suivis de 2000
secteurs de B
.
Juste pour vérifier :
# blockdev --getsz /dev/mapper/AerrorB
4096
# hexdump -C /dev/mapper/AerrorB
00000000 41 30 30 30 30 30 30 0a 41 30 30 30 30 30 31 0a |A000000.A000001.|
00000010 41 30 30 30 30 30 32 0a 41 30 30 30 30 30 33 0a |A000002.A000003.|
[...]
000f9fe0 41 31 32 37 39 39 36 0a 41 31 32 37 39 39 37 0a |A127996.A127997.|
000f9ff0 41 31 32 37 39 39 38 0a 41 31 32 37 39 39 39 0a |A127998.A127999.|
000fa000
hexdump: /dev/mapper/AerrorB: Erreur d'entrée/sortie
Il lit donc jusqu'à A127999\n
, car chaque ligne contient 8 octets, ce qui totalise 1024000 octets, soit nos 2000 secteurs de 512 octets. Tout semble être en ordre...
Est-ce que ça va fonctionner ?
for bs in 1M 64K 16K 4K 512 42
do
dd bs=$bs conv=noerror,sync if=/dev/mapper/AerrorB of=AerrorB.$bs.gnu-dd
busybox dd bs=$bs conv=noerror,sync if=/dev/mapper/AerrorB of=AerrorB.$bs.bb-dd
done
ddrescue /dev/mapper/AerrorB AerrorB.ddrescue
Résultats :
# ls -l
-rw-r--r-- 1 root root 2113536 11 mai 23:54 AerrorB.16K.bb-dd
-rw-r--r-- 1 root root 2064384 11 mai 23:54 AerrorB.16K.gnu-dd
-rw-r--r-- 1 root root 3145728 11 mai 23:54 AerrorB.1M.bb-dd
-rw-r--r-- 1 root root 2097152 11 mai 23:54 AerrorB.1M.gnu-dd
-rw-r--r-- 1 root root 2097186 11 mai 23:54 AerrorB.42.bb-dd
-rw-r--r-- 1 root root 2048004 11 mai 23:54 AerrorB.42.gnu-dd
-rw-r--r-- 1 root root 2097152 11 mai 23:54 AerrorB.4K.bb-dd
-rw-r--r-- 1 root root 2097152 11 mai 23:54 AerrorB.4K.gnu-dd
-rw-r--r-- 1 root root 2097152 11 mai 23:54 AerrorB.512.bb-dd
-rw-r--r-- 1 root root 2097152 11 mai 23:54 AerrorB.512.gnu-dd
-rw-r--r-- 1 root root 2162688 11 mai 23:54 AerrorB.64K.bb-dd
-rw-r--r-- 1 root root 2097152 11 mai 23:54 AerrorB.64K.gnu-dd
-rw-r--r-- 1 root root 2097152 11 mai 23:54 AerrorB.ddrescue
Rien qu'avec les tailles de fichiers, vous pouvez voir que quelque chose ne va pas pour certaines tailles de bloc.
Checksums :
# md5sum *
8972776e4bd29eb5a55aa4d1eb3b8a43 AerrorB.16K.bb-dd
4ee0b656ff9be862a7e96d37a2ebdeb0 AerrorB.16K.gnu-dd
7874ef3fe3426436f19ffa0635a53f63 AerrorB.1M.bb-dd
6f60e9d5ec06eb7721dbfddaaa625473 AerrorB.1M.gnu-dd
94abec9a526553c5aa063b0c917d8e8f AerrorB.42.bb-dd
1413c824cd090cba5c33b2d7de330339 AerrorB.42.gnu-dd
b381efd87f17354cfb121dae49e3487a AerrorB.4K.bb-dd
b381efd87f17354cfb121dae49e3487a AerrorB.4K.gnu-dd
b381efd87f17354cfb121dae49e3487a AerrorB.512.bb-dd
b381efd87f17354cfb121dae49e3487a AerrorB.512.gnu-dd
3c101af5623fe8c6f3d764631582a18e AerrorB.64K.bb-dd
6f60e9d5ec06eb7721dbfddaaa625473 AerrorB.64K.gnu-dd
b381efd87f17354cfb121dae49e3487a AerrorB.ddrescue
dd
est d'accord avec ddrescue
seulement pour les tailles de bloc qui se trouvent à être alignées sur notre zone d'erreur (512
, 4K
).
Vérifions les données brutes.
# grep -a -b --only-matching B130000 *
AerrorB.16K.bb-dd: 2096768:B130000
AerrorB.16K.gnu-dd: 2047616:B130000
AerrorB.1M.bb-dd: 2113152:B130000
AerrorB.1M.gnu-dd: 2064000:B130000
AerrorB.42.bb-dd: 2088578:B130000
AerrorB.42.gnu-dd: 2039426:B130000
AerrorB.4K.bb-dd: 2088576:B130000
AerrorB.4K.gnu-dd: 2088576:B130000
AerrorB.512.bb-dd: 2088576:B130000
AerrorB.512.gnu-dd: 2088576:B130000
AerrorB.64K.bb-dd: 2113152:B130000
AerrorB.64K.gnu-dd: 2064000:B130000
AerrorB.ddrescue: 2088576:B130000
Alors que les données semblent bien être présentes, elles ne sont manifestement pas synchronisées ; les décalages sont complètement hors de propos pour bs=16K, 1M, 42, 64K... seules celles avec le décalage 2088576
sont correctes, comme on peut le vérifier par rapport au périphérique d'origine.
# dd bs=1 skip=2088576 count=8 if=/dev/mapper/AerrorB
B130000
Ceci est-il un comportement attendu de dd conv=noerror,sync
? Je ne sais pas et les deux implémentations de dd
que j'avais disponibles ne sont même pas d'accord entre elles. Le résultat est très inutile si vous avez utilisé dd
avec un choix de taille de bloc performant.
Le texte ci-dessus a été produit en utilisant dd (coreutils) 8.25
, BusyBox v1.24.2
, GNU ddrescue 1.21
.
3 votes
Upvote pour la question "Est-ce que conv=sync,noerror est une exigence lors de la réalisation d'analyses forensiques? "