2014-12-06 77 views
1

我有以下示例代碼模仿應用程序中的代碼。strncpy複製超過指定的大小

#include <iostream> 
#include <string.h> 
#include <cstring> 
#include <atlstr.h> 
using namespace std; 

    void test(char *s, int size) 
    { 
     //s = ""; 
     int lens = strlen(s); 
     char *str1 = "((State:0.000000 Std30c5 = State:T) OR ((State:0.000000 Std30c6 = State:T) OR ((State:0.000000 Std30c7 = State:T) OR ((State:0.000000 Std30c8 = State:T) OR ((State:0.000000 Std30c9 = State:T) OR ((State:0.000000 Std30ca = State:T) OR ((State:0.000000 Std30cb = State:T) OR ((State:0.000000 Std30cc = State:T) OR ((State:0.000000 Std30cd = State:T) OR ((State:0.000000 Std30ce = State:T) OR ((State:0.000000 Std30cf = State:T) OR (...0.000000 = State:T))))))))))))"; 
     int len1 = strlen(str1); 
     strncpy(s, str1, 512); 
     int len = strlen(s); 

    } 

    int main() 
    { 

     char strDisplay[512] = ""; 
     test(strDisplay, 512); 


     cout << strDisplay << endl; 
     system("pause"); 
     return 0; 
    } 

結果是: lenofstrtest = 523; lenofstr1 = 512; (狀態:0.000000 Std30c5 =狀態:T)OR((狀態:0.000000 Std30c6 =狀態:T)OR((狀態:0.000000 Std30c7 =狀態:T)或((狀態:0.000000 Std30c8 =狀態:T)

狀態:T)OR((狀態:0.000000 Std30c9 =狀態:T)OR((狀態:0.000000 Std30cc =狀態:T)狀態: T)OR((狀態:0.000000 Std30cf =狀態:T)OR((狀態:0.000000 Std30ce =狀態:T)OR((狀態:0.000000 Std30cf =狀態:T)) )))))))))))ÌÌÌÌJ¢øø)「

爲什麼strncpy複製附加字符?

(這是造成問題,因爲不正確的strnlen導致拆包邏輯就會失控!)

我想這是關係到「strncpy()函數漏洞512個字節」 ......請幫助我理解這個bug。

+0

int len = strlen(strDisplay); cout << len << endl;它的512不是523 – 2014-12-06 11:08:54

回答

0

當您使用功能strncpy時,你總是必須附加零終止。例如

strncpy(s, str1, n); 
s[n-1] = '\0'; 

否則代碼將是不安全的,因爲在你的情況。

考慮到沒有任何意義來使用這兩個標頭一起

#include <string.h> 
#include <cstring> 

取下第一首標和用C僅使用第二報頭++。

#include <cstring> 
0

strDisplay應該分配,因爲沒有空終止字符內strncpy隱含地添加至少513個單位。

char strDisplay[513] = ""; 
strDisplay[512] = '\0'; //recommended 
+0

...而且你需要實際上放置空終止符。 – 2014-12-06 11:28:27

+0

或者,他可以簡單地編寫他的程序來完全消除這些錯誤。 – Puppy 2014-12-06 11:50:32

-1

strncpy是一個不好的功能,因爲它不會產生一個字符串。如果您想使用C語言風格的字符串處理,然後snprintf更容易安全地使用:

snprintf(s, size, "%s", str1); 

注意char *str1 = "...是用C++棄用;您可以改用char const *str1 = "...

-1

在C++中使用std::string。它會自動爲您處理所有這些問題。

#include <iostream> 
#include <string> 
std::string test() 
{ 
    return "((State:0.000000 Std30c5 = State:T) OR ((State:0.000000 Std30c6 = State:T) OR ((State:0.000000 Std30c7 = State:T) OR ((State:0.000000 Std30c8 = State:T) OR ((State:0.000000 Std30c9 = State:T) OR ((State:0.000000 Std30ca = State:T) OR ((State:0.000000 Std30cb = State:T) OR ((State:0.000000 Std30cc = State:T) OR ((State:0.000000 Std30cd = State:T) OR ((State:0.000000 Std30ce = State:T) OR ((State:0.000000 Std30cf = State:T) OR (...0.000000 = State:T))))))))))))"; 
} 

int main() 
{   
    std::cout << test() << std::endl; 
    return 0; 
} 

請注意,不需要內存管理,臨時魔術大小緩衝區或空終止符。

0

strncpy不會添加終止'\ 0'字符截斷字符串,導致您遇到的問題。當字符串未正確終止時,它看起來更長,但實際上看到的是放置在緩衝區之後的數據。它會導致嚴重的問題。

相反的strncpy你應該使用strlcpy這不正確終止字符串,並返回源字符串,你可以比較你的緩衝區的長度知道,如果字符串被截斷或沒有的長度。 strncpy返回指向緩衝區的指針(這不是很有用,因爲您已經知道它 - 您將它作爲第一個參數傳遞),並且不會告訴您是否發生任何截斷。

見人是strlcpy:

的strlcpy和strlcat函數複製和連接字符串 以相同的輸入參數和輸出結果作爲的snprintf(3)。他們 被設計爲更安全,更一致,更容易出錯 替換容易誤用的函數strncpy(3)和 strncat(3)。 strlcpy()和strlcat()採用 目標緩衝區的全部大小,並保證NUL終止(如果有空間)。 請注意,NUL的空間應包含在dstsize中。

C string handling - Replacements維基百科:

最流行的[A]替換是strlcat提供和是strlcpy功能, 出現於2.4的OpenBSD十二月,1998。[84]這些功能 總是向目標緩衝區寫入一個NUL,如果需要則截斷結果 ,並返回將需要的緩衝區的大小, 允許檢測到截斷併爲 提供創建新緩衝區的大小截短。

遺憾的是它不包含在glibc - 看Secure Portability紙由 達米安·米勒(PDF):

的是strlcpy和strlcat API正確檢查目標緩衝區的邊界, NUL,終止所有並返回源字符串的長度, 允許檢測截斷。這個API已被大多數 現代操作系統和許多獨立軟件包, ,包括OpenBSD(它起源於),Sun Solaris,FreeBSD,NetBSD,Linux內核,rsync和GNOME項目所採用。值得注意的例外 是GNU標準C庫glibc [12],其維護者 堅決拒絕包含這些改進的API,並將它們標記爲「非常低效的BSD垃圾」[4],儘管之前有證據表明它們的 更快病例比他們取代的API更多[13]。因此,在OpenBSD端口樹 中存在的超過100個軟件包中的 保留了自己的strlcpy和/或strlcat替換或等效的API - 這不是理想狀態。

它可用於Linux的libbsd庫:

有在Debian和Ubuntu等發行版的軟件包:

即使你不想依賴於其他比glibc的是很容易的,因爲整個源添加到您的項目什麼是短暫的ANA下提供一個許可證:

/* 
* Copyright (c) 1998 Todd C. Miller <[email protected]> 
* 
* Permission to use, copy, modify, and distribute this software for any 
* purpose with or without fee is hereby granted, provided that the above 
* copyright notice and this permission notice appear in all copies. 
* 
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 
*/ 

#include <sys/types.h> 
#include <string.h> 

/* 
* Copy src to string dst of size siz. At most siz-1 characters 
* will be copied. Always NUL terminates (unless siz == 0). 
* Returns strlen(src); if retval >= siz, truncation occurred. 
*/ 
size_t 
strlcpy(char *dst, const char *src, size_t siz) 
{ 
    char *d = dst; 
    const char *s = src; 
    size_t n = siz; 

    /* Copy as many bytes as will fit */ 
    if (n != 0) { 
     while (--n != 0) { 
      if ((*d++ = *s++) == '\0') 
       break; 
     } 
    } 

    /* Not enough room in dst, add NUL and traverse rest of src */ 
    if (n == 0) { 
     if (siz != 0) 
      *d = '\0';  /* NUL-terminate dst */ 
     while (*s++) 
      ; 
    } 

    return(s - src - 1); /* count does not include NUL */ 
} 

來源:http://cvsweb.openbsd.org/cgi-bin/cvsweb/src/lib/libc/string/strlcpy.c?rev=1.11