2011-09-17 48 views
3

我只是好奇這件事。 strtol並不要求你指定要處理的字節數,所以理論上它可能被送入一個包含無盡數字的字符串消耗,導致拒絕服務攻擊。當然,通過意識到長時間精度已經被耗盡(不能超過65個字符的二進制數字),很容易被挫敗,因此沒有任何進一步閱讀的意義。`strtol`的實現是什麼?

但是,strtol也需要根據需要丟棄儘可能多的空白字符,直到遇到第一個非空白字符。那麼即使閱讀數字很聰明,它是否可以不受無盡空白字符串的攻擊?

+5

你的「無盡的」空白字符串需要無盡的記憶。 [Here](ftp://ftp.irisa.fr/pub/OpenBSD/src/sys/lib/libsa/strtol.c)是一個實現的例子。不讀太多數字確實很聰明。 – user786653

+0

你應該驗證你給strtol的參數 - 就像你應該使用大多數庫函數一樣。例如1.參數必須是一個字符串(即它必須以nul結尾)。如果它涉及到你,請確認你沒有給它一個無限長的字符串。 – nos

+0

使用'fgets()'(和'sscanf()')來讀取用戶輸入! – pmg

回答

3

然而這個與strtol,還需要strtol將在必要時,直到第一個非空白字符丟棄儘可能多的空白字符遇到。那麼即使閱讀數字很聰明,它是否可以不受無盡空白字符串的攻擊?

由於strtol作品上的繩子已經在內存中,你將不得不存儲(從攻擊者讀取)空白的「永無止境」的金額(或忘記NUL,終止您的字符串)之前,甚至將其送入與strtol。

由於實現可以保持計算可以存在於有效字符串中的最大位數,因此您不必繼續前進。

DOS攻擊可能會出現錯誤的實現,儘管如此,請查看this相關案例(這是在Java和PHP中讀取雙精度數據時,但在C或C++實現中可能會發生的情況)。

1

strtol沒有單一的實現。我懷疑任何實現都不容易受到你描述的那種攻擊的影響;顯而易見的實現只會遍歷數字序列,而不會一次全部存儲它們。 (請注意,由於領先的0 s,數字序列可以任意長。)

如果您想查看實現的代碼,可以下載glibc版本here; strtol()stdlib/strtol.c

0

那麼,如果你想看看你可以通過大學看到加州

/* 
* strtol.c -- 
* 
* Source code for the "strtol" library procedure. 
* 
* Copyright (c) 1988 The Regents of the University of California. 
* All rights reserved. 
* 
* Permission is hereby granted, without written agreement and without 
* license or royalty fees, to use, copy, modify, and distribute this 
* software and its documentation for any purpose, provided that the 
* above copyright notice and the following two paragraphs appear in 
* all copies of this software. 
* 
* IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY FOR 
* DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT 
* OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF THE UNIVERSITY OF 
* CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 
* 
* THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES, 
* INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY 
* AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS 
* ON AN "AS IS" BASIS, AND THE UNIVERSITY OF CALIFORNIA HAS NO OBLIGATION TO 
* PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. 
*/ 
static const char rcsid[] = "$Header$ SPRITE (Berkeley)"; 

#include <ctype.h> 

extern unsigned long int strtoul(char *string, char **endPtr, int base); 

/* 
*---------------------------------------------------------------------- 
* 
* strtol -- 
* 
* Convert an ASCII string into an integer. 
* 
* Results: 
* The return value is the integer equivalent of string. If endPtr 
* is non-NULL, then *endPtr is filled in with the character 
* after the last one that was part of the integer. If string 
* doesn't contain a valid integer value, then zero is returned 
* and *endPtr is set to string. 
* 
* Side effects: 
* None. 
* 
*---------------------------------------------------------------------- 
*/ 

long int 
strtol(
    char *string,  /* String of ASCII digits, possibly 
       * preceded by white space. For bases 
       * greater than 10, either lower- or 
       * upper-case digits may be used. 
       */ 
    char **endPtr,  /* Where to store address of terminating 
       * character, or NULL. */ 
    int base   /* Base for conversion. Must be less 
       * than 37. If 0, then the base is chosen 
       * from the leading characters of string: 
       * "0x" means hex, "0" means octal, anything 
       * else means decimal. 
       */ 
) 
{ 
    register char *p; 
    int result; 

    /* 
    * Skip any leading blanks. 
    */ 
    p = string; 
    while (isspace(*p)) { 
    p += 1; 
    } 

    /* 
    * Check for a sign. 
    */ 
    if (*p == '-') { 
    p += 1; 
    result = -1*(strtoul(p, endPtr, base)); 
    } else { 
    if (*p == '+') { 
     p += 1; 
    } 
    result = strtoul(p, endPtr, base); 
    } 
    if ((result == 0) && (endPtr != 0) && (*endPtr == p)) { 
    *endPtr = string; 
    } 
    return result; 
} 
+1

這個'strtol()'不會像C規範中指定的那樣在溢出時返回'INT_MAX'和'INT_MIN'。 – chux

+4

無用的答案,這個代碼只是調用'strtoul' – izabera

0

我的個人實施。我沒有使用任何lookahead(訪問p[1]或類似的東西),因此理論上你可以將它轉換爲從流中讀取的內容(例如,get_long(),它爲字符調用getc())。

#include <errno.h> 
#define LONG_MAX ((long)(~0UL>>1)) 
#define LONG_MIN (~LONG_MAX) 
int isspace(int c); /* <-- Forward declare from <ctype.h> */ 

long strtol(const char *restrict nptr, char **restrict endptr, int base) { 
    const char *p = nptr, *endp; 
    _Bool is_neg = 0, overflow = 0; 
    /* Need unsigned so (-LONG_MIN) can fit in these: */ 
    unsigned long n = 0UL, cutoff; 
    int cutlim; 
    if (base < 0 || base == 1 || base > 36) { 
#ifdef EINVAL /* errno value defined by POSIX */ 
     errno = EINVAL; 
#endif 
     return 0L; 
    } 
    endp = nptr; 
    while (isspace(*p)) 
     p++; 
    if (*p == '+') { 
     p++; 
    } else if (*p == '-') { 
     is_neg = 1, p++; 
    } 
    if (*p == '0') { 
     p++; 
     /* For strtol(" 0xZ", &endptr, 16), endptr should point to 'x'; 
     * pointing to ' ' or '0' is non-compliant. 
     * (Many implementations do this wrong.) */ 
     endp = p; 
     if (base == 16 && (*p == 'X' || *p == 'x')) { 
      p++; 
     } else if (base == 0) { 
      if (*p == 'X' || *p == 'x') { 
       base = 16, p++; 
      } else { 
       base = 8; 
      } 
     } 
    } else if (base == 0) { 
     base = 10; 
    } 
    cutoff = (is_neg) ? -(LONG_MIN/base) : LONG_MAX/base; 
    cutlim = (is_neg) ? -(LONG_MIN % base) : LONG_MAX % base; 
    while (1) { 
     int c; 
     if (*p >= 'A') 
      digit = ((*p - 'A') & (~('a'^'A'))) + 10; 
     else if (*p <= '9') 
      digit = *p - '0'; 
     else 
      break; 
     if (c < 0 || c >= base) break; 
     endp = ++p; 
     if (overflow) { 
      /* endptr should go forward and point to the non-digit character 
      * (of the given base); required by ANSI standard. */ 
      if (endptr) continue; 
      break; 
     } 
     if (n > cutoff || (n == cutoff && c > cutlim)) { 
      overflow = 1; continue; 
     } 
     n = n * base + c; 
    } 
    if (endptr) *endptr = (char *)endp; 
    if (overflow) { 
     errno = ERANGE; return ((is_neg) ? LONG_MIN : LONG_MAX); 
    } 
    return (long)((is_neg) ? -n : n); 
}