001c179c4e26 xfs: fix NULL pointer dereference in xfs_getbmap()
[ 68.392204] BUG: kernel NULL pointer dereference, address: 000000000000002a
...
[ 68.428987] Call Trace:
[ 68.429726] <TASK>
[ 68.450295] xfs_ioc_getbmap+0x192/0x310
xfs_file_ioctl+0x4a4/0xe70
[ 68.451510] [ 68.473513] vfs_ioctl+0x3b/0x70
__se_sys_ioctl+0xbd/0xe0
[ 68.474434] [ 68.475341] __x64_sys_ioctl+0x1f/0x30
do_syscall_64+0x43/0x120
[ 68.476259] [ 68.477174] entry_SYSCALL_64_after_hwframe+0x6e/0x76
--git a/fs/xfs/xfs_bmap_util.c b/fs/xfs/xfs_bmap_util.c
diff 1a1d1f881037..d886be3d301e 100644
index --- a/fs/xfs/xfs_bmap_util.c
+++ b/fs/xfs/xfs_bmap_util.c
-29,6 +29,7 @@
@@ #include "xfs_iomap.h"
#include "xfs_reflink.h"
#include "xfs_rtbitmap.h"
+#include <linux/delay.h>
/* Kernel only BMAP related definitions and functions */
-433,6 +434,10 @@ xfs_getbmap(
@@ = XFS_DATA_FORK;
whichfork = xfs_ifork_ptr(ip, whichfork);
ifp
+ printk("delay begin\n");
+ mdelay(5000);
+ printk("delay end\n");
+
(ip, XFS_IOLOCK_SHARED);
xfs_ilockswitch (whichfork) {
case XFS_ATTR_FORK:
ioctl.c
文件:
#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <sys/ioctl.h>
#include <unistd.h>
int main() {
const char *path = "/mnt";
int fd;
= open(path, O_RDONLY | O_DIRECTORY);
fd if (fd == -1) {
("无法打开目录");
perrorreturn EXIT_FAILURE;
}
char arg[32] = "\x01\xff\x00\x00\x00\x00\x03\x00\x00\x00\x00\x00\x00"
"\x00\x00\x00\x00\x00\x08\x00\x00\x00\xc6\x2a\xf7";
if (ioctl(fd, _IOC(_IOC_READ | _IOC_WRITE, 0x58, 0x2c, 0x20), arg) == -1) {
("ioctl 操作失败");
perror(fd);
closereturn EXIT_FAILURE;
}
("ioctl 操作成功\n");
printf
(fd);
closereturn EXIT_SUCCESS;
}
setxattr.c
文件:
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/xattr.h>
int main() {
const char *path = "/mnt";
const char *attr_name = "trusted.overlay.upper";
int result = setxattr(path, attr_name, NULL, 0, XATTR_CREATE);
if (result == 0) {
("扩展属性设置成功。\n");
printf} else {
("设置扩展属性时发生错误");
perrorreturn EXIT_FAILURE;
}
return EXIT_SUCCESS;
}
apt-get install xfsprogs -y
fallocate -l 100M image
mkfs.xfs -f image
mount image /mnt
gcc setxattr.c -o setxattr
gcc ioctl.c -o ioctl
./ioctl & # 这里会deley 3秒
sleep 1
./setxattr
| setxattr
ioctl ----------------------------|---------------------------
|
xfs_getbmap |
xfs_ifork_ptr |
xfs_inode_has_attr_fork ->i_forkoff == 0 |
ipreturn NULL |
== NULL |
ifp ----------------------------|---------------------------
| xfs_bmap_set_attrforkoff
| ip->i_forkoff > 0
----------------------------|---------------------------
|
xfs_inode_has_attr_fork ->i_forkoff > 0 |
ip== NULL |
ifp ->if_format // null-ptr-deref ifp
构造复现后,顺便导出vmcore解析一下玩玩。
dmesg
日志:
[ 87.104528] BUG: kernel NULL pointer dereference, address: 000000000000002a
[ 87.107238] #PF: supervisor read access in kernel mode
[ 87.108798] #PF: error_code(0x0000) - not-present page
[ 87.110274] PGD 0 P4D 0
[ 87.111077] Oops: 0000 [#1] PREEMPT SMP NOPTI
[ 87.112368] CPU: 1 PID: 502 Comm: ioctl Not tainted 6.7.0-rc2+ #14
[ 87.114143] Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS rel-1.16.2-0-gea1b7a073390-prebuilt.qemu.org 04/01/2014
[ 87.117309] RIP: 0010:xfs_getbmap+0x17c/0x7d0
[ 87.118657] Code: aa 2a 02 00 41 83 ff 01 0f 84 25 01 00 00 e8 6b c5 9a ff 45 85 ff 0f 84 4f 01 00 00 44 89 3c 24 e8 59 c5 9a ff 48 8b 44 24 18 <0f> b6 58 2a 80 fb 01 0f 84 c3 05 00 00 e8 42 c5 9a ff 84 db 0f 8e
[ 87.123959] RSP: 0018:ffffc90003267bf0 EFLAGS: 00010246
[ 87.125499] RAX: 0000000000000000 RBX: 0000000000000000 RCX: 0000000000000001
[ 87.127580] RDX: 0000000000000001 RSI: ffff888105568000 RDI: 0000000000000002
[ 87.129627] RBP: ffffffffffffffff R08: ffff88813ba72d70 R09: 0000000000000002
[ 87.131635] R10: 0000000000000001 R11: 0000000000000001 R12: ffffc90003267cb8
[ 87.133646] R13: ffff88810a8a9000 R14: 0000000000000001 R15: 0000000000000001
[ 87.135657] FS: 00007f59e6862540(0000) GS:ffff88813ba40000(0000) knlGS:0000000000000000
[ 87.137933] CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033
[ 87.139576] CR2: 000000000000002a CR3: 00000001048c2000 CR4: 0000000000350ef0
[ 87.141589] Call Trace:
[ 87.142325] <TASK>
[ 87.161495] xfs_ioc_getbmap+0x192/0x310
xfs_file_ioctl+0x4a4/0xe70
[ 87.162716] [ 87.184714] vfs_ioctl+0x3b/0x70
__se_sys_ioctl+0xbd/0xe0
[ 87.185563] [ 87.186472] __x64_sys_ioctl+0x1f/0x30
do_syscall_64+0x43/0x120
[ 87.187390] [ 87.188301] entry_SYSCALL_64_after_hwframe+0x6e/0x76
解析崩在哪一行:
./scripts/faddr2line build/vmlinux xfs_getbmap+0x17c/0x7d0
xfs_getbmap+0x17c/0x7d0:
xfs_getbmap at fs/xfs/xfs_bmap_util.c:491
查看if_format
在struct xfs_ifork
中的偏移量:
crash> struct xfs_ifork -ox
struct xfs_ifork {
...
[0x2a] int8_t if_format;
...
}
SIZE: 0x30
这就是为什么报错发生空指针解引用的地址是000000000000002a
。