diff options
| author | Kees Cook <kees+treewide@kernel.org> | 2026-09-02 15:31:14 -0700 |
|---|---|---|
| committer | Kees Cook <kees@kernel.org> | 2026-09-04 21:37:00 -0700 |
| commit | 3a2c4d55e32ad65efebdb6de44eef3bfa08bb49d (patch) | |
| tree | c65086f9bdcd48c6360fb7cb4598bca084da1f32 /fs/udf/dir.c | |
| download | linux-stable-3a2c4d55e32ad65efebdb6de44eef3bfa08bb49d.tar.gz linux-stable-3a2c4d55e32ad65efebdb6de44eef3bfa08bb49d.zip | |
treewide: refresh kmalloc_obj() conversionsgrafted
This is another run of the Coccinelle script for converting kmalloc()
family of allocations to kmalloc_obj() via the existing rules in
scripts/coccinelle/api/kmalloc_objs.cocci
This catches both the set of kmalloc() uses added since the first
kmalloc_obj() conversions in v7.0 and adds a large group missed in the
first pass due to Coccinelle not interacting well with the cleanup.h
scoped_...() family of macros[1]. I worked around this with spatch's
"--macro-file" argument to a file with all the scoped_...() macros mapped
to Coccinelle's YACFE_ITERATOR[2] as that was the closest viable control
flow indicator I could find.
Build tested allmodconfig on x86, arm64, arm, loongarch, mips, powerpc,
riscv, and s390 with no new warnings.
Link: https://lore.kernel.org/lkml/202609021314.8A9C0B8@keescook/ [1]
Link: https://github.com/coccinelle/coccinelle/blob/master/standard.h [2]
Signed-off-by: Kees Cook <kees+treewide@kernel.org>
Diffstat (limited to 'fs/udf/dir.c')
| -rw-r--r-- | fs/udf/dir.c | 162 |
1 files changed, 162 insertions, 0 deletions
diff --git a/fs/udf/dir.c b/fs/udf/dir.c new file mode 100644 index 000000000..425e3c162 --- /dev/null +++ b/fs/udf/dir.c @@ -0,0 +1,162 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * dir.c + * + * PURPOSE + * Directory handling routines for the OSTA-UDF(tm) filesystem. + * + * COPYRIGHT + * (C) 1998-2004 Ben Fennema + * + * HISTORY + * + * 10/05/98 dgb Split directory operations into its own file + * Implemented directory reads via do_udf_readdir + * 10/06/98 Made directory operations work! + * 11/17/98 Rewrote directory to support ICBTAG_FLAG_AD_LONG + * 11/25/98 blf Rewrote directory handling (readdir+lookup) to support reading + * across blocks. + * 12/12/98 Split out the lookup code to namei.c. bulk of directory + * code now in directory.c:udf_fileident_read. + */ + +#include "udfdecl.h" + +#include <linux/string.h> +#include <linux/errno.h> +#include <linux/filelock.h> +#include <linux/mm.h> +#include <linux/slab.h> +#include <linux/bio.h> +#include <linux/iversion.h> + +#include "udf_i.h" +#include "udf_sb.h" + +static int udf_readdir(struct file *file, struct dir_context *ctx) +{ + struct inode *dir = file_inode(file); + loff_t nf_pos, emit_pos = 0; + int flen; + unsigned char *fname = NULL; + int ret = 0; + struct super_block *sb = dir->i_sb; + bool pos_valid = false; + struct udf_fileident_iter iter; + + if (ctx->pos == 0) { + if (!dir_emit_dot(file, ctx)) + return 0; + ctx->pos = 1; + } + nf_pos = (ctx->pos - 1) << 2; + if (nf_pos >= dir->i_size) + goto out; + + /* + * Something changed since last readdir (either lseek was called or dir + * changed)? We need to verify the position correctly points at the + * beginning of some dir entry so that the directory parsing code does + * not get confused. Since UDF does not have any reliable way of + * identifying beginning of dir entry (names are under user control), + * we need to scan the directory from the beginning. + */ + if (!inode_eq_iversion(dir, *(u64 *)file->private_data)) { + emit_pos = nf_pos; + nf_pos = 0; + } else { + pos_valid = true; + } + + fname = kmalloc(UDF_NAME_LEN, GFP_KERNEL); + if (!fname) { + ret = -ENOMEM; + goto out; + } + + for (ret = udf_fiiter_init(&iter, dir, nf_pos); + !ret && iter.pos < dir->i_size; + ret = udf_fiiter_advance(&iter)) { + struct kernel_lb_addr tloc; + udf_pblk_t iblock; + + /* Still not at offset where user asked us to read from? */ + if (iter.pos < emit_pos) + continue; + + /* Update file position only if we got past the current one */ + pos_valid = true; + ctx->pos = (iter.pos >> 2) + 1; + + if (iter.fi.fileCharacteristics & FID_FILE_CHAR_DELETED) { + if (!UDF_QUERY_FLAG(sb, UDF_FLAG_UNDELETE)) + continue; + } + + if (iter.fi.fileCharacteristics & FID_FILE_CHAR_HIDDEN) { + if (!UDF_QUERY_FLAG(sb, UDF_FLAG_UNHIDE)) + continue; + } + + if (iter.fi.fileCharacteristics & FID_FILE_CHAR_PARENT) { + if (!dir_emit_dotdot(file, ctx)) + goto out_iter; + continue; + } + + flen = udf_get_filename(sb, iter.name, + iter.fi.lengthFileIdent, fname, UDF_NAME_LEN); + if (flen < 0) + continue; + + tloc = lelb_to_cpu(iter.fi.icb.extLocation); + iblock = udf_get_lb_pblock(sb, &tloc, 0); + if (!dir_emit(ctx, fname, flen, iblock, DT_UNKNOWN)) + goto out_iter; + } + + if (!ret) { + ctx->pos = (iter.pos >> 2) + 1; + pos_valid = true; + } +out_iter: + udf_fiiter_release(&iter); +out: + if (pos_valid) + *(u64 *)file->private_data = inode_query_iversion(dir); + kfree(fname); + + return ret; +} + +static int udf_dir_open(struct inode *inode, struct file *file) +{ + file->private_data = kzalloc(sizeof(u64), GFP_KERNEL); + if (!file->private_data) + return -ENOMEM; + return 0; +} + +static int udf_dir_release(struct inode *inode, struct file *file) +{ + kfree(file->private_data); + return 0; +} + +static loff_t udf_dir_llseek(struct file *file, loff_t offset, int whence) +{ + return generic_llseek_cookie(file, offset, whence, + (u64 *)file->private_data); +} + +/* readdir and lookup functions */ +const struct file_operations udf_dir_operations = { + .open = udf_dir_open, + .release = udf_dir_release, + .llseek = udf_dir_llseek, + .read = generic_read_dir, + .iterate_shared = udf_readdir, + .unlocked_ioctl = udf_ioctl, + .fsync = simple_fsync, + .setlease = generic_setlease, +}; |
