8wDlpd.png
8wDFp9.png
8wDEOx.png
8wDMfH.png
8wDKte.png

数百次迭代后,C strcat 缓冲区溢出

vinuZachariah 2月前

27 0

我用 C 语言为 DWM 编写了一个状态栏实用程序,用于显示时间、日期、CPU 温度和电池电量。我最近注意到该程序崩溃了,并发现它有一个核心转储。我重新编译了

编写了一个状态栏实用程序, DWM 用于显示时间、日期、CPU 温度和电池电量。我最近注意到该程序崩溃了,并且发现它有一个核心转储。我重新编译了该实用程序以包含调试符号来调试 gdb ,它在启动后大约 10 分钟崩溃了。在分析核心转储时, coredumpctl debug 我在回溯中发现了以下行。

0x0000716af522c799 in __GI___fortify_fail (msg=msg@entry=0x716af52ba153 "buffer overflow detected") at fortify_fail.c:24

我一直在梳理代码,但我不明白是什么导致了缓冲区溢出,因为它在很长一段时间内运行良好,并且没有发生另一次崩溃。

代码中导致该问题的那一行是:

strcat(status, battery_buff); 

包含代码的 GitHub 存储库

我创建的 Github 问题

系统信息:

  • 操作系统:Arch Linux(6.10.5-arch1-1)
  • 窗口管理器:DWM(6.4.r5-3)
  • X11:libx11 (1.8.10-1)
  • 抄送:GCC(14.2.1+r32+geccf707e5ce-1)

完整的 GDB 回溯( thread apply all backtrace full )

Thread 1 (Thread 0x716af50ce2c0 (LWP 1963)):
#0  __pthread_kill_implementation (threadid=<optimized out>, signo=signo@entry=6, no_tid=no_tid@entry=0) at pthread_kill.c:44
        tid = <optimized out>
        ret = 0
        pd = <optimized out>
        old_mask = {__val = {23}}
        ret = <optimized out>
#1  0x0000716af519d463 in __pthread_kill_internal (threadid=<optimized out>, signo=6) at pthread_kill.c:78
No locals.
#2  0x0000716af5144120 in __GI_raise (sig=sig@entry=6) at ../sysdeps/posix/raise.c:26
        ret = <optimized out>
#3  0x0000716af512b4c3 in __GI_abort () at abort.c:79
        save_stage = 1
        act = {__sigaction_handler = {sa_handler = 0x20, sa_sigaction = 0x20}, sa_mask = {__val = {6786648855210017280, 0, 140721397189936, 101591911342992, 101591911411072, 100, 32, 140721397190128, 124704192526143, 101591911343744, 101591911343751, 101591911343752, 0, 140720308486146, 124704193122162, 1088703904}}, sa_flags = 907723264, sa_restorer = 0xb}
#4  0x0000716af512c354 in __libc_message_impl (fmt=fmt@entry=0x716af52ba16c "*** %s ***: terminated\n") at ../sysdeps/posix/libc_fatal.c:132
        ap = {{gp_offset = 16, fp_offset = 23653, overflow_arg_area = 0x7ffc40e44ec0, reg_save_area = 0x7ffc40e44e50}}
        fd = 2
        iov = {{iov_base = 0x716af52ba16c, iov_len = 4}, {iov_base = 0x716af52ba153, iov_len = 24}, {iov_base = 0x716af52ba172, iov_len = 17}, {iov_base = 0x3000000030, iov_len = 140721397190376}, {iov_base = 0x7ffc40e44e20, iov_len = 6786648855210017280}, {iov_base = 0x7ffc40e44e60, iov_len = 124704192628220}, {iov_base = 0x5c65b5c98010, iov_len = 528}}
        iovcnt = <optimized out>
        total = <optimized out>
        cp = <optimized out>
#5  0x0000716af522c799 in __GI___fortify_fail (msg=msg@entry=0x716af52ba153 "buffer overflow detected") at fortify_fail.c:24
No locals.
#6  0x0000716af522c124 in __GI___chk_fail () at chk_fail.c:28
No locals.
#7  0x0000716af522db1a in __strcat_chk (dest=dest@entry=0x5c65b5c9a390 " 12:17:25 PM | 08/18/2024 | 100°C | 100% ", src=src@entry=0x5c65b5c9a680 "| 100% ", destlen=<optimized out>, destlen@entry=42) at strcat_chk.c:34
        s1 = <optimized out>
        s2 = <optimized out>
        c = <optimized out>
#8  0x00005c658482c381 in strcat (__dest=0x5c65b5c9a390 " 12:17:25 PM | 08/18/2024 | 100°C | 100% ", __src=0x5c65b5c9a680 "| 100% ") at /usr/include/bits/string_fortified.h:140
No locals.
#9  main (argc=<optimized out>, argv=<optimized out>) at /usr/src/debug/dmenustatus/dmenustatus/src/dmenustatus.c:87
        step = 1
        status = 0x5c65b5c9a390 " 12:17:25 PM | 08/18/2024 | 100°C | 100% "
        datetime_buff = 0x5c65b5c9a9a0 " 12:17:25 PM | 08/18/2024 "
        cputemp_buff = 0x5c65b5c9a450 "| 100°C "
        battery_buff = 0x5c65b5c9a680 "| 100% "
帖子版权声明 1、本帖标题:数百次迭代后,C strcat 缓冲区溢出
    本站网址:http://xjnalaquan.com/
2、本网站的资源部分来源于网络,如有侵权,请联系站长进行删除处理。
3、会员发帖仅代表会员个人观点,并不代表本站赞同其观点和对其真实性负责。
4、本站一律禁止以任何方式发布或转载任何违法的相关信息,访客发现请向站长举报
5、站长邮箱:yeweds@126.com 除非注明,本帖由vinuZachariah在本站《c》版块原创发布, 转载请注明出处!
最新回复 (0)
  • @AndrewHenle,哦,注意到了,谢谢,我刚刚阅读了 dmenustatus.c 中的代码,那里有很多改进空间

    1. p0

    2. p1

    char battery_status(char *base)
    {
      char status;
      char *buff = readfile(base, "status");
    
      if (buff == NULL) {
        return 'E';
      }
      if (!strncmp(buff, "Discharging", 11)) {
    ...
      } else {
        buff[strlen(buff) - 1] = '\0';
        status = '?';
      }
    

    buff == NULL 假的( readfile 永远不会返回 NULL 在这种 存在缓冲区 下溢 else :如果 buff 是空的,则您正在写入 buff[-1] .


    一般来说,只分配 42 个字节既有 status 缺陷又浪费( malloc 可能 将其四舍五入为 48 或 64 个字节)。

    最好重新构造它,这样您就可以将 char status[512]; 之后的 指针 。类似于以下内容:

    char status[513];
    const int sz = sizeof(status) - 1;
    while (running) {
      char *p = datetime(status, sz /*sz characters remaining*/);
      p = cputemp(9, p, sz - (p - status) /* remaining space*/);
      p = battery(0, p, sz - (p - status) /* remaining space*/);
    ...
    
  • 提示:为了应对意外的高温,请使用 %g 而不是 %f 来打印 sprintf。当值非常大/非常小时,它将转为指数表示法,并保持所需的缓冲区大小合理。

  • 关于“完全没必要”——该代码不是以空字符终止字符串,而是用空字符终止符替换最后一个字符(可能是换行符)。这就是 - 1 的原因。

返回
作者最近主题: