Use of 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. The 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++
По умолчанию: Off
Синтаксис командной строки: SETJMP_LONGJMP_USE
Влияние: Низкое
ИДЕНТИФИКАТОР CWE: 691
Введенный в R2015b