> У меня питон с RX выделением памяти. Только питонокоду, исполняемому интерпретатором СPython, eXecute разрешения страницы до лампочки, потому что роль "CPU" в этом случае играет сам интерпретатор.
А он прекрасно позволит добавить или изменить код с помощью eval, патчинга и еще 100500 способов:
>>> import new# f(x) = x²
>>> def foo(x):
... return x*x
...
>>> foo(4)
16
>>> foo(10)
100
# байткод функции
>>> foo.__code__.co_code
'|\x00\x00|\x00\x00\x18S'
# меняем опкод MUL на ADD
>>> co=foo.__code__
>>> foo.__code__ = new.code(co.co_argcount,
... co.co_nlocals,
... co.co_stacksize,
... co.co_flags,
... '|\x00\x00|\x00\x00\x17S',
... co.co_consts,
... co.co_names,
... co.co_varnames,
... co.co_filename,
... co.co_name,
... co.co_firstlineno,
... co.co_lnotab)
>>> foo(4)
8
>>> foo(10)
20
# а можно было просто
>>> foo = lambda y: y+y
# любой вызов foo теперь будет выполнять совершенно другой код.
>>> foo(10)
20
Хуже того: любой ЯП, позволяющий переопределять методы/функции/процедуры во время выполнения или использовать структуры данных для реализации динамической замены (о как завернул!) методов (классический callback в си или хранилка указателя к обработчику в структуре данных -- это оно, ага) так или иначе, принципиально обходит W^X.
Но ходовые скриптовые ЯП делают это на "базовом" уровне, предоставляя атакующему не просто возможность заменить функцию-другую или поизвращаться с ROP в ASLR, а весь мощьный, базовый набор "опкодов" интерпретатора, шикарнейшим образом вырубая рандомизацию адресного пространства, memory-guards и все "гарантии неизменности кода" (толку-то от того, что код интерпретатора не изменился, если он все равно выполнит любое нужное действие) …
Так что придется или сильно переписывать CPython или удалять, увы.
(Ba/Da/Z) sh однозначно только удалять, там слишком много завязанно на повсеместной интерпретации-выполнения ввода пользователя.
% echo "my $(time ls)"
ls -GF 0,00s user 0,00s system 68% cpu 0,006 total
my Makefile
> Свои мне проще переписать без lambad и они сразу начинают нормально работать.
Это может показаться удивительным и невероятным, но лямбды в питоне в реализации не особо отличаются от "именных" фукции:
>>> import dis
>>> def foo(x): return x+x...
>>> dis.dis(foo)
3 0 LOAD_FAST 0 (x)
3 LOAD_FAST 0 (x)
6 BINARY_ADD
7 RETURN_VALUE
>>> dis.dis(lambda x: x+x)
3 0 LOAD_FAST 0 (x)
3 LOAD_FAST 0 (x)
6 BINARY_ADD
7 RETURN_VALUE
>>> y=lambda x: x+x
>>> y.__code__.co_code
'|\x00\x00|\x00\x00\x17S'
>>> foo.__code__.co_code
'|\x00\x00|\x00\x00\x17S'
>>>