[PATCH 1/3] apfsck: check that xfields are not repeated

2 views
Skip to first unread message

Ernesto A. Fernández

unread,
Mar 7, 2019, 12:45:49 PM3/7/19
to linux...@googlegroups.com
There doesn't seem to be any reason for an inode to have more than one
extended field of the same type, so verify that it doesn't happen.

Signed-off-by: Ernesto A. Fernández <ernesto.mn...@gmail.com>
---
apfsck/inode.c | 7 +++++++
1 file changed, 7 insertions(+)

diff --git a/apfsck/inode.c b/apfsck/inode.c
index 3e844d7..37332f3 100644
--- a/apfsck/inode.c
+++ b/apfsck/inode.c
@@ -313,6 +313,7 @@ static void parse_inode_xfields(struct apfs_xf_blob *xblob, int len,
struct inode *inode)
{
struct apfs_x_field *xfield;
+ u16 type_bitmap = 0;
char *xval;
int xcount;
int i;
@@ -340,6 +341,7 @@ static void parse_inode_xfields(struct apfs_xf_blob *xblob, int len,

for (i = 0; i < le16_to_cpu(xblob->xf_num_exts); ++i) {
int xlen, xpad_len;
+ u16 type_flag;

switch (xfield[i].x_type) {
case APFS_INO_EXT_TYPE_FS_UUID:
@@ -381,6 +383,11 @@ static void parse_inode_xfields(struct apfs_xf_blob *xblob, int len,
report("Inode xfield", "invalid type.");
}

+ type_flag = 1 << xfield[i].x_type;
+ if (type_bitmap & type_flag)
+ report("Inode record", "two xfields of the same type.");
+ type_bitmap |= type_flag;
+
if (xlen != le16_to_cpu(xfield[i].x_size))
report("Inode xfield", "wrong size");
len -= xlen;
--
2.11.0

Ernesto A. Fernández

unread,
Mar 7, 2019, 12:46:03 PM3/7/19
to linux...@googlegroups.com
I don't yet know which xfields will have which flags, but add some basic
checks that are common to all of them.

Signed-off-by: Ernesto A. Fernández <ernesto.mn...@gmail.com>
---
apfsck/dir.c | 2 ++
apfsck/inode.c | 16 ++++++++++++++++
apfsck/inode.h | 11 +++++++++++
3 files changed, 29 insertions(+)

diff --git a/apfsck/dir.c b/apfsck/dir.c
index eaaa7e9..af50320 100644
--- a/apfsck/dir.c
+++ b/apfsck/dir.c
@@ -70,6 +70,8 @@ static void parse_dentry_xfields(struct apfs_xf_blob *xblob, int len,
report("Dentry record",
"value size incompatible with xfields.");

+ check_xfield_flags(xfield->x_flags);
+
if (xfield->x_type != APFS_DREC_EXT_TYPE_SIBLING_ID)
report("Dentry xfield", "invalid type.");
xlen = read_sibling_id_xfield(xval, len, sibling_id);
diff --git a/apfsck/inode.c b/apfsck/inode.c
index 37332f3..2e6a2be 100644
--- a/apfsck/inode.c
+++ b/apfsck/inode.c
@@ -302,6 +302,20 @@ static int read_dstream_xfield(char *xval, int len, struct inode *inode)
}

/**
+ * check_xfield_flags - Run common flag checks for all xfield types
+ * @flags: flags to check
+ */
+void check_xfield_flags(u8 flags)
+{
+ if (flags & APFS_XF_RESERVED_4 || flags & APFS_XF_RESERVED_40 ||
+ flags & APFS_XF_RESERVED_80)
+ report("Inode xfield", "reserved flag in use.");
+
+ if (flags & APFS_XF_USER_FIELD && flags & APFS_XF_SYSTEM_FIELD)
+ report("Inode xfield", "created by both user and kernel.");
+}
+
+/**
* parse_inode_xfields - Parse and check an inode extended fields
* @xblob: pointer to the beginning of the xfields in the inode value
* @len: length of the xfields
@@ -343,6 +357,8 @@ static void parse_inode_xfields(struct apfs_xf_blob *xblob, int len,
int xlen, xpad_len;
u16 type_flag;

+ check_xfield_flags(xfield[i].x_flags);
+
switch (xfield[i].x_type) {
case APFS_INO_EXT_TYPE_FS_UUID:
xlen = 16;
diff --git a/apfsck/inode.h b/apfsck/inode.h
index c04515a..e6c4dff 100644
--- a/apfsck/inode.h
+++ b/apfsck/inode.h
@@ -78,6 +78,16 @@ struct apfs_inode_val {
#define APFS_INO_EXT_TYPE_SPARSE_BYTES 13
#define APFS_INO_EXT_TYPE_RDEV 14

+/* Extended field flags */
+#define APFS_XF_DATA_DEPENDENT 0x01
+#define APFS_XF_DO_NOT_COPY 0x02
+#define APFS_XF_RESERVED_4 0x04
+#define APFS_XF_CHILDREN_INHERIT 0x08
+#define APFS_XF_USER_FIELD 0x10
+#define APFS_XF_SYSTEM_FIELD 0x20
+#define APFS_XF_RESERVED_40 0x40
+#define APFS_XF_RESERVED_80 0x80
+
/* Constants for extended fields */
#define APFS_MIN_DOC_ID 3 /* Smallest not reserved document id */

@@ -192,5 +202,6 @@ extern void set_or_check_sibling(u64 parent_id, int namelen, u8 *name,
struct sibling *sibling);
extern void parse_sibling_record(struct apfs_sibling_link_key *key,
struct apfs_sibling_val *val, int len);
+extern void check_xfield_flags(u8 flags);

#endif /* _INODE_H */
--
2.11.0

Ernesto A. Fernández

unread,
Mar 7, 2019, 12:46:20 PM3/7/19
to linux...@googlegroups.com
Verify that extended fields of known types have the expected set of
flags. This information has been obtained via testing, and some choices
don't seem to make sense yet.

Signed-off-by: Ernesto A. Fernández <ernesto.mn...@gmail.com>
---
apfsck/inode.c | 12 +++++++++++-
1 file changed, 11 insertions(+), 1 deletion(-)

diff --git a/apfsck/inode.c b/apfsck/inode.c
index 2e6a2be..cce1e87 100644
--- a/apfsck/inode.c
+++ b/apfsck/inode.c
@@ -356,8 +356,9 @@ static void parse_inode_xfields(struct apfs_xf_blob *xblob, int len,
for (i = 0; i < le16_to_cpu(xblob->xf_num_exts); ++i) {
int xlen, xpad_len;
u16 type_flag;
+ u8 xflags = xfield[i].x_flags;

- check_xfield_flags(xfield[i].x_flags);
+ check_xfield_flags(xflags);

switch (xfield[i].x_type) {
case APFS_INO_EXT_TYPE_FS_UUID:
@@ -365,12 +366,17 @@ static void parse_inode_xfields(struct apfs_xf_blob *xblob, int len,
break;
case APFS_INO_EXT_TYPE_PREV_FSIZE:
printf("Inode xfield: filesystem has crashed.\n");
+ if (xflags != 0)
+ report("Previous size xfield", "wrong flags.");
case APFS_INO_EXT_TYPE_SNAP_XID:
case APFS_INO_EXT_TYPE_DELTA_TREE_OID:
xlen = 8;
break;
case APFS_INO_EXT_TYPE_SPARSE_BYTES:
xlen = read_sparse_bytes_xfield(xval, len, inode);
+ if (xflags != (APFS_XF_SYSTEM_FIELD |
+ APFS_XF_CHILDREN_INHERIT))
+ report("Sparse bytes xfield", "wrong flags.");
break;
case APFS_INO_EXT_TYPE_DOCUMENT_ID:
xlen = read_document_id_xfield(xval, len, inode);
@@ -383,9 +389,13 @@ static void parse_inode_xfields(struct apfs_xf_blob *xblob, int len,
break;
case APFS_INO_EXT_TYPE_NAME:
xlen = read_name_xfield(xval, len, inode);
+ if (xflags != APFS_XF_DO_NOT_COPY)
+ report("Name xfield", "wrong flags.");
break;
case APFS_INO_EXT_TYPE_DSTREAM:
xlen = read_dstream_xfield(xval, len, inode);
+ if (xflags != APFS_XF_SYSTEM_FIELD)
+ report("Data stream xfield", "wrong flags.");
break;
case APFS_INO_EXT_TYPE_DIR_STATS_KEY:
xlen = sizeof(struct apfs_dir_stats_val);
--
2.11.0

Reply all
Reply to author
Forward
0 new messages