Messages in this thread | | | From | Steve Magnani <> | Subject | [PATCH 0/1] udf: fix silent AED tagLocation corruption | Date | Thu, 7 Jan 2021 17:41:15 -0600 |
| |
From: Steven J. Magnani <magnani@ieee.org>
Certain scenarios involving enlargement of a large and/or fragmented file result in corruption of the file's Allocation Extent Descriptor tag. Once this has happened, attempts to read the file in Windows 10 fail with "Data error (cyclic redundancy check)". A "chkdsk /f" in Windows causes extents of the file described by the corrupted AED (and any subsequent chained AEDs) to be truncated.
No problems are noted when the file is accessed in Linux.
The script below creates a toy UDF filesystem to illustrate the problem. The filesystem can be dd'd to a flash disk partition of the same size to observe how Windows handles the corruption. --- #!/bin/bash
# Tool to illustrate / test fix for bug in UDF driver # that can result in corruption of Allocation Extent Descriptor tag location # Developed using mkudffs from udftools 2.2.
# Terminology: # LSN == Logical Sector Number (media / volume relative) # LBN == Logical Block Number (UDF partition relative)
TEST_UDFFS=/tmp/test.udf
# Changing these may alter filesystem layout and/or invalidate the test UDFFS_SIZE=1M # --size argument to 'truncate' command UDF_BLOCKSIZE=512 PD_LSN=98 # Expected UDF Partition Descriptor location AED_LSN=1343 # Location of Allocation Extent Descriptor under test
require() { local APP_REALPATH=`which $1` local PACKAGE_NAME=${2:-$1} if [ -z "$APP_REALPATH" ] ; then echo This test requires $1. Please install the $PACKAGE_NAME package. exit 1 fi }
# "Quiet" dd command ddq() { dd $* 2> /dev/null }
# Extract a 16-bit little-endian unsigned value at a specified byte offset ($2) # of a specified LSN ($1) # extract16() { local value=`ddq if=$TEST_UDFFS bs=$UDF_BLOCKSIZE skip=$1 count=1 | ddq bs=1 skip=$2 count=2 | od -A none -t u2 --endian=little` [ -z "$value" ] && value=0 # Fail in a sane manner
echo -n $value }
# Extract a 32-bit little-endian unsigned value at a specified byte offset ($2) # of a specified LSN ($1) # extract32() { local value=`ddq if=$TEST_UDFFS bs=$UDF_BLOCKSIZE skip=$1 count=1 | ddq bs=1 skip=$2 count=4 | od -A none -t u4 --endian=little` [ -z "$value" ] && value=0 # Fail in a sane manner
echo -n $value }
# $1 = LSN # $2 = Expected tag ID value (decimal) - i.e., 266 for EFE require_tag_id() { local found_tag=`extract16 $1 0`
if [ $found_tag -ne $2 ] ; then echo Expected tag $2 in LSN $1, found $found_tag. echo Unexpected test conditions - results must be verified manually exit 1 fi }
gen_provoker_data() { ddq if=/dev/zero bs=$UDF_BLOCKSIZE count=1 of=/tmp/hole.$$
openssl rand 172032 cat /tmp/hole.$$ openssl rand 149504 cat /tmp/hole.$$ openssl rand 22528 cat /tmp/hole.$$ openssl rand 2048 cat /tmp/hole.$$ openssl rand 4096 cat /tmp/hole.$$ openssl rand 4096 cat /tmp/hole.$$ openssl rand 8192 cat /tmp/hole.$$ openssl rand 184320 cat /tmp/hole.$$ openssl rand 131072
rm -f /tmp/hole.$$ }
# $1 == loopback UDF filesystem to create make_test_udf() { rm -f $1 truncate --size=$UDFFS_SIZE $1 mkudffs --label=SPARSE --uid=$UID --blocksize=$UDF_BLOCKSIZE $1 > /dev/null
mkdir -p /tmp/testudf.mnt echo Mounting test UDF filesystem. Please provide the root password if prompted. sudo mount $1 /tmp/testudf.mnt cp --sparse=always /tmp/provoker.$$ /tmp/testudf.mnt/provoker sync sudo umount /tmp/testudf.mnt rmdir /tmp/testudf.mnt echo Test UDF filesystem generated in $1. }
### MAIN
require openssl require mkudffs udftools
if [ -e $TEST_UDFFS ] ; then echo $TEST_UDFFS already exists - please dismount and remove it exit 1 fi
gen_provoker_data > /tmp/provoker.$$ make_test_udf $TEST_UDFFS
# Verify hardcoded LSNs involved in testing require_tag_id $PD_LSN 5 # PD require_tag_id $AED_LSN 258 # AED
LBN_BASE=`extract32 $PD_LSN 188` # Partition Starting Location AED_LBN=`expr $AED_LSN - $LBN_BASE` AED_TAG_LOCATION=`extract32 $AED_LSN 12`
if [ $AED_TAG_LOCATION -ne $AED_LBN ] ; then echo Test FAILED: expected AED tag location $AED_LBN, actual is $AED_TAG_LOCATION exit 1 else echo Test PASSED. AED tag location field is correct. fi ------------------------------------------------------------------------ Steven J. Magnani "I claim this network for MARS! Earthling, return my space modulator!" #include <standard.disclaimer>
| |