Какова реализация `strtol`? - PullRequest
       1

Какова реализация `strtol`?

3 голосов
/ 17 сентября 2011

Мне просто интересно об этом.strtol не требует указания количества обрабатываемых байтов, поэтому теоретически может передаваться строка, содержащая бесконечную последовательность цифр для использования, что приводит к атаке типа «отказ в обслуживании».Конечно, это легко срывается, когда понимаешь, что сразу же исчерпана точность long (не может быть больше 65 символов двоичного числа), нет смысла читать дальше.

Однако, strtol также требуется, чтобы отбросить столько пробельных символов, сколько необходимо, пока не встретится первый непробельный символ.Так не может ли он быть атакован бесконечной строкой пробела, даже если он умеет читать цифры?

Ответы [ 4 ]

3 голосов
/ 18 сентября 2011

Однако strtol также требуется для удаления столько пробельных символов, сколько необходимо, пока не встретится первый непробельный символ.Так не может ли он быть атакован бесконечной строкой пробела, даже если он умеет читать цифры?

Поскольку strtol работает со строкой, уже находящейся в памяти, которую вам пришлось бы хранить (и читать иззлоумышленник) «бесконечное» количество пробелов (или забытое для NUL-завершения вашей строки), прежде чем даже передать его в strtol.

Поскольку реализация может продолжать вычислять максимальное количество цифр, которое может быть в допустимой строке, она не должна продолжать идти, как вы подозреваете.

Атаки DOS могут происходить с ошибкойреализации, однако, проверьте этот связанный случай (это было в java и PHP при чтении double, но то же самое могло произойти в реализации C или C ++).

1 голос
/ 17 сентября 2011

Нет единой реализации strtol. Я сомневаюсь, что любая реализация подвержена той атаке, которую вы описываете; очевидная реализация будет просто проходить последовательность цифр, не сохраняя их все сразу. (Обратите внимание, что последовательность цифр может быть произвольно длинной из-за начала 0 с.)

Если вы хотите увидеть код для реализации, вы можете скачать версию glibc здесь ; strtol() в stdlib/strtol.c.

0 голосов
/ 15 апреля 2017

Моя личная реализация. Я не использовал какой-либо прогноз (доступ к 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);
}
0 голосов
/ 17 сентября 2011

Ну, если вы хотите увидеть strtol, вы можете увидеть это в Университете Калифорнии

/* 
 * 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;
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...