что такое стековое переполнение

Обнаружено переполнение стекового буфера в данном приложении — как исправить?

Несмотря на то, что прошло уже много лет после появления первых компьютерных программ, они и сегодня не являются полностью надёжными. Любой программный продукт может сообщить о внутренних конфликтах и внезапно завершить свою работу. Сегодня мы узнаем, что делать, если при использовании определённого ПО мы видим ошибку «Обнаружено переполнение стекового буфера в данном приложении». что такое стековое переполнение. Смотреть фото что такое стековое переполнение. Смотреть картинку что такое стековое переполнение. Картинка про что такое стековое переполнение. Фото что такое стековое переполнение

Причины возникновения ошибки переполнения стекового буфера

Известны также интернет-черви для получения доступа к ПК в UNIX-системах. Такое поведение программы достаточно просто организовать. Буфер является вместилищем данных, с которыми компьютер работает в любой программе или процессе. Буфер — это блок памяти с чётко определённым размером. Когда в него попадает или считывается больше памяти, вы видите ошибку о переполнении.

Что делать, если обнаружена уязвимость в данном приложении

Чистая загрузка ОС Windows

Если вы перезагрузили компьютер и даже переустановили программу, но всё равно видите на экране ошибку, попробуйте загрузку системы в «чистом» виде. Ведь ошибка «Обнаружено переполнение стекового буфера в данном приложении» может появляться и по другим причинам. Которые не имеют отношения к данной программе. Помимо программ, с которыми мы работаем в данным момент, в системе запущены другие процессы. Именно они могут способствовать появлению сбоя.

Чтобы выполнить чистую загрузку ОС, необходимо быть администратором Windows или войти с этой учётной записью. Когда вы войдёте в систему в чистом режиме, некоторые функции и программы могут быть недоступными. Но после возврата в стандартный режим, всё снова будет работать как раньше.

Итак, выполните последовательно ряд таких действий:

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

Использование антивирусного ПО

С этим видом уязвимости программ борются уже на протяжении 30 лет. Но каких-то уникальных средств обнаружено пока не было. Такому виду сбоя подвержены программы всех типов. Хакеры часто используются переполнение стекового буфера для взлома систем. Этот вид ошибки может позволить им завладеть любыми вашими данными на компьютере. Ведь они научились вызывать эту ошибку в программах искусственно, при помощи троянов и червей.

Если сбой не удаётся решить описанными выше методами, скорее всего у вас в компьютере появился вирус. Систему необходимо просканировать. Если вы загружали стороннюю антивирусную программу, то встроенный Windows Defender (Защитник) сейчас отключён. Так как два вируса не «уживаются» на одном ПК. Попробуйте найти Защитник через поисковую строку компьютера и активировать его.

что такое стековое переполнение. Смотреть фото что такое стековое переполнение. Смотреть картинку что такое стековое переполнение. Картинка про что такое стековое переполнение. Фото что такое стековое переполнение

После включения программы, запустите полное сканирование компьютера.

Специализированный софт

В интернете можно найти эффективные противовирусные и лечащие утилиты. Они просканируют ваш компьютер и предоставят подробный отчёт о состоянии системы. Это небольшие портативные программы, которые не нужно устанавливать. Их загрузка является временной. И, чтобы использовать её снова спустя какое-то время, нужно загружать новый пакет с обновлённой вирусной базой.

Источник

Как происходит «переполнение стека» и как его предотвратить?

Как происходит переполнение стека и как лучше всего этого избежать или как предотвратить его, особенно на веб-серверах, но были бы интересны и другие примеры?

Когда вы вызываете функцию в своем коде, следующая инструкция после вызова функции сохраняется в стеке и любое пространство памяти, которое может быть перезаписано вызовом функции. Вызываемая функция может использовать больше стека для собственных локальных переменных. Когда это будет сделано, он освобождает используемое пространство стека локальной переменной, а затем возвращается к предыдущей функции.

Переполнение стека

Многие программисты делают эту ошибку, вызывая функцию A, которая затем вызывает функцию B, которая затем вызывает функцию C, которая затем вызывает функцию A. Она может работать большую часть времени, но только один раз неправильный ввод заставит ее навсегда войти в этот круг. пока компьютер не обнаружит, что стек слишком раздут.

Рекурсивные функции также являются причиной этого, но если вы пишете рекурсивно (т. Е. Ваша функция вызывает сама себя), вам необходимо знать об этом и использовать статические / глобальные переменные для предотвращения бесконечной рекурсии.

Обычно операционная система и язык программирования, который вы используете, управляют стеком, и это вне ваших рук. Вы должны посмотреть на свой граф вызовов (древовидную структуру, которая показывает из вашего main, что вызывает каждая функция), чтобы увидеть, насколько глубоко заходят ваши вызовы функций, и чтобы обнаружить циклы и рекурсию, которые не предназначены. Преднамеренные циклы и рекурсия необходимо искусственно проверять, чтобы исключить ошибки, если они вызывают друг друга слишком много раз.

Помимо хороших практик программирования, статического и динамического тестирования, на этих высокоуровневых системах мало что можно сделать.

Встроенные системы

Во встраиваемом мире, особенно в коде высокой надежности (автомобильный, авиационный, космический), вы выполняете обширный анализ и проверку кода, но вы также делаете следующее:

Языки и системы высокого уровня

Но на языках высокого уровня, работающих в операционных системах:

Веб-серверы

Источник

Как защититься от переполнения стека (на Cortex M)?

Если вы программируете на «большом» компьютере, то у вас такой вопрос, скорее всего, вообще не возникает. Стека много, чтобы его переполнить, нужно постараться. В худшем случае вы нажмёте ОК на окошке вроде этого и пойдете разбираться, в чем дело.

что такое стековое переполнение. Смотреть фото что такое стековое переполнение. Смотреть картинку что такое стековое переполнение. Картинка про что такое стековое переполнение. Фото что такое стековое переполнение

Но вот если вы программируете микроконтроллеры, то проблема выглядит немного иначе. Для начала нужно заметить, что стек переполняется.

В этой статье я расскажу о собственных изысканиях на эту тему. Поскольку я программирую в основном под STM32 и под Миландр 1986 — на них я и фокусировался.

Введение

Представим самый простой случай — мы пишем простой однопоточный код без всяких операционных систем, т.е. стек у нас всего один. И если вы, как и я, программируете в uVision Keil, то память распределяется как-то так:

что такое стековое переполнение. Смотреть фото что такое стековое переполнение. Смотреть картинку что такое стековое переполнение. Картинка про что такое стековое переполнение. Фото что такое стековое переполнение

А если вы, как и я, считаете динамическую память на микроконтроллерах злом, то вот так:

что такое стековое переполнение. Смотреть фото что такое стековое переполнение. Смотреть картинку что такое стековое переполнение. Картинка про что такое стековое переполнение. Фото что такое стековое переполнение

Если вы хотите запретить использование кучи, то можно сделать вот так:

Окей, и в чем проблема? Проблема в том, что Keil размещает стек сразу за областью статических данных. А стек в Cortex-M растет в сторону уменьшения адресов. И когда он переполняется, то он просто вылезает за пределы отведенного ему куска памяти. И перезаписывает какие-нибудь статические или глобальные переменные.

Особенно здорово, если стек переполняется только при заходе в прерывание. Или, еще лучше, во вложенное прерывание! И тихо портит какую-нибудь переменную, которая используется совершенно в другом участке кода. И программа падает на ассерте. Если вам повезет. Сферический гейзенбаг, такой можно целую неделю с фонарём искать.

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

Окей, проблема понятна. Что делать?

Самое простое и очевидное — использовать MPU (сиречь, Memory Protection Unit). Позволяет назначать разным кускам памяти разные атрибуты; в частности можно окружить стек регионами «только для чтения» и ловить MemFault при записи туда.

Например, в stm32f407 MPU есть. К сожалению, во многих других «младших» stm его нет. И в Миландровском 1986ВЕ1 его тоже нет.

Т.е. решение хорошее, но не всегда доступное.

Ручной контроль

Причем в самом начале отчета написан путь, приводящий к максимальному использованию стека:

что такое стековое переполнение. Смотреть фото что такое стековое переполнение. Смотреть картинку что такое стековое переполнение. Картинка про что такое стековое переполнение. Фото что такое стековое переполнение

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

Хитрое размещение стека

Об этом способе я узнал из вот этой статьи. Статья про rust, но основная идея состоит в следующем:

что такое стековое переполнение. Смотреть фото что такое стековое переполнение. Смотреть картинку что такое стековое переполнение. Картинка про что такое стековое переполнение. Фото что такое стековое переполнение

При использовании gcc это возможно сделать с помощью «двойной линковки».

А в Keil’е расположение областей можно изменить с помощью своего скрипта для линкера (scatter file в терминологии Keil’a). Для этого нужно открыть опции проекта и снять галку «Use memory layout from target dialog». Тогда в поле «Scatter file» появится файл по-умолчанию. Он выглядит примерно так:

Что делать дальше? Возможны варианты. Официальная документация предлагает определить секции с зарезервированными именами — ARM_LIB_HEAP и ARM_LIB_STACK. Но это влечет за собой неприятные последствия, по крайней мере, для меня — размеры стека и кучи придется задавать в scatter-файле.

Во всех проектах, которые я использую, размер стека и кучи задается в ассемблерном startup-файле (который Keil генерирует при создании проекта). Менять его не очень хочется. Хочется, чтобы я просто включил в проект новый scatter-файл, и все стало хорошо. Поэтому я пошел немного другим путем:

Тут я сказал, что все объекты по имени STACK должны размещаться в регионе REGION_STACK, а все объекты HEAP — в регионе REGION_HEAP. А все остальное — в регионе RW_IRAM1. И расположил регионы в таком порядке — начало оперативы, стек, куча, все остальное. Расчет на то, что в ассемблерном startup-файле стек и куча задаются с помощью вот такого кода (т.е. как массивы с названиями STACK и HEAP):

Окей, возможно спросите вы, но что это нам дает? А вот что. Теперь при выходе за пределы стека процессор пытается записать (или прочитать) память, которой нет. И на STM32 при этом возникает прерывание по исключительной ситуации — HardFault.

Это не так удобно, как MemFault из-за MPU, потому что HardFault может возникать из-за множества причин, но, по крайней мере, ошибка получается громкой, а не тихой. Т.е. она возникает сразу, а не через неизвестный промежуток времени, как было раньше.

Что самое классное, мы ничем за это не заплатили, никакого оверхеда времени выполнения! Здорово. Но есть одна проблема.

Это не работает на Миландре.

Да. Конечно, на Миландрах (меня интересуют в основном 1986ВЕ1 и ВЕ91) карта памяти выглядит иначе. В STM32 до начала оперативы нет ничего, а на Миландрах до оперативы лежит область внешней шины.

Но даже если вы не используете внешнюю шину, то никакого HardFault’a вы не получите. А может и получите. А может быть, получите, но не сразу. Я не смог найти никакой информации на этот счет (что для Миландра неудивительно), а эксперименты не дали никаких внятных результатов. HardFault иногда возникал, если размер стека был кратен 256. Иногда HardFault возникал, если стек углублялся уж очень далеко в несуществующую память.

Но это даже неважно. Если HardFault не возникает каждый раз, то простое перемещение стека в начало RAM нас уже не спасает. И если уж совсем честно, STM тоже не обязан генерировать исключение при этом, спецификация ядер Cortex-M ничего конкретного на этот счет вроде бы не говорит.

Так что даже на STM это скорее хак, просто не очень грязный.

Значит, нужно искать какой-то другой способ.

Access breakpoint на запись

Но это не очень надежный способ. Этот брейкпоинт будет срабатывать каждый раз при инициализации стека. Его легко случайно прибить, нажав «Kill all breakpoints». А еще он будет вас защищать только в присутствии отладчика. Не годится.

Динамическая защита от переполнений

Быстрый поиск на этот счет вывел меня к опциям Keil’a «—protect_stack» и «—protect_stack_all». Опции полезные, к сожалению, защищают они не от переполнения всего стека, а от залезания в стековый кадр другой функции. Например, если ваш код выходит за границы массива или неудачно работает с переменным числом параметров. Gcc, разумеется, тоже так умеет (-fstack-protector).

Суть этой опции в следующем: в каждый стековый кадр добавляется «guard variable», то бишь, сторожевое число. Если после выхода из функции это число изменилось, то вызывается функция-обработчик ошибки. Подробности тут.

Полезная штука, но не совсем то, что мне нужно. Мне нужна гораздо более простая проверка — чтобы при входе в каждую функцию значение регистра SP (Stack Pointer) сверялось с заранее известным минимальным значением. Но не писать же эту проверку руками на входе в каждую функцию?

Динамический контроль SP

К счастью, gcc имеет чудесную опцию «-finstrument-functions», которая позволяет вызывать пользовательскую функцию при входе в каждую функцию и при выходе из каждой функции. Обычно это используется для вывода отладочной информации, но какая разница?

К еще большему счастью, Keil вполне сознательно копирует функционал gcc, и там эта же опция доступна под названием «—gnu_instrument» (подробности).

После этого нужно всего лишь написать вот такой код:

И вуаля! Теперь при входе в каждую функцию (в том числе в обработчики прерываний) будет выполняться проверка на переполнение стека. И если стек переполнился — будет ассерт.

Идеально ли полученное решение? Конечно, нет.

Во-первых, эта проверка далеко не бесплатна, код от нее распухает процентов на 10. Ну и работать код будет медленнее (хотя я не измерял). Критично это или нет — решать вам; на мой взгляд, это разумная цена за безопасность.

Во-вторых, это, скорее всего, не будет работать при использовании прекомпилированных библиотек (но т.к. я их не использую вообще, я не проверял).

Зато это решение потенциально пригодно и для многопоточных программ, поскольку проверку мы делаем полностью сами. Но эту мысль я еще не додумал толком, поэтому пока придержу.

Подведем итоги

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

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

И я вообще достаточно часто замечаю за собой (да и за другими людьми) такое — вместо того, чтобы потратить 5 минут в гугле и найти тривиальное решение — живу со своими проблемами годами.

На этом у меня все. Я понимаю, что ничего кардинально нового я не открыл, но готовых статей с таким решением мне не попадалось (по крайней мере, сам Джозеф Ю в статье на эту тему прямым текстом это не предлагает). Надеюсь, в комментариях мне подскажут, прав я или нет, и каковы подводные камни такого подхода.

UPD: Если при добавлении scatter-файла Keil начинает выдавать непонятный warning аля «AppData\Local\Temp\p17af8-2(33): warning: #1-D: last line of file ends without a newline» — но сам этот файл не открывается, ибо он временный, — то просто добавьте перенос строки последним символом в scatter-файл.

Источник

Переполнение стека

Определение

Стек программы

Последствия ошибки

Чтобы быть совсем точным, следует отметить, что подобное описание событий верно лишь для компиляторов, компилирующих в «родной» (native) код. В управляемых языках у виртуальной машины есть свой стек для управляемых программ, за состоянием которого гораздо проще следить, и можно даже позволить себе при возникновении переполнения передать программе исключение. В языках Си и Си++ на подобную «роскошь» рассчитывать не приходится.

Причины ошибки

Примеры

В качестве примера рассмотрим код для рекурсивного поиска файлов, расположенный на MSDN:

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

Пример второго подхода, взятый из вопроса «Почему происходит переполнение стека?» с сайта под названием Stack Overflow (сайт является сборником вопросов и ответов на любые программистские темы, а не только по переполнению стека, как может показаться):

Как видно, в функции main выделяется память в стеке под массивы типов int и float по миллиону элементов каждый, что в сумме дает чуть менее 8 мегабайт. Если учесть, что по умолчанию Visual C++ резервирует под стек лишь 1 мегабайт, то ответ становится очевидным.

А вот пример, взятый из GitHub-репозитория проекта Flash-плеера Lightspark:

Можно надеятся, что h.getLength()-7 не будет слишком большим числом, чтобы на следующей строчке не произошло переполнения. Но стоит ли сэкономленное на выделении памяти время «потенциального» вылета программы?

Источник

Исправление ошибки переполнения стекового буфера

Среди многочисленных проблем программного характера, возникающих при работе с компьютером, пользователям может встречаться ошибка, сообщающая об обнаружении переполнения стекового буфера в конкретном приложении и возможности получения злоумышленником управления данными софта. Этому багу уже десятки лет, но и сегодня разрабатываемые программы не могут похвастать абсолютной надёжностью. Переполнение стековой памяти может возникать у любого неидеально продуманного приложения, что влечёт за собой аварийное закрытие или зависание софта, а также позволяет злоумышленнику внедрить вредоносный код, выполняемый от имени уязвимой программы. Если при этом приложение выполняется с наивысшими привилегиями, это открывает путь взломщику к любым манипуляциям в системе.

что такое стековое переполнение. Смотреть фото что такое стековое переполнение. Смотреть картинку что такое стековое переполнение. Картинка про что такое стековое переполнение. Фото что такое стековое переполнение

Бывает, что переполнение буфера при программировании продукта является средством, служащим определённым целям, например, намеренно применяется системным софтом для обхода отдельных ограничений. Рассмотрим подробнее, что это за явление, почему возникает и как избавиться от системной ошибки.

Причины возникновения ошибки переполнения стекового буфера

Для размещения данных программами используются блоки памяти (буферы), обычно фиксированной длины, то есть вмещающие ограниченный объём информации. Ошибка переполнения стекового буфера возникает, когда приложение пишет больше данных, чем выделено под стековый буфер, провоцируя перезаписывание, и не исключено, что будут перезаписаны важные избыточные данные в стеке, расположенные следом за массивом или перед ним.

что такое стековое переполнение. Смотреть фото что такое стековое переполнение. Смотреть картинку что такое стековое переполнение. Картинка про что такое стековое переполнение. Фото что такое стековое переполнение

Стек (абстрактный тип данных) являет собой список элементов, располагающихся стопкой, где информация упорядочена таким образом, что добавление элемента делает его головным, а удаление убирает первый элемент, тогда как головным станет следующий за ним. Принцип работы стека часто сравнивается со стопкой тарелок – выдернуть из середины тарелку нельзя, снимаются они поочерёдно, начиная с верхней, то есть порядок взаимодействия осуществляется по принципу LIFO (Last In, First Out – последним пришёл, первым ушёл).

Такое явление как переполнение буфера, когда программа захватывает больше данных, чем выделенный под них массив, в лучшем случае при ошибочном переполнении приводит к отказу софта или некорректной работе. В худшем, это будет означать, что уязвимость может быть применена в целях вредительства. Переполнение в стековом кадре используется злоумышленниками для изменения адреса возврата выполняемой функции, открывая возможности управления данными, независимо от того, буфер расположен в стеке, который растёт вниз, и адрес возврата идёт после буфера, или же стек растёт вниз, и адрес возврата находится перед буфером. Реализовать такое поведение программы несложно с применением вредоносного кода. С блоками памяти определённого размера компьютер работает в любых приложениях или процессах.

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

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

Что делать, если обнаружена уязвимость в данном приложении

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

Рассмотрим, несколько способов, как исправить ошибку, если произошло переполнение стекового буфера Windows 10.

Использование антивирусного ПО

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

Рекомендуется просканировать систему на вирусы, можно в безопасном режиме, если ОС не загружается, и выполнить проверку и устранение угроз посредством встроенного Защитника Windows.

Как очистить компьютер от вирусов при появлении ошибки «Стековый буфер переполнен»:

Чистая загрузка ОС Windows

Если переустановка софта и перезагрузка не помогли, и ошибка переполнения стекового буфера не исчезла, стоит попробовать выполнить чистую загрузку системы. Возможно, причины проблемы не относятся к данному приложению, ведь кроме работающих программ в Windows запущен ряд прочих процессов, которые и могут провоцировать баг. Для выполнения загрузки ОС в чистом виде нужно войти под учётной записью администратора компьютера, некоторые функции и приложения при этом будут недоступны, поскольку в данном режиме запускаются только необходимые системе файлы.

что такое стековое переполнение. Смотреть фото что такое стековое переполнение. Смотреть картинку что такое стековое переполнение. Картинка про что такое стековое переполнение. Фото что такое стековое переполнение

Для чистой загрузки Windows выполняем следующие действия:

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

Специализированный софт

В сети есть немало лечащих утилит (Dr.Web CureIt, Kaspersky и др.), способных избавить компьютер от вирусов. Портативные программы не будут конфликтовать с уже установленным антивирусом и эффективно выполнят задачу сканирования и удаления вредоносного ПО. Есть также антивирусный софт, способный решать проблему на низком уровне, если вирусы не дают системе запуститься. Используя утилиты с обновлённой вирусной базой, можно исправить, в том числе ошибку переполнения стекового буфера.

Восстановление Windows

Ещё одна мера, позволяющая избавится от системной ошибки, предполагает выполнение восстановления системы. Для использования функции потребуется наличие заранее созданного накопителя восстановления Windows, в качестве которого можно использовать диск или флешку. Выполняем следующие действия:

что такое стековое переполнение. Смотреть фото что такое стековое переполнение. Смотреть картинку что такое стековое переполнение. Картинка про что такое стековое переполнение. Фото что такое стековое переполнение

Крайней мерой, когда более простые и гуманные способы решения не помогли исправить ошибку, является переустановка Windows.

Источник

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *