C “strtol”的实现是什么?
我只是好奇而已C “strtol”的实现是什么?,c,C,我只是好奇而已strtol不要求您指定要处理的字节数,因此理论上,它可能会被输入一个包含要使用的无限数字序列的字符串,从而导致拒绝服务攻击。当然,它很容易被挫败,因为它意识到long的精度已经耗尽(实际上不可能超过一个二进制数的65个字符),没有必要再进一步读取了 但是,strtol还需要根据需要丢弃尽可能多的空白字符,直到遇到第一个非空白字符为止。所以,即使它在读取数字方面很聪明,它也不能被无休止的空白字符串攻击吗 没有单一的strtol实现。我怀疑任何实现都会受到您描述的那种攻击;显而易见的
strtol
不要求您指定要处理的字节数,因此理论上,它可能会被输入一个包含要使用的无限数字序列的字符串,从而导致拒绝服务攻击。当然,它很容易被挫败,因为它意识到long的精度已经耗尽(实际上不可能超过一个二进制数的65个字符),没有必要再进一步读取了
但是,
strtol
还需要根据需要丢弃尽可能多的空白字符,直到遇到第一个非空白字符为止。所以,即使它在读取数字方面很聪明,它也不能被无休止的空白字符串攻击吗 没有单一的strtol
实现。我怀疑任何实现都会受到您描述的那种攻击;显而易见的实现是只遍历数字序列,而不同时存储所有数字。(请注意,由于前导0
s,数字序列可以任意长。)
如果您想查看实现的代码,可以下载glibc版本<代码> STRTROR()/<代码> <代码> STDLIB/Struto.C.<代码> < P>。如果你想看Strutl,你可以在加利福尼亚大学看到它。
/*
* 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;
}
/*
*strtol.c--
*
*“strtol”库过程的源代码。
*
* Copyright(C)1988加利福尼亚大学的摄政王。
*版权所有。
*
*特此授予许可,无需书面同意,也无需
*使用、复制、修改和分发本文件的许可费或版税
*任何目的的软件及其文档,前提是
*上述版权声明及以下两段内容见
*此软件的所有副本。
*
*加利福尼亚大学概不应对任何一方负责。
*因以下原因引起的直接、间接、特殊、附带或后果性损害:
*使用该软件及其文档,即使大学
*加利福尼亚州已被告知可能发生这种损害。
*
*加利福尼亚大学特别否认任何保证,
*包括但不限于对适销性的默示保证
*以及适合特定用途。以下提供的软件是
*“按原样”,加利福尼亚大学没有义务
*提供维护、支持、更新、增强或修改。
*/
静态常量字符rcsid[]=“$Header$SPRITE(Berkeley)”;
#包括
外部无符号长整数字符串(字符*字符串,字符**endPtr,整数基);
/*
*----------------------------------------------------------------------
*
*斯特托--
*
*将ASCII字符串转换为整数。
*
*结果:
*返回值是与字符串等效的整数。如果endPtr
*为非NULL,则*endPtr用字符填充
*最后一个是整数的一部分。如果字符串
*不包含有效的整数值,则返回零
*并且*endPtr设置为string。
*
*副作用:
*没有。
*
*----------------------------------------------------------------------
*/
长整型
斯特托(
字符*字符串,/*ASCII数字字符串,可能
*前面有空格。用于基数
*大于10,低于或低于
*可以使用大写数字。
*/
字符**endPtr,/*在何处存储终止地址
*字符,或NULL*/
用于转换的int base/*base。必须小于
*小于37。如果为0,则选择基数
*从字符串的前导字符:
*“0x”表示十六进制,“0”表示八进制,任何形式
*否则表示十进制。
*/
)
{
寄存器char*p;
int结果;
/*
*跳过任何前导空格。
*/
p=字符串;
while(isspace(*p)){
p+=1;
}
/*
*检查是否有迹象。
*/
如果(*p=='-'){
p+=1;
结果=-1*(strtoul(p,endPtr,base));
}否则{
如果(*p=='+')){
p+=1;
}
结果=strtoul(p,endPtr,base);
}
如果((结果==0)&&(endPtr!=0)&&(*endPtr==p)){
*endPtr=字符串;
}
返回结果;
}
但是,strtol还需要根据需要丢弃尽可能多的空白字符,直到遇到第一个非空白字符为止。所以,即使它在读取数字方面很聪明,它也不能被无休止的空白字符串攻击吗
由于strtol
对内存中已经存在的字符串起作用,因此在将其输入strtol之前,您必须存储(并从攻击者处读取)一个“无止境”的空白(或忘记NUL终止您的字符串)
由于实现可以计算有效字符串中可能存在的最大位数,因此它不必像您所怀疑的那样继续运行
DoS攻击可能会发生在错误的实现中,但是请检查相关的情况(这是在java和PHP中读取双倍的,但是同样的情况也可能发生在C++或C++实现中)。p> 我的个人实现。我没有使用任何前瞻功能(访问
p[1]
或类似的功能),因此理论上可以将其转换为从流读取的内容(例如get_long()
调用getc()
字符)
#包括
#定义LONG_MAX((长)(~0UL>>1))
#定义长_最小值(~LONG_最大值)
intIsSpace(intC);/*36) {
#ifdef EINVAL/*POSIX定义的错误值*/
errno=EINVAL;
#恩迪夫
返回0升;
}
endp=nptr;
while(isspace(*p))
p++;
如果(*p=='+')){
p++;
}else if(*p=='-'){
is_neg=1,p++;
}
如果(*p==“0”){
p++;
/*对于strtol(“0xZ”&endptr,16),endptr应指向“x”;
*指向“”或“0”是不兼容的。
#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);
}