Message ID | 20230112140509.11525-1-linkinjeon@kernel.org (mailing list archive) |
---|---|
State | New, archived |
Headers | show |
Series | [v2] exfat: handle unreconized benign secondary entries | expand |
> + if (!(flags & ALLOC_FAT_CHAIN) || !start_clu || !size) > + return; From '7.9.2.2 NoFatChain Field' of the exFAT spec, flags can also be ALLOC_NO_FAT_CHAIN. The NoFatChain field shall conform to the definition provided in the Generic Secondary DirectoryEntry template (see Section 6.4.2.2). > + if (exfat_get_entry_type(ep) & TYPE_BENIGN_SEC) > + exfat_free_benign_secondary_clusters(inode, ep); > + Only vendor allocation entry(0xE1) have associated cluster allocations, vendor extension entry(0xE0) do not have associated cluster allocations.
2023-01-13 11:36 GMT+09:00, Yuezhang.Mo@sony.com <Yuezhang.Mo@sony.com>: >> + if (!(flags & ALLOC_FAT_CHAIN) || !start_clu || !size) >> + return; > > From '7.9.2.2 NoFatChain Field' of the exFAT spec, flags can also be > ALLOC_NO_FAT_CHAIN. > > The NoFatChain field shall conform to the definition provided in the Generic > Secondary DirectoryEntry template (see Section 6.4.2.2). This is to check the AllocationPossible field. We can probably add ALLOC_POSSIBLE macro to avoid confusion. > >> + if (exfat_get_entry_type(ep) & TYPE_BENIGN_SEC) >> + exfat_free_benign_secondary_clusters(inode, ep); >> + > > Only vendor allocation entry(0xE1) have associated cluster allocations, > vendor extension entry(0xE0) do not have associated cluster allocations. This is to free associated cluster allocation of the unrecognized benign secondary entries, not only vendor alloc entry. Could you elaborate more if there is any issue ? >
> > > >> + if (exfat_get_entry_type(ep) & TYPE_BENIGN_SEC) > >> + exfat_free_benign_secondary_clusters(inode, ep); > >> + > > > > Only vendor allocation entry(0xE1) have associated cluster > > allocations, vendor extension entry(0xE0) do not have associated cluster > allocations. > This is to free associated cluster allocation of the unrecognized benign > secondary entries, not only vendor alloc entry. Could you elaborate more if > there is any issue ? From exFAT spec, there are 2 types benign secondary entries only, Vendor Extension entry and Vendor Allocation entry. For different Vendor, Different Vendors are distinguished by different VendorGuid. For a better understanding, please refer to https://dokumen.pub/sd-specifications-part-2-file-system-specification-version-300.html. This is the specification that the SD Card Association defines Vendor Extension entries and Vendor Allocation entries for SD card. "Figure 5-3 : Continuous Information Management" is an example of an entry set containing a Vendor Extension entry and a Vendor Allocation entry. In the example, we can see vendor extension entry(0xE0) do not have associated cluster allocations.
> > > > > >> + if (exfat_get_entry_type(ep) & TYPE_BENIGN_SEC) > > >> + exfat_free_benign_secondary_clusters(inode, ep); > > >> + > > > > > > Only vendor allocation entry(0xE1) have associated cluster > > > allocations, vendor extension entry(0xE0) do not have associated > > > cluster > > allocations. > > This is to free associated cluster allocation of the unrecognized > > benign secondary entries, not only vendor alloc entry. Could you > > elaborate more if there is any issue ? > > From exFAT spec, there are 2 types benign secondary entries only, Vendor > Extension entry and Vendor Allocation entry. > > For different Vendor, Different Vendors are distinguished by different > VendorGuid. > > For a better understanding, please refer to https://dokumen.pub/sd- > specifications-part-2-file-system-specification-version-300.html. This is > the specification that the SD Card Association defines Vendor Extension > entries and Vendor Allocation entries for SD card. "Figure 5-3 : > Continuous Information Management" is an example of an entry set > containing a Vendor Extension entry and a Vendor Allocation entry. In the > example, we can see vendor extension entry(0xE0) do not have associated > cluster allocations. From "8.2 in the exFAT spec" as below, it is needed to handle all unrecognized benign secondary entries that include NOT specified in Revision 1.00. 8.2 Implications of Unrecognized Directory Entries Future exFAT specifications of the same major revision number, 1, and minor revision number higher than 0, may define new benign primary, critical secondary, and benign secondary directory entries. Only exFAT specifications of a higher major revision number may define new critical primary directory entries. Implementations of this specification, exFAT Revision 1.00 File System Basic Specification, should be able to mount and access any exFAT volume of major revision number 1 and any minor revision number. This presents scenarios in which an implementation may encounter directory entries which it does not recognize. The following describe implications of these scenarios: ... 4. Implementations shall not modify unrecognized benign secondary directory entries or their associated cluster allocations. Implementations should ignore unrecognized benign secondary directory entries. When deleting a directory entry set, implementations shall free all cluster allocations, if any, associated with unrecognized benign secondary directory entries.
> > > > > > > >> + if (exfat_get_entry_type(ep) & TYPE_BENIGN_SEC) > > > >> + exfat_free_benign_secondary_clusters(inode, ep); > > > >> + > > > > > > > > Only vendor allocation entry(0xE1) have associated cluster > > > > allocations, vendor extension entry(0xE0) do not have associated > > > > cluster > > > allocations. > > > This is to free associated cluster allocation of the unrecognized > > > benign secondary entries, not only vendor alloc entry. Could you > > > elaborate more if there is any issue ? > > > > From exFAT spec, there are 2 types benign secondary entries only, > > Vendor Extension entry and Vendor Allocation entry. > > > > For different Vendor, Different Vendors are distinguished by different > > VendorGuid. > > > > For a better understanding, please refer to > > https://urldefense.com/v3/__https://dokumen.pub/sd-__;!!JmoZiZGBv3RvKR > > > Sx!-iaK3DSO2yh1pGjdOLoZjMhH7s6QEAbN-Yd05bnBzTzpPks10JNCptYbvAdHZ > XYYvox > > 5D4Pi2xC3TBqH1pHEIg$ > > specifications-part-2-file-system-specification-version-300.html. This > > is the specification that the SD Card Association defines Vendor > > Extension entries and Vendor Allocation entries for SD card. "Figure 5-3 : > > Continuous Information Management" is an example of an entry set > > containing a Vendor Extension entry and a Vendor Allocation entry. In > > the example, we can see vendor extension entry(0xE0) do not have > > associated cluster allocations. > > From "8.2 in the exFAT spec" as below, it is needed to handle all unrecognized > benign secondary entries that include NOT specified in Revision 1.00. > > 8.2 Implications of Unrecognized Directory Entries Future exFAT specifications > of the same major revision number, 1, and minor revision number higher than > 0, may define new benign primary, critical secondary, and benign secondary > directory entries. Only exFAT specifications of a higher major revision number > may define new critical primary directory entries. Implementations of this > specification, exFAT Revision 1.00 File System Basic Specification, should be > able to mount and access any exFAT volume of major revision number 1 and > any minor revision number. This presents scenarios in which an > implementation may encounter directory entries which it does not recognize. > The following describe implications of these scenarios: > ... > 4. Implementations shall not modify unrecognized benign secondary > directory entries or their associated cluster allocations. > Implementations should ignore unrecognized benign secondary directory > entries. When deleting a directory entry set, implementations shall > free all cluster allocations, if any, associated with unrecognized > benign secondary directory entries. > My understanding are 1. If new benign directory entries are defined in the future, the minor version number will be incremented. - If FileSystemRevision is 1.0, Benign secondary is only Vendor Extension DirectoryEntry or Vendor Allocation DirectoryEntry. - If FileSystemRevision is higher than 1.0, another Benign secondary entries are defined. - So it seems we need to add a check for FileSystemRevision in exfat_read_boot_sector() - If FileSystemRevision is higher than 1.0, mount with read only, because we can not handle the version. 2. Not all Benign secondary have FirstCluster and DataLength Fields. - Vendor Extension DirectoryEntry has no FirstCluster and DataLength Fields, and there are no clusters to free when deleting it. Table 36 Vendor Extension DirectoryEntry Field Name Offset(byte) Size(byte) EntryType 0 1 GeneralSecondaryFlags 1 1 VendorGuid 2 16 VendorDefined 18 14 - Vendor Allocation DirectoryEntry has FirstCluster and DataLength Fields, the associated cluster should be freed when deleting it. Field Name Offset(byte) Size(byte) EntryType 0 1 GeneralSecondaryFlags 1 1 VendorGuid 2 16 VendorDefined 18 2 FirstCluster 20 4 DataLength 24 8 BTW, I start my Spring Festival vacation tomorrow, so I may not be able to respond to emails in time.
2023-01-13 17:35 GMT+09:00, Yuezhang.Mo@sony.com <Yuezhang.Mo@sony.com>: >> > > > >> > > >> + if (exfat_get_entry_type(ep) & TYPE_BENIGN_SEC) >> > > >> + exfat_free_benign_secondary_clusters(inode, ep); >> > > >> + >> > > > >> > > > Only vendor allocation entry(0xE1) have associated cluster >> > > > allocations, vendor extension entry(0xE0) do not have associated >> > > > cluster >> > > allocations. >> > > This is to free associated cluster allocation of the unrecognized >> > > benign secondary entries, not only vendor alloc entry. Could you >> > > elaborate more if there is any issue ? >> > >> > From exFAT spec, there are 2 types benign secondary entries only, >> > Vendor Extension entry and Vendor Allocation entry. >> > >> > For different Vendor, Different Vendors are distinguished by different >> > VendorGuid. >> > >> > For a better understanding, please refer to >> > https://urldefense.com/v3/__https://dokumen.pub/sd-__;!!JmoZiZGBv3RvKR >> > >> Sx!-iaK3DSO2yh1pGjdOLoZjMhH7s6QEAbN-Yd05bnBzTzpPks10JNCptYbvAdHZ >> XYYvox >> > 5D4Pi2xC3TBqH1pHEIg$ >> > specifications-part-2-file-system-specification-version-300.html. This >> > is the specification that the SD Card Association defines Vendor >> > Extension entries and Vendor Allocation entries for SD card. "Figure 5-3 >> > : >> > Continuous Information Management" is an example of an entry set >> > containing a Vendor Extension entry and a Vendor Allocation entry. In >> > the example, we can see vendor extension entry(0xE0) do not have >> > associated cluster allocations. >> >> From "8.2 in the exFAT spec" as below, it is needed to handle all >> unrecognized >> benign secondary entries that include NOT specified in Revision 1.00. >> >> 8.2 Implications of Unrecognized Directory Entries Future exFAT >> specifications >> of the same major revision number, 1, and minor revision number higher >> than >> 0, may define new benign primary, critical secondary, and benign >> secondary >> directory entries. Only exFAT specifications of a higher major revision >> number >> may define new critical primary directory entries. Implementations of >> this >> specification, exFAT Revision 1.00 File System Basic Specification, should >> be >> able to mount and access any exFAT volume of major revision number 1 and >> any minor revision number. This presents scenarios in which an >> implementation may encounter directory entries which it does not >> recognize. >> The following describe implications of these scenarios: >> ... >> 4. Implementations shall not modify unrecognized benign secondary >> directory entries or their associated cluster allocations. >> Implementations should ignore unrecognized benign secondary directory >> entries. When deleting a directory entry set, implementations shall >> free all cluster allocations, if any, associated with unrecognized >> benign secondary directory entries. >> > > My understanding are > > 1. If new benign directory entries are defined in the future, the minor > version number will be incremented. > - If FileSystemRevision is 1.0, Benign secondary is only Vendor Extension > DirectoryEntry or Vendor Allocation DirectoryEntry. > - If FileSystemRevision is higher than 1.0, another Benign secondary > entries are defined. > - So it seems we need to add a check for FileSystemRevision in > exfat_read_boot_sector() > - If FileSystemRevision is higher than 1.0, mount with read only, > because we can not handle the version. Well, I can't agree it. The current problem is that exfat has no handling for unrecognized benign secondary entries. Currently, exfat does not support vendor alloc/ext entries, so exfat handle unrecognized benign secondary entry as described in the spec. Of course, even if a new entry is added to the updated specification later, there is no problem because it is handled as an unrecognized benign secondary entry. > > 2. Not all Benign secondary have FirstCluster and DataLength Fields. > - Vendor Extension DirectoryEntry has no FirstCluster and DataLength > Fields, and there are no clusters to free when deleting it. We can know if it is defined by checking the AllocationPossible field of GeneralSecondaryFlags. If that bit is set, the FirstCluster and DataLength fields are defined. This patch has code that checks it. > > Table 36 Vendor Extension DirectoryEntry > Field Name Offset(byte) Size(byte) > EntryType 0 1 > GeneralSecondaryFlags 1 1 > VendorGuid 2 16 > VendorDefined 18 14 > > - Vendor Allocation DirectoryEntry has FirstCluster and DataLength Fields, > the associated cluster should be freed when deleting it. > > Field Name Offset(byte) Size(byte) > EntryType 0 1 > GeneralSecondaryFlags 1 1 > VendorGuid 2 16 > VendorDefined 18 2 > FirstCluster 20 4 > DataLength 24 8 > > BTW, I start my Spring Festival vacation tomorrow, so I may not be able to > respond to emails in time. >
diff --git a/fs/exfat/dir.c b/fs/exfat/dir.c index 158427e8124e..63c2f09ff93a 100644 --- a/fs/exfat/dir.c +++ b/fs/exfat/dir.c @@ -29,14 +29,15 @@ static int exfat_extract_uni_name(struct exfat_dentry *ep, } -static void exfat_get_uniname_from_ext_entry(struct super_block *sb, +static int exfat_get_uniname_from_ext_entry(struct super_block *sb, struct exfat_chain *p_dir, int entry, unsigned short *uniname) { - int i; + int i, err; struct exfat_entry_set_cache es; - if (exfat_get_dentry_set(&es, sb, p_dir, entry, ES_ALL_ENTRIES)) - return; + err = exfat_get_dentry_set(&es, sb, p_dir, entry, ES_ALL_ENTRIES); + if (err) + return err; /* * First entry : file entry @@ -56,12 +57,13 @@ static void exfat_get_uniname_from_ext_entry(struct super_block *sb, } exfat_put_dentry_set(&es, false); + return 0; } /* read a directory entry from the opened directory */ static int exfat_readdir(struct inode *inode, loff_t *cpos, struct exfat_dir_entry *dir_entry) { - int i, dentries_per_clu, num_ext; + int i, dentries_per_clu, num_ext, err; unsigned int type, clu_offset, max_dentries; struct exfat_chain dir, clu; struct exfat_uni_name uni_name; @@ -146,8 +148,12 @@ static int exfat_readdir(struct inode *inode, loff_t *cpos, struct exfat_dir_ent 0); *uni_name.name = 0x0; - exfat_get_uniname_from_ext_entry(sb, &clu, i, + err = exfat_get_uniname_from_ext_entry(sb, &clu, i, uni_name.name); + if (err) { + brelse(bh); + continue; + } exfat_utf16_to_nls(sb, &uni_name, dir_entry->namebuf.lfn, dir_entry->namebuf.lfnbuf_len); @@ -375,6 +381,12 @@ unsigned int exfat_get_entry_type(struct exfat_dentry *ep) return TYPE_ACL; return TYPE_CRITICAL_SEC; } + + if (ep->type == EXFAT_VENDOR_EXT) + return TYPE_VENDOR_EXT; + if (ep->type == EXFAT_VENDOR_ALLOC) + return TYPE_VENDOR_ALLOC; + return TYPE_BENIGN_SEC; } @@ -518,6 +530,25 @@ int exfat_update_dir_chksum(struct inode *inode, struct exfat_chain *p_dir, return ret; } +static void exfat_free_benign_secondary_clusters(struct inode *inode, + struct exfat_dentry *ep) +{ + struct super_block *sb = inode->i_sb; + struct exfat_chain dir; + unsigned int start_clu = + le32_to_cpu(ep->dentry.generic_secondary.start_clu); + u64 size = le64_to_cpu(ep->dentry.generic_secondary.size); + unsigned char flags = ep->dentry.generic_secondary.flags; + + if (!(flags & ALLOC_FAT_CHAIN) || !start_clu || !size) + return; + + exfat_chain_set(&dir, start_clu, + EXFAT_B_TO_CLU_ROUND_UP(size, EXFAT_SB(sb)), + flags); + exfat_free_cluster(inode, &dir); +} + int exfat_init_ext_entry(struct inode *inode, struct exfat_chain *p_dir, int entry, int num_entries, struct exfat_uni_name *p_uniname) { @@ -550,6 +581,9 @@ int exfat_init_ext_entry(struct inode *inode, struct exfat_chain *p_dir, if (!ep) return -EIO; + if (exfat_get_entry_type(ep) & TYPE_BENIGN_SEC) + exfat_free_benign_secondary_clusters(inode, ep); + exfat_init_name_entry(ep, uniname); exfat_update_bh(bh, sync); brelse(bh); @@ -573,6 +607,9 @@ int exfat_remove_entries(struct inode *inode, struct exfat_chain *p_dir, if (!ep) return -EIO; + if (exfat_get_entry_type(ep) & TYPE_BENIGN_SEC) + exfat_free_benign_secondary_clusters(inode, ep); + exfat_set_entry_type(ep, TYPE_DELETED); exfat_update_bh(bh, IS_DIRSYNC(inode)); brelse(bh); @@ -741,6 +778,7 @@ enum exfat_validate_dentry_mode { ES_MODE_GET_STRM_ENTRY, ES_MODE_GET_NAME_ENTRY, ES_MODE_GET_CRITICAL_SEC_ENTRY, + ES_MODE_GET_BENIGN_SEC_ENTRY, }; static bool exfat_validate_entry(unsigned int type, @@ -754,36 +792,33 @@ static bool exfat_validate_entry(unsigned int type, if (type != TYPE_FILE && type != TYPE_DIR) return false; *mode = ES_MODE_GET_FILE_ENTRY; - return true; + break; case ES_MODE_GET_FILE_ENTRY: if (type != TYPE_STREAM) return false; *mode = ES_MODE_GET_STRM_ENTRY; - return true; + break; case ES_MODE_GET_STRM_ENTRY: if (type != TYPE_EXTEND) return false; *mode = ES_MODE_GET_NAME_ENTRY; - return true; + break; case ES_MODE_GET_NAME_ENTRY: - if (type == TYPE_STREAM) + if (type & TYPE_BENIGN_SEC) + *mode = ES_MODE_GET_BENIGN_SEC_ENTRY; + else if (type != TYPE_EXTEND) return false; - if (type != TYPE_EXTEND) { - if (!(type & TYPE_CRITICAL_SEC)) - return false; - *mode = ES_MODE_GET_CRITICAL_SEC_ENTRY; - } - return true; - case ES_MODE_GET_CRITICAL_SEC_ENTRY: - if (type == TYPE_EXTEND || type == TYPE_STREAM) - return false; - if ((type & TYPE_CRITICAL_SEC) != TYPE_CRITICAL_SEC) + break; + case ES_MODE_GET_BENIGN_SEC_ENTRY: + /* Assume unreconized benign secondary entry */ + if (!(type & TYPE_BENIGN_SEC)) return false; - return true; + break; default: - WARN_ON_ONCE(1); return false; } + + return true; } struct exfat_dentry *exfat_get_dentry_cached( @@ -1164,10 +1199,8 @@ int exfat_count_ext_entries(struct super_block *sb, struct exfat_chain *p_dir, type = exfat_get_entry_type(ext_ep); brelse(bh); - if (type == TYPE_EXTEND || type == TYPE_STREAM) + if (type & TYPE_CRITICAL_SEC || type & TYPE_BENIGN_SEC) count++; - else - break; } return count; } diff --git a/fs/exfat/exfat_fs.h b/fs/exfat/exfat_fs.h index 25a5df0fdfe0..8a399e234aab 100644 --- a/fs/exfat/exfat_fs.h +++ b/fs/exfat/exfat_fs.h @@ -71,6 +71,8 @@ enum { #define TYPE_PADDING 0x0402 #define TYPE_ACLTAB 0x0403 #define TYPE_BENIGN_SEC 0x0800 +#define TYPE_VENDOR_EXT 0x0801 +#define TYPE_VENDOR_ALLOC 0x0802 #define MAX_CHARSET_SIZE 6 /* max size of multi-byte character */ #define MAX_NAME_LENGTH 255 /* max len of file name excluding NULL */ diff --git a/fs/exfat/exfat_raw.h b/fs/exfat/exfat_raw.h index 7f39b1c6469c..066df432f38e 100644 --- a/fs/exfat/exfat_raw.h +++ b/fs/exfat/exfat_raw.h @@ -50,6 +50,8 @@ #define EXFAT_STREAM 0xC0 /* stream entry */ #define EXFAT_NAME 0xC1 /* file name entry */ #define EXFAT_ACL 0xC2 /* stream entry */ +#define EXFAT_VENDOR_EXT 0xE0 /* vendor extension entry */ +#define EXFAT_VENDOR_ALLOC 0xE1 /* vendor allocation entry */ #define IS_EXFAT_CRITICAL_PRI(x) (x < 0xA0) #define IS_EXFAT_BENIGN_PRI(x) (x < 0xC0) @@ -155,6 +157,24 @@ struct exfat_dentry { __le32 start_clu; __le64 size; } __packed upcase; /* up-case table directory entry */ + struct { + __u8 flags; + __u8 vendor_guid[16]; + __u8 vendor_defined[14]; + } __packed vendor_ext; /* vendor extension directory entry */ + struct { + __u8 flags; + __u8 vendor_guid[16]; + __u8 vendor_defined[2]; + __le32 start_clu; + __le64 size; + } __packed vendor_alloc; /* vendor allocation directory entry */ + struct { + __u8 flags; + __u8 custom_defined[18]; + __le32 start_clu; + __le64 size; + } __packed generic_secondary; /* generic secondary directory entry */ } __packed dentry; } __packed;