Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

qnx4: Extract dir entry filename processing into helper

Both dir.c and namei.c need to perform the same work to figure out a
directory entry's name and size. Extract this into a helper for use
in the next patch.

Acked-by: Anders Larsen <al@alarsen.net>
Link: https://lore.kernel.org/r/20231130205120.3642477-1-keescook@chromium.org
Signed-off-by: Kees Cook <keescook@chromium.org>

+67 -45
+7 -45
fs/qnx4/dir.c
··· 15 15 #include <linux/buffer_head.h> 16 16 #include "qnx4.h" 17 17 18 - /* 19 - * A qnx4 directory entry is an inode entry or link info 20 - * depending on the status field in the last byte. The 21 - * first byte is where the name start either way, and a 22 - * zero means it's empty. 23 - * 24 - * Also, due to a bug in gcc, we don't want to use the 25 - * real (differently sized) name arrays in the inode and 26 - * link entries, but always the 'de_name[]' one in the 27 - * fake struct entry. 28 - * 29 - * See 30 - * 31 - * https://gcc.gnu.org/bugzilla/show_bug.cgi?id=99578#c6 32 - * 33 - * for details, but basically gcc will take the size of the 34 - * 'name' array from one of the used union entries randomly. 35 - * 36 - * This use of 'de_name[]' (48 bytes) avoids the false positive 37 - * warnings that would happen if gcc decides to use 'inode.di_name' 38 - * (16 bytes) even when the pointer and size were to come from 39 - * 'link.dl_name' (48 bytes). 40 - * 41 - * In all cases the actual name pointer itself is the same, it's 42 - * only the gcc internal 'what is the size of this field' logic 43 - * that can get confused. 44 - */ 45 - union qnx4_directory_entry { 46 - struct { 47 - const char de_name[48]; 48 - u8 de_pad[15]; 49 - u8 de_status; 50 - }; 51 - struct qnx4_inode_entry inode; 52 - struct qnx4_link_info link; 53 - }; 54 - 55 18 static int qnx4_readdir(struct file *file, struct dir_context *ctx) 56 19 { 57 20 struct inode *inode = file_inode(file); ··· 37 74 ix = (ctx->pos >> QNX4_DIR_ENTRY_SIZE_BITS) % QNX4_INODES_PER_BLOCK; 38 75 for (; ix < QNX4_INODES_PER_BLOCK; ix++, ctx->pos += QNX4_DIR_ENTRY_SIZE) { 39 76 union qnx4_directory_entry *de; 77 + const char *fname; 40 78 41 79 offset = ix * QNX4_DIR_ENTRY_SIZE; 42 80 de = (union qnx4_directory_entry *) (bh->b_data + offset); 43 81 44 - if (!de->de_name[0]) 82 + fname = get_entry_fname(de, &size); 83 + if (!fname) 45 84 continue; 46 - if (!(de->de_status & (QNX4_FILE_USED|QNX4_FILE_LINK))) 47 - continue; 85 + 48 86 if (!(de->de_status & QNX4_FILE_LINK)) { 49 - size = sizeof(de->inode.di_fname); 50 87 ino = blknum * QNX4_INODES_PER_BLOCK + ix - 1; 51 88 } else { 52 - size = sizeof(de->link.dl_fname); 53 89 ino = ( le32_to_cpu(de->link.dl_inode_blk) - 1 ) * 54 90 QNX4_INODES_PER_BLOCK + 55 91 de->link.dl_inode_ndx; 56 92 } 57 - size = strnlen(de->de_name, size); 58 - QNX4DEBUG((KERN_INFO "qnx4_readdir:%.*s\n", size, name)); 59 - if (!dir_emit(ctx, de->de_name, size, ino, DT_UNKNOWN)) { 93 + 94 + QNX4DEBUG((KERN_INFO "qnx4_readdir:%.*s\n", size, fname)); 95 + if (!dir_emit(ctx, fname, size, ino, DT_UNKNOWN)) { 60 96 brelse(bh); 61 97 return 0; 62 98 }
+60
fs/qnx4/qnx4.h
··· 44 44 { 45 45 return &qnx4_i(inode)->raw; 46 46 } 47 + 48 + /* 49 + * A qnx4 directory entry is an inode entry or link info 50 + * depending on the status field in the last byte. The 51 + * first byte is where the name start either way, and a 52 + * zero means it's empty. 53 + * 54 + * Also, due to a bug in gcc, we don't want to use the 55 + * real (differently sized) name arrays in the inode and 56 + * link entries, but always the 'de_name[]' one in the 57 + * fake struct entry. 58 + * 59 + * See 60 + * 61 + * https://gcc.gnu.org/bugzilla/show_bug.cgi?id=99578#c6 62 + * 63 + * for details, but basically gcc will take the size of the 64 + * 'name' array from one of the used union entries randomly. 65 + * 66 + * This use of 'de_name[]' (48 bytes) avoids the false positive 67 + * warnings that would happen if gcc decides to use 'inode.di_name' 68 + * (16 bytes) even when the pointer and size were to come from 69 + * 'link.dl_name' (48 bytes). 70 + * 71 + * In all cases the actual name pointer itself is the same, it's 72 + * only the gcc internal 'what is the size of this field' logic 73 + * that can get confused. 74 + */ 75 + union qnx4_directory_entry { 76 + struct { 77 + const char de_name[48]; 78 + u8 de_pad[15]; 79 + u8 de_status; 80 + }; 81 + struct qnx4_inode_entry inode; 82 + struct qnx4_link_info link; 83 + }; 84 + 85 + static inline const char *get_entry_fname(union qnx4_directory_entry *de, 86 + int *size) 87 + { 88 + /* Make sure the status byte is in the same place for all structs. */ 89 + BUILD_BUG_ON(offsetof(struct qnx4_inode_entry, di_status) != 90 + offsetof(struct qnx4_link_info, dl_status)); 91 + BUILD_BUG_ON(offsetof(struct qnx4_inode_entry, di_status) != 92 + offsetof(union qnx4_directory_entry, de_status)); 93 + 94 + if (!de->de_name[0]) 95 + return NULL; 96 + if (!(de->de_status & (QNX4_FILE_USED|QNX4_FILE_LINK))) 97 + return NULL; 98 + if (!(de->de_status & QNX4_FILE_LINK)) 99 + *size = sizeof(de->inode.di_fname); 100 + else 101 + *size = sizeof(de->link.dl_fname); 102 + 103 + *size = strnlen(de->de_name, *size); 104 + 105 + return de->de_name; 106 + }