mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
synced 2026-08-30 11:03:07 -04:00
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:
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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)
|
||||
|
||||
Reference in New Issue
Block a user