Я знал о jmp инструкции некоторое время, но она никогда, казалось мне, не была даже удаленно небезопасна. Я недавно имел причину проверить спецификации CIL и был очень удивлен обнаружить, что jmp считают не поддающимся проверке.
Потому что, в отличие от вызова
, callvirt
или calli
, где кадр стека вызывающего абонента останется включенным стек, который будет виден будущими обходами стека безопасности доступа к коду, запускаемыми (возможно, косвенно) вызываемым пользователем, инструкция jmp
срывает кадр стека вызывающего абонента до перехода к вызываемому и, таким образом, невидима для любых обходов стека CAS, которые вызываемый может сработать.
Редактировать: Я думаю, что я не ошибаюсь, если ответ выше неверен. Теперь я думаю, что разница между (проверяемыми) последовательностями tail.call и (непроверяемыми) последовательностями jmp может заключаться в том, что хвостовой вызов требует помещения аргументов вызова в стек оценки, где они могут быть проверены обычным способом, тогда как a jmp
требует, чтобы стек оценки был пуст, и заставляет jump-ee унаследовать аргументы перемычки. Вероятно, не было причин усложнять верификатор для проверки инструкций jmp
, но это могло быть возможно сделать в условиях, аналогичных тем, которые накладываются на хвост .call
последовательностей (одна из которых состоит в том, что вызывающий и вызываемый должны быть в одной сборке, что исключает мое предположение CAS выше, по крайней мере, до явных вызовов .Deny ()
).
Если так, это будет соответствующая часть спецификации: (Раздел III, Раздел 3.37)
Текущие аргументы передаются к методу назначения.
Стек оценки должен быть пуст когда эта инструкция выполняется. В соглашение о вызове, номер и тип аргументы в адресе назначения должен соответствовать текущему методу.