Как сломать gmtime_r C ++ - PullRequest
       1

Как сломать gmtime_r C ++

2 голосов
/ 02 февраля 2020

Это может быть странный вопрос, но я пытаюсь найти способ сломать функцию gmtime_r. Я пишу тест для этого блока кода, но не могу найти случай, чтобы достичь оператора else, который не включает установку ptr или dates в NULL.

int main() {
    time_t ptr; // Actual storage for time_t
    struct tm dates; // Actual storage for struct tm
    time(&ptr); // Pointer to a time_t
    if(gmtime_r(&ptr, &dates)) { // Pointer to a time_t, pointer to a
        size_t a = 10;
    }
    else
    {
        size_t a = 20; //<-- trying to reach this else statement
    }
return 0;
}

Существуют ли допустимые значения, отличные от NULL, для установки ptr или dates, которые обойдут оператор if и go в else?

Ответы [ 2 ]

4 голосов
/ 02 февраля 2020

Чтобы получить точный ответ на ваш вопрос, нам необходимо знать, какую реализацию вы используете для создания своего проекта.

Обычно стандартные заголовки, например, имеют исходный текст c, поэтому вы можете осуществлять поиск по себя за возможности неудачи.

Для glib c, я спустился в кроличью нору, чтобы привести пример. (См. Источник здесь )

В time/gmtime.c мы видим, что gmtime_r является слабым псевдонимом для __gmtime_r, который возвращает __tz_convert напрямую.

В time/txset.c мы обратите внимание, что __tz_convert может возвращать NULL только в случае сбоя функции __offtime (возвращает 0).

Наконец, в time/offtime.c мы видим, что:

  tp->tm_year = y - 1900;
  if (tp->tm_year != y - 1900)
    {
      /* The year cannot be represented due to overflow.  */
      __set_errno (EOVERFLOW);
      return 0;
    }

Что указывает на хорошую подсказку о том, как мы можем заставить его потерпеть неудачу. Вы можете проверить свою идею с помощью короткой программы.

Например, Sample program to test out how to make gmtime_r fail

В моем случае простое предоставление большого положительного времени помогает, так как код использует целые годы, но time_t - 64-битное значение (в моей системе), у меня может быть гораздо больше лет, чем может представлять int (в моей системе).

Конечно, вы можете сделать Образец тестовой программы сразу же, не глядя на источник ... но разве это не намного интереснее? : P

1 голос
/ 02 февраля 2020

Это возможно, используя трюк LD_PRELOAD. Я не буду углубляться в объяснение этого, так как это можно увидеть здесь , а также в кратком поиске в Google.

Я покажу, как я это реализовал в C, чтобы он действовал и для C пользователей:

Давайте создадим еще один C файл и назовем его trick. c:

#define _GNU_SOURCE

#include <dlfcn.h>
#include <time.h>

typedef struct tm * (*gmtime_r_t)(const time_t *, struct tm *);

static int __fail = 0;

void __fail_gmtime_r() { __fail = 1; }
void __pass_gmtime_r() { __fail = 0; }

struct tm *gmtime_r(const time_t *timep, struct tm *result)
{
    if (__fail) { return NULL; }

    return ((gmtime_r_t)dlsym(RTLD_NEXT, "gmtime_r"))(timep, result);
}

Здесь мы реализуем нашу версию gmtime_r() и либо вызываем оригинальный метод, либо не выполняем его (возвращая NULL), в зависимости от флага (__fail).

Мы также предоставляем два метода для установки значения этого флага: __fail_gmtime_r() и __pass_gmtime_r().

Мы компилируем этот файл в общий объект с помощью командной строки gcc trick.c -shared -fPIC -o trick.so -ldl.

Я также реализовал небольшой исполняемый файл с main(), похожим на ваш, для его тестирования, где я использую общий объект trick. main. c:

#define _GNU_SOURCE

#include <dlfcn.h>
#include <time.h>
#include <stdio.h>

typedef void (*__fail_gmtime_r_t)();
typedef void (*__pass_gmtime_r_t)();

int main()
{
    __fail_gmtime_r_t __fail_gmtime_r = dlsym(RTLD_DEFAULT, "__fail_gmtime_r");
    __pass_gmtime_r_t __pass_gmtime_r = dlsym(RTLD_DEFAULT, "__pass_gmtime_r");

    time_t ptr;
    time(&ptr);

    struct tm dates;

    printf(gmtime_r(&ptr, &dates) ? "OK\n" : "FAIL\n");

    __fail_gmtime_r();
    printf(gmtime_r(&ptr, &dates) ? "OK\n" : "FAIL\n");

    __pass_gmtime_r();
    printf(gmtime_r(&ptr, &dates) ? "OK\n" : "FAIL\n");

    return 0;
}

И я компилирую его, используя командную строку gcc main.c -o main -ldl.

Затем я использовал следующую команду для запуска исполняемый файл с общим объектом trick , заменяющим gmtime_r(): LD_PRELOAD=<FULL PATH TO trick.so> ./main.

Вы должны вызвать __fail_gmtime_r() и __pass_gmtime_r() из вашего main(), чтобы получить тот же эффект.

Я не go углубился в объяснения, но если это то, что вам нужно, у меня нет проблем с дальнейшим объяснением здесь.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...