While parsing the catalog tree, check that the length of each xattr
record is consistent with its fields.
Signed-off-by: Ernesto A. Fernández <
ernesto.mn...@gmail.com>
---
apfsck/Makefile | 2 +-
apfsck/btree.c | 4 ++++
apfsck/xattr.c | 42 ++++++++++++++++++++++++++++++++++++++++++
apfsck/xattr.h | 50 ++++++++++++++++++++++++++++++++++++++++++++++++++
4 files changed, 97 insertions(+), 1 deletion(-)
create mode 100644 apfsck/xattr.c
create mode 100644 apfsck/xattr.h
diff --git a/apfsck/Makefile b/apfsck/Makefile
index cef4a1e..3beeb38 100644
--- a/apfsck/Makefile
+++ b/apfsck/Makefile
@@ -1,5 +1,5 @@
SRCS = apfsck.c btree.c crc32c.c dir.c extents.c \
- inode.c key.c object.c super.c unicode.c
+ inode.c key.c object.c super.c unicode.c xattr.c
OBJS = $(SRCS:.c=.o)
DEPS = $(SRCS:.c=.d)
diff --git a/apfsck/btree.c b/apfsck/btree.c
index f2200cf..419e96a 100644
--- a/apfsck/btree.c
+++ b/apfsck/btree.c
@@ -18,6 +18,7 @@
#include "object.h"
#include "super.h"
#include "types.h"
+#include "xattr.h"
/**
* node_is_valid - Check basic sanity of the node index
@@ -512,6 +513,9 @@ static void parse_cat_record(void *key, void *val, int len)
case APFS_TYPE_SIBLING_LINK:
parse_sibling_record(key, val, len);
break;
+ case APFS_TYPE_XATTR:
+ parse_xattr_record(key, val, len);
+ break;
default:
break;
}
diff --git a/apfsck/xattr.c b/apfsck/xattr.c
new file mode 100644
index 0000000..1ec3627
--- /dev/null
+++ b/apfsck/xattr.c
@@ -0,0 +1,42 @@
+/*
+ * apfsprogs/apfsck/xattr.c
+ *
+ * Copyright (C) 2018 Ernesto A. Fernández <
ernesto.mn...@gmail.com>
+ */
+
+#include "apfsck.h"
+#include "key.h"
+#include "types.h"
+#include "xattr.h"
+
+/**
+ * parse_xattr_record - Parse a xattr record value and check for corruption
+ * @key: pointer to the raw key
+ * @val: pointer to the raw value
+ * @len: length of the raw value
+ *
+ * Internal consistency of @key must be checked before calling this function.
+ */
+void parse_xattr_record(struct apfs_xattr_key *key,
+ struct apfs_xattr_val *val, int len)
+{
+ u16 flags;
+
+ if (len < sizeof(*val))
+ report("Xattr record", "value is too small.");
+ len -= sizeof(*val);
+
+ flags = le16_to_cpu(val->flags);
+
+ if (flags & APFS_XATTR_DATA_STREAM) {
+ if (len != sizeof(struct apfs_xattr_dstream))
+ report("Xattr record",
+ "bad length for dstream structure.");
+ if (len != le16_to_cpu(val->xdata_len))
+ /* Never seems to happen, but the docs don't ban it */
+ report_weird("Xattr data length for dstream structure");
+ } else {
+ if (len != le16_to_cpu(val->xdata_len))
+ report("Xattr record", "bad length for embedded data.");
+ }
+}
diff --git a/apfsck/xattr.h b/apfsck/xattr.h
new file mode 100644
index 0000000..ca18bf6
--- /dev/null
+++ b/apfsck/xattr.h
@@ -0,0 +1,50 @@
+/*
+ * apfsprogs/apfsck/xattr.h
+ *
+ * Copyright (C) 2018 Ernesto A. Fernández <
ernesto.mn...@gmail.com>
+ */
+
+#ifndef _XATTR_H
+#define _XATTR_H
+
+#include "types.h"
+#include "inode.h"
+
+struct apfs_xattr_key;
+
+/* Extended attributes constants */
+#define APFS_XATTR_MAX_EMBEDDED_SIZE 3804
+
+/* Extended attributes names */
+#define APFS_XATTR_NAME_SYMLINK "com.apple.fs.symlink"
+#define APFS_XATTR_NAME_COMPRESSED "com.apple.decmpfs"
+
+/* Extended attributes flags */
+enum {
+ APFS_XATTR_DATA_STREAM = 0x00000001,
+ APFS_XATTR_DATA_EMBEDDED = 0x00000002,
+ APFS_XATTR_FILE_SYSTEM_OWNED = 0x00000004,
+ APFS_XATTR_RESERVED_8 = 0x00000008,
+};
+
+/*
+ * Structure of the value of an extended attributes record
+ */
+struct apfs_xattr_val {
+ __le16 flags;
+ __le16 xdata_len;
+ u8 xdata[0];
+} __packed;
+
+/*
+ * Structure used to store the data of an extended attributes record
+ */
+struct apfs_xattr_dstream {
+ __le64 xattr_obj_id;
+ struct apfs_dstream dstream;
+} __packed;
+
+extern void parse_xattr_record(struct apfs_xattr_key *key,
+ struct apfs_xattr_val *val, int len);
+
+#endif /* _XATTR_H */
--
2.11.0