Merge tag 'ecryptfs-7.3-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/tyhicks/ecryptfs

Pull eCryptfs updates from Tyler Hicks:

 - Hardening and fixes for maliciously crafted eCryptfs metadata in the
   lower encrypted file

 - Hardening and fixes for maliciously crafted userspace <-> kernel
   miscdev communications

 - Locking fixes for userspace <-> kernel miscdev communications

 - Fix to display encrypted filename related mount options

 - Clean up address_space_operations and reduce build dependencies by
   moving to filemap_dirty_folio()

 - Get rid of an unnecessary memory allocation in the inode update path

 - Kernel-doc formatting corrections

* tag 'ecryptfs-7.3-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/tyhicks/ecryptfs:
  ecryptfs: ecryptfs_kernel.h: clean up kernel-doc comments
  ecryptfs: use filemap_dirty_folio for address space operations
  ecryptfs: avoid heap allocation for inode size write
  ecryptfs: show filename encryption options
  eCryptfs: bound the packet-length peek to the user buffer
  ecryptfs: reject too-small tag 70 packets
  ecryptfs: fix tag 11 packet exact-fit size check
  ecryptfs: pass packet set buffer size to parser
  ecryptfs: hold msg ctx list lock when cleaning daemon queue
  ecryptfs: release message context on send failure
  ecryptfs: reject oversized encrypted_key_size in parse_tag_3_packet
This commit is contained in:
Linus Torvalds
2026-08-21 12:32:01 -07:00
7 changed files with 73 additions and 42 deletions

View File

@@ -1197,7 +1197,7 @@ static int ecryptfs_read_headers_virt(char *page_virt,
} else
set_default_header_data(crypt_stat);
rc = ecryptfs_parse_packet_set(crypt_stat, (page_virt + offset),
ecryptfs_dentry);
PAGE_SIZE - offset, ecryptfs_dentry);
out:
return rc;
}

View File

@@ -1,5 +1,5 @@
/* SPDX-License-Identifier: GPL-2.0-or-later */
/**
/*
* eCryptfs: Linux filesystem encryption layer
* Kernel declarations.
*
@@ -204,7 +204,7 @@ struct ecryptfs_filename {
char dentry_name[ECRYPTFS_ENCRYPTED_DENTRY_NAME_LEN + 1];
};
/**
/*
* This is the primary struct associated with each encrypted file.
*
* TODO: cache align/pack?
@@ -255,7 +255,8 @@ struct ecryptfs_inode_info {
};
/**
* ecryptfs_global_auth_tok - A key used to encrypt all new files under the mountpoint
* struct ecryptfs_global_auth_tok - A key used to encrypt all new files
* under the mountpoint
* @flags: Status flags
* @mount_crypt_stat_list: These auth_toks hang off the mount-wide
* cryptographic context. Every time a new
@@ -263,7 +264,6 @@ struct ecryptfs_inode_info {
* the auth_toks on that list to the set of
* auth_toks on the inode's crypt_stat
* @global_auth_tok_key: The key from the user's keyring for the sig
* @global_auth_tok: The key contents
* @sig: The key identifier
*
* ecryptfs_global_auth_tok structs refer to authentication token keys
@@ -283,7 +283,7 @@ struct ecryptfs_global_auth_tok {
};
/**
* ecryptfs_key_tfm - Persistent key tfm
* struct ecryptfs_key_tfm - Persistent key tfm
* @key_tfm: crypto API handle to the key
* @key_size: Key size in bytes
* @key_tfm_mutex: Mutex to ensure only one operation in eCryptfs is
@@ -306,7 +306,7 @@ struct ecryptfs_key_tfm {
extern struct mutex key_tfm_list_mutex;
/**
/*
* This struct is to enable a mount-wide passphrase/salt combo. This
* is more or less a stopgap to provide similar functionality to other
* crypto filesystems like EncFS or CFS until full policy support is
@@ -580,7 +580,8 @@ int ecryptfs_generate_key_packet_set(char *dest_base,
size_t *len, size_t max);
int
ecryptfs_parse_packet_set(struct ecryptfs_crypt_stat *crypt_stat,
unsigned char *src, struct dentry *ecryptfs_dentry);
unsigned char *src, size_t src_size,
struct dentry *ecryptfs_dentry);
int ecryptfs_truncate(struct dentry *dentry, loff_t new_length);
ssize_t
ecryptfs_getxattr_lower(struct dentry *lower_dentry, struct inode *lower_inode,

View File

@@ -894,6 +894,12 @@ ecryptfs_parse_tag_70_packet(char **filename, size_t *filename_size,
"rc = [%d]\n", __func__, rc);
goto out;
}
if (s->parsed_tag_70_packet_size < (ECRYPTFS_SIG_SIZE + 2)) {
ecryptfs_printk(KERN_WARNING, "Invalid packet size [%zd]\n",
s->parsed_tag_70_packet_size);
rc = -EINVAL;
goto out;
}
s->block_aligned_filename_size = (s->parsed_tag_70_packet_size
- ECRYPTFS_SIG_SIZE - 1);
if ((1 + s->packet_size_len + s->parsed_tag_70_packet_size)
@@ -1384,10 +1390,20 @@ parse_tag_3_packet(struct ecryptfs_crypt_stat *crypt_stat,
}
(*new_auth_tok)->session_key.encrypted_key_size =
(body_size - (ECRYPTFS_SALT_SIZE + 5));
/*
* Although encrypted_key_size is copied into the
* encrypted_key[ECRYPTFS_MAX_ENCRYPTED_KEY_BYTES] buffer here,
* it later bounds operations on a smaller buffer:
* decrypt_passphrase_encrypted_session_key() sets decrypted_key_size =
* encrypted_key_size and decrypts into
* decrypted_key[ECRYPTFS_MAX_KEY_BYTES], then memcpy's into
* crypt_stat->key[ECRYPTFS_MAX_KEY_BYTES]. Limit to
* ECRYPTFS_MAX_KEY_BYTES to protect those smaller buffers.
*/
if ((*new_auth_tok)->session_key.encrypted_key_size
> ECRYPTFS_MAX_ENCRYPTED_KEY_BYTES) {
> ECRYPTFS_MAX_KEY_BYTES) {
printk(KERN_WARNING "Tag 3 packet contains key larger "
"than ECRYPTFS_MAX_ENCRYPTED_KEY_BYTES\n");
"than ECRYPTFS_MAX_KEY_BYTES\n");
rc = -EINVAL;
goto out_free;
}
@@ -1537,7 +1553,7 @@ parse_tag_11_packet(unsigned char *data, unsigned char *contents,
}
(*packet_size) += length_size;
(*tag_11_contents_size) = (body_size - 14);
if (unlikely((*packet_size) + body_size + 1 > max_packet_size)) {
if (unlikely((*packet_size) + body_size > max_packet_size)) {
printk(KERN_ERR "Packet size exceeds max\n");
rc = -EINVAL;
goto out;
@@ -1704,6 +1720,7 @@ decrypt_passphrase_encrypted_session_key(struct ecryptfs_auth_tok *auth_tok,
* ecryptfs_parse_packet_set
* @crypt_stat: The cryptographic context
* @src: Virtual address of region of memory containing the packets
* @src_size: Size of the packet set buffer
* @ecryptfs_dentry: The eCryptfs dentry associated with the packet set
*
* Get crypt_stat to have the file's session key if the requisite key
@@ -1714,7 +1731,7 @@ decrypt_passphrase_encrypted_session_key(struct ecryptfs_auth_tok *auth_tok,
* conditions.
*/
int ecryptfs_parse_packet_set(struct ecryptfs_crypt_stat *crypt_stat,
unsigned char *src,
unsigned char *src, size_t src_size,
struct dentry *ecryptfs_dentry)
{
size_t i = 0;
@@ -1736,7 +1753,11 @@ int ecryptfs_parse_packet_set(struct ecryptfs_crypt_stat *crypt_stat,
* added the our &auth_tok_list */
next_packet_is_auth_tok_packet = 1;
while (next_packet_is_auth_tok_packet) {
size_t max_packet_size = ((PAGE_SIZE - 8) - i);
size_t max_packet_size;
if (i >= src_size)
break;
max_packet_size = src_size - i;
switch (src[i]) {
case ECRYPTFS_TAG_3_PACKET_TYPE:
@@ -1751,12 +1772,16 @@ int ecryptfs_parse_packet_set(struct ecryptfs_crypt_stat *crypt_stat,
goto out_wipe_list;
}
i += packet_size;
if (i > src_size) {
rc = -EIO;
goto out_wipe_list;
}
rc = parse_tag_11_packet((unsigned char *)&src[i],
sig_tmp_space,
ECRYPTFS_SIG_SIZE,
&tag_11_contents_size,
&tag_11_packet_size,
max_packet_size);
src_size - i);
if (rc) {
ecryptfs_printk(KERN_ERR, "No valid "
"(ecryptfs-specific) literal "
@@ -1768,6 +1793,10 @@ int ecryptfs_parse_packet_set(struct ecryptfs_crypt_stat *crypt_stat,
goto out_wipe_list;
}
i += tag_11_packet_size;
if (i > src_size) {
rc = -EIO;
goto out_wipe_list;
}
if (ECRYPTFS_SIG_SIZE != tag_11_contents_size) {
ecryptfs_printk(KERN_ERR, "Expected "
"signature of size [%d]; "
@@ -1793,6 +1822,10 @@ int ecryptfs_parse_packet_set(struct ecryptfs_crypt_stat *crypt_stat,
goto out_wipe_list;
}
i += packet_size;
if (i > src_size) {
rc = -EIO;
goto out_wipe_list;
}
crypt_stat->flags |= ECRYPTFS_ENCRYPTED;
break;
case ECRYPTFS_TAG_11_PACKET_TYPE:

View File

@@ -166,6 +166,7 @@ int ecryptfs_exorcise_daemon(struct ecryptfs_daemon *daemon)
mutex_unlock(&daemon->mux);
goto out;
}
mutex_lock(&ecryptfs_msg_ctx_lists_mux);
list_for_each_entry_safe(msg_ctx, msg_ctx_tmp,
&daemon->msg_ctx_out_queue, daemon_out_list) {
list_del(&msg_ctx->daemon_out_list);
@@ -174,6 +175,7 @@ int ecryptfs_exorcise_daemon(struct ecryptfs_daemon *daemon)
"the out queue of a dying daemon\n", __func__);
ecryptfs_msg_ctx_alloc_to_free(msg_ctx);
}
mutex_unlock(&ecryptfs_msg_ctx_lists_mux);
hlist_del(&daemon->euid_chain);
mutex_unlock(&daemon->mux);
kfree_sensitive(daemon);
@@ -284,9 +286,16 @@ ecryptfs_send_message_locked(char *data, int data_len, u8 msg_type,
mutex_unlock(&ecryptfs_msg_ctx_lists_mux);
rc = ecryptfs_send_miscdev(data, data_len, *msg_ctx, msg_type, 0,
daemon);
if (rc)
if (rc) {
printk(KERN_ERR "%s: Error attempting to send message to "
"userspace daemon; rc = [%d]\n", __func__, rc);
mutex_lock(&ecryptfs_msg_ctx_lists_mux);
mutex_lock(&(*msg_ctx)->mux);
ecryptfs_msg_ctx_alloc_to_free(*msg_ctx);
mutex_unlock(&(*msg_ctx)->mux);
mutex_unlock(&ecryptfs_msg_ctx_lists_mux);
*msg_ctx = NULL;
}
out:
return rc;
}

View File

@@ -360,7 +360,7 @@ ecryptfs_miscdev_write(struct file *file, const char __user *buf,
u32 seq;
size_t packet_size, packet_size_length;
char *data;
unsigned char packet_size_peek[ECRYPTFS_MAX_PKT_LEN_SIZE];
unsigned char packet_size_peek[ECRYPTFS_MAX_PKT_LEN_SIZE] = { };
ssize_t rc;
if (count == 0) {
@@ -376,7 +376,8 @@ ecryptfs_miscdev_write(struct file *file, const char __user *buf,
}
if (copy_from_user(packet_size_peek, &buf[PKT_LEN_OFFSET],
sizeof(packet_size_peek))) {
min_t(size_t, count - PKT_LEN_OFFSET,
sizeof(packet_size_peek)))) {
printk(KERN_WARNING "%s: Error while inspecting packet size\n",
__func__);
return -EFAULT;

View File

@@ -355,24 +355,17 @@ static int ecryptfs_write_begin(const struct kiocb *iocb,
*/
static int ecryptfs_write_inode_size_to_header(struct inode *ecryptfs_inode)
{
char *file_size_virt;
__be64 file_size;
int rc;
file_size_virt = kmalloc(sizeof(u64), GFP_KERNEL);
if (!file_size_virt) {
rc = -ENOMEM;
goto out;
}
put_unaligned_be64(i_size_read(ecryptfs_inode), file_size_virt);
rc = ecryptfs_write_lower(ecryptfs_inode, file_size_virt, 0,
sizeof(u64));
kfree(file_size_virt);
file_size = cpu_to_be64(i_size_read(ecryptfs_inode));
rc = ecryptfs_write_lower(ecryptfs_inode, (char *)&file_size, 0,
sizeof(file_size));
if (rc < 0)
printk(KERN_ERR "%s: Error writing file size to header; "
"rc = [%d]\n", __func__, rc);
else
rc = 0;
out:
return rc;
}
@@ -510,21 +503,8 @@ static sector_t ecryptfs_bmap(struct address_space *mapping, sector_t block)
return block;
}
#include <linux/buffer_head.h>
const struct address_space_operations ecryptfs_aops = {
/*
* XXX: This is pretty broken for multiple reasons: ecryptfs does not
* actually use buffer_heads, and ecryptfs will crash without
* CONFIG_BLOCK. But it matches the behavior before the default for
* address_space_operations without the ->dirty_folio method was
* cleaned up, so this is the best we can do without maintainer
* feedback.
*/
#ifdef CONFIG_BLOCK
.dirty_folio = block_dirty_folio,
.invalidate_folio = block_invalidate_folio,
#endif
.dirty_folio = filemap_dirty_folio,
.writepages = ecryptfs_writepages,
.read_folio = ecryptfs_read_folio,
.write_begin = ecryptfs_write_begin,

View File

@@ -150,6 +150,13 @@ static int ecryptfs_show_options(struct seq_file *m, struct dentry *root)
if (mount_crypt_stat->global_default_cipher_key_size)
seq_printf(m, ",ecryptfs_key_bytes=%zd",
mount_crypt_stat->global_default_cipher_key_size);
if (mount_crypt_stat->flags & ECRYPTFS_GLOBAL_ENCRYPT_FILENAMES) {
seq_printf(m, ",ecryptfs_fn_cipher=%s",
mount_crypt_stat->global_default_fn_cipher_name);
if (mount_crypt_stat->global_default_fn_cipher_key_bytes)
seq_printf(m, ",ecryptfs_fn_key_bytes=%zd",
mount_crypt_stat->global_default_fn_cipher_key_bytes);
}
if (mount_crypt_stat->flags & ECRYPTFS_PLAINTEXT_PASSTHROUGH_ENABLED)
seq_printf(m, ",ecryptfs_passthrough");
if (mount_crypt_stat->flags & ECRYPTFS_XATTR_METADATA_ENABLED)