diff options
Diffstat (limited to 'fs')
40 files changed, 526 insertions, 600 deletions
diff --git a/fs/binfmt_elf.c b/fs/binfmt_elf.c index e3b56b603192..264fba0d44bd 100644 --- a/fs/binfmt_elf.c +++ b/fs/binfmt_elf.c @@ -519,7 +519,7 @@ static struct elf_phdr *load_elf_phdrs(const struct elfhdr *elf_ex, /* Sanity check the number of program headers... */ /* ...and their total size. */ size = sizeof(struct elf_phdr) * elf_ex->e_phnum; - if (size == 0 || size > 65536 || size > ELF_MIN_ALIGN) + if (size == 0 || size > 65536) goto out; elf_phdata = kmalloc(size, GFP_KERNEL); @@ -1450,8 +1450,8 @@ static void fill_elf_note_phdr(struct elf_phdr *phdr, int sz, loff_t offset) phdr->p_align = 4; } -static void fill_note(struct memelfnote *note, const char *name, int type, - unsigned int sz, void *data) +static void __fill_note(struct memelfnote *note, const char *name, int type, + unsigned int sz, void *data) { note->name = name; note->type = type; @@ -1459,6 +1459,9 @@ static void fill_note(struct memelfnote *note, const char *name, int type, note->data = data; } +#define fill_note(note, type, sz, data) \ + __fill_note(note, NN_ ## type, NT_ ## type, sz, data) + /* * fill up all the fields in prstatus from the given task struct, except * registers which need to be filled up separately. @@ -1549,14 +1552,14 @@ static void fill_auxv_note(struct memelfnote *note, struct mm_struct *mm) do i += 2; while (auxv[i - 2] != AT_NULL); - fill_note(note, NN_AUXV, NT_AUXV, i * sizeof(elf_addr_t), auxv); + fill_note(note, AUXV, i * sizeof(elf_addr_t), auxv); } static void fill_siginfo_note(struct memelfnote *note, user_siginfo_t *csigdata, const kernel_siginfo_t *siginfo) { copy_siginfo_to_external(csigdata, siginfo); - fill_note(note, NN_SIGINFO, NT_SIGINFO, sizeof(*csigdata), csigdata); + fill_note(note, SIGINFO, sizeof(*csigdata), csigdata); } /* @@ -1652,7 +1655,7 @@ static int fill_files_note(struct memelfnote *note, struct coredump_params *cprm } size = name_curpos - (char *)data; - fill_note(note, NN_FILE, NT_FILE, size, data); + fill_note(note, FILE, size, data); return 0; } @@ -1713,8 +1716,7 @@ static int fill_thread_core_info(struct elf_thread_core_info *t, regset_get(t->task, &view->regsets[0], sizeof(t->prstatus.pr_reg), &t->prstatus.pr_reg); - fill_note(&t->notes[0], NN_PRSTATUS, NT_PRSTATUS, - PRSTATUS_SIZE, &t->prstatus); + fill_note(&t->notes[0], PRSTATUS, PRSTATUS_SIZE, &t->prstatus); info->size += notesize(&t->notes[0]); do_thread_regset_writeback(t->task, &view->regsets[0]); @@ -1727,6 +1729,7 @@ static int fill_thread_core_info(struct elf_thread_core_info *t, for (view_iter = 1; view_iter < view->n; ++view_iter) { const struct user_regset *regset = &view->regsets[view_iter]; int note_type = regset->core_note_type; + const char *note_name = regset->core_note_name; bool is_fpreg = note_type == NT_PRFPREG; void *data; int ret; @@ -1747,8 +1750,16 @@ static int fill_thread_core_info(struct elf_thread_core_info *t, if (is_fpreg) SET_PR_FPVALID(&t->prstatus); - fill_note(&t->notes[note_iter], is_fpreg ? NN_PRFPREG : "LINUX", - note_type, ret, data); + /* There should be a note name, but if not, guess: */ + if (WARN_ON_ONCE(!note_name)) + note_name = "LINUX"; + else + /* Warn on non-legacy-compatible names, for now. */ + WARN_ON_ONCE(strcmp(note_name, + is_fpreg ? "CORE" : "LINUX")); + + __fill_note(&t->notes[note_iter], note_name, note_type, + ret, data); info->size += notesize(&t->notes[note_iter]); note_iter++; @@ -1767,8 +1778,7 @@ static int fill_thread_core_info(struct elf_thread_core_info *t, fill_prstatus(&t->prstatus.common, p, signr); elf_core_copy_task_regs(p, &t->prstatus.pr_reg); - fill_note(&t->notes[0], NN_PRSTATUS, NT_PRSTATUS, sizeof(t->prstatus), - &(t->prstatus)); + fill_note(&t->notes[0], PRSTATUS, sizeof(t->prstatus), &t->prstatus); info->size += notesize(&t->notes[0]); fpu = kzalloc(sizeof(elf_fpregset_t), GFP_KERNEL); @@ -1778,7 +1788,7 @@ static int fill_thread_core_info(struct elf_thread_core_info *t, } t->prstatus.pr_fpvalid = 1; - fill_note(&t->notes[1], NN_PRFPREG, NT_PRFPREG, sizeof(*fpu), fpu); + fill_note(&t->notes[1], PRFPREG, sizeof(*fpu), fpu); info->size += notesize(&t->notes[1]); return 1; @@ -1798,7 +1808,7 @@ static int fill_note_info(struct elfhdr *elf, int phdrs, psinfo = kmalloc(sizeof(*psinfo), GFP_KERNEL); if (!psinfo) return 0; - fill_note(&info->psinfo, NN_PRPSINFO, NT_PRPSINFO, sizeof(*psinfo), psinfo); + fill_note(&info->psinfo, PRPSINFO, sizeof(*psinfo), psinfo); #ifdef CORE_DUMP_USE_REGSET view = task_user_regset_view(dump_task); diff --git a/fs/binfmt_elf_fdpic.c b/fs/binfmt_elf_fdpic.c index 59b138062352..48fd2de3bca0 100644 --- a/fs/binfmt_elf_fdpic.c +++ b/fs/binfmt_elf_fdpic.c @@ -1275,8 +1275,8 @@ static inline void fill_elf_note_phdr(struct elf_phdr *phdr, int sz, loff_t offs return; } -static inline void fill_note(struct memelfnote *note, const char *name, int type, - unsigned int sz, void *data) +static inline void __fill_note(struct memelfnote *note, const char *name, int type, + unsigned int sz, void *data) { note->name = name; note->type = type; @@ -1285,6 +1285,9 @@ static inline void fill_note(struct memelfnote *note, const char *name, int type return; } +#define fill_note(note, type, sz, data) \ + __fill_note(note, NN_ ## type, NT_ ## type, sz, data) + /* * fill up all the fields in prstatus from the given task struct, except * registers which need to be filled up separately. @@ -1398,8 +1401,7 @@ static struct elf_thread_status *elf_dump_thread_status(long signr, struct task_ regset_get(p, &view->regsets[0], sizeof(t->prstatus.pr_reg), &t->prstatus.pr_reg); - fill_note(&t->notes[0], NN_PRSTATUS, NT_PRSTATUS, sizeof(t->prstatus), - &t->prstatus); + fill_note(&t->notes[0], PRSTATUS, sizeof(t->prstatus), &t->prstatus); t->num_notes++; *sz += notesize(&t->notes[0]); @@ -1416,8 +1418,7 @@ static struct elf_thread_status *elf_dump_thread_status(long signr, struct task_ } if (t->prstatus.pr_fpvalid) { - fill_note(&t->notes[1], NN_PRFPREG, NT_PRFPREG, sizeof(t->fpu), - &t->fpu); + fill_note(&t->notes[1], PRFPREG, sizeof(t->fpu), &t->fpu); t->num_notes++; *sz += notesize(&t->notes[1]); } @@ -1531,7 +1532,7 @@ static int elf_fdpic_core_dump(struct coredump_params *cprm) */ fill_psinfo(psinfo, current->group_leader, current->mm); - fill_note(&psinfo_note, NN_PRPSINFO, NT_PRPSINFO, sizeof(*psinfo), psinfo); + fill_note(&psinfo_note, PRPSINFO, sizeof(*psinfo), psinfo); thread_status_size += notesize(&psinfo_note); auxv = (elf_addr_t *) current->mm->saved_auxv; @@ -1539,7 +1540,7 @@ static int elf_fdpic_core_dump(struct coredump_params *cprm) do i += 2; while (auxv[i - 2] != AT_NULL); - fill_note(&auxv_note, NN_AUXV, NT_AUXV, i * sizeof(elf_addr_t), auxv); + fill_note(&auxv_note, AUXV, i * sizeof(elf_addr_t), auxv); thread_status_size += notesize(&auxv_note); offset = sizeof(*elf); /* ELF header */ diff --git a/fs/btrfs/disk-io.c b/fs/btrfs/disk-io.c index 9cc14ab35297..70fc4e7cc5a0 100644 --- a/fs/btrfs/disk-io.c +++ b/fs/btrfs/disk-io.c @@ -2029,14 +2029,10 @@ static int btrfs_init_csum_hash(struct btrfs_fs_info *fs_info, u16 csum_type) fs_info->csum_shash = csum_shash; - /* - * Check if the checksum implementation is a fast accelerated one. - * As-is this is a bit of a hack and should be replaced once the csum - * implementations provide that information themselves. - */ + /* Check if the checksum implementation is a fast accelerated one. */ switch (csum_type) { case BTRFS_CSUM_TYPE_CRC32: - if (!strstr(crypto_shash_driver_name(csum_shash), "generic")) + if (crc32_optimizations() & CRC32C_OPTIMIZATION) set_bit(BTRFS_FS_CSUM_IMPL_FAST, &fs_info->flags); break; case BTRFS_CSUM_TYPE_XXHASH: diff --git a/fs/btrfs/ioctl.c b/fs/btrfs/ioctl.c index 895009b147ac..7e13de2bdcbf 100644 --- a/fs/btrfs/ioctl.c +++ b/fs/btrfs/ioctl.c @@ -4607,6 +4607,13 @@ out_acct: return ret; } +struct btrfs_uring_encoded_data { + struct btrfs_ioctl_encoded_io_args args; + struct iovec iovstack[UIO_FASTIOV]; + struct iovec *iov; + struct iov_iter iter; +}; + /* * Context that's attached to an encoded read io_uring command, in cmd->pdu. It * contains the fields in btrfs_uring_read_extent that are necessary to finish @@ -4628,6 +4635,7 @@ struct btrfs_uring_priv { }; struct io_btrfs_cmd { + struct btrfs_uring_encoded_data *data; struct btrfs_uring_priv *priv; }; @@ -4686,6 +4694,7 @@ out: kfree(priv->pages); kfree(priv->iov); kfree(priv); + kfree(bc->data); } void btrfs_uring_read_extent_endio(void *ctx, int err) @@ -4769,13 +4778,6 @@ out_fail: return ret; } -struct btrfs_uring_encoded_data { - struct btrfs_ioctl_encoded_io_args args; - struct iovec iovstack[UIO_FASTIOV]; - struct iovec *iov; - struct iov_iter iter; -}; - static int btrfs_uring_encoded_read(struct io_uring_cmd *cmd, unsigned int issue_flags) { size_t copy_end_kernel = offsetofend(struct btrfs_ioctl_encoded_io_args, flags); @@ -4791,7 +4793,11 @@ static int btrfs_uring_encoded_read(struct io_uring_cmd *cmd, unsigned int issue struct extent_state *cached_state = NULL; u64 start, lockend; void __user *sqe_addr; - struct btrfs_uring_encoded_data *data = io_uring_cmd_get_async_data(cmd)->op_data; + struct io_btrfs_cmd *bc = io_uring_cmd_to_pdu(cmd, struct io_btrfs_cmd); + struct btrfs_uring_encoded_data *data = NULL; + + if (cmd->flags & IORING_URING_CMD_REISSUE) + data = bc->data; if (!capable(CAP_SYS_ADMIN)) { ret = -EPERM; @@ -4821,7 +4827,7 @@ static int btrfs_uring_encoded_read(struct io_uring_cmd *cmd, unsigned int issue goto out_acct; } - io_uring_cmd_get_async_data(cmd)->op_data = data; + bc->data = data; if (issue_flags & IO_URING_F_COMPAT) { #if defined(CONFIG_64BIT) && defined(CONFIG_COMPAT) @@ -4919,6 +4925,9 @@ out_acct: add_rchar(current, ret); inc_syscr(current); + if (ret != -EIOCBQUEUED && ret != -EAGAIN) + kfree(data); + return ret; } @@ -4929,7 +4938,11 @@ static int btrfs_uring_encoded_write(struct io_uring_cmd *cmd, unsigned int issu struct file *file; ssize_t ret; void __user *sqe_addr; - struct btrfs_uring_encoded_data *data = io_uring_cmd_get_async_data(cmd)->op_data; + struct io_btrfs_cmd *bc = io_uring_cmd_to_pdu(cmd, struct io_btrfs_cmd); + struct btrfs_uring_encoded_data *data = NULL; + + if (cmd->flags & IORING_URING_CMD_REISSUE) + data = bc->data; if (!capable(CAP_SYS_ADMIN)) { ret = -EPERM; @@ -4951,7 +4964,7 @@ static int btrfs_uring_encoded_write(struct io_uring_cmd *cmd, unsigned int issu goto out_acct; } - io_uring_cmd_get_async_data(cmd)->op_data = data; + bc->data = data; if (issue_flags & IO_URING_F_COMPAT) { #if defined(CONFIG_64BIT) && defined(CONFIG_COMPAT) @@ -5041,6 +5054,9 @@ out_acct: if (ret > 0) add_wchar(current, ret); inc_syscw(current); + + if (ret != -EAGAIN) + kfree(data); return ret; } diff --git a/fs/ceph/crypto.c b/fs/ceph/crypto.c index e312f52f48e4..cab722619207 100644 --- a/fs/ceph/crypto.c +++ b/fs/ceph/crypto.c @@ -488,15 +488,13 @@ int ceph_fscrypt_decrypt_block_inplace(const struct inode *inode, int ceph_fscrypt_encrypt_block_inplace(const struct inode *inode, struct page *page, unsigned int len, - unsigned int offs, u64 lblk_num, - gfp_t gfp_flags) + unsigned int offs, u64 lblk_num) { struct ceph_client *cl = ceph_inode_to_client(inode); doutc(cl, "%p %llx.%llx len %u offs %u blk %llu\n", inode, ceph_vinop(inode), len, offs, lblk_num); - return fscrypt_encrypt_block_inplace(inode, page, len, offs, lblk_num, - gfp_flags); + return fscrypt_encrypt_block_inplace(inode, page, len, offs, lblk_num); } /** @@ -614,9 +612,8 @@ int ceph_fscrypt_decrypt_extents(struct inode *inode, struct page **page, * @page: pointer to page array * @off: offset into the file that the data starts * @len: max length to encrypt - * @gfp: gfp flags to use for allocation * - * Decrypt an array of cleartext pages and return the amount of + * Encrypt an array of cleartext pages and return the amount of * data encrypted. Any data in the page prior to the start of the * first complete block in the read is ignored. Any incomplete * crypto blocks at the end of the array are ignored. @@ -624,7 +621,7 @@ int ceph_fscrypt_decrypt_extents(struct inode *inode, struct page **page, * Returns the length of the encrypted data or a negative errno. */ int ceph_fscrypt_encrypt_pages(struct inode *inode, struct page **page, u64 off, - int len, gfp_t gfp) + int len) { int i, num_blocks; u64 baseblk = off >> CEPH_FSCRYPT_BLOCK_SHIFT; @@ -645,7 +642,7 @@ int ceph_fscrypt_encrypt_pages(struct inode *inode, struct page **page, u64 off, fret = ceph_fscrypt_encrypt_block_inplace(inode, page[pgidx], CEPH_FSCRYPT_BLOCK_SIZE, pgoffs, - baseblk + i, gfp); + baseblk + i); if (fret < 0) { if (ret == 0) ret = fret; diff --git a/fs/ceph/crypto.h b/fs/ceph/crypto.h index f752bbb2eb06..23612b2e9837 100644 --- a/fs/ceph/crypto.h +++ b/fs/ceph/crypto.h @@ -152,15 +152,14 @@ int ceph_fscrypt_decrypt_block_inplace(const struct inode *inode, unsigned int offs, u64 lblk_num); int ceph_fscrypt_encrypt_block_inplace(const struct inode *inode, struct page *page, unsigned int len, - unsigned int offs, u64 lblk_num, - gfp_t gfp_flags); + unsigned int offs, u64 lblk_num); int ceph_fscrypt_decrypt_pages(struct inode *inode, struct page **page, u64 off, int len); int ceph_fscrypt_decrypt_extents(struct inode *inode, struct page **page, u64 off, struct ceph_sparse_extent *map, u32 ext_cnt); int ceph_fscrypt_encrypt_pages(struct inode *inode, struct page **page, u64 off, - int len, gfp_t gfp); + int len); static inline struct page *ceph_fscrypt_pagecache_page(struct page *page) { @@ -236,8 +235,7 @@ static inline int ceph_fscrypt_decrypt_block_inplace(const struct inode *inode, static inline int ceph_fscrypt_encrypt_block_inplace(const struct inode *inode, struct page *page, unsigned int len, - unsigned int offs, u64 lblk_num, - gfp_t gfp_flags) + unsigned int offs, u64 lblk_num) { return 0; } @@ -259,7 +257,7 @@ static inline int ceph_fscrypt_decrypt_extents(struct inode *inode, static inline int ceph_fscrypt_encrypt_pages(struct inode *inode, struct page **page, u64 off, - int len, gfp_t gfp) + int len) { return 0; } diff --git a/fs/ceph/file.c b/fs/ceph/file.c index 8c06dc4655a8..bdde6ac5a60d 100644 --- a/fs/ceph/file.c +++ b/fs/ceph/file.c @@ -1992,8 +1992,7 @@ ceph_sync_write(struct kiocb *iocb, struct iov_iter *from, loff_t pos, if (IS_ENCRYPTED(inode)) { ret = ceph_fscrypt_encrypt_pages(inode, pages, - write_pos, write_len, - GFP_KERNEL); + write_pos, write_len); if (ret < 0) { doutc(cl, "encryption failed with %d\n", ret); ceph_release_page_vector(pages, num_pages); diff --git a/fs/ceph/inode.c b/fs/ceph/inode.c index 06cd2963e41e..fc543075b827 100644 --- a/fs/ceph/inode.c +++ b/fs/ceph/inode.c @@ -2436,8 +2436,7 @@ static int fill_fscrypt_truncate(struct inode *inode, /* encrypt the last block */ ret = ceph_fscrypt_encrypt_block_inplace(inode, page, CEPH_FSCRYPT_BLOCK_SIZE, - 0, block, - GFP_KERNEL); + 0, block); if (ret) goto out; } diff --git a/fs/crypto/bio.c b/fs/crypto/bio.c index 0ad8c30b8fa5..486fcb2ecf13 100644 --- a/fs/crypto/bio.c +++ b/fs/crypto/bio.c @@ -7,10 +7,12 @@ * Copyright (C) 2015, Motorola Mobility */ -#include <linux/pagemap.h> -#include <linux/module.h> #include <linux/bio.h> +#include <linux/export.h> +#include <linux/module.h> #include <linux/namei.h> +#include <linux/pagemap.h> + #include "fscrypt_private.h" /** @@ -165,8 +167,7 @@ int fscrypt_zeroout_range(const struct inode *inode, pgoff_t lblk, do { err = fscrypt_crypt_data_unit(ci, FS_ENCRYPT, du_index, ZERO_PAGE(0), pages[i], - du_size, offset, - GFP_NOFS); + du_size, offset); if (err) goto out; du_index++; diff --git a/fs/crypto/crypto.c b/fs/crypto/crypto.c index b74b5937e695..b6ccab524fde 100644 --- a/fs/crypto/crypto.c +++ b/fs/crypto/crypto.c @@ -20,12 +20,14 @@ * Special Publication 800-38E and IEEE P1619/D16. */ -#include <linux/pagemap.h> +#include <crypto/skcipher.h> +#include <linux/export.h> #include <linux/mempool.h> #include <linux/module.h> -#include <linux/scatterlist.h> +#include <linux/pagemap.h> #include <linux/ratelimit.h> -#include <crypto/skcipher.h> +#include <linux/scatterlist.h> + #include "fscrypt_private.h" static unsigned int num_prealloc_crypto_pages = 32; @@ -108,15 +110,13 @@ void fscrypt_generate_iv(union fscrypt_iv *iv, u64 index, int fscrypt_crypt_data_unit(const struct fscrypt_inode_info *ci, fscrypt_direction_t rw, u64 index, struct page *src_page, struct page *dest_page, - unsigned int len, unsigned int offs, - gfp_t gfp_flags) + unsigned int len, unsigned int offs) { + struct crypto_sync_skcipher *tfm = ci->ci_enc_key.tfm; + SYNC_SKCIPHER_REQUEST_ON_STACK(req, tfm); union fscrypt_iv iv; - struct skcipher_request *req = NULL; - DECLARE_CRYPTO_WAIT(wait); struct scatterlist dst, src; - struct crypto_skcipher *tfm = ci->ci_enc_key.tfm; - int res = 0; + int err; if (WARN_ON_ONCE(len <= 0)) return -EINVAL; @@ -125,31 +125,23 @@ int fscrypt_crypt_data_unit(const struct fscrypt_inode_info *ci, fscrypt_generate_iv(&iv, index, ci); - req = skcipher_request_alloc(tfm, gfp_flags); - if (!req) - return -ENOMEM; - skcipher_request_set_callback( req, CRYPTO_TFM_REQ_MAY_BACKLOG | CRYPTO_TFM_REQ_MAY_SLEEP, - crypto_req_done, &wait); - + NULL, NULL); sg_init_table(&dst, 1); sg_set_page(&dst, dest_page, len, offs); sg_init_table(&src, 1); sg_set_page(&src, src_page, len, offs); skcipher_request_set_crypt(req, &src, &dst, len, &iv); if (rw == FS_DECRYPT) - res = crypto_wait_req(crypto_skcipher_decrypt(req), &wait); + err = crypto_skcipher_decrypt(req); else - res = crypto_wait_req(crypto_skcipher_encrypt(req), &wait); - skcipher_request_free(req); - if (res) { + err = crypto_skcipher_encrypt(req); + if (err) fscrypt_err(ci->ci_inode, "%scryption failed for data unit %llu: %d", - (rw == FS_DECRYPT ? "De" : "En"), index, res); - return res; - } - return 0; + (rw == FS_DECRYPT ? "De" : "En"), index, err); + return err; } /** @@ -204,7 +196,7 @@ struct page *fscrypt_encrypt_pagecache_blocks(struct folio *folio, for (i = offs; i < offs + len; i += du_size, index++) { err = fscrypt_crypt_data_unit(ci, FS_ENCRYPT, index, &folio->page, ciphertext_page, - du_size, i, gfp_flags); + du_size, i); if (err) { fscrypt_free_bounce_page(ciphertext_page); return ERR_PTR(err); @@ -225,7 +217,6 @@ EXPORT_SYMBOL(fscrypt_encrypt_pagecache_blocks); * @offs: Byte offset within @page at which the block to encrypt begins * @lblk_num: Filesystem logical block number of the block, i.e. the 0-based * number of the block within the file - * @gfp_flags: Memory allocation flags * * Encrypt a possibly-compressed filesystem block that is located in an * arbitrary page, not necessarily in the original pagecache page. The @inode @@ -237,13 +228,12 @@ EXPORT_SYMBOL(fscrypt_encrypt_pagecache_blocks); */ int fscrypt_encrypt_block_inplace(const struct inode *inode, struct page *page, unsigned int len, unsigned int offs, - u64 lblk_num, gfp_t gfp_flags) + u64 lblk_num) { if (WARN_ON_ONCE(inode->i_sb->s_cop->supports_subblock_data_units)) return -EOPNOTSUPP; return fscrypt_crypt_data_unit(inode->i_crypt_info, FS_ENCRYPT, - lblk_num, page, page, len, offs, - gfp_flags); + lblk_num, page, page, len, offs); } EXPORT_SYMBOL(fscrypt_encrypt_block_inplace); @@ -283,8 +273,7 @@ int fscrypt_decrypt_pagecache_blocks(struct folio *folio, size_t len, struct page *page = folio_page(folio, i >> PAGE_SHIFT); err = fscrypt_crypt_data_unit(ci, FS_DECRYPT, index, page, - page, du_size, i & ~PAGE_MASK, - GFP_NOFS); + page, du_size, i & ~PAGE_MASK); if (err) return err; } @@ -317,8 +306,7 @@ int fscrypt_decrypt_block_inplace(const struct inode *inode, struct page *page, if (WARN_ON_ONCE(inode->i_sb->s_cop->supports_subblock_data_units)) return -EOPNOTSUPP; return fscrypt_crypt_data_unit(inode->i_crypt_info, FS_DECRYPT, - lblk_num, page, page, len, offs, - GFP_NOFS); + lblk_num, page, page, len, offs); } EXPORT_SYMBOL(fscrypt_decrypt_block_inplace); diff --git a/fs/crypto/fname.c b/fs/crypto/fname.c index 010f9c0a4c2f..f9f6713e144f 100644 --- a/fs/crypto/fname.c +++ b/fs/crypto/fname.c @@ -11,11 +11,13 @@ * This has not yet undergone a rigorous security audit. */ -#include <linux/namei.h> -#include <linux/scatterlist.h> #include <crypto/hash.h> #include <crypto/sha2.h> #include <crypto/skcipher.h> +#include <linux/export.h> +#include <linux/namei.h> +#include <linux/scatterlist.h> + #include "fscrypt_private.h" /* @@ -92,13 +94,12 @@ static inline bool fscrypt_is_dot_dotdot(const struct qstr *str) int fscrypt_fname_encrypt(const struct inode *inode, const struct qstr *iname, u8 *out, unsigned int olen) { - struct skcipher_request *req = NULL; - DECLARE_CRYPTO_WAIT(wait); const struct fscrypt_inode_info *ci = inode->i_crypt_info; - struct crypto_skcipher *tfm = ci->ci_enc_key.tfm; + struct crypto_sync_skcipher *tfm = ci->ci_enc_key.tfm; + SYNC_SKCIPHER_REQUEST_ON_STACK(req, tfm); union fscrypt_iv iv; struct scatterlist sg; - int res; + int err; /* * Copy the filename to the output buffer for encrypting in-place and @@ -109,28 +110,17 @@ int fscrypt_fname_encrypt(const struct inode *inode, const struct qstr *iname, memcpy(out, iname->name, iname->len); memset(out + iname->len, 0, olen - iname->len); - /* Initialize the IV */ fscrypt_generate_iv(&iv, 0, ci); - /* Set up the encryption request */ - req = skcipher_request_alloc(tfm, GFP_NOFS); - if (!req) - return -ENOMEM; - skcipher_request_set_callback(req, - CRYPTO_TFM_REQ_MAY_BACKLOG | CRYPTO_TFM_REQ_MAY_SLEEP, - crypto_req_done, &wait); + skcipher_request_set_callback( + req, CRYPTO_TFM_REQ_MAY_BACKLOG | CRYPTO_TFM_REQ_MAY_SLEEP, + NULL, NULL); sg_init_one(&sg, out, olen); skcipher_request_set_crypt(req, &sg, &sg, olen, &iv); - - /* Do the encryption */ - res = crypto_wait_req(crypto_skcipher_encrypt(req), &wait); - skcipher_request_free(req); - if (res < 0) { - fscrypt_err(inode, "Filename encryption failed: %d", res); - return res; - } - - return 0; + err = crypto_skcipher_encrypt(req); + if (err) + fscrypt_err(inode, "Filename encryption failed: %d", err); + return err; } EXPORT_SYMBOL_GPL(fscrypt_fname_encrypt); @@ -148,34 +138,25 @@ static int fname_decrypt(const struct inode *inode, const struct fscrypt_str *iname, struct fscrypt_str *oname) { - struct skcipher_request *req = NULL; - DECLARE_CRYPTO_WAIT(wait); - struct scatterlist src_sg, dst_sg; const struct fscrypt_inode_info *ci = inode->i_crypt_info; - struct crypto_skcipher *tfm = ci->ci_enc_key.tfm; + struct crypto_sync_skcipher *tfm = ci->ci_enc_key.tfm; + SYNC_SKCIPHER_REQUEST_ON_STACK(req, tfm); union fscrypt_iv iv; - int res; - - /* Allocate request */ - req = skcipher_request_alloc(tfm, GFP_NOFS); - if (!req) - return -ENOMEM; - skcipher_request_set_callback(req, - CRYPTO_TFM_REQ_MAY_BACKLOG | CRYPTO_TFM_REQ_MAY_SLEEP, - crypto_req_done, &wait); + struct scatterlist src_sg, dst_sg; + int err; - /* Initialize IV */ fscrypt_generate_iv(&iv, 0, ci); - /* Create decryption request */ + skcipher_request_set_callback( + req, CRYPTO_TFM_REQ_MAY_BACKLOG | CRYPTO_TFM_REQ_MAY_SLEEP, + NULL, NULL); sg_init_one(&src_sg, iname->name, iname->len); sg_init_one(&dst_sg, oname->name, oname->len); skcipher_request_set_crypt(req, &src_sg, &dst_sg, iname->len, &iv); - res = crypto_wait_req(crypto_skcipher_decrypt(req), &wait); - skcipher_request_free(req); - if (res < 0) { - fscrypt_err(inode, "Filename decryption failed: %d", res); - return res; + err = crypto_skcipher_decrypt(req); + if (err) { + fscrypt_err(inode, "Filename decryption failed: %d", err); + return err; } oname->len = strnlen(oname->name, iname->len); diff --git a/fs/crypto/fscrypt_private.h b/fs/crypto/fscrypt_private.h index c1d92074b65c..d8b485b9881c 100644 --- a/fs/crypto/fscrypt_private.h +++ b/fs/crypto/fscrypt_private.h @@ -45,6 +45,24 @@ */ #undef FSCRYPT_MAX_KEY_SIZE +/* + * This mask is passed as the third argument to the crypto_alloc_*() functions + * to prevent fscrypt from using the Crypto API drivers for non-inline crypto + * engines. Those drivers have been problematic for fscrypt. fscrypt users + * have reported hangs and even incorrect en/decryption with these drivers. + * Since going to the driver, off CPU, and back again is really slow, such + * drivers can be over 50 times slower than the CPU-based code for fscrypt's + * workload. Even on platforms that lack AES instructions on the CPU, using the + * offloads has been shown to be slower, even staying with AES. (Of course, + * Adiantum is faster still, and is the recommended option on such platforms...) + * + * Note that fscrypt also supports inline crypto engines. Those don't use the + * Crypto API and work much better than the old-style (non-inline) engines. + */ +#define FSCRYPT_CRYPTOAPI_MASK \ + (CRYPTO_ALG_ASYNC | CRYPTO_ALG_ALLOCATES_MEMORY | \ + CRYPTO_ALG_KERN_DRIVER_ONLY) + #define FSCRYPT_CONTEXT_V1 1 #define FSCRYPT_CONTEXT_V2 2 @@ -221,7 +239,7 @@ struct fscrypt_symlink_data { * Normally only one of the fields will be non-NULL. */ struct fscrypt_prepared_key { - struct crypto_skcipher *tfm; + struct crypto_sync_skcipher *tfm; #ifdef CONFIG_FS_ENCRYPTION_INLINE_CRYPT struct blk_crypto_key *blk_key; #endif @@ -319,8 +337,7 @@ int fscrypt_initialize(struct super_block *sb); int fscrypt_crypt_data_unit(const struct fscrypt_inode_info *ci, fscrypt_direction_t rw, u64 index, struct page *src_page, struct page *dest_page, - unsigned int len, unsigned int offs, - gfp_t gfp_flags); + unsigned int len, unsigned int offs); struct page *fscrypt_alloc_bounce_page(gfp_t gfp_flags); void __printf(3, 4) __cold diff --git a/fs/crypto/hkdf.c b/fs/crypto/hkdf.c index 0f3028adc9c7..b1ef506cd341 100644 --- a/fs/crypto/hkdf.c +++ b/fs/crypto/hkdf.c @@ -8,8 +8,8 @@ */ #include <crypto/hash.h> -#include <crypto/sha2.h> #include <crypto/hkdf.h> +#include <crypto/sha2.h> #include "fscrypt_private.h" @@ -58,7 +58,7 @@ int fscrypt_init_hkdf(struct fscrypt_hkdf *hkdf, const u8 *master_key, u8 prk[HKDF_HASHLEN]; int err; - hmac_tfm = crypto_alloc_shash(HKDF_HMAC_ALG, 0, 0); + hmac_tfm = crypto_alloc_shash(HKDF_HMAC_ALG, 0, FSCRYPT_CRYPTOAPI_MASK); if (IS_ERR(hmac_tfm)) { fscrypt_err(NULL, "Error allocating " HKDF_HMAC_ALG ": %ld", PTR_ERR(hmac_tfm)); diff --git a/fs/crypto/hooks.c b/fs/crypto/hooks.c index d8d5049b8fe1..e0b32ac841f7 100644 --- a/fs/crypto/hooks.c +++ b/fs/crypto/hooks.c @@ -5,6 +5,8 @@ * Encryption hooks for higher-level filesystem operations. */ +#include <linux/export.h> + #include "fscrypt_private.h" /** diff --git a/fs/crypto/inline_crypt.c b/fs/crypto/inline_crypt.c index 1d008c440cb6..caaff809765b 100644 --- a/fs/crypto/inline_crypt.c +++ b/fs/crypto/inline_crypt.c @@ -15,6 +15,7 @@ #include <linux/blk-crypto.h> #include <linux/blkdev.h> #include <linux/buffer_head.h> +#include <linux/export.h> #include <linux/sched/mm.h> #include <linux/slab.h> #include <linux/uio.h> diff --git a/fs/crypto/keyring.c b/fs/crypto/keyring.c index ace369f13068..7557f6a88b8f 100644 --- a/fs/crypto/keyring.c +++ b/fs/crypto/keyring.c @@ -18,12 +18,13 @@ * information about these ioctls. */ -#include <linux/unaligned.h> #include <crypto/skcipher.h> +#include <linux/export.h> #include <linux/key-type.h> -#include <linux/random.h> #include <linux/once.h> +#include <linux/random.h> #include <linux/seq_file.h> +#include <linux/unaligned.h> #include "fscrypt_private.h" diff --git a/fs/crypto/keysetup.c b/fs/crypto/keysetup.c index 0d71843af946..4f3b9ecbfe4e 100644 --- a/fs/crypto/keysetup.c +++ b/fs/crypto/keysetup.c @@ -9,6 +9,7 @@ */ #include <crypto/skcipher.h> +#include <linux/export.h> #include <linux/random.h> #include "fscrypt_private.h" @@ -96,14 +97,15 @@ select_encryption_mode(const union fscrypt_policy *policy, } /* Create a symmetric cipher object for the given encryption mode and key */ -static struct crypto_skcipher * +static struct crypto_sync_skcipher * fscrypt_allocate_skcipher(struct fscrypt_mode *mode, const u8 *raw_key, const struct inode *inode) { - struct crypto_skcipher *tfm; + struct crypto_sync_skcipher *tfm; int err; - tfm = crypto_alloc_skcipher(mode->cipher_str, 0, 0); + tfm = crypto_alloc_sync_skcipher(mode->cipher_str, 0, + FSCRYPT_CRYPTOAPI_MASK); if (IS_ERR(tfm)) { if (PTR_ERR(tfm) == -ENOENT) { fscrypt_warn(inode, @@ -123,21 +125,22 @@ fscrypt_allocate_skcipher(struct fscrypt_mode *mode, const u8 *raw_key, * first time a mode is used. */ pr_info("fscrypt: %s using implementation \"%s\"\n", - mode->friendly_name, crypto_skcipher_driver_name(tfm)); + mode->friendly_name, + crypto_skcipher_driver_name(&tfm->base)); } - if (WARN_ON_ONCE(crypto_skcipher_ivsize(tfm) != mode->ivsize)) { + if (WARN_ON_ONCE(crypto_sync_skcipher_ivsize(tfm) != mode->ivsize)) { err = -EINVAL; goto err_free_tfm; } - crypto_skcipher_set_flags(tfm, CRYPTO_TFM_REQ_FORBID_WEAK_KEYS); - err = crypto_skcipher_setkey(tfm, raw_key, mode->keysize); + crypto_sync_skcipher_set_flags(tfm, CRYPTO_TFM_REQ_FORBID_WEAK_KEYS); + err = crypto_sync_skcipher_setkey(tfm, raw_key, mode->keysize); if (err) goto err_free_tfm; return tfm; err_free_tfm: - crypto_free_skcipher(tfm); + crypto_free_sync_skcipher(tfm); return ERR_PTR(err); } @@ -150,7 +153,7 @@ err_free_tfm: int fscrypt_prepare_key(struct fscrypt_prepared_key *prep_key, const u8 *raw_key, const struct fscrypt_inode_info *ci) { - struct crypto_skcipher *tfm; + struct crypto_sync_skcipher *tfm; if (fscrypt_using_inline_encryption(ci)) return fscrypt_prepare_inline_crypt_key(prep_key, raw_key, @@ -174,7 +177,7 @@ int fscrypt_prepare_key(struct fscrypt_prepared_key *prep_key, void fscrypt_destroy_prepared_key(struct super_block *sb, struct fscrypt_prepared_key *prep_key) { - crypto_free_skcipher(prep_key->tfm); + crypto_free_sync_skcipher(prep_key->tfm); fscrypt_destroy_inline_crypt_key(sb, prep_key); memzero_explicit(prep_key, sizeof(*prep_key)); } diff --git a/fs/crypto/keysetup_v1.c b/fs/crypto/keysetup_v1.c index b70521c55132..c4d05168522b 100644 --- a/fs/crypto/keysetup_v1.c +++ b/fs/crypto/keysetup_v1.c @@ -48,39 +48,30 @@ static int derive_key_aes(const u8 *master_key, const u8 nonce[FSCRYPT_FILE_NONCE_SIZE], u8 *derived_key, unsigned int derived_keysize) { - int res = 0; - struct skcipher_request *req = NULL; - DECLARE_CRYPTO_WAIT(wait); - struct scatterlist src_sg, dst_sg; - struct crypto_skcipher *tfm = crypto_alloc_skcipher("ecb(aes)", 0, 0); - - if (IS_ERR(tfm)) { - res = PTR_ERR(tfm); - tfm = NULL; - goto out; - } - crypto_skcipher_set_flags(tfm, CRYPTO_TFM_REQ_FORBID_WEAK_KEYS); - req = skcipher_request_alloc(tfm, GFP_KERNEL); - if (!req) { - res = -ENOMEM; - goto out; - } - skcipher_request_set_callback(req, - CRYPTO_TFM_REQ_MAY_BACKLOG | CRYPTO_TFM_REQ_MAY_SLEEP, - crypto_req_done, &wait); - res = crypto_skcipher_setkey(tfm, nonce, FSCRYPT_FILE_NONCE_SIZE); - if (res < 0) - goto out; + struct crypto_sync_skcipher *tfm; + int err; - sg_init_one(&src_sg, master_key, derived_keysize); - sg_init_one(&dst_sg, derived_key, derived_keysize); - skcipher_request_set_crypt(req, &src_sg, &dst_sg, derived_keysize, - NULL); - res = crypto_wait_req(crypto_skcipher_encrypt(req), &wait); -out: - skcipher_request_free(req); - crypto_free_skcipher(tfm); - return res; + tfm = crypto_alloc_sync_skcipher("ecb(aes)", 0, FSCRYPT_CRYPTOAPI_MASK); + if (IS_ERR(tfm)) + return PTR_ERR(tfm); + + err = crypto_sync_skcipher_setkey(tfm, nonce, FSCRYPT_FILE_NONCE_SIZE); + if (err == 0) { + SYNC_SKCIPHER_REQUEST_ON_STACK(req, tfm); + struct scatterlist src_sg, dst_sg; + + skcipher_request_set_callback(req, + CRYPTO_TFM_REQ_MAY_BACKLOG | + CRYPTO_TFM_REQ_MAY_SLEEP, + NULL, NULL); + sg_init_one(&src_sg, master_key, derived_keysize); + sg_init_one(&dst_sg, derived_key, derived_keysize); + skcipher_request_set_crypt(req, &src_sg, &dst_sg, + derived_keysize, NULL); + err = crypto_skcipher_encrypt(req); + } + crypto_free_sync_skcipher(tfm); + return err; } /* diff --git a/fs/crypto/policy.c b/fs/crypto/policy.c index 701259991277..6ad30ae07c06 100644 --- a/fs/crypto/policy.c +++ b/fs/crypto/policy.c @@ -10,11 +10,13 @@ * Modified by Eric Biggers, 2019 for v2 policy support. */ +#include <linux/export.h> #include <linux/fs_context.h> +#include <linux/mount.h> #include <linux/random.h> #include <linux/seq_file.h> #include <linux/string.h> -#include <linux/mount.h> + #include "fscrypt_private.h" /** diff --git a/fs/debugfs/file.c b/fs/debugfs/file.c index 69e9ddcb113d..3ec3324c2060 100644 --- a/fs/debugfs/file.c +++ b/fs/debugfs/file.c @@ -47,29 +47,12 @@ const struct file_operations debugfs_noop_file_operations = { #define F_DENTRY(filp) ((filp)->f_path.dentry) -const void *debugfs_get_aux(const struct file *file) +void *debugfs_get_aux(const struct file *file) { return DEBUGFS_I(file_inode(file))->aux; } EXPORT_SYMBOL_GPL(debugfs_get_aux); -const struct file_operations *debugfs_real_fops(const struct file *filp) -{ - struct debugfs_fsdata *fsd = F_DENTRY(filp)->d_fsdata; - - if (!fsd) { - /* - * Urgh, we've been called w/o a protecting - * debugfs_file_get(). - */ - WARN_ON(1); - return NULL; - } - - return fsd->real_fops; -} -EXPORT_SYMBOL_GPL(debugfs_real_fops); - enum dbgfs_get_mode { DBGFS_GET_ALREADY, DBGFS_GET_REGULAR, @@ -302,15 +285,13 @@ static int debugfs_locked_down(struct inode *inode, static int open_proxy_open(struct inode *inode, struct file *filp) { struct dentry *dentry = F_DENTRY(filp); - const struct file_operations *real_fops = NULL; + const struct file_operations *real_fops = DEBUGFS_I(inode)->real_fops; int r; r = __debugfs_file_get(dentry, DBGFS_GET_REGULAR); if (r) return r == -EIO ? -ENOENT : r; - real_fops = debugfs_real_fops(filp); - r = debugfs_locked_down(inode, filp, real_fops); if (r) goto out; @@ -352,7 +333,6 @@ static ret_type full_proxy_ ## name(proto) \ { \ struct dentry *dentry = F_DENTRY(filp); \ struct debugfs_fsdata *fsd = dentry->d_fsdata; \ - const struct file_operations *real_fops; \ ret_type r; \ \ if (!(fsd->methods & bit)) \ @@ -360,14 +340,13 @@ static ret_type full_proxy_ ## name(proto) \ r = debugfs_file_get(dentry); \ if (unlikely(r)) \ return r; \ - real_fops = debugfs_real_fops(filp); \ - r = real_fops->name(args); \ + r = fsd->real_fops->name(args); \ debugfs_file_put(dentry); \ return r; \ } -#define FULL_PROXY_FUNC_BOTH(name, ret_type, filp, proto, args, bit, ret) \ -static ret_type full_proxy_ ## name(proto) \ +#define SHORT_PROXY_FUNC(name, ret_type, filp, proto, args, bit, ret) \ +static ret_type short_proxy_ ## name(proto) \ { \ struct dentry *dentry = F_DENTRY(filp); \ struct debugfs_fsdata *fsd = dentry->d_fsdata; \ @@ -378,27 +357,38 @@ static ret_type full_proxy_ ## name(proto) \ r = debugfs_file_get(dentry); \ if (unlikely(r)) \ return r; \ - if (fsd->real_fops) \ - r = fsd->real_fops->name(args); \ - else \ - r = fsd->short_fops->name(args); \ + r = fsd->short_fops->name(args); \ debugfs_file_put(dentry); \ return r; \ } -FULL_PROXY_FUNC_BOTH(llseek, loff_t, filp, - PROTO(struct file *filp, loff_t offset, int whence), - ARGS(filp, offset, whence), HAS_LSEEK, -ESPIPE); +SHORT_PROXY_FUNC(llseek, loff_t, filp, + PROTO(struct file *filp, loff_t offset, int whence), + ARGS(filp, offset, whence), HAS_LSEEK, -ESPIPE); -FULL_PROXY_FUNC_BOTH(read, ssize_t, filp, - PROTO(struct file *filp, char __user *buf, size_t size, - loff_t *ppos), - ARGS(filp, buf, size, ppos), HAS_READ, -EINVAL); +FULL_PROXY_FUNC(llseek, loff_t, filp, + PROTO(struct file *filp, loff_t offset, int whence), + ARGS(filp, offset, whence), HAS_LSEEK, -ESPIPE); -FULL_PROXY_FUNC_BOTH(write, ssize_t, filp, - PROTO(struct file *filp, const char __user *buf, - size_t size, loff_t *ppos), - ARGS(filp, buf, size, ppos), HAS_WRITE, -EINVAL); +SHORT_PROXY_FUNC(read, ssize_t, filp, + PROTO(struct file *filp, char __user *buf, size_t size, + loff_t *ppos), + ARGS(filp, buf, size, ppos), HAS_READ, -EINVAL); + +FULL_PROXY_FUNC(read, ssize_t, filp, + PROTO(struct file *filp, char __user *buf, size_t size, + loff_t *ppos), + ARGS(filp, buf, size, ppos), HAS_READ, -EINVAL); + +SHORT_PROXY_FUNC(write, ssize_t, filp, + PROTO(struct file *filp, const char __user *buf, + size_t size, loff_t *ppos), + ARGS(filp, buf, size, ppos), HAS_WRITE, -EINVAL); + +FULL_PROXY_FUNC(write, ssize_t, filp, + PROTO(struct file *filp, const char __user *buf, + size_t size, loff_t *ppos), + ARGS(filp, buf, size, ppos), HAS_WRITE, -EINVAL); FULL_PROXY_FUNC(unlocked_ioctl, long, filp, PROTO(struct file *filp, unsigned int cmd, unsigned long arg), @@ -410,22 +400,21 @@ static __poll_t full_proxy_poll(struct file *filp, struct dentry *dentry = F_DENTRY(filp); struct debugfs_fsdata *fsd = dentry->d_fsdata; __poll_t r = 0; - const struct file_operations *real_fops; if (!(fsd->methods & HAS_POLL)) return DEFAULT_POLLMASK; if (debugfs_file_get(dentry)) return EPOLLHUP; - real_fops = debugfs_real_fops(filp); - r = real_fops->poll(filp, wait); + r = fsd->real_fops->poll(filp, wait); debugfs_file_put(dentry); return r; } -static int full_proxy_release(struct inode *inode, struct file *filp) +static int full_proxy_release(struct inode *inode, struct file *file) { - const struct file_operations *real_fops = debugfs_real_fops(filp); + struct debugfs_fsdata *fsd = F_DENTRY(file)->d_fsdata; + const struct file_operations *real_fops = fsd->real_fops; int r = 0; /* @@ -435,7 +424,7 @@ static int full_proxy_release(struct inode *inode, struct file *filp) * ->i_private is still being meaningful here. */ if (real_fops->release) - r = real_fops->release(inode, filp); + r = real_fops->release(inode, file); fops_put(real_fops); return r; @@ -517,9 +506,9 @@ static int full_proxy_open_short(struct inode *inode, struct file *filp) const struct file_operations debugfs_full_short_proxy_file_operations = { .open = full_proxy_open_short, - .llseek = full_proxy_llseek, - .read = full_proxy_read, - .write = full_proxy_write, + .llseek = short_proxy_llseek, + .read = short_proxy_read, + .write = short_proxy_write, }; ssize_t debugfs_attr_read(struct file *file, char __user *buf, diff --git a/fs/debugfs/inode.c b/fs/debugfs/inode.c index 6677991c7e4b..a0357b0cf362 100644 --- a/fs/debugfs/inode.c +++ b/fs/debugfs/inode.c @@ -444,7 +444,7 @@ static struct dentry *__debugfs_create_file(const char *name, umode_t mode, proxy_fops = &debugfs_noop_file_operations; inode->i_fop = proxy_fops; DEBUGFS_I(inode)->raw = real_fops; - DEBUGFS_I(inode)->aux = aux; + DEBUGFS_I(inode)->aux = (void *)aux; d_instantiate(dentry, inode); fsnotify_create(d_inode(dentry->d_parent), dentry); diff --git a/fs/debugfs/internal.h b/fs/debugfs/internal.h index 93483fe84425..427987f81571 100644 --- a/fs/debugfs/internal.h +++ b/fs/debugfs/internal.h @@ -19,7 +19,7 @@ struct debugfs_inode_info { const struct debugfs_short_fops *short_fops; debugfs_automount_t automount; }; - const void *aux; + void *aux; }; static inline struct debugfs_inode_info *DEBUGFS_I(struct inode *inode) diff --git a/fs/fuse/virtio_fs.c b/fs/fuse/virtio_fs.c index 53c2626e90e7..3fbfb1a2942b 100644 --- a/fs/fuse/virtio_fs.c +++ b/fs/fuse/virtio_fs.c @@ -862,7 +862,7 @@ static void virtio_fs_requests_done_work(struct work_struct *work) static void virtio_fs_map_queues(struct virtio_device *vdev, struct virtio_fs *fs) { const struct cpumask *mask, *masks; - unsigned int q, cpu; + unsigned int q, cpu, nr_masks; /* First attempt to map using existing transport layer affinities * e.g. PCIe MSI-X @@ -882,7 +882,7 @@ static void virtio_fs_map_queues(struct virtio_device *vdev, struct virtio_fs *f return; fallback: /* Attempt to map evenly in groups over the CPUs */ - masks = group_cpus_evenly(fs->num_request_queues); + masks = group_cpus_evenly(fs->num_request_queues, &nr_masks); /* If even this fails we default to all CPUs use first request queue */ if (!masks) { for_each_possible_cpu(cpu) @@ -891,7 +891,7 @@ fallback: } for (q = 0; q < fs->num_request_queues; q++) { - for_each_cpu(cpu, &masks[q]) + for_each_cpu(cpu, &masks[q % nr_masks]) fs->mq_map[cpu] = q + VQ_REQUEST; } kfree(masks); diff --git a/fs/proc/base.c b/fs/proc/base.c index e93149a01341..62d35631ba8c 100644 --- a/fs/proc/base.c +++ b/fs/proc/base.c @@ -3290,7 +3290,7 @@ static int proc_pid_ksm_stat(struct seq_file *m, struct pid_namespace *ns, } #endif /* CONFIG_KSM */ -#ifdef CONFIG_STACKLEAK_METRICS +#ifdef CONFIG_KSTACK_ERASE_METRICS static int proc_stack_depth(struct seq_file *m, struct pid_namespace *ns, struct pid *pid, struct task_struct *task) { @@ -3303,7 +3303,7 @@ static int proc_stack_depth(struct seq_file *m, struct pid_namespace *ns, prev_depth, depth); return 0; } -#endif /* CONFIG_STACKLEAK_METRICS */ +#endif /* CONFIG_KSTACK_ERASE_METRICS */ /* * Thread groups @@ -3410,7 +3410,7 @@ static const struct pid_entry tgid_base_stuff[] = { #ifdef CONFIG_LIVEPATCH ONE("patch_state", S_IRUSR, proc_pid_patch_state), #endif -#ifdef CONFIG_STACKLEAK_METRICS +#ifdef CONFIG_KSTACK_ERASE_METRICS ONE("stack_depth", S_IRUGO, proc_stack_depth), #endif #ifdef CONFIG_PROC_PID_ARCH_STATUS diff --git a/fs/resctrl/pseudo_lock.c b/fs/resctrl/pseudo_lock.c index ccc2f9213b4b..87bbc2605de1 100644 --- a/fs/resctrl/pseudo_lock.c +++ b/fs/resctrl/pseudo_lock.c @@ -764,13 +764,9 @@ static ssize_t pseudo_lock_measure_trigger(struct file *file, if (ret == 0) { if (sel != 1 && sel != 2 && sel != 3) return -EINVAL; - ret = debugfs_file_get(file->f_path.dentry); - if (ret) - return ret; ret = pseudo_lock_measure_cycles(rdtgrp, sel); if (ret == 0) ret = count; - debugfs_file_put(file->f_path.dentry); } return ret; diff --git a/fs/smb/server/smb2pdu.c b/fs/smb/server/smb2pdu.c index 63d17cea2e95..6fc6ad63d004 100644 --- a/fs/smb/server/smb2pdu.c +++ b/fs/smb/server/smb2pdu.c @@ -1594,7 +1594,7 @@ static int krb5_authenticate(struct ksmbd_work *work, struct ksmbd_conn *conn = work->conn; struct ksmbd_session *sess = work->sess; char *in_blob, *out_blob; - struct channel *chann = NULL; + struct channel *chann = NULL, *old; u64 prev_sess_id; int in_len, out_len; int retval; @@ -1621,11 +1621,24 @@ static int krb5_authenticate(struct ksmbd_work *work, rsp->SecurityBufferLength = cpu_to_le16(out_len); - if ((conn->sign || server_conf.enforced_signing) || + /* + * If session state is SMB2_SESSION_VALID, We can assume + * that it is reauthentication. And the user/password + * has been verified, so return it here. + */ + if (sess->state == SMB2_SESSION_VALID) { + if (conn->binding) + goto binding_session; + return 0; + } + + if ((rsp->SessionFlags != SMB2_SESSION_FLAG_IS_GUEST_LE && + (conn->sign || server_conf.enforced_signing)) || (req->SecurityMode & SMB2_NEGOTIATE_SIGNING_REQUIRED)) sess->sign = true; - if (smb3_encryption_negotiated(conn)) { + if (smb3_encryption_negotiated(conn) && + !(req->Flags & SMB2_SESSION_REQ_FLAG_BINDING)) { retval = conn->ops->generate_encryptionkey(conn, sess); if (retval) { ksmbd_debug(SMB, @@ -1638,6 +1651,7 @@ static int krb5_authenticate(struct ksmbd_work *work, sess->sign = false; } +binding_session: if (conn->dialect >= SMB30_PROT_ID) { chann = lookup_chann_list(sess, conn); if (!chann) { @@ -1646,7 +1660,12 @@ static int krb5_authenticate(struct ksmbd_work *work, return -ENOMEM; chann->conn = conn; - xa_store(&sess->ksmbd_chann_list, (long)conn, chann, KSMBD_DEFAULT_GFP); + old = xa_store(&sess->ksmbd_chann_list, (long)conn, + chann, KSMBD_DEFAULT_GFP); + if (xa_is_err(old)) { + kfree(chann); + return xa_err(old); + } } } @@ -1833,8 +1852,6 @@ int smb2_sess_setup(struct ksmbd_work *work) ksmbd_conn_set_good(conn); sess->state = SMB2_SESSION_VALID; } - kfree(sess->Preauth_HashValue); - sess->Preauth_HashValue = NULL; } else if (conn->preferred_auth_mech == KSMBD_AUTH_NTLMSSP) { if (negblob->MessageType == NtLmNegotiate) { rc = ntlm_negotiate(work, negblob, negblob_len, rsp); @@ -1861,8 +1878,6 @@ int smb2_sess_setup(struct ksmbd_work *work) kfree(preauth_sess); } } - kfree(sess->Preauth_HashValue); - sess->Preauth_HashValue = NULL; } else { pr_info_ratelimited("Unknown NTLMSSP message type : 0x%x\n", le32_to_cpu(negblob->MessageType)); @@ -2581,7 +2596,7 @@ static void smb2_update_xattrs(struct ksmbd_tree_connect *tcon, } } -static int smb2_creat(struct ksmbd_work *work, struct path *parent_path, +static int smb2_creat(struct ksmbd_work *work, struct path *path, char *name, int open_flags, umode_t posix_mode, bool is_dir) { @@ -2610,7 +2625,7 @@ static int smb2_creat(struct ksmbd_work *work, struct path *parent_path, return rc; } - rc = ksmbd_vfs_kern_path_locked(work, name, 0, parent_path, path, 0); + rc = ksmbd_vfs_kern_path(work, name, 0, path, 0); if (rc) { pr_err("cannot get linux path (%s), err = %d\n", name, rc); @@ -2860,7 +2875,7 @@ int smb2_open(struct ksmbd_work *work) struct ksmbd_tree_connect *tcon = work->tcon; struct smb2_create_req *req; struct smb2_create_rsp *rsp; - struct path path, parent_path; + struct path path; struct ksmbd_share_config *share = tcon->share_conf; struct ksmbd_file *fp = NULL; struct file *filp = NULL; @@ -3116,8 +3131,8 @@ int smb2_open(struct ksmbd_work *work) goto err_out2; } - rc = ksmbd_vfs_kern_path_locked(work, name, LOOKUP_NO_SYMLINKS, - &parent_path, &path, 1); + rc = ksmbd_vfs_kern_path(work, name, LOOKUP_NO_SYMLINKS, + &path, 1); if (!rc) { file_present = true; @@ -3238,7 +3253,7 @@ int smb2_open(struct ksmbd_work *work) /*create file if not present */ if (!file_present) { - rc = smb2_creat(work, &parent_path, &path, name, open_flags, + rc = smb2_creat(work, &path, name, open_flags, posix_mode, req->CreateOptions & FILE_DIRECTORY_FILE_LE); if (rc) { @@ -3443,7 +3458,7 @@ int smb2_open(struct ksmbd_work *work) } if (file_present || created) - ksmbd_vfs_kern_path_unlock(&parent_path, &path); + path_put(&path); if (!S_ISDIR(file_inode(filp)->i_mode) && open_flags & O_TRUNC && !fp->attrib_only && !stream_name) { @@ -3724,7 +3739,7 @@ reconnected_fp: err_out: if (rc && (file_present || created)) - ksmbd_vfs_kern_path_unlock(&parent_path, &path); + path_put(&path); err_out1: ksmbd_revert_fsids(work); @@ -4108,20 +4123,6 @@ struct smb2_query_dir_private { int info_level; }; -static void lock_dir(struct ksmbd_file *dir_fp) -{ - struct dentry *dir = dir_fp->filp->f_path.dentry; - - inode_lock_nested(d_inode(dir), I_MUTEX_PARENT); -} - -static void unlock_dir(struct ksmbd_file *dir_fp) -{ - struct dentry *dir = dir_fp->filp->f_path.dentry; - - inode_unlock(d_inode(dir)); -} - static int process_query_dir_entries(struct smb2_query_dir_private *priv) { struct mnt_idmap *idmap = file_mnt_idmap(priv->dir_fp->filp); @@ -4136,12 +4137,10 @@ static int process_query_dir_entries(struct smb2_query_dir_private *priv) if (dentry_name(priv->d_info, priv->info_level)) return -EINVAL; - lock_dir(priv->dir_fp); - dent = lookup_one(idmap, - &QSTR_LEN(priv->d_info->name, - priv->d_info->name_len), - priv->dir_fp->filp->f_path.dentry); - unlock_dir(priv->dir_fp); + dent = lookup_one_unlocked(idmap, + &QSTR_LEN(priv->d_info->name, + priv->d_info->name_len), + priv->dir_fp->filp->f_path.dentry); if (IS_ERR(dent)) { ksmbd_debug(SMB, "Cannot lookup `%s' [%ld]\n", @@ -6052,8 +6051,7 @@ static int smb2_create_link(struct ksmbd_work *work, struct nls_table *local_nls) { char *link_name = NULL, *target_name = NULL, *pathname = NULL; - struct path path, parent_path; - bool file_present = false; + struct path path; int rc; if (buf_len < (u64)sizeof(struct smb2_file_link_info) + @@ -6082,15 +6080,12 @@ static int smb2_create_link(struct ksmbd_work *work, ksmbd_debug(SMB, "target name is %s\n", target_name); rc = ksmbd_vfs_kern_path_locked(work, link_name, LOOKUP_NO_SYMLINKS, - &parent_path, &path, 0); + &path, 0); if (rc) { if (rc != -ENOENT) goto out; - } else - file_present = true; - - if (file_info->ReplaceIfExists) { - if (file_present) { + } else { + if (file_info->ReplaceIfExists) { rc = ksmbd_vfs_remove_file(work, &path); if (rc) { rc = -EINVAL; @@ -6098,21 +6093,17 @@ static int smb2_create_link(struct ksmbd_work *work, link_name); goto out; } - } - } else { - if (file_present) { + } else { rc = -EEXIST; ksmbd_debug(SMB, "link already exists\n"); goto out; } + ksmbd_vfs_kern_path_unlock(&path); } - rc = ksmbd_vfs_link(work, target_name, link_name); if (rc) rc = -EINVAL; out: - if (file_present) - ksmbd_vfs_kern_path_unlock(&parent_path, &path); if (!IS_ERR(link_name)) kfree(link_name); diff --git a/fs/smb/server/vfs.c b/fs/smb/server/vfs.c index 34871a7f3e4b..04539037108c 100644 --- a/fs/smb/server/vfs.c +++ b/fs/smb/server/vfs.c @@ -66,13 +66,12 @@ int ksmbd_vfs_lock_parent(struct dentry *parent, struct dentry *child) return 0; } -static int ksmbd_vfs_path_lookup_locked(struct ksmbd_share_config *share_conf, - char *pathname, unsigned int flags, - struct path *parent_path, - struct path *path) +static int ksmbd_vfs_path_lookup(struct ksmbd_share_config *share_conf, + char *pathname, unsigned int flags, + struct path *path, bool do_lock) { struct qstr last; - struct filename *filename; + struct filename *filename __free(putname) = NULL; struct path *root_share_path = &share_conf->vfs_path; int err, type; struct dentry *d; @@ -89,51 +88,57 @@ static int ksmbd_vfs_path_lookup_locked(struct ksmbd_share_config *share_conf, return PTR_ERR(filename); err = vfs_path_parent_lookup(filename, flags, - parent_path, &last, &type, + path, &last, &type, root_share_path); - if (err) { - putname(filename); + if (err) return err; - } if (unlikely(type != LAST_NORM)) { - path_put(parent_path); - putname(filename); + path_put(path); return -ENOENT; } - err = mnt_want_write(parent_path->mnt); - if (err) { - path_put(parent_path); - putname(filename); + if (do_lock) { + err = mnt_want_write(path->mnt); + if (err) { + path_put(path); + return -ENOENT; + } + + inode_lock_nested(path->dentry->d_inode, I_MUTEX_PARENT); + d = lookup_one_qstr_excl(&last, path->dentry, 0); + + if (!IS_ERR(d)) { + dput(path->dentry); + path->dentry = d; + return 0; + } + inode_unlock(path->dentry->d_inode); + mnt_drop_write(path->mnt); + path_put(path); return -ENOENT; } - inode_lock_nested(parent_path->dentry->d_inode, I_MUTEX_PARENT); - d = lookup_one_qstr_excl(&last, parent_path->dentry, 0); - if (IS_ERR(d)) - goto err_out; - + d = lookup_noperm_unlocked(&last, path->dentry); + if (!IS_ERR(d) && d_is_negative(d)) { + dput(d); + d = ERR_PTR(-ENOENT); + } + if (IS_ERR(d)) { + path_put(path); + return -ENOENT; + } + dput(path->dentry); path->dentry = d; - path->mnt = mntget(parent_path->mnt); if (test_share_config_flag(share_conf, KSMBD_SHARE_FLAG_CROSSMNT)) { err = follow_down(path, 0); if (err < 0) { path_put(path); - goto err_out; + return -ENOENT; } } - - putname(filename); return 0; - -err_out: - inode_unlock(d_inode(parent_path->dentry)); - mnt_drop_write(parent_path->mnt); - path_put(parent_path); - putname(filename); - return -ENOENT; } void ksmbd_vfs_query_maximal_access(struct mnt_idmap *idmap, @@ -548,7 +553,8 @@ int ksmbd_vfs_getattr(const struct path *path, struct kstat *stat) { int err; - err = vfs_getattr(path, stat, STATX_BTIME, AT_STATX_SYNC_AS_STAT); + err = vfs_getattr(path, stat, STATX_BASIC_STATS | STATX_BTIME, + AT_STATX_SYNC_AS_STAT); if (err) pr_err("getattr failed, err %d\n", err); return err; @@ -1198,104 +1204,114 @@ static int ksmbd_vfs_lookup_in_dir(const struct path *dir, char *name, return ret; } -/** - * ksmbd_vfs_kern_path_locked() - lookup a file and get path info - * @work: work - * @name: file path that is relative to share - * @flags: lookup flags - * @parent_path: if lookup succeed, return parent_path info - * @path: if lookup succeed, return path info - * @caseless: caseless filename lookup - * - * Return: 0 on success, otherwise error - */ -int ksmbd_vfs_kern_path_locked(struct ksmbd_work *work, char *name, - unsigned int flags, struct path *parent_path, - struct path *path, bool caseless) +static +int __ksmbd_vfs_kern_path(struct ksmbd_work *work, char *filepath, + unsigned int flags, + struct path *path, bool caseless, bool do_lock) { struct ksmbd_share_config *share_conf = work->tcon->share_conf; + struct path parent_path; + size_t path_len, remain_len; int err; - err = ksmbd_vfs_path_lookup_locked(share_conf, name, flags, parent_path, - path); - if (!err) - return 0; - - if (caseless) { - char *filepath; - size_t path_len, remain_len; - - filepath = name; - path_len = strlen(filepath); - remain_len = path_len; - - *parent_path = share_conf->vfs_path; - path_get(parent_path); +retry: + err = ksmbd_vfs_path_lookup(share_conf, filepath, flags, path, do_lock); + if (!err || !caseless) + return err; - while (d_can_lookup(parent_path->dentry)) { - char *filename = filepath + path_len - remain_len; - char *next = strchrnul(filename, '/'); - size_t filename_len = next - filename; - bool is_last = !next[0]; + path_len = strlen(filepath); + remain_len = path_len; - if (filename_len == 0) - break; + parent_path = share_conf->vfs_path; + path_get(&parent_path); - err = ksmbd_vfs_lookup_in_dir(parent_path, filename, - filename_len, - work->conn->um); - if (err) - goto out2; + while (d_can_lookup(parent_path.dentry)) { + char *filename = filepath + path_len - remain_len; + char *next = strchrnul(filename, '/'); + size_t filename_len = next - filename; + bool is_last = !next[0]; - next[0] = '\0'; - - err = vfs_path_lookup(share_conf->vfs_path.dentry, - share_conf->vfs_path.mnt, - filepath, - flags, - path); - if (!is_last) - next[0] = '/'; - if (err) - goto out2; - else if (is_last) - goto out1; - path_put(parent_path); - *parent_path = *path; + if (filename_len == 0) + break; - remain_len -= filename_len + 1; + err = ksmbd_vfs_lookup_in_dir(&parent_path, filename, + filename_len, + work->conn->um); + path_put(&parent_path); + if (err) + goto out; + if (is_last) { + caseless = false; + goto retry; } + next[0] = '\0'; + + err = vfs_path_lookup(share_conf->vfs_path.dentry, + share_conf->vfs_path.mnt, + filepath, + flags, + &parent_path); + next[0] = '/'; + if (err) + goto out; - err = -EINVAL; -out2: - path_put(parent_path); + remain_len -= filename_len + 1; } -out1: - if (!err) { - err = mnt_want_write(parent_path->mnt); - if (err) { - path_put(path); - path_put(parent_path); - return err; - } - - err = ksmbd_vfs_lock_parent(parent_path->dentry, path->dentry); - if (err) { - mnt_drop_write(parent_path->mnt); - path_put(path); - path_put(parent_path); - } - } + err = -EINVAL; + path_put(&parent_path); +out: return err; } -void ksmbd_vfs_kern_path_unlock(struct path *parent_path, struct path *path) +/** + * ksmbd_vfs_kern_path() - lookup a file and get path info + * @work: work + * @filepath: file path that is relative to share + * @flags: lookup flags + * @path: if lookup succeed, return path info + * @caseless: caseless filename lookup + * + * Perform the lookup, possibly crossing over any mount point. + * On return no locks will be held and write-access to filesystem + * won't have been checked. + * Return: 0 if file was found, otherwise error + */ +int ksmbd_vfs_kern_path(struct ksmbd_work *work, char *filepath, + unsigned int flags, + struct path *path, bool caseless) +{ + return __ksmbd_vfs_kern_path(work, filepath, flags, path, + caseless, false); +} + +/** + * ksmbd_vfs_kern_path_locked() - lookup a file and get path info + * @work: work + * @filepath: file path that is relative to share + * @flags: lookup flags + * @path: if lookup succeed, return path info + * @caseless: caseless filename lookup + * + * Perform the lookup, but don't cross over any mount point. + * On return the parent of path->dentry will be locked and write-access to + * filesystem will have been gained. + * Return: 0 on if file was found, otherwise error + */ +int ksmbd_vfs_kern_path_locked(struct ksmbd_work *work, char *filepath, + unsigned int flags, + struct path *path, bool caseless) { - inode_unlock(d_inode(parent_path->dentry)); - mnt_drop_write(parent_path->mnt); + return __ksmbd_vfs_kern_path(work, filepath, flags, path, + caseless, true); +} + +void ksmbd_vfs_kern_path_unlock(struct path *path) +{ + /* While lock is still held, ->d_parent is safe */ + inode_unlock(d_inode(path->dentry->d_parent)); + mnt_drop_write(path->mnt); path_put(path); - path_put(parent_path); } struct dentry *ksmbd_vfs_kern_path_create(struct ksmbd_work *work, diff --git a/fs/smb/server/vfs.h b/fs/smb/server/vfs.h index 2893f59803a6..d47472f3e30b 100644 --- a/fs/smb/server/vfs.h +++ b/fs/smb/server/vfs.h @@ -117,10 +117,13 @@ int ksmbd_vfs_xattr_stream_name(char *stream_name, char **xattr_stream_name, int ksmbd_vfs_remove_xattr(struct mnt_idmap *idmap, const struct path *path, char *attr_name, bool get_write); +int ksmbd_vfs_kern_path(struct ksmbd_work *work, char *name, + unsigned int flags, + struct path *path, bool caseless); int ksmbd_vfs_kern_path_locked(struct ksmbd_work *work, char *name, - unsigned int flags, struct path *parent_path, + unsigned int flags, struct path *path, bool caseless); -void ksmbd_vfs_kern_path_unlock(struct path *parent_path, struct path *path); +void ksmbd_vfs_kern_path_unlock(struct path *path); struct dentry *ksmbd_vfs_kern_path_create(struct ksmbd_work *work, const char *name, unsigned int flags, diff --git a/fs/sysfs/file.c b/fs/sysfs/file.c index c3d3b079aedd..1ca143d2f22a 100644 --- a/fs/sysfs/file.c +++ b/fs/sysfs/file.c @@ -83,7 +83,7 @@ static int sysfs_kf_seq_show(struct seq_file *sf, void *v) static ssize_t sysfs_kf_bin_read(struct kernfs_open_file *of, char *buf, size_t count, loff_t pos) { - struct bin_attribute *battr = of->kn->priv; + const struct bin_attribute *battr = of->kn->priv; struct kobject *kobj = sysfs_file_kobj(of->kn); loff_t size = file_inode(of->file)->i_size; @@ -149,7 +149,7 @@ static ssize_t sysfs_kf_write(struct kernfs_open_file *of, char *buf, static ssize_t sysfs_kf_bin_write(struct kernfs_open_file *of, char *buf, size_t count, loff_t pos) { - struct bin_attribute *battr = of->kn->priv; + const struct bin_attribute *battr = of->kn->priv; struct kobject *kobj = sysfs_file_kobj(of->kn); loff_t size = file_inode(of->file)->i_size; @@ -173,7 +173,7 @@ static ssize_t sysfs_kf_bin_write(struct kernfs_open_file *of, char *buf, static int sysfs_kf_bin_mmap(struct kernfs_open_file *of, struct vm_area_struct *vma) { - struct bin_attribute *battr = of->kn->priv; + const struct bin_attribute *battr = of->kn->priv; struct kobject *kobj = sysfs_file_kobj(of->kn); return battr->mmap(of->file, kobj, battr, vma); @@ -182,7 +182,7 @@ static int sysfs_kf_bin_mmap(struct kernfs_open_file *of, static loff_t sysfs_kf_bin_llseek(struct kernfs_open_file *of, loff_t offset, int whence) { - struct bin_attribute *battr = of->kn->priv; + const struct bin_attribute *battr = of->kn->priv; struct kobject *kobj = sysfs_file_kobj(of->kn); if (battr->llseek) @@ -193,7 +193,7 @@ static loff_t sysfs_kf_bin_llseek(struct kernfs_open_file *of, loff_t offset, static int sysfs_kf_bin_open(struct kernfs_open_file *of) { - struct bin_attribute *battr = of->kn->priv; + const struct bin_attribute *battr = of->kn->priv; if (battr->f_mapping) of->file->f_mapping = battr->f_mapping(); diff --git a/fs/ubifs/crypto.c b/fs/ubifs/crypto.c index 921f9033d0d2..fb5ac358077b 100644 --- a/fs/ubifs/crypto.c +++ b/fs/ubifs/crypto.c @@ -51,7 +51,7 @@ int ubifs_encrypt(const struct inode *inode, struct ubifs_data_node *dn, memset(p + in_len, 0, pad_len - in_len); err = fscrypt_encrypt_block_inplace(inode, virt_to_page(p), pad_len, - offset_in_page(p), block, GFP_NOFS); + offset_in_page(p), block); if (err) { ubifs_err(c, "fscrypt_encrypt_block_inplace() failed: %d", err); return err; diff --git a/fs/verity/Kconfig b/fs/verity/Kconfig index 40569d3527a7..76d1c5971b82 100644 --- a/fs/verity/Kconfig +++ b/fs/verity/Kconfig @@ -2,11 +2,9 @@ config FS_VERITY bool "FS Verity (read-only file-based authenticity protection)" - select CRYPTO select CRYPTO_HASH_INFO - # SHA-256 is selected as it's intended to be the default hash algorithm. - # To avoid bloat, other wanted algorithms must be selected explicitly. - select CRYPTO_SHA256 + select CRYPTO_LIB_SHA256 + select CRYPTO_LIB_SHA512 help This option enables fs-verity. fs-verity is the dm-verity mechanism implemented at the file level. On supported diff --git a/fs/verity/enable.c b/fs/verity/enable.c index c284f46d1b53..503268cf4296 100644 --- a/fs/verity/enable.c +++ b/fs/verity/enable.c @@ -7,7 +7,7 @@ #include "fsverity_private.h" -#include <crypto/hash.h> +#include <linux/export.h> #include <linux/mount.h> #include <linux/sched/signal.h> #include <linux/uaccess.h> @@ -24,7 +24,6 @@ static int hash_one_block(struct inode *inode, struct block_buffer *cur) { struct block_buffer *next = cur + 1; - int err; /* * Safety check to prevent a buffer overflow in case of a filesystem bug @@ -37,10 +36,8 @@ static int hash_one_block(struct inode *inode, /* Zero-pad the block if it's shorter than the block size. */ memset(&cur->data[cur->filled], 0, params->block_size - cur->filled); - err = fsverity_hash_block(params, inode, cur->data, - &next->data[next->filled]); - if (err) - return err; + fsverity_hash_block(params, inode, cur->data, + &next->data[next->filled]); next->filled += params->digest_size; cur->filled = 0; return 0; diff --git a/fs/verity/fsverity_private.h b/fs/verity/fsverity_private.h index b3506f56e180..5fe854a5b9ad 100644 --- a/fs/verity/fsverity_private.h +++ b/fs/verity/fsverity_private.h @@ -20,7 +20,6 @@ /* A hash algorithm supported by fs-verity */ struct fsverity_hash_alg { - struct crypto_shash *tfm; /* hash tfm, allocated on demand */ const char *name; /* crypto API name, e.g. sha256 */ unsigned int digest_size; /* digest size in bytes, e.g. 32 for SHA-256 */ unsigned int block_size; /* block size in bytes, e.g. 64 for SHA-256 */ @@ -31,10 +30,16 @@ struct fsverity_hash_alg { enum hash_algo algo_id; }; +union fsverity_hash_ctx { + struct sha256_ctx sha256; + struct sha512_ctx sha512; +}; + /* Merkle tree parameters: hash algorithm, initial hash state, and topology */ struct merkle_tree_params { const struct fsverity_hash_alg *hash_alg; /* the hash algorithm */ - const u8 *hashstate; /* initial hash state or NULL */ + /* initial hash state if salted, NULL if unsalted */ + const union fsverity_hash_ctx *hashstate; unsigned int digest_size; /* same as hash_alg->digest_size */ unsigned int block_size; /* size of data and tree blocks */ unsigned int hashes_per_block; /* number of hashes per tree block */ @@ -76,16 +81,17 @@ struct fsverity_info { /* hash_algs.c */ -extern struct fsverity_hash_alg fsverity_hash_algs[]; +extern const struct fsverity_hash_alg fsverity_hash_algs[]; const struct fsverity_hash_alg *fsverity_get_hash_alg(const struct inode *inode, unsigned int num); -const u8 *fsverity_prepare_hash_state(const struct fsverity_hash_alg *alg, - const u8 *salt, size_t salt_size); -int fsverity_hash_block(const struct merkle_tree_params *params, - const struct inode *inode, const void *data, u8 *out); -int fsverity_hash_buffer(const struct fsverity_hash_alg *alg, - const void *data, size_t size, u8 *out); +union fsverity_hash_ctx * +fsverity_prepare_hash_state(const struct fsverity_hash_alg *alg, + const u8 *salt, size_t salt_size); +void fsverity_hash_block(const struct merkle_tree_params *params, + const struct inode *inode, const void *data, u8 *out); +void fsverity_hash_buffer(const struct fsverity_hash_alg *alg, + const void *data, size_t size, u8 *out); void __init fsverity_check_hash_algs(void); /* init.c */ diff --git a/fs/verity/hash_algs.c b/fs/verity/hash_algs.c index 6b08b1d9a7d7..9bb3c6344907 100644 --- a/fs/verity/hash_algs.c +++ b/fs/verity/hash_algs.c @@ -7,10 +7,8 @@ #include "fsverity_private.h" -#include <crypto/hash.h> - /* The hash algorithms supported by fs-verity */ -struct fsverity_hash_alg fsverity_hash_algs[] = { +const struct fsverity_hash_alg fsverity_hash_algs[] = { [FS_VERITY_HASH_ALG_SHA256] = { .name = "sha256", .digest_size = SHA256_DIGEST_SIZE, @@ -25,106 +23,42 @@ struct fsverity_hash_alg fsverity_hash_algs[] = { }, }; -static DEFINE_MUTEX(fsverity_hash_alg_init_mutex); - /** - * fsverity_get_hash_alg() - validate and prepare a hash algorithm + * fsverity_get_hash_alg() - get a hash algorithm by number * @inode: optional inode for logging purposes * @num: the hash algorithm number * - * Get the struct fsverity_hash_alg for the given hash algorithm number, and - * ensure it has a hash transform ready to go. The hash transforms are - * allocated on-demand so that we don't waste resources unnecessarily, and - * because the crypto modules may be initialized later than fs/verity/. + * Get the struct fsverity_hash_alg for the given hash algorithm number. * - * Return: pointer to the hash alg on success, else an ERR_PTR() + * Return: pointer to the hash alg if it's known, otherwise NULL. */ const struct fsverity_hash_alg *fsverity_get_hash_alg(const struct inode *inode, unsigned int num) { - struct fsverity_hash_alg *alg; - struct crypto_shash *tfm; - int err; - if (num >= ARRAY_SIZE(fsverity_hash_algs) || !fsverity_hash_algs[num].name) { fsverity_warn(inode, "Unknown hash algorithm number: %u", num); - return ERR_PTR(-EINVAL); - } - alg = &fsverity_hash_algs[num]; - - /* pairs with smp_store_release() below */ - if (likely(smp_load_acquire(&alg->tfm) != NULL)) - return alg; - - mutex_lock(&fsverity_hash_alg_init_mutex); - - if (alg->tfm != NULL) - goto out_unlock; - - tfm = crypto_alloc_shash(alg->name, 0, 0); - if (IS_ERR(tfm)) { - if (PTR_ERR(tfm) == -ENOENT) { - fsverity_warn(inode, - "Missing crypto API support for hash algorithm \"%s\"", - alg->name); - alg = ERR_PTR(-ENOPKG); - goto out_unlock; - } - fsverity_err(inode, - "Error allocating hash algorithm \"%s\": %ld", - alg->name, PTR_ERR(tfm)); - alg = ERR_CAST(tfm); - goto out_unlock; + return NULL; } - - err = -EINVAL; - if (WARN_ON_ONCE(alg->digest_size != crypto_shash_digestsize(tfm))) - goto err_free_tfm; - if (WARN_ON_ONCE(alg->block_size != crypto_shash_blocksize(tfm))) - goto err_free_tfm; - - pr_info("%s using implementation \"%s\"\n", - alg->name, crypto_shash_driver_name(tfm)); - - /* pairs with smp_load_acquire() above */ - smp_store_release(&alg->tfm, tfm); - goto out_unlock; - -err_free_tfm: - crypto_free_shash(tfm); - alg = ERR_PTR(err); -out_unlock: - mutex_unlock(&fsverity_hash_alg_init_mutex); - return alg; + return &fsverity_hash_algs[num]; } /** * fsverity_prepare_hash_state() - precompute the initial hash state * @alg: hash algorithm * @salt: a salt which is to be prepended to all data to be hashed - * @salt_size: salt size in bytes, possibly 0 + * @salt_size: salt size in bytes * - * Return: NULL if the salt is empty, otherwise the kmalloc()'ed precomputed - * initial hash state on success or an ERR_PTR() on failure. + * Return: the kmalloc()'ed initial hash state, or NULL if out of memory. */ -const u8 *fsverity_prepare_hash_state(const struct fsverity_hash_alg *alg, - const u8 *salt, size_t salt_size) +union fsverity_hash_ctx * +fsverity_prepare_hash_state(const struct fsverity_hash_alg *alg, + const u8 *salt, size_t salt_size) { - u8 *hashstate = NULL; - SHASH_DESC_ON_STACK(desc, alg->tfm); u8 *padded_salt = NULL; size_t padded_salt_size; - int err; - - desc->tfm = alg->tfm; - - if (salt_size == 0) - return NULL; - - hashstate = kmalloc(crypto_shash_statesize(alg->tfm), GFP_KERNEL); - if (!hashstate) - return ERR_PTR(-ENOMEM); + union fsverity_hash_ctx ctx; + void *res = NULL; /* * Zero-pad the salt to the next multiple of the input size of the hash @@ -135,30 +69,26 @@ const u8 *fsverity_prepare_hash_state(const struct fsverity_hash_alg *alg, */ padded_salt_size = round_up(salt_size, alg->block_size); padded_salt = kzalloc(padded_salt_size, GFP_KERNEL); - if (!padded_salt) { - err = -ENOMEM; - goto err_free; - } + if (!padded_salt) + return NULL; memcpy(padded_salt, salt, salt_size); - err = crypto_shash_init(desc); - if (err) - goto err_free; - - err = crypto_shash_update(desc, padded_salt, padded_salt_size); - if (err) - goto err_free; - - err = crypto_shash_export(desc, hashstate); - if (err) - goto err_free; -out: - kfree(padded_salt); - return hashstate; -err_free: - kfree(hashstate); - hashstate = ERR_PTR(err); - goto out; + switch (alg->algo_id) { + case HASH_ALGO_SHA256: + sha256_init(&ctx.sha256); + sha256_update(&ctx.sha256, padded_salt, padded_salt_size); + res = kmemdup(&ctx.sha256, sizeof(ctx.sha256), GFP_KERNEL); + break; + case HASH_ALGO_SHA512: + sha512_init(&ctx.sha512); + sha512_update(&ctx.sha512, padded_salt, padded_salt_size); + res = kmemdup(&ctx.sha512, sizeof(ctx.sha512), GFP_KERNEL); + break; + default: + WARN_ON_ONCE(1); + } + kfree(padded_salt); + return res; } /** @@ -170,31 +100,32 @@ err_free: * * Hash a single data or hash block. The hash is salted if a salt is specified * in the Merkle tree parameters. - * - * Return: 0 on success, -errno on failure */ -int fsverity_hash_block(const struct merkle_tree_params *params, - const struct inode *inode, const void *data, u8 *out) +void fsverity_hash_block(const struct merkle_tree_params *params, + const struct inode *inode, const void *data, u8 *out) { - SHASH_DESC_ON_STACK(desc, params->hash_alg->tfm); - int err; - - desc->tfm = params->hash_alg->tfm; - - if (params->hashstate) { - err = crypto_shash_import(desc, params->hashstate); - if (err) { - fsverity_err(inode, - "Error %d importing hash state", err); - return err; - } - err = crypto_shash_finup(desc, data, params->block_size, out); - } else { - err = crypto_shash_digest(desc, data, params->block_size, out); + union fsverity_hash_ctx ctx; + + if (!params->hashstate) { + fsverity_hash_buffer(params->hash_alg, data, params->block_size, + out); + return; + } + + switch (params->hash_alg->algo_id) { + case HASH_ALGO_SHA256: + ctx.sha256 = params->hashstate->sha256; + sha256_update(&ctx.sha256, data, params->block_size); + sha256_final(&ctx.sha256, out); + return; + case HASH_ALGO_SHA512: + ctx.sha512 = params->hashstate->sha512; + sha512_update(&ctx.sha512, data, params->block_size); + sha512_final(&ctx.sha512, out); + return; + default: + BUG(); } - if (err) - fsverity_err(inode, "Error %d computing block hash", err); - return err; } /** @@ -203,13 +134,20 @@ int fsverity_hash_block(const struct merkle_tree_params *params, * @data: the data to hash * @size: size of data to hash, in bytes * @out: output digest, size 'alg->digest_size' bytes - * - * Return: 0 on success, -errno on failure */ -int fsverity_hash_buffer(const struct fsverity_hash_alg *alg, - const void *data, size_t size, u8 *out) +void fsverity_hash_buffer(const struct fsverity_hash_alg *alg, + const void *data, size_t size, u8 *out) { - return crypto_shash_tfm_digest(alg->tfm, data, size, out); + switch (alg->algo_id) { + case HASH_ALGO_SHA256: + sha256(data, size, out); + return; + case HASH_ALGO_SHA512: + sha512(data, size, out); + return; + default: + BUG(); + } } void __init fsverity_check_hash_algs(void) diff --git a/fs/verity/measure.c b/fs/verity/measure.c index 175d2f1bc089..388734132f01 100644 --- a/fs/verity/measure.c +++ b/fs/verity/measure.c @@ -9,6 +9,7 @@ #include <linux/bpf.h> #include <linux/btf.h> +#include <linux/export.h> #include <linux/uaccess.h> /** diff --git a/fs/verity/open.c b/fs/verity/open.c index fdeb95eca3af..c561e130cd0c 100644 --- a/fs/verity/open.c +++ b/fs/verity/open.c @@ -7,6 +7,7 @@ #include "fsverity_private.h" +#include <linux/export.h> #include <linux/mm.h> #include <linux/slab.h> @@ -42,18 +43,18 @@ int fsverity_init_merkle_tree_params(struct merkle_tree_params *params, memset(params, 0, sizeof(*params)); hash_alg = fsverity_get_hash_alg(inode, hash_algorithm); - if (IS_ERR(hash_alg)) - return PTR_ERR(hash_alg); + if (!hash_alg) + return -EINVAL; params->hash_alg = hash_alg; params->digest_size = hash_alg->digest_size; - params->hashstate = fsverity_prepare_hash_state(hash_alg, salt, - salt_size); - if (IS_ERR(params->hashstate)) { - err = PTR_ERR(params->hashstate); - params->hashstate = NULL; - fsverity_err(inode, "Error %d preparing hash state", err); - goto out_err; + if (salt_size) { + params->hashstate = + fsverity_prepare_hash_state(hash_alg, salt, salt_size); + if (!params->hashstate) { + err = -ENOMEM; + goto out_err; + } } /* @@ -158,18 +159,15 @@ out_err: * Compute the file digest by hashing the fsverity_descriptor excluding the * builtin signature and with the sig_size field set to 0. */ -static int compute_file_digest(const struct fsverity_hash_alg *hash_alg, - struct fsverity_descriptor *desc, - u8 *file_digest) +static void compute_file_digest(const struct fsverity_hash_alg *hash_alg, + struct fsverity_descriptor *desc, + u8 *file_digest) { __le32 sig_size = desc->sig_size; - int err; desc->sig_size = 0; - err = fsverity_hash_buffer(hash_alg, desc, sizeof(*desc), file_digest); + fsverity_hash_buffer(hash_alg, desc, sizeof(*desc), file_digest); desc->sig_size = sig_size; - - return err; } /* @@ -201,12 +199,7 @@ struct fsverity_info *fsverity_create_info(const struct inode *inode, memcpy(vi->root_hash, desc->root_hash, vi->tree_params.digest_size); - err = compute_file_digest(vi->tree_params.hash_alg, desc, - vi->file_digest); - if (err) { - fsverity_err(inode, "Error %d computing file digest", err); - goto fail; - } + compute_file_digest(vi->tree_params.hash_alg, desc, vi->file_digest); err = fsverity_verify_signature(vi, desc->signature, le32_to_cpu(desc->sig_size)); diff --git a/fs/verity/read_metadata.c b/fs/verity/read_metadata.c index f58432772d9e..cba5d6af4e04 100644 --- a/fs/verity/read_metadata.c +++ b/fs/verity/read_metadata.c @@ -8,6 +8,7 @@ #include "fsverity_private.h" #include <linux/backing-dev.h> +#include <linux/export.h> #include <linux/highmem.h> #include <linux/sched/signal.h> #include <linux/uaccess.h> diff --git a/fs/verity/verify.c b/fs/verity/verify.c index 4fcad0825a12..a1f00c3fd3b2 100644 --- a/fs/verity/verify.c +++ b/fs/verity/verify.c @@ -7,8 +7,8 @@ #include "fsverity_private.h" -#include <crypto/hash.h> #include <linux/bio.h> +#include <linux/export.h> static struct workqueue_struct *fsverity_read_workqueue; @@ -202,8 +202,7 @@ descend: unsigned long hblock_idx = hblocks[level - 1].index; unsigned int hoffset = hblocks[level - 1].hoffset; - if (fsverity_hash_block(params, inode, haddr, real_hash) != 0) - goto error; + fsverity_hash_block(params, inode, haddr, real_hash); if (memcmp(want_hash, real_hash, hsize) != 0) goto corrupted; /* @@ -222,8 +221,7 @@ descend: } /* Finally, verify the data block. */ - if (fsverity_hash_block(params, inode, data, real_hash) != 0) - goto error; + fsverity_hash_block(params, inode, data, real_hash); if (memcmp(want_hash, real_hash, hsize) != 0) goto corrupted; return true; diff --git a/fs/xfs/xfs_mount.c b/fs/xfs/xfs_mount.c index 0b690bc119d7..2133fbaf1766 100644 --- a/fs/xfs/xfs_mount.c +++ b/fs/xfs/xfs_mount.c @@ -673,11 +673,6 @@ static inline xfs_extlen_t xfs_calc_atomic_write_max(struct xfs_mount *mp) return rounddown_pow_of_two(XFS_B_TO_FSB(mp, MAX_RW_COUNT)); } -static inline unsigned int max_pow_of_two_factor(const unsigned int nr) -{ - return 1 << (ffs(nr) - 1); -} - /* * If the underlying device advertises atomic write support, limit the size of * atomic writes to the greatest power-of-two factor of the group size so diff --git a/fs/zonefs/super.c b/fs/zonefs/super.c index d165eb979f21..4dc7f967c861 100644 --- a/fs/zonefs/super.c +++ b/fs/zonefs/super.c @@ -1113,11 +1113,12 @@ static int zonefs_read_super(struct super_block *sb) u32 crc, stored_crc; int ret; - super = kmalloc(PAGE_SIZE, GFP_KERNEL); + super = kmalloc(ZONEFS_SUPER_SIZE, GFP_KERNEL); if (!super) return -ENOMEM; - ret = bdev_rw_virt(sb->s_bdev, 0, super, PAGE_SIZE, REQ_OP_READ); + ret = bdev_rw_virt(sb->s_bdev, 0, super, ZONEFS_SUPER_SIZE, + REQ_OP_READ); if (ret) goto free_super; |