summaryrefslogtreecommitdiff
path: root/fs
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2024-01-10 22:03:52 +0300
committerLinus Torvalds <torvalds@linux-foundation.org>2024-01-10 22:03:52 +0300
commit120a201bd2ad0bffebdd2cf62c389dbba79bbfae (patch)
tree82250acc579a556aae85ca08c7c6ce77dceec554 /fs
parent72116efd6307077546c93e0432a197876cedff70 (diff)
parenta75b3809dce2ad006ebf7fa641f49881fa0d79d7 (diff)
downloadlinux-120a201bd2ad0bffebdd2cf62c389dbba79bbfae.tar.xz
Merge tag 'hardening-v6.8-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/kees/linux
Pull hardening updates from Kees Cook: - Introduce the param_unknown_fn type and other clean ups (Andy Shevchenko) - Various __counted_by annotations (Christophe JAILLET, Gustavo A. R. Silva, Kees Cook) - Add KFENCE test to LKDTM (Stephen Boyd) - Various strncpy() refactorings (Justin Stitt) - Fix qnx4 to avoid writing into the smaller of two overlapping buffers - Various strlcpy() refactorings * tag 'hardening-v6.8-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/kees/linux: qnx4: Use get_directory_fname() in qnx4_match() qnx4: Extract dir entry filename processing into helper atags_proc: Add __counted_by for struct buffer and use struct_size() tracing/uprobe: Replace strlcpy() with strscpy() params: Fix multi-line comment style params: Sort headers params: Use size_add() for kmalloc() params: Do not go over the limit when getting the string length params: Introduce the param_unknown_fn type lkdtm: Add kfence read after free crash type nvme-fc: replace deprecated strncpy with strscpy nvdimm/btt: replace deprecated strncpy with strscpy nvme-fabrics: replace deprecated strncpy with strscpy drm/modes: replace deprecated strncpy with strscpy_pad afs: Add __counted_by for struct afs_acl and use struct_size() VMCI: Annotate struct vmci_handle_arr with __counted_by i40e: Annotate struct i40e_qvlist_info with __counted_by HID: uhid: replace deprecated strncpy with strscpy samples: Replace strlcpy() with strscpy() SUNRPC: Replace strlcpy() with strscpy()
Diffstat (limited to 'fs')
-rw-r--r--fs/afs/internal.h2
-rw-r--r--fs/afs/xattr.c2
-rw-r--r--fs/qnx4/dir.c52
-rw-r--r--fs/qnx4/namei.c29
-rw-r--r--fs/qnx4/qnx4.h60
5 files changed, 80 insertions, 65 deletions
diff --git a/fs/afs/internal.h b/fs/afs/internal.h
index e33ace259cc6..55aa0679d8ce 100644
--- a/fs/afs/internal.h
+++ b/fs/afs/internal.h
@@ -1213,7 +1213,7 @@ extern void afs_fs_inline_bulk_status(struct afs_operation *);
struct afs_acl {
u32 size;
- u8 data[];
+ u8 data[] __counted_by(size);
};
extern void afs_fs_fetch_acl(struct afs_operation *);
diff --git a/fs/afs/xattr.c b/fs/afs/xattr.c
index 64b2c0224f62..e19f396aa370 100644
--- a/fs/afs/xattr.c
+++ b/fs/afs/xattr.c
@@ -75,7 +75,7 @@ static bool afs_make_acl(struct afs_operation *op,
{
struct afs_acl *acl;
- acl = kmalloc(sizeof(*acl) + size, GFP_KERNEL);
+ acl = kmalloc(struct_size(acl, data, size), GFP_KERNEL);
if (!acl) {
afs_op_nomem(op);
return false;
diff --git a/fs/qnx4/dir.c b/fs/qnx4/dir.c
index 66645a5a35f3..42a529e26bd6 100644
--- a/fs/qnx4/dir.c
+++ b/fs/qnx4/dir.c
@@ -15,43 +15,6 @@
#include <linux/buffer_head.h>
#include "qnx4.h"
-/*
- * A qnx4 directory entry is an inode entry or link info
- * depending on the status field in the last byte. The
- * first byte is where the name start either way, and a
- * zero means it's empty.
- *
- * Also, due to a bug in gcc, we don't want to use the
- * real (differently sized) name arrays in the inode and
- * link entries, but always the 'de_name[]' one in the
- * fake struct entry.
- *
- * See
- *
- * https://gcc.gnu.org/bugzilla/show_bug.cgi?id=99578#c6
- *
- * for details, but basically gcc will take the size of the
- * 'name' array from one of the used union entries randomly.
- *
- * This use of 'de_name[]' (48 bytes) avoids the false positive
- * warnings that would happen if gcc decides to use 'inode.di_name'
- * (16 bytes) even when the pointer and size were to come from
- * 'link.dl_name' (48 bytes).
- *
- * In all cases the actual name pointer itself is the same, it's
- * only the gcc internal 'what is the size of this field' logic
- * that can get confused.
- */
-union qnx4_directory_entry {
- struct {
- const char de_name[48];
- u8 de_pad[15];
- u8 de_status;
- };
- struct qnx4_inode_entry inode;
- struct qnx4_link_info link;
-};
-
static int qnx4_readdir(struct file *file, struct dir_context *ctx)
{
struct inode *inode = file_inode(file);
@@ -74,26 +37,25 @@ static int qnx4_readdir(struct file *file, struct dir_context *ctx)
ix = (ctx->pos >> QNX4_DIR_ENTRY_SIZE_BITS) % QNX4_INODES_PER_BLOCK;
for (; ix < QNX4_INODES_PER_BLOCK; ix++, ctx->pos += QNX4_DIR_ENTRY_SIZE) {
union qnx4_directory_entry *de;
+ const char *fname;
offset = ix * QNX4_DIR_ENTRY_SIZE;
de = (union qnx4_directory_entry *) (bh->b_data + offset);
- if (!de->de_name[0])
- continue;
- if (!(de->de_status & (QNX4_FILE_USED|QNX4_FILE_LINK)))
+ fname = get_entry_fname(de, &size);
+ if (!fname)
continue;
+
if (!(de->de_status & QNX4_FILE_LINK)) {
- size = sizeof(de->inode.di_fname);
ino = blknum * QNX4_INODES_PER_BLOCK + ix - 1;
} else {
- size = sizeof(de->link.dl_fname);
ino = ( le32_to_cpu(de->link.dl_inode_blk) - 1 ) *
QNX4_INODES_PER_BLOCK +
de->link.dl_inode_ndx;
}
- size = strnlen(de->de_name, size);
- QNX4DEBUG((KERN_INFO "qnx4_readdir:%.*s\n", size, name));
- if (!dir_emit(ctx, de->de_name, size, ino, DT_UNKNOWN)) {
+
+ QNX4DEBUG((KERN_INFO "qnx4_readdir:%.*s\n", size, fname));
+ if (!dir_emit(ctx, fname, size, ino, DT_UNKNOWN)) {
brelse(bh);
return 0;
}
diff --git a/fs/qnx4/namei.c b/fs/qnx4/namei.c
index 8d72221735d7..bb8db6550ca5 100644
--- a/fs/qnx4/namei.c
+++ b/fs/qnx4/namei.c
@@ -26,31 +26,24 @@
static int qnx4_match(int len, const char *name,
struct buffer_head *bh, unsigned long *offset)
{
- struct qnx4_inode_entry *de;
- int namelen, thislen;
+ union qnx4_directory_entry *de;
+ const char *fname;
+ int fnamelen;
if (bh == NULL) {
printk(KERN_WARNING "qnx4: matching unassigned buffer !\n");
return 0;
}
- de = (struct qnx4_inode_entry *) (bh->b_data + *offset);
+ de = (union qnx4_directory_entry *) (bh->b_data + *offset);
*offset += QNX4_DIR_ENTRY_SIZE;
- if ((de->di_status & QNX4_FILE_LINK) != 0) {
- namelen = QNX4_NAME_MAX;
- } else {
- namelen = QNX4_SHORT_NAME_MAX;
- }
- thislen = strlen( de->di_fname );
- if ( thislen > namelen )
- thislen = namelen;
- if (len != thislen) {
+
+ fname = get_entry_fname(de, &fnamelen);
+ if (!fname || len != fnamelen)
return 0;
- }
- if (strncmp(name, de->di_fname, len) == 0) {
- if ((de->di_status & (QNX4_FILE_USED|QNX4_FILE_LINK)) != 0) {
- return 1;
- }
- }
+
+ if (strncmp(name, fname, len) == 0)
+ return 1;
+
return 0;
}
diff --git a/fs/qnx4/qnx4.h b/fs/qnx4/qnx4.h
index 6283705466a4..5c2b1fb6b952 100644
--- a/fs/qnx4/qnx4.h
+++ b/fs/qnx4/qnx4.h
@@ -44,3 +44,63 @@ static inline struct qnx4_inode_entry *qnx4_raw_inode(struct inode *inode)
{
return &qnx4_i(inode)->raw;
}
+
+/*
+ * A qnx4 directory entry is an inode entry or link info
+ * depending on the status field in the last byte. The
+ * first byte is where the name start either way, and a
+ * zero means it's empty.
+ *
+ * Also, due to a bug in gcc, we don't want to use the
+ * real (differently sized) name arrays in the inode and
+ * link entries, but always the 'de_name[]' one in the
+ * fake struct entry.
+ *
+ * See
+ *
+ * https://gcc.gnu.org/bugzilla/show_bug.cgi?id=99578#c6
+ *
+ * for details, but basically gcc will take the size of the
+ * 'name' array from one of the used union entries randomly.
+ *
+ * This use of 'de_name[]' (48 bytes) avoids the false positive
+ * warnings that would happen if gcc decides to use 'inode.di_name'
+ * (16 bytes) even when the pointer and size were to come from
+ * 'link.dl_name' (48 bytes).
+ *
+ * In all cases the actual name pointer itself is the same, it's
+ * only the gcc internal 'what is the size of this field' logic
+ * that can get confused.
+ */
+union qnx4_directory_entry {
+ struct {
+ const char de_name[48];
+ u8 de_pad[15];
+ u8 de_status;
+ };
+ struct qnx4_inode_entry inode;
+ struct qnx4_link_info link;
+};
+
+static inline const char *get_entry_fname(union qnx4_directory_entry *de,
+ int *size)
+{
+ /* Make sure the status byte is in the same place for all structs. */
+ BUILD_BUG_ON(offsetof(struct qnx4_inode_entry, di_status) !=
+ offsetof(struct qnx4_link_info, dl_status));
+ BUILD_BUG_ON(offsetof(struct qnx4_inode_entry, di_status) !=
+ offsetof(union qnx4_directory_entry, de_status));
+
+ if (!de->de_name[0])
+ return NULL;
+ if (!(de->de_status & (QNX4_FILE_USED|QNX4_FILE_LINK)))
+ return NULL;
+ if (!(de->de_status & QNX4_FILE_LINK))
+ *size = sizeof(de->inode.di_fname);
+ else
+ *size = sizeof(de->link.dl_fname);
+
+ *size = strnlen(de->de_name, *size);
+
+ return de->de_name;
+}