簡體   English   中英

我在ubuntu12.04中使用Libtar時出現strncpy()核心轉儲

[英]strncpy() core dump when I use Libtar in ubuntu12.04

我在encode.c:33中跟蹤coredump。

像這樣的源代碼:

if (t->options & TAR_GNU) 
    strncpy(t->th_buf.magic, "ustar  ", 8);    // here is the coredump                                                                                                                                 
else
    .... 

函數調用堆棧如下所示:

0x4064d73a in strncpy (__len=8, __src=0x40663b34 "ustar  ", __dest=0x4104e5ed "") at /usr/include/i386-linux-gnu/bits/string3.h:121
0x4024e342 in __strncpy_chk () from /lib/i386-linux-gnu/libc.so.6
0x4024ee1a in __chk_fail () from /lib/i386-linux-gnu/libc.so.6
0x40250065 in __fortify_fail () from /lib/i386-linux-gnu/libc.so.6
0x401b739a in ?? () from /lib/i386-linux-gnu/libc.so.6
0x4017d825 in abort () from /lib/i386-linux-gnu/libc.so.6
0x4017a1df in raise () from /lib/i386-linux-gnu/libc.so.6
0x40064424 in __kernel_vsyscall ()
<signal handler called>
sig_coredump (sig=6) at mpm_common.c:1207

t-> th_buf.magic是tar_header的縮寫,定義如下:

struct tar_header{
    ...;
    char magic[6];
    char version[2];
    ...;
}

我很確定strncpy可以這種方式使用。

在我的情況下,t-> th_buf已經有malloc了。

在gdb中:

(gdb) p t->th_buf
$5 = {name = "/TARFILE.C", '\000' <repeats 89 times>, mode = "100644 ", 
      uid = "    41", gid = "    41 ", size = "     207114 ", mtime = "12115070475 ", 
      chksum = "\000\000\000\000\000\000\000", typeflag = 48 '0', linkname = '\000' <repeats 99 times>, 
      magic = "\000\000\000\000\000", version = "\000",
      ...

您正在嘗試復制8個字節:

strncpy(t->th_buf.magic, "ustar  ", 8); 

放入具有6個已分配空間的緩沖區

char magic[6];

不上班

magic只有6個字符,而您正在寫8個字符。

盡管您試圖將8個字節復制到只有6個空間的緩沖區中,但這通常不是問題。

通常不會出現問題的原因是緊隨其后的是一個兩個字節的字符數組,該數組完全能夠解決緩沖區溢出的問題:

struct tar_header{
    ...;
    char magic[6];
    char version[2];     // Can absorb extra two chars easily.
    ...;
}

strncpy的真正問題是大多數人不了解它是如何工作的。

如果要復制的緩沖區大於您指定的大小,則基本上停止在該大小,並且不再復制, 包括字符串末尾的空終止符。

因此, strncpy最終會給您的東西不是 C字符串,並且,如果您隨后嘗試將其用作C字符串(例如將其傳遞給strlen ),那么所有的事情都可能會變得strlen

這就是為什么我更喜歡在strcpy之后使用strlen check的原因,假設數據在兩個部分之間不能更改。 這樣,您可以保證以C字符串結尾(或者您事先知道它)。


但是,這也不是這里的特定問題。

在您的調用堆棧中,有一個對檢查函數__strncpy_chk的調用,它類似於以下內容:

char *
__strncpy_chk (s1, s2, n, s1len)
     char *s1;
     const char *s2;
     size_t n;
     size_t s1len;
{
    char c;
    char *s = s1;

    if (__builtin_expect (s1len < n, 0))
        __chk_fail ();
    :
    rest of function to copy the stuff.
}

因此,它將預先檢查源字符串是否超過您指定的長度,並且在嘗試復制之前就失敗了。 基本上,這與我前面提到的步驟相同,但是會導致崩潰,而不是您自己的代碼中知道崩潰。

這就是您的錯誤出處,運行時庫中有一些額外的安全性。

請記住,此額外檢查僅在調試代碼中 ,而不在生產就緒代碼中 這樣,您可以確認自己在開發期間做的正確,而不會減慢現場代碼的速度。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM