Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

exFAT: volume label directory entry reading failure on drives formatted without a label by mkfs.exfat #2857

Open
jengbou opened this issue Aug 21, 2023 · 2 comments

Comments

@jengbou
Copy link

jengbou commented Aug 21, 2023

To reproduce the issue, simply format a drive as follows:

mkfs.exfat /dev/sda1
fsstat /dev/sda1 -v
output
tsk_img_open: Type: 0   NumImg: 1  Img1: /dev/sda1
aff_open: Error determining type of file: /dev/sda1
aff_open: No such file or directory
Error opening vmdk file
Error checking file signature for vhd file
tsk_img_findFiles: /dev/sda1 found
tsk_img_findFiles: 1 total segments found
raw_open: segment: 0  size: 256640024576  max offset: 256640024576  path: /dev/sda1
fsopen: Auto detection mode at offset 0
raw_read: byte offset: 0 len: 65536
raw_read: found in image 0 relative offset: 0 len: 65536
raw_read_segment: opening file into slot 0: /dev/sda1
ntfs_open: invalid sector size: 0
fatxxfs_open: Invalid sector size (0)
raw_read: byte offset: 9830400 len: 65536
raw_read: found in image 0 relative offset: 9830400 len: 65536
ext2fs_open: invalid magic
raw_read: byte offset: 65536 len: 65536
raw_read: found in image 0 relative offset: 65536 len: 65536
ufs_open: Trying 256KB UFS2 location
raw_read: byte offset: 262144 len: 65536
raw_read: found in image 0 relative offset: 262144 len: 65536
ufs_open: Trying UFS1 location
ufs_open: No UFS magic found
raw_read: byte offset: 156160 len: 65536
raw_read: found in image 0 relative offset: 156160 len: 65536
raw_read: byte offset: 426496 len: 65536
raw_read: found in image 0 relative offset: 426496 len: 65536
raw_read: byte offset: 561664 len: 65536
...
exfatfs_is_vol_label_dentry: incorrect volume label length
exfatfs_is_vol_label_dentry: incorrect volume label length
exfatfs_is_vol_label_dentry: incorrect volume label length
exfatfs_is_vol_label_dentry: incorrect volume label length
...

By default mkfs.exfat sets EntryType = 0x83 for volume label entry regardless of the entry's status (exfatprogs/exfatprogs#230). When formatting without a label, the CharacterCount field is set to 0 (i.e., dentry->volume_label_length_chars = 0) so it will fail the check at L128 of exfatfs_meta.c and unable to proceed:

if ((dentry->volume_label_length_chars < 1) || (dentry->volume_label_length_chars > EXFATFS_MAX_VOLUME_LABEL_LEN_CHAR)) {

In addition, the primary reason that it got stuck at exfatfs_find_volume_label_dentry is because the current_sector was never incremented in (as mentioned in #2673):

while (current_sector < last_sector_of_data_area) {

Changing it to:
for (current_sector = a_fatfs->rootsect; current_sector < last_sector_of_data_area; current_sector++) {

would suffice to address both this issue and #2673. However, with only this fix, TSK would have to walk through all sectors to exit the exfatfs_find_volume_label_dentry function before moving on to subsequent steps, resulting in a waste of time, especially when the drive being analyzed is large. To quickly complete this function call to address the incorrect InUse bit issue, one can for example expand L128-133 from:

    if(exfatfs_get_alloc_status_from_type(dentry->entry_type) == 1){
        /* There is supposed to be a label, check its length. */
        if ((dentry->volume_label_length_chars < 1) || (dentry->volume_label_length_chars > EXFATFS_MAX_VOLUME_LABEL_LEN_CHAR)) {
            if (tsk_verbose) {
                fprintf(stderr, "%s: incorrect volume label length\n", func_name);
            }
            return 0;
        }
    }
    else {
...

to:

    if(exfatfs_get_alloc_status_from_type(dentry->entry_type) == 1){
        /* There is supposed to be a label, check its length. */
        if ((dentry->volume_label_length_chars < 1) || (dentry->volume_label_length_chars > EXFATFS_MAX_VOLUME_LABEL_LEN_CHAR)) {
            /* If formatted with an empty label but the InUse field was set to 1, e.g., by mkfs.exfat*/
            if (dentry->volume_label_length_chars == 0) {
                /* Every byte of the UTF-16 volume label string should be 0. */
                for (i = 0; i < EXFATFS_MAX_VOLUME_LABEL_LEN_BYTE; ++i) {
                    if (dentry->volume_label[i] != 0x00) {
                        if (tsk_verbose) {
                            fprintf(stderr, "%s: non-zero byte in label for volume label entry with incorrect InUse bit\n", func_name);
                        }
                        return 0;
                    }
                }
                /* Change the InUse bit for subsequent steps */
                dentry->entry_type ^= 0x80;
                if (tsk_verbose) {
                  fprintf(stderr, "%s: after correcting the InUse bit, dentry->entry_type = %i\n", func_name, dentry->entry_type);
                }
            }
            else {
              if (tsk_verbose) {
                  fprintf(stderr, "%s: incorrect volume label length\n", func_name);
              }
              return 0;
            }
        }
    }
    else {
...
@jengbou
Copy link
Author

jengbou commented Aug 28, 2023

In addition to the change in L594,

while (current_sector < last_sector_of_data_area) {

Changing it to:
for (current_sector = a_fatfs->rootsect; current_sector < last_sector_of_data_area; current_sector++) {

I think L646 should also be fixed to avoid fsstat segmentation fault1 when going through all data area sectors but still can't find a volume label entry to retrieve the relevant info of interest:

return FATFS_OK;

Change it from:
return FATFS_OK;
To:
return FATFS_FAIL;

Footnotes

  1. When it reached L689 in exfatfs.c: https://github.com/sleuthkit/sleuthkit/blob/a14a5a80a72eaf8b283fd6f2dbc29648fbc7fa39/tsk/fs/exfatfs.c#L689

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants