searchusermenu
  • 发布文章
  • 消息中心
点赞
收藏
评论
分享
原创

一次Crash问题的分析

2024-08-20 09:57:52
9
0

客户报告某资源池一台机器有3crash

操作系统:centos 3.10.0-957.el7.x86_64

cpu: Intel(R) Xeon(R) Gold 6132 CPU @ 2.60GHz

分析3crash生成的vmcore文件,都发现是同一个调用栈出现问题。下面以其中一次crash日志分析,其calltrace如图1-1所示


1-1 crash 信息

 

查看代码,出问题位置如下:


1-2 生成crash的代码

 

是通过如下函数调用实现cp 数据到用户态时出了问题。


1-3 调用crash函数的上层代码

 

出问题点位于往用户态拷贝对访问的数据区进行检查时,copy_to_user函数原型如下:

unsigned long

copy_to_user(void __user *to, const void *from, unsigned long n)

 

根据错误提示,ffff918d92a12005 对应的是一个kmalloc-4096 slab,在未开启slabslub)的debug的情况下,对应的size应该是4096字节,而(16379 bytes),就是我们本次需要访问的长度,对于copy_to_user的检查来说,是越界了,产生了crash

 

通过分析图1-4的函数调用栈


1-4 crash函数调用栈跟踪信息

 

从图1-4中得出 copy_from_read_buftty参数地址为0xffff918191dbe800

tty->disc_data地址如下:


1-5 ldata信息与代码信息

 


1-6 crash时的ldata结构中的数据

 

从图1-6得出 ldata->read_buf = 0xffff918d92a12000

ldata->read_buf[ldata->read_tail] = 0xffff918d92a12000+5=0xffff918d92a12005和图1-1中出问题的地址一致。

 

从图1-4size_t *nr


1-7 copy_from_read_buf函数的nr参数

 

16379和图1-1中读取的数据相符

 

        n = min(ldata->read_cnt, N_TTY_BUF_SIZE - ldata->read_tail);

        n = min(*nr, n);

ldata->read_cnt = -5

N_TTY_BUF_SIZE = 4096

ldata->read_tail = 5

*nr = 16379

计算出n 16379(注意n的类型是size_t,所以-5是一个非常大的数)

 

这里ldata->read_buf大小是N_TTY_BUF_SIZE 4096

*nr是上层应用提供的缓冲区的大小,超过4096也没有问题,

 

这里我们注意到ldata->read_cnt = -5


1-8 n_tty_data结构体定义

 

在高版本内核此结构体已经把read_cnt去掉,read_head,read_tail定义成size_t


1-9 高版本内核n_tty_data结构体定义

 

通过trace 发现正常情况下centos7.6下的tty,不会出现read_cnt为负的情况,出现负数的场景通过分析代码无法得知,社区也没有发现相关讨论。


1-10 centos 7.6正常情况下traceread_cnt为非负数

 

所以只能确定此问题是tty 驱动程序的一个bug,通过查找发现upstream 相关修改的commit如图1-11所示

 


1-11 社区修改read_cntcommit

 

对应版本信息为linux 3.12,出问题系统为3.10.0-957.el7.x86_64 低于社区3.12版本。


1-12 社区修改read_cnt的版本信息

 

通过分析centos镜像中的源代码,发现Centos 3.10.0-1062.el7  linux-3.10.0-1127  linux-3.10.0-1160都已修复了此问题


1-13 3.10.0-1062修复此问题对应结构体

 

基于目前的分析和信息来说,解决此问题方法为升级系统到Centos 3.10.0-1062.el7及以上版本。

0条评论
0 / 1000
刘强
6文章数
2粉丝数
刘强
6 文章 | 2 粉丝
原创

一次Crash问题的分析

2024-08-20 09:57:52
9
0

客户报告某资源池一台机器有3crash

操作系统:centos 3.10.0-957.el7.x86_64

cpu: Intel(R) Xeon(R) Gold 6132 CPU @ 2.60GHz

分析3crash生成的vmcore文件,都发现是同一个调用栈出现问题。下面以其中一次crash日志分析,其calltrace如图1-1所示


1-1 crash 信息

 

查看代码,出问题位置如下:


1-2 生成crash的代码

 

是通过如下函数调用实现cp 数据到用户态时出了问题。


1-3 调用crash函数的上层代码

 

出问题点位于往用户态拷贝对访问的数据区进行检查时,copy_to_user函数原型如下:

unsigned long

copy_to_user(void __user *to, const void *from, unsigned long n)

 

根据错误提示,ffff918d92a12005 对应的是一个kmalloc-4096 slab,在未开启slabslub)的debug的情况下,对应的size应该是4096字节,而(16379 bytes),就是我们本次需要访问的长度,对于copy_to_user的检查来说,是越界了,产生了crash

 

通过分析图1-4的函数调用栈


1-4 crash函数调用栈跟踪信息

 

从图1-4中得出 copy_from_read_buftty参数地址为0xffff918191dbe800

tty->disc_data地址如下:


1-5 ldata信息与代码信息

 


1-6 crash时的ldata结构中的数据

 

从图1-6得出 ldata->read_buf = 0xffff918d92a12000

ldata->read_buf[ldata->read_tail] = 0xffff918d92a12000+5=0xffff918d92a12005和图1-1中出问题的地址一致。

 

从图1-4size_t *nr


1-7 copy_from_read_buf函数的nr参数

 

16379和图1-1中读取的数据相符

 

        n = min(ldata->read_cnt, N_TTY_BUF_SIZE - ldata->read_tail);

        n = min(*nr, n);

ldata->read_cnt = -5

N_TTY_BUF_SIZE = 4096

ldata->read_tail = 5

*nr = 16379

计算出n 16379(注意n的类型是size_t,所以-5是一个非常大的数)

 

这里ldata->read_buf大小是N_TTY_BUF_SIZE 4096

*nr是上层应用提供的缓冲区的大小,超过4096也没有问题,

 

这里我们注意到ldata->read_cnt = -5


1-8 n_tty_data结构体定义

 

在高版本内核此结构体已经把read_cnt去掉,read_head,read_tail定义成size_t


1-9 高版本内核n_tty_data结构体定义

 

通过trace 发现正常情况下centos7.6下的tty,不会出现read_cnt为负的情况,出现负数的场景通过分析代码无法得知,社区也没有发现相关讨论。


1-10 centos 7.6正常情况下traceread_cnt为非负数

 

所以只能确定此问题是tty 驱动程序的一个bug,通过查找发现upstream 相关修改的commit如图1-11所示

 


1-11 社区修改read_cntcommit

 

对应版本信息为linux 3.12,出问题系统为3.10.0-957.el7.x86_64 低于社区3.12版本。


1-12 社区修改read_cnt的版本信息

 

通过分析centos镜像中的源代码,发现Centos 3.10.0-1062.el7  linux-3.10.0-1127  linux-3.10.0-1160都已修复了此问题


1-13 3.10.0-1062修复此问题对应结构体

 

基于目前的分析和信息来说,解决此问题方法为升级系统到Centos 3.10.0-1062.el7及以上版本。

文章来自个人专栏
内核
6 文章 | 1 订阅
0条评论
0 / 1000
请输入你的评论
0
0