exponenta event banner

Использование setjmp/longjmp

setjmp и longjmp причина отклонения от нормального потока управления

Описание

Этот дефект возникает при использовании комбинации setjmp и longjmp или sigsetjmp и siglongjmp для отклонения от нормального потока управления и выполнения нелокальных прыжков в коде.

Риск

Используя setjmp и longjmp, или sigsetjmp и siglongjmp имеет следующие риски:

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

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

  • Если вы используете setjmp и longjmp в комбинации с обработчиком сигнала может произойти неожиданный поток управления. POSIX ® не указывает, setjmp сохраняет маску сигнала.

  • Используя setjmp и longjmp или sigsetjmp и siglongjmp затрудняет понимание и обслуживание программы.

Зафиксировать

Выполнение нелокальных прыжков в коде с помощью setjmp/longjmp или sigsetjmp/siglongjmp только в контекстах, где такие прыжки могут выполняться безопасно. По возможности используйте потоки POSIX.

В C++ для моделирования исключений метания и захвата используйте стандартные идиомы, такие как throw выражения и catch заявления.

Примеры

развернуть все

#include <setjmp.h>
#include <signal.h>

extern int update(int);
extern void print_int(int);

static jmp_buf env;
void sighandler(int signum) {
    longjmp(env, signum);
}
void func_main(int i) {
    signal(SIGINT, sighandler);
    if (setjmp(env)==0) {
        while(1) {
            /* Main loop of program, iterates until SIGINT signal catch */
            i = update(i);
        }
    } else {
        /* Managing longjmp return */
        i = -update(i);
    }

    print_int(i);
    return;
}

В этом примере начальное возвращаемое значение setjmp равно 0. update функция вызывается в бесконечном while закольцовывается до тех пор, пока пользователь не прервет его по сигналу.

В функции обработки сигнала longjmp оператор вызывает возврат к main и возвращаемое значение setjmp теперь 1. Следовательно, else выполняется ветвь.

Исправление - использовать альтернативу setjmp и longjmp

Чтобы более безопасно эмулировать то же поведение, используйте volatile глобальная переменная вместо комбинации setjmp и longjmp.

#include <setjmp.h>
#include <signal.h>

extern int update(int);
extern void print_int(int);

volatile sig_atomic_t eflag = 0;

void sighandler(int signum) {
     eflag = signum;                   /* Fix: using global variable */
}

void func_main(int i) {
      /* Fix: Better design to avoid use of setjmp/longjmp */
    signal(SIGINT, sighandler);
    while(!eflag) {                   /* Fix: using global variable */
        /* Main loop of program, iterates until eflag is changed */
        i = update(i);
    }

    print_int(i);
    return;
}

Информация о результатах

Группа: Надлежащая практика
Язык: C | C++
По умолчанию: Откл.
Синтаксис командной строки: SETJMP_LONGJMP_USE
Воздействие: Низкий
ИДЕНТИФИКАТОР CWE: 691
Представлен в R2015b