Я прочитал приведенный ниже код в книге, в которой говорилось, что это уязвимо для переполнения стека. Хотя fgets () был использован, я не смог понять, почему он уязвим?
Насколько я понимаю, использование fgets () вместо gets () обычно помогает нам избавиться от переполнения буфера, поместив нулевое значение в конце. Я что-то пропустил? Что следует использовать вместо fgets () для исправления переполнения стека?
void getinp(char *inp, int siz)
{
puts("Input value: ");
fgets(inp, siz, stdin);
printf("buffer3 getinp read %s\n", inp);
}
void display(char * val)
{
char tmp[16];
sprintf(tmp, "read val: %s\n", val);
puts(tmp);
}
int main(int argc, char *argv[])
{
char buf[16];
getinp(buf, sizeof(buf));
display(buf);
printf("buffer3 done\n");
}
В display
tmp
объявлен как 16 char
долго, но вы пишете (с sprintf
) там не только val
(который гарантированно будет 16 символов или меньше), но также "read val: "
и финал \n
).
Это означает, что если пользователь вставляет более 16-11 = 5 символов, у вас переполнение буфера в display
,
Одним из решений может быть объявление buf
в display
быть достаточно большим, чтобы хранить оба val
и дополнительный текст, хотя в реальном мире вы бы просто написать stdout
с помощью printf
(без промежуточного буфера).
Кроме того, обычно, когда у вас есть sprintf
и есть некоторый потенциальный риск переполнения буфера, который вы используете snprintf
вместо этого (на самом деле, я использую это всегда); snprintf
вместо переполнения буфера обрезает вывод, если он будет слишком длинным, и возвращает количество символов, которое было бы записано, если бы выходной буфер был достаточно большим.
На дисплее нет никакого способа убедиться, что val + 12 байтов помещается в 16-символьный буфер.