Замена strcpy на strncpy

Допустим, у меня есть устаревший код, который был написан с использованием небезопасных вызовов функций C STL, таких как strcpy. Мы все знаем, что strcpy небезопасен, потому что делает программу уязвимой для проблем с переполнением буфера. Допустим, я хочу заменить все вызовы strcpy вызовами strncpy. Техника замены всех вызовов strcpy(dest, src) включает вызов strncpy с параметрами (dest, src, length of dest - 1) и последующее завершение dest с \0. Я знаю, что проблема в том, что мы не всегда знаем длину dest, потому что это может быть указатель на память, выделенную в куче.

Предположим, я могу вычислить длину dest на каждом из этих сайтов вызовов. Я мог бы заменить все вызовы strcpy вызовами strncpy, что гарантирует, что моя программа невосприимчива к атакам переполнения буфера (по крайней мере, из-за неправильного использования strcpy). Однако этот подход может незаметно усекать данные и нежелательным образом изменять поведение программы. Является ли это лучшим подходом, чем обнаружение усечения и прерывание программы? Или лучше разрешить усечение, но также зарегистрировать его?

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


person RouteMapper    schedule 14.11.2013    source источник
comment
strncpy() намного хуже. Посмотрите на свою реализацию CRT для альтернатив. Или просто напишите свой. Это не простая замена, вам нужно знать размер буфера, а для этого вполне может потребоваться изменить сигнатуры функций, чтобы размер буфера передавался в качестве аргумента.   -  person Hans Passant    schedule 14.11.2013
comment
Я бы не стал изменять исходный код для реализации этих изменений. Я бы модифицировал программу на промежуточном языке, который позволяет получить доступ к этим размерам буфера. Я бы хотел, чтобы возвращаемый тип этих вызовов оставался прежним, поэтому альтернатив CRT будет недостаточно.   -  person RouteMapper    schedule 14.11.2013
comment
Я не могу себе представить, что молчаливое усечение данных — это хорошо. Я согласен с @HansPassant в том, что реализация собственного strncpy может быть правильным путем. Затем вы можете поместить (как минимум) ведение журнала, когда усечение происходит прямо внутри этой функции.   -  person Jud    schedule 14.11.2013
comment
Я думал о регистрации, а не об отмене, потому что такое поведение эквивалентно перехвату ArrayIndexOutOfBoundsException в Java и регистрации исключения где-то. Прерывание программы кажется немного чрезмерным. Мне просто интересно, что другие люди думают о подходе к логированию.   -  person RouteMapper    schedule 14.11.2013
comment
Если программа ранее имела неопределенное поведение из-за переполнения буфера, то прерывание (с подходящим сообщением) кажется мне вполне разумным. Нет особой причины ожидать, что код, который ожидал, что строка уместится в буфере, будет вести себя правильно, когда строка усекается до размера буфера. Таким образом, при отсутствии конкретной информации о желательности усечения (которой у вас нет, если вы заменяете вызов strcpy без проверки контекста, в котором оно происходит), вы не должны усекать.   -  person Steve Jessop    schedule 14.11.2013
comment
@SteveJessop - Будет ли такое изменение в программе разумно квалифицироваться как модернизация функции безопасности в существующей кодовой базе? Я думаю, что это так, потому что он предотвращает небезопасную работу программы из-за переполнения буфера, гарантируя, что она вообще не работает. Из этого следует, что некоторое вмешательство человека могло бы более внимательно изучить состояние прерывания и устранить корень проблемы позже. Просто интересно, что вы думаете :)   -  person RouteMapper    schedule 14.11.2013
comment
@RouteMapper: я думаю, что прерву. Это лучше, чем замена одного неопределенного поведения другим, что произойдет, если хитрая программа не обрабатывает усечение. По сути, никакая функция безопасности не должна переводить программу в состояние, в котором ее автор не ожидал и никогда бы не столкнулся при разработке и тестировании (усеченные данные). С другой стороны, уничтожение хитрых программ звучит для меня как функция безопасности :-)   -  person Steve Jessop    schedule 14.11.2013
comment
@SteveJessop - Понятно, но мне интересно, могу ли я привести аргумент, что прерывание по-прежнему считается патчем. Как я уже говорил ранее, это тема исследования, связанная с модернизацией функций безопасности, поэтому мне нужно убедиться, что все, что я предлагаю, квалифицируется как функция безопасности, в которой люди действительно могут быть заинтересованы.   -  person RouteMapper    schedule 14.11.2013
comment
@RouteMapper: тогда, я полагаю, это зависит от того, кого вам нужно убедить, что это улучшение по сравнению с продолжением работы кода после переполнения буфера. Я думаю, что это очевидно, но я действительно не знаю, каковы критерии для того, чтобы что-то было патчем. Но дело не столько в том, что прерывание — это хорошее поведение, сколько в том, что хуже позволить запуску неправильной программы :-) Конечно, если вы найдете способ запустить всю программу в песочнице, которая каким-то образом гарантирует, что она не сделает ничего вредного, даже если данные неожиданно обрезаются, то запуск будет безопасным. Я предполагаю, что нет.   -  person Steve Jessop    schedule 14.11.2013
comment
@SteveJessop - Поскольку это только для магистерской диссертации, я полагаю, было бы достаточно просто объяснить плюсы и минусы ведения журнала по сравнению с прерыванием. Мне не нужно проявлять религиозную преданность ни одному из подходов; моя главная мысль заключается в том, чтобы показать, что существуют автоматизированные подходы к замене функций. Я не продаю это никому и не гарантирую, что это волшебное решение. Это подход, который я продаю.   -  person RouteMapper    schedule 14.11.2013
comment
@RouteMapper: Хорошо, в этом случае, возможно, способ представить это состоит в том, что у вас есть альтернативная реализация strcpy, которая (а) является правильной реализацией в соответствии со стандартом, поэтому, кроме производительности, она не влияет на любую программу, которая правильно вызывает strcpy ( хотя для того, чтобы это было правдой, вы не должны не просто вызывать strncpy из-за поведения нулевого заполнения strncpy) (b) предотвращает переполнение буфера, (c) заменяет переполнение буфера UB каким-либо другим поведением, которое (будь то прерывание или запись в журнал) помогает диагностировать проблему.   -  person Steve Jessop    schedule 14.11.2013


Ответы (2)


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

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

Допустим, я хочу заменить все вызовы strcpy вызовами strncpy.

Вы не должны этого делать, если только вы не работаете со строками фиксированного размера: помните, что strncpy не только копирует до завершающего нуля, но и заполняет остальную часть строки нулевыми байтами. Если вы ищете «современную замену» strcpy, рассмотрите возможность использования strlcpy. вместо.

Этот подход может незаметно обрезать данные и изменить поведение программы нежелательным образом. Является ли это лучшим подходом, чем обнаружение усечения и прерывание программы? Или лучше разрешить усечение, но также зарегистрировать его?

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

person Sergey Kalinichenko    schedule 14.11.2013
comment
Я понимаю, что strcpy делает именно то, что обещает, и не виноват ни в чем, что делает программист. Подобно заряженному ружью в руках неопытного оператора, он считается небезопасным. Причина, по которой я спрашиваю об этом, заключается в том, что я изучаю способы модернизации функций безопасности в существующих кодовых базах. Я полагаю, что с точки зрения исследования я мог бы просто объяснить плюсы и минусы ведения журнала по сравнению с прерыванием. Я не привязан к выбору определенного подхода. Я просто хочу убедиться, что выслушаю другие мнения по этому вопросу и уделю должное внимание всем сторонам. - person RouteMapper; 14.11.2013
comment
Этот оператор strncpy не только копирует до завершающего нуля, но и заполняет остальную часть строки нулевыми байтами. Из стандарта C: символы, следующие за нулевым символом, не копируются. - person Vlad from Moscow; 14.11.2013
comment
@RouteMapper Продолжая аналогию с оружием, у вас есть как минимум два способа решить проблему: обучить оператора или забрать оружие. - person Sergey Kalinichenko; 14.11.2013
comment
@VladfromMoscow Конечно, они не копируются! Это связано с тем, что нулевые символы записываются вместо них (доказательная ссылка). - person Sergey Kalinichenko; 14.11.2013
comment
@VladfromMoscow Если конец исходной строки C (обозначенной нулевым символом) обнаружен до того, как было скопировано число символов, место назначения дополняется нулями до тех пор, пока в него не будет записано общее число символов. - person RouteMapper; 14.11.2013
comment
С исследовательской точки зрения может быть достаточно сказать, что существуют автоматизированные подходы к защите программ от переполнения буфера из-за неправильного использования strcpy и других подобных небезопасных функций, но требуется некоторое понимание программы, чтобы гарантировать отсутствие нежелательного поведения. внутри программы. Это звучит разумно? - person RouteMapper; 14.11.2013
comment
@RouteMapper Вы не можете автоматизировать часть защиты, не автоматизировав также часть понимания. Это самая большая проблема. Например, если ваш автоматический исправитель кода просматривает изолированную функцию, которая принимает указатель на буфер назначения, но не принимает также размер буфера, для исправления этого потребуется найти все сайты вызова рассматриваемой функции и добавить код для передачи размера буфера; для этого может потребоваться пройти по цепочке вызовов, пока вы не увидите распределение - непростая задача. - person Sergey Kalinichenko; 14.11.2013
comment
@dasblinkenlight - Хорошее замечание! Однако у меня уже есть подход к решению этой проблемы. Вот почему я сказал в своем OP, что мы можем предположить, что я знаю размер каждого буфера :) - person RouteMapper; 14.11.2013

strncpy не является функцией STL. :) C не имеет библиотеки STL. Я не думаю, что это хорошая идея заменять все вхождения strcpy на strncpy. Подход должен быть разным в зависимости от ситуации. В большинстве случаев достаточно использовать strcpy.

person Vlad from Moscow    schedule 14.11.2013