From 1bb972b8bf86accb5e53f0a35e64c89e5908a889 Mon Sep 17 00:00:00 2001 From: Andreas Dilger Date: Fri, 10 Nov 2023 04:54:35 +0000 Subject: [PATCH] Revert "LU-17131 ldiskfs: el9.2 encdata and filename-encode" This reverts commit b0cc96a1ff516f79f26be32945a237ef8373e408 as it is likely causing ldiskfs to crash immediately at mount: LDISKFS-fs (dm-0): mounted filesystem with ordered data mode. Quota mode: journalled. BUG: kernel NULL pointer dereference, address: 0000000000000000 #PF: error_code(0x0000) - not-present page Oops: 0000 [#1] PREEMPT SMP PTI CPU: 0 PID: 7148 Comm: mkfs.lustre 5.14.0-284.30.1_lustre.el9.x86_64 #1 Hardware name: Red Hat KVM, BIOS 0.5.1 01/01/2011 RIP: 0010:__ldiskfs_find_entry+0xab/0x440 [ldiskfs] Call Trace: ldiskfs_lookup.part.0+0x6c/0x2c0 [ldiskfs] __lookup_hash+0x70/0xa0 __filename_create+0x87/0x150 do_mkdirat+0x4b/0x160 __x64_sys_mkdir+0x48/0x70 Change-Id: Idc8448c9e6d2300bc5eccb6ea190252eaaca9f75 Test-Parameters: trivial Test-Parameters: serverdistro=el9.2 testlist=sanity Test-Parameters: serverdistro=el9.2 testlist=conf-sanity Signed-off-by: Andreas Dilger Reviewed-on: https://review.whamcloud.com/c/fs/lustre-release/+/53069 Reviewed-by: Alex Zhuravlev Reviewed-by: Shaun Tancheff Reviewed-by: Oleg Drokin Tested-by: jenkins Tested-by: Maloo --- .../patches/rhel9.2/ext4-encdata.patch | 441 --------------------- .../patches/rhel9.2/ext4-filename-encode.patch | 398 ------------------- .../series/ldiskfs-5.14-rhel9.2.series | 2 - 3 files changed, 841 deletions(-) delete mode 100644 ldiskfs/kernel_patches/patches/rhel9.2/ext4-encdata.patch delete mode 100644 ldiskfs/kernel_patches/patches/rhel9.2/ext4-filename-encode.patch diff --git a/ldiskfs/kernel_patches/patches/rhel9.2/ext4-encdata.patch b/ldiskfs/kernel_patches/patches/rhel9.2/ext4-encdata.patch deleted file mode 100644 index a7a71c8..0000000 --- a/ldiskfs/kernel_patches/patches/rhel9.2/ext4-encdata.patch +++ /dev/null @@ -1,441 +0,0 @@ -diff --git a/fs/ext4/encdata.h b/fs/ext4/encdata.h -new file mode 100644 -index 00000000..aa83832f ---- /dev/null -+++ b/fs/ext4/encdata.h -@@ -0,0 +1,128 @@ -+/* -+ * encdata.h -+ * -+ * Copyright (c) 2022 Whamcloud -+ */ -+ -+#ifndef _ENCDATA_H -+#define _ENCDATA_H -+ -+/* Define a fixed 4096-byte encryption unit size */ -+/* Must be identical to LUSTRE_ENCRYPTION_UNIT_SIZE */ -+#define EXT4_ENCRYPTION_BLOCKBITS 12 -+#define EXT4_ENCRYPTION_UNIT_SIZE ((size_t)1 << EXT4_ENCRYPTION_BLOCKBITS) -+#define EXT4_ENCRYPTION_MASK (~(EXT4_ENCRYPTION_UNIT_SIZE - 1)) -+#define LLCRYPT_SET_CONTEXT_MAX_SIZE 40 -+#define ENCDATA_XATTR_FMT_1 "{ encoding: " -+#define ENCDATA_XATTR_FMT_2 ", size: " -+#define ENCDATA_XATTR_FMT_3 ", enc_ctx: " -+#define ENCDATA_XATTR_FMT_4 ", enc_name: " -+#define ENCDATA_XATTR_FMT_END " }" -+#define ENCDATA_XATTR_FMT_COMP ENCDATA_XATTR_FMT_1 ENCDATA_XATTR_FMT_2 \ -+ ENCDATA_XATTR_FMT_3 ENCDATA_XATTR_FMT_4 \ -+ ENCDATA_XATTR_FMT_END -+ -+extern char encdata_xattr_fmt[NAME_MAX]; -+ -+/* -+ * base64url encoding, lifted from fs/crypto/fname.c. -+ */ -+ -+static const char base64url_table[] = -+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_"; -+ -+#define BASE64URL_CHARS(nbytes) DIV_ROUND_UP((nbytes) * 4, 3) -+ -+/** -+ * base64url_encode() - base64url-encode some binary data -+ * @src: the binary data to encode -+ * @srclen: the length of @src in bytes -+ * @dst: (output) the base64url-encoded string. Not NUL-terminated. -+ * -+ * Encodes data using base64url encoding, i.e. the "Base 64 Encoding with URL -+ * and Filename Safe Alphabet" specified by RFC 4648. '='-padding isn't used, -+ * as it's unneeded and not required by the RFC. base64url is used instead of -+ * base64 to avoid the '/' character, which isn't allowed in filenames. -+ * -+ * Return: the length of the resulting base64url-encoded string in bytes. -+ * This will be equal to LLCRYPT_BASE64URL_CHARS(srclen). -+ */ -+static inline int base64url_encode(const u8 *src, int srclen, char *dst) -+{ -+ u32 ac = 0; -+ int bits = 0; -+ int i; -+ char *cp = dst; -+ -+ for (i = 0; i < srclen; i++) { -+ ac = (ac << 8) | src[i]; -+ bits += 8; -+ do { -+ bits -= 6; -+ *cp++ = base64url_table[(ac >> bits) & 0x3f]; -+ } while (bits >= 6); -+ } -+ if (bits) -+ *cp++ = base64url_table[(ac << (6 - bits)) & 0x3f]; -+ return cp - dst; -+} -+ -+/** -+ * base64url_decode() - base64url-decode a string -+ * @src: the string to decode. Doesn't need to be NUL-terminated. -+ * @srclen: the length of @src in bytes -+ * @dst: (output) the decoded binary data -+ * -+ * Decodes a string using base64url encoding, i.e. the "Base 64 Encoding with -+ * URL and Filename Safe Alphabet" specified by RFC 4648. '='-padding isn't -+ * accepted, nor are non-encoding characters such as whitespace. -+ * -+ * This implementation hasn't been optimized for performance. -+ * -+ * Return: the length of the resulting decoded binary data in bytes, -+ * or -1 if the string isn't a valid base64url string. -+ */ -+static inline int base64url_decode(const char *src, int srclen, u8 *dst) -+{ -+ u32 ac = 0; -+ int bits = 0; -+ int i; -+ u8 *bp = dst; -+ -+ for (i = 0; i < srclen; i++) { -+ const char *p = strchr(base64url_table, src[i]); -+ -+ if (p == NULL || src[i] == 0) -+ return -1; -+ ac = (ac << 6) | (p - base64url_table); -+ bits += 6; -+ if (bits >= 8) { -+ bits -= 8; -+ *bp++ = (u8)(ac >> bits); -+ } -+ } -+ if (ac & ((1 << bits) - 1)) -+ return -1; -+ return bp - dst; -+} -+ -+/* This version of the code uses base64url encoding for binary data. */ -+#define ENCDATA_ENCODING "base64url" -+ -+/* Wrappers to support various encodings. Add new methods in there. -+ */ -+static inline int encode(const u8 *src, int srclen, char *dst, char *encoding) -+{ -+ if (!strcmp(encoding, "base64url")) -+ return base64url_encode(src, srclen, dst); -+ return -EINVAL; -+} -+ -+static inline int decode(const char *src, int srclen, u8 *dst, char *encoding) -+{ -+ if (!strcmp(encoding, "base64url")) -+ return base64url_decode(src, srclen, dst); -+ return -EINVAL; -+} -+ -+#endif /* _ENCDATA_H */ -diff --git a/fs/ext4/inode.c b/fs/ext4/inode.c -index fb500d12..769eabce 100644 ---- a/fs/ext4/inode.c -+++ b/fs/ext4/inode.c -@@ -46,6 +46,7 @@ - #include "xattr.h" - #include "acl.h" - #include "truncate.h" -+#include "encdata.h" - - #include - -@@ -5620,6 +5621,12 @@ int ext4_getattr(struct user_namespace *mnt_userns, const struct path *path, - STATX_ATTR_VERITY); - - generic_fillattr(mnt_userns, inode, stat); -+ -+ if (flags & EXT4_ENCRYPT_FL && -+ unlikely(!IS_LUSTRE_MOUNT(inode->i_sb))) -+ stat->size = round_up(stat->size, -+ EXT4_ENCRYPTION_UNIT_SIZE); -+ - return 0; - } - -diff --git a/fs/ext4/super.c b/fs/ext4/super.c -index 89d609c9..fd066751 100644 ---- a/fs/ext4/super.c -+++ b/fs/ext4/super.c -@@ -55,6 +55,7 @@ - #include "acl.h" - #include "mballoc.h" - #include "fsmap.h" -+#include "encdata.h" - - #define CREATE_TRACE_POINTS - #include -@@ -7260,6 +7261,7 @@ MODULE_ALIAS_FS("ext4"); - - /* Shared across all ext4 file systems */ - wait_queue_head_t ext4__ioend_wq[EXT4_WQ_HASH_SZ]; -+char encdata_xattr_fmt[NAME_MAX]; - - static int __init ext4_init_fs(void) - { -@@ -7313,6 +7315,12 @@ static int __init ext4_init_fs(void) - if (err) - goto out; - -+ snprintf(encdata_xattr_fmt, sizeof(encdata_xattr_fmt), -+ ENCDATA_XATTR_FMT_1"%%%u[^,]"ENCDATA_XATTR_FMT_2"%%llu" -+ ENCDATA_XATTR_FMT_3"%%%us"ENCDATA_XATTR_FMT_4"%%%us", -+ NAME_MAX, BASE64URL_CHARS(LLCRYPT_SET_CONTEXT_MAX_SIZE), -+ BASE64URL_CHARS(NAME_MAX)); -+ - return 0; - out: - ext4_fc_destroy_dentry_cache(); -diff --git a/fs/ext4/xattr.h b/fs/ext4/xattr.h -index 824faf0b..1e8aa6f2 100644 ---- a/fs/ext4/xattr.h -+++ b/fs/ext4/xattr.h -@@ -140,6 +140,8 @@ extern const struct xattr_handler ext4_xattr_security_handler; - extern const struct xattr_handler ext4_xattr_hurd_handler; - - #define EXT4_XATTR_NAME_ENCRYPTION_CONTEXT "c" -+#define EXT4_XATTR_NAME_ENCDATA "encdata" -+#define EXT4_XATTR_NAME_RAWENCNAME "rawencname" - - /* - * The EXT4_STATE_NO_EXPAND is overloaded and used for two purposes. -diff --git a/fs/ext4/xattr_security.c b/fs/ext4/xattr_security.c -index 8213f66f..6fb465a8 100644 ---- a/fs/ext4/xattr_security.c -+++ b/fs/ext4/xattr_security.c -@@ -10,13 +10,217 @@ - #include - #include "ext4_jbd2.h" - #include "ext4.h" -+#include "critical_encode.h" -+#include "encdata.h" - #include "xattr.h" - -+/* security.encdata is a virtual xattr containing information related -+ * to encrypted files. It is expressed as ASCII text with a "key: value" -+ * format, and space as field separator. For instance: -+ * -+ * { encoding: base64url, size: 3012, enc_ctx: YWJjZGVmZ2hpamtsbW -+ * 5vcHFyc3R1dnd4eXphYmNkZWZnaGlqa2xtbg, enc_name: ZmlsZXdpdGh2ZX -+ * J5bG9uZ25hbWVmaWxld2l0aHZlcnlsb25nbmFtZWZpbGV3aXRodmVyeWxvbmdu -+ * YW1lZmlsZXdpdGg } -+ * -+ * 'encoding' is the encoding method used for binary data, assume name -+ * can be up to 255 chars. -+ * 'size' is the clear text file data length in bytes. -+ * 'enc_ctx' is encoded encryption context, 40 bytes for v2. -+ * 'enc_name' is encoded encrypted name, 256 bytes max. -+ * So on overall, this xattr is at most 727 chars plus terminating '\0'. -+ */ -+static int ext4_build_xattr_encdata(struct dentry *dentry, -+ struct inode *inode, -+ void *buffer, size_t size) -+{ -+ char encoded_enc_ctx[BASE64URL_CHARS(LLCRYPT_SET_CONTEXT_MAX_SIZE) + 1]; -+ unsigned char enc_ctx[LLCRYPT_SET_CONTEXT_MAX_SIZE]; -+ char encoded_name[BASE64URL_CHARS(NAME_MAX) + 1]; -+ struct ext4_filename fname = { 0 }; -+ struct inode *parent = NULL; -+ int encoded_enc_ctx_len = 0; -+ int encoded_name_len = 0; -+ char size_str[32]; -+ int retval; -+ -+ if (!IS_ENCRYPTED(inode)) { -+ retval = -ENODATA; -+ goto out; -+ } -+ -+ /* get size */ -+ retval = snprintf(size_str, sizeof(size_str), "%llu", -+ S_ISDIR(inode->i_mode) ? 0 : inode->i_size); -+ if (retval >= sizeof(size_str)) { -+ retval = -ERANGE; -+ goto out; -+ } -+ -+ /* get raw name */ -+ if (dentry && dentry->d_parent) -+ parent = dentry->d_parent->d_inode; -+ -+ retval = ext4_setup_filename(parent, &dentry->d_name, 1, &fname); -+ if (retval) -+ goto out; -+ -+ /* base64url-encode raw name */ -+ encoded_name_len = encode(fname.disk_name.name, fname.disk_name.len, -+ encoded_name, ENCDATA_ENCODING); -+ if (encoded_name_len == -EINVAL) { -+ retval = -EINVAL; -+ goto out; -+ } -+ encoded_name[encoded_name_len] = '\0'; -+ -+ if (!buffer) { -+ /* Return exact xattr length we would return if called with -+ * non-NULL buffer. -+ */ -+ retval = sizeof(ENCDATA_XATTR_FMT_COMP) - 1 + -+ sizeof(ENCDATA_ENCODING) - 1 + strlen(size_str) + -+ BASE64URL_CHARS(LLCRYPT_SET_CONTEXT_MAX_SIZE) + -+ encoded_name_len; -+ goto out; -+ } -+ -+ /* get encryption context */ -+ retval = ext4_xattr_get(inode, EXT4_XATTR_INDEX_ENCRYPTION, -+ EXT4_XATTR_NAME_ENCRYPTION_CONTEXT, -+ enc_ctx, sizeof(enc_ctx)); -+ -+ if (retval < 0) -+ goto out; -+ -+ /* base64url-encode encryption context */ -+ encoded_enc_ctx_len = encode(enc_ctx, retval, encoded_enc_ctx, -+ ENCDATA_ENCODING); -+ if (encoded_enc_ctx_len == -EINVAL) { -+ retval = -EINVAL; -+ goto out; -+ } -+ encoded_enc_ctx[encoded_enc_ctx_len] = '\0'; -+ -+ /* write EXT4_XATTR_ENCDATA info into buffer */ -+ retval = snprintf(buffer, size, -+ ENCDATA_XATTR_FMT_1 ENCDATA_ENCODING -+ ENCDATA_XATTR_FMT_2"%s"ENCDATA_XATTR_FMT_3"%s" -+ ENCDATA_XATTR_FMT_4"%s"ENCDATA_XATTR_FMT_END, -+ size_str, encoded_enc_ctx, -+ encoded_name_len ? encoded_name : ""); -+ if (retval >= size) -+ retval = -ERANGE; -+ -+out: -+ if (fname.disk_name.name != dentry->d_name.name) -+ kfree(fname.disk_name.name); -+ -+ return retval; -+} -+ -+static int ext4_process_xattr_encdata(struct inode *inode, -+ const void *value, size_t size, -+ int flags) -+{ -+ char encoded_enc_ctx[BASE64URL_CHARS(LLCRYPT_SET_CONTEXT_MAX_SIZE) + 1]; -+ unsigned char enc_ctx[LLCRYPT_SET_CONTEXT_MAX_SIZE]; -+ char encoded_name[BASE64URL_CHARS(NAME_MAX) + 1]; -+ char encoding[NAME_MAX + 1]; -+ char name[NAME_MAX + 1]; -+ loff_t disk_size = 0; -+ char *buffer = NULL; -+ int enc_ctx_len = 0; -+ int name_len = 0; -+ int retval = 0; -+ -+ if (IS_ENCRYPTED(inode) || !value || flags & XATTR_REPLACE) { -+ retval = -EINVAL; -+ goto out; -+ } -+ -+ buffer = kmalloc(size + 1, GFP_NOFS); -+ if (!buffer) { -+ retval = -ENOMEM; -+ goto out; -+ } -+ memcpy(buffer, value, size); -+ buffer[size] = '\0'; -+ -+ retval = sscanf(buffer, encdata_xattr_fmt, -+ encoding, &disk_size, encoded_enc_ctx, encoded_name); -+ if (retval < 4) { -+ retval = -EINVAL; -+ goto out; -+ } -+ -+ /* get former encryption context: should not exist */ -+ retval = ext4_xattr_get(inode, EXT4_XATTR_INDEX_ENCRYPTION, -+ EXT4_XATTR_NAME_ENCRYPTION_CONTEXT, NULL, 0); -+ if (retval != -ENODATA) { -+ retval = -EINVAL; -+ goto out; -+ } -+ -+ if (strlen(encoded_enc_ctx) > -+ BASE64URL_CHARS(LLCRYPT_SET_CONTEXT_MAX_SIZE)) { -+ retval = -EINVAL; -+ goto out; -+ } -+ -+ /* base64url-decode encryption context */ -+ retval = decode(encoded_enc_ctx, strlen(encoded_enc_ctx), -+ enc_ctx, encoding); -+ if (retval < 0) { -+ retval = -EINVAL; -+ goto out; -+ } -+ enc_ctx_len = retval; -+ -+ /* set encryption context, this will set encryption flag */ -+ retval = ext4_xattr_set(inode, EXT4_XATTR_INDEX_ENCRYPTION, -+ EXT4_XATTR_NAME_ENCRYPTION_CONTEXT, -+ enc_ctx, enc_ctx_len, XATTR_CREATE); -+ if (retval < 0) -+ goto out; -+ -+ if (disk_size) { -+ /* set size on inode */ -+ spin_lock(&inode->i_lock); -+ i_size_write(inode, disk_size); -+ EXT4_I(inode)->i_disksize = disk_size; -+ spin_unlock(&inode->i_lock); -+ mark_inode_dirty(inode); -+ } -+ -+ /* put raw encrypted name in EXT4_XATTR_NAME_RAWENCNAME xattr, -+ * for later use, but base64url-decode first -+ */ -+ retval = decode(encoded_name, strlen(encoded_name), name, encoding); -+ if (retval < 0) { -+ retval = -EINVAL; -+ goto out; -+ } -+ name_len = retval; -+ -+ retval = ext4_xattr_set(inode, EXT4_XATTR_INDEX_LUSTRE, -+ EXT4_XATTR_NAME_RAWENCNAME, -+ name, name_len, XATTR_CREATE); -+ -+out: -+ kfree(buffer); -+ -+ return retval; -+} -+ - static int - ext4_xattr_security_get(const struct xattr_handler *handler, -- struct dentry *unused, struct inode *inode, -+ struct dentry *dentry, struct inode *inode, - const char *name, void *buffer, size_t size) - { -+ if (!strncmp(name, EXT4_XATTR_NAME_ENCDATA, strlen(name))) -+ return ext4_build_xattr_encdata(dentry, inode, buffer, size); -+ - return ext4_xattr_get(inode, EXT4_XATTR_INDEX_SECURITY, - name, buffer, size); - } -@@ -28,6 +232,9 @@ ext4_xattr_security_set(const struct xattr_handler *handler, - const char *name, const void *value, - size_t size, int flags) - { -+ if (!strncmp(name, EXT4_XATTR_NAME_ENCDATA, strlen(name))) -+ return ext4_process_xattr_encdata(inode, value, size, flags); -+ - return ext4_xattr_set(inode, EXT4_XATTR_INDEX_SECURITY, - name, value, size, flags); - } --- -2.25.1 - diff --git a/ldiskfs/kernel_patches/patches/rhel9.2/ext4-filename-encode.patch b/ldiskfs/kernel_patches/patches/rhel9.2/ext4-filename-encode.patch deleted file mode 100644 index e40ac38..0000000 --- a/ldiskfs/kernel_patches/patches/rhel9.2/ext4-filename-encode.patch +++ /dev/null @@ -1,398 +0,0 @@ -diff --git a/fs/ext4/critical_encode.h b/fs/ext4/critical_encode.h -new file mode 100644 -index 00000000..a624594d ---- /dev/null -+++ b/fs/ext4/critical_encode.h -@@ -0,0 +1,168 @@ -+/* -+ * critical_encode.h -+ * -+ * Copyright (c) 2022 Whamcloud -+ */ -+ -+#ifndef _CRITICAL_ENCODE_H -+#define _CRITICAL_ENCODE_H -+ -+#include -+ -+/* Encoding/decoding routines inspired from yEnc principles. -+ * We just take care of a few critical characters: -+ * NULL, LF, CR, /, DEL and =. -+ * If such a char is found, it is replaced with '=' followed by -+ * the char value + 64. -+ * All other chars are left untouched. -+ * Efficiency of this encoding depends on the occurences of the -+ * critical chars, but statistically on binary data it can be much higher -+ * than base64 for instance. -+ */ -+static inline int critical_encode(const u8 *src, int len, char *dst) -+{ -+ u8 *p = (u8 *)src, *q = dst; -+ -+ while (p - src < len) { -+ /* escape NULL, LF, CR, /, DEL and = */ -+ if (unlikely(*p == 0x0 || *p == 0xA || *p == 0xD || -+ *p == '/' || *p == 0x7F || *p == '=')) { -+ *(q++) = '='; -+ *(q++) = *(p++) + 64; -+ } else { -+ *(q++) = *(p++); -+ } -+ } -+ -+ return (char *)q - dst; -+} -+ -+/* returns the number of chars encoding would produce */ -+static inline int critical_chars(const u8 *src, int len) -+{ -+ u8 *p = (u8 *)src; -+ int newlen = len; -+ -+ while (p - src < len) { -+ /* NULL, LF, CR, /, DEL and = cost an additional '=' */ -+ if (unlikely(*p == 0x0 || *p == 0xA || *p == 0xD || -+ *p == '/' || *p == 0x7F || *p == '=')) -+ newlen++; -+ p++; -+ } -+ -+ return newlen; -+} -+ -+/* decoding routine - returns the number of chars in output */ -+static inline int critical_decode(const u8 *src, int len, char *dst) -+{ -+ u8 *p = (u8 *)src, *q = dst; -+ -+ while (p - src < len) { -+ if (unlikely(*p == '=')) { -+ *(q++) = *(++p) - 64; -+ p++; -+ } else { -+ *(q++) = *(p++); -+ } -+ } -+ -+ return (char *)q - dst; -+} -+ -+#define fscrypt_get_encryption_info(inode) \ -+ (unlikely(!IS_LUSTRE_MOUNT(inode->i_sb)) ? 0 : -EOPNOTSUPP) -+ -+static inline int ext4_has_permitted_context(struct inode *parent, -+ struct inode *child) -+{ -+ if (unlikely(!IS_LUSTRE_MOUNT(parent->i_sb))) -+ return 1; -+ return fscrypt_has_permitted_context(parent, child); -+} -+ -+struct ext4_filename; -+ -+static inline int ext4_prepare_lookup(struct inode *dir, -+ struct dentry *dentry, -+ struct ext4_filename *fname) -+{ -+ if (unlikely(!IS_LUSTRE_MOUNT(dir->i_sb))) -+ return 0; -+ return ext4_fname_prepare_lookup(dir, dentry, fname); -+} -+ -+static inline int ext4_fname_alloc_buffer(const struct inode *inode, -+ u32 max_encrypted_len, -+ struct fscrypt_str *crypto_str) -+{ -+ crypto_str->name = kmalloc(max_encrypted_len + 1, GFP_NOFS); -+ if (!crypto_str->name) -+ return -ENOMEM; -+ crypto_str->len = max_encrypted_len; -+ return 0; -+} -+ -+static inline void ext4_fname_free_buffer(struct fscrypt_str *crypto_str) -+{ -+ if (!crypto_str) -+ return; -+ kfree(crypto_str->name); -+ crypto_str->name = NULL; -+} -+ -+static inline int ext4_fname_disk_to_usr(struct inode *inode, -+ u32 hash, u32 minor_hash, -+ const struct fscrypt_str *iname, -+ struct fscrypt_str *oname) -+{ -+ int presented_len; -+ -+ presented_len = critical_encode(iname->name, iname->len, oname->name); -+ if (presented_len > NAME_MAX) { -+ /* truncate at NAME_MAX, -+ * or NAME_MAX-1 if name ends with '=' to avoid decoding issue -+ */ -+ presented_len = NAME_MAX; -+ if (oname->name[presented_len - 1] == '=') -+ presented_len--; -+ oname->len = presented_len; -+ } -+ oname->name[presented_len] = '\0'; -+ -+ return 0; -+} -+ -+static inline int ext4_setup_filename(struct inode *dir, -+ const struct qstr *iname, -+ int lookup, -+ struct ext4_filename *fname) -+{ -+ fname->usr_fname = iname; -+ -+ if (lookup && IS_ENCRYPTED(dir) && -+ unlikely(!IS_LUSTRE_MOUNT(dir->i_sb) && -+ strnchr(iname->name, iname->len, '='))) { -+ /* Only proceed to critical decode if -+ * iname contains escape char '='. -+ */ -+ int len = iname->len; -+ char *buf; -+ -+ buf = kmalloc(len, GFP_NOFS); -+ if (!buf) -+ return -ENOMEM; -+ -+ len = critical_decode(iname->name, len, buf); -+ fname->disk_name.name = (unsigned char *)buf; -+ fname->disk_name.len = len; -+ return 0; -+ } -+ -+ fname->disk_name.name = (unsigned char *) iname->name; -+ fname->disk_name.len = iname->len; -+ return 0; -+} -+ -+#endif /* _CRITICAL_ENCODE_H */ -diff --git a/fs/ext4/dir.c b/fs/ext4/dir.c -index b8e4df14..a3e4904e 100644 ---- a/fs/ext4/dir.c -+++ b/fs/ext4/dir.c -@@ -29,6 +29,7 @@ - #include - #include "ext4.h" - #include "xattr.h" -+#include "critical_encode.h" - - static int ext4_dx_readdir(struct file *, struct dir_context *); - -@@ -161,7 +162,8 @@ static int ext4_readdir(struct file *file, struct dir_context *ctx) - return err; - } - -- if (IS_ENCRYPTED(inode)) { -+ /* disable decryption of filename, present only escaped name */ -+ if (0 && IS_ENCRYPTED(inode)) { - err = fscrypt_fname_alloc_buffer(EXT4_NAME_LEN, &fstr); - if (err < 0) - return err; -@@ -275,24 +277,35 @@ static int ext4_readdir(struct file *file, struct dir_context *ctx) - get_dtype(sb, de->file_type))) - goto done; - } else { -- int save_len = fstr.len; - struct fscrypt_str de_name = - FSTR_INIT(de->name, - de->name_len); -+ int presented_len; - - /* Directory is encrypted */ -- err = fscrypt_fname_disk_to_usr(inode, -+ presented_len = critical_chars(de->name, -+ de->name_len); -+ err = ext4_fname_alloc_buffer(inode, -+ presented_len, -+ &fstr); -+ if (err) -+ goto errout; -+ -+ err = ext4_fname_disk_to_usr(inode, - EXT4_DIRENT_HASH(de), - EXT4_DIRENT_MINOR_HASH(de), - &de_name, &fstr); - de_name = fstr; -- fstr.len = save_len; -- if (err) -+ if (err) { -+ ext4_fname_free_buffer(&fstr); - goto errout; -- if (!dir_emit(ctx, -+ } -+ err = dir_emit(ctx, - de_name.name, de_name.len, - le32_to_cpu(de->inode), -- get_dtype(sb, de->file_type))) -+ get_dtype(sb, de->file_type)); -+ ext4_fname_free_buffer(&fstr); -+ if (!err) - goto done; - } - } -diff --git a/fs/ext4/ialloc.c b/fs/ext4/ialloc.c -index 5d5641b6..8dee069a 100644 ---- a/fs/ext4/ialloc.c -+++ b/fs/ext4/ialloc.c -@@ -30,6 +30,7 @@ - #include "ext4_jbd2.h" - #include "xattr.h" - #include "acl.h" -+#include "critical_encode.h" - - #include - -diff --git a/fs/ext4/namei.c b/fs/ext4/namei.c -index 4934a46a..8f35bd62 100644 ---- a/fs/ext4/namei.c -+++ b/fs/ext4/namei.c -@@ -42,6 +42,7 @@ - - #include "xattr.h" - #include "acl.h" -+#include "critical_encode.h" - - #include - /* -@@ -1478,22 +1479,31 @@ static int htree_dirblock_to_tree(struct file *dir_file, - hinfo->hash, hinfo->minor_hash, de, - &tmp_str); - } else { -- int save_len = fname_crypto_str.len; - struct fscrypt_str de_name = FSTR_INIT(de->name, - de->name_len); -+ int presented_len; - - /* Directory is encrypted */ -- err = fscrypt_fname_disk_to_usr(dir, hinfo->hash, -+ presented_len = critical_chars(de->name, de->name_len); -+ err = ext4_fname_alloc_buffer(dir, presented_len, -+ &fname_crypto_str); -+ if (err) { -+ count = err; -+ goto errout; -+ } -+ -+ err = ext4_fname_disk_to_usr(dir, hinfo->hash, - hinfo->minor_hash, &de_name, - &fname_crypto_str); - if (err) { -+ ext4_fname_free_buffer(&fname_crypto_str); - count = err; - goto errout; - } - err = ext4_htree_store_dirent(dir_file, - hinfo->hash, hinfo->minor_hash, de, - &fname_crypto_str); -- fname_crypto_str.len = save_len; -+ ext4_fname_free_buffer(&fname_crypto_str); - } - if (err != 0) { - count = err; -@@ -1818,7 +1828,7 @@ int ext4_fname_setup_ci_filename(struct inode *dir, const struct qstr *iname, - */ - static bool ext4_match(struct inode *parent, - const struct ext4_filename *fname, -- struct ext4_dir_entry_2 *de) -+ struct ext4_dir_entry_2 *de, int denamelen) - { - struct fscrypt_name f; - -@@ -1853,7 +1863,7 @@ static bool ext4_match(struct inode *parent, - } - #endif - -- return fscrypt_match_name(&f, de->name, de->name_len); -+ return fscrypt_match_name(&f, de->name, denamelen); - } - - /* -@@ -1864,16 +1874,30 @@ int ext4_search_dir(struct buffer_head *bh, char *search_buf, int buf_size, - unsigned int offset, struct ext4_dir_entry_2 **res_dir) - { - struct ext4_dir_entry_2 * de; -+ bool probablytrunc; - char * dlimit; -- int de_len; -+ int de_len, denamelen; - - de = (struct ext4_dir_entry_2 *)search_buf; - dlimit = search_buf + buf_size; -+ /* fname is probably truncated if it is the decoded representation of -+ * an encrypted filename not aligned on a 32-byte boundary -+ */ -+ probablytrunc = !IS_LUSTRE_MOUNT(dir->i_sb) && IS_ENCRYPTED(dir) && -+ fname->disk_name.len & 31; - while ((char *) de < dlimit - EXT4_BASE_DIR_LEN) { - /* this code is executed quadratically often */ - /* do minimal checking `by hand' */ -+ denamelen = de->name_len; -+ if (unlikely(probablytrunc) && -+ de->name_len > fname->disk_name.len) -+ /* Adjust name len to look for a partial match. -+ * Since it is binary encrypted names, there -+ * should not be any collision between names. -+ */ -+ denamelen = fname->disk_name.len; - if (de->name + de->name_len <= dlimit && -- ext4_match(dir, fname, de)) { -+ ext4_match(dir, fname, de, denamelen)) { - /* found a match - just to be sure, do - * a full check */ - if (ext4_check_dir_entry(dir, NULL, de, bh, search_buf, -@@ -2075,7 +2099,7 @@ struct buffer_head *ext4_find_entry_locked(struct inode *dir, - struct ext4_filename fname; - struct buffer_head *bh; - -- err = ext4_fname_setup_filename(dir, d_name, 1, &fname); -+ err = ext4_setup_filename(dir, d_name, 1, &fname); - if (err == -ENOENT) - return NULL; - if (err) -@@ -2083,7 +2107,9 @@ struct buffer_head *ext4_find_entry_locked(struct inode *dir, - - bh = __ext4_find_entry(dir, &fname, res_dir, inlined, lck); - -- ext4_fname_free_filename(&fname); -+ if (fname.disk_name.name != d_name->name) -+ kfree(fname.disk_name.name); -+ - return bh; - } - -@@ -2097,7 +2123,7 @@ static struct buffer_head *ext4_lookup_entry(struct inode *dir, - struct ext4_filename fname; - struct buffer_head *bh; - -- err = ext4_fname_prepare_lookup(dir, dentry, &fname); -+ err = ext4_prepare_lookup(dir, dentry, &fname); - generic_set_encrypted_ci_d_ops(dentry); - if (err == -ENOENT) - return NULL; -@@ -2198,7 +2224,7 @@ static struct dentry *ext4_lookup(struct inode *dir, struct dentry *dentry, unsi - } - if (!IS_ERR(inode) && IS_ENCRYPTED(dir) && - (S_ISDIR(inode->i_mode) || S_ISLNK(inode->i_mode)) && -- !fscrypt_has_permitted_context(dir, inode)) { -+ !ext4_has_permitted_context(dir, inode)) { - ext4_warning(inode->i_sb, - "Inconsistent encryption contexts: %lu/%lu", - dir->i_ino, inode->i_ino); -@@ -2498,7 +2524,7 @@ int ext4_find_dest_de(struct inode *dir, struct inode *inode, - if (ext4_check_dir_entry(dir, NULL, de, bh, - buf, buf_size, offset)) - return -EFSCORRUPTED; -- if (ext4_match(dir, fname, de)) -+ if (ext4_match(dir, fname, de, de->name_len)) - return -EEXIST; - nlen = EXT4_DIR_ENTRY_LEN(de, dir); - rlen = ext4_rec_len_from_disk(de->rec_len, buf_size); --- -2.25.1 - diff --git a/ldiskfs/kernel_patches/series/ldiskfs-5.14-rhel9.2.series b/ldiskfs/kernel_patches/series/ldiskfs-5.14-rhel9.2.series index 078007e..243409e 100644 --- a/ldiskfs/kernel_patches/series/ldiskfs-5.14-rhel9.2.series +++ b/ldiskfs/kernel_patches/series/ldiskfs-5.14-rhel9.2.series @@ -32,7 +32,5 @@ rhel8/ext4-ext-merge.patch linux-5.14/ext4-xattr-disable-credits-check.patch rhel9.2/ext4-fiemap-kernel-data.patch rhel8/ext4-old_ea_inodes_handling_fix.patch -rhel9.2/ext4-filename-encode.patch rhel9.1/ext4-enc-flag.patch -rhel9.2/ext4-encdata.patch rhel9/ext4-add-periodic-superblock-update.patch -- 1.8.3.1