C (x86_64), 11, 30, 34 o 34 + 15 = 49 bytes
main[]="/";
c=6;main(){((void(*)())&c)();}
main(){int c=6;((void(*)())&c)();}
He presentado un par de soluciones que usan funciones de biblioteca para lanzar a SIGILL
través de varios medios, pero podría decirse que es trampa, ya que la función de biblioteca resuelve el problema. Aquí hay una gama de soluciones que no utilizan funciones de biblioteca y hacen suposiciones variables sobre dónde el sistema operativo está dispuesto a permitirle ejecutar código no ejecutable. (Las constantes aquí se eligen para x86_64, pero puede cambiarlas para obtener soluciones de trabajo para la mayoría de los otros procesadores que tienen instrucciones ilegales).
06
es el byte de código máquina con el número más bajo que no corresponde a una instrucción definida en un procesador x86_64. Entonces, todo lo que tenemos que hacer es ejecutarlo. (Alternativamente, 2F
también está indefinido y corresponde a un único carácter ASCII imprimible). Ninguno de estos está garantizado que siempre esté indefinido, pero no están definidos a partir de hoy.
El primer programa aquí se ejecuta 2F
desde el segmento de datos de solo lectura. La mayoría de los enlazadores no son capaces de producir un salto trabajando desde .text
a .rodata
(o el equivalente en su sistema operativo) ya que no es algo que nunca sería útil en un programa correctamente segmentada; Todavía no he encontrado un sistema operativo en el que esto funcione. También debería tener en cuenta el hecho de que muchos compiladores quieren que la cadena en cuestión sea una cadena ancha, lo que requeriría un adicionalL
; Supongo que cualquier sistema operativo en el que funcione tiene una visión bastante desactualizada de las cosas y, por lo tanto, se está construyendo para un estándar anterior a C94 por defecto. Es posible que no haya ningún lugar donde funcione este programa, pero también es posible que haya algún lugar donde funcione este programa, y por lo tanto lo estoy enumerando en esta colección de posibles respuestas más dudosas a menos dudosas. (Después de publicar esta respuesta, Dennis también mencionó la posibilidad main[]={6}
en el chat, que tiene la misma longitud y que no tiene problemas con el ancho de los caracteres, e incluso insinuó el potencial para main=6
; No puedo reclamar razonablemente estas respuestas como mía, ya que no pensé en ellos yo mismo).
El segundo programa aquí se ejecuta 06
desde el segmento de datos de lectura-escritura. En la mayoría de los sistemas operativos, esto causará una falla de segmentación, ya que los segmentos de datos grabables se consideran un defecto de diseño incorrecto que hace que las vulnerabilidades sean probables. Sin embargo, este no siempre ha sido el caso, por lo que probablemente funcione en una versión suficientemente antigua de Linux, pero no puedo probarlo fácilmente.
El tercer programa se ejecuta 06
desde la pila. Nuevamente, esto causa una falla de segmentación hoy en día, porque la pila normalmente se clasifica como no escribible por razones de seguridad. La documentación del enlazador que he visto implica en gran medida que solía ser legal ejecutarlo desde la pila (a diferencia de los dos casos anteriores, hacerlo ocasionalmente es útil), así que aunque no puedo probarlo, estoy bastante seguro de que hay algunos versión de Linux (y probablemente otros sistemas operativos) en la que esto funciona.
Finalmente, si le da -Wl,-z,execstack
(penalización de 15 bytes) a gcc
(si usa GNU ld
como parte del backend), desactivará explícitamente la protección de la pila ejecutable, permitiendo que el tercer programa funcione y dé una señal de operación ilegal como se esperaba. Yo he probado y verificado esta versión 49 bytes para trabajar. (Dennis menciona en el chat que aparentemente esta opción funciona main=6
, lo que daría un puntaje de 6 + 15. Estoy bastante sorprendido de que esto funcione, dado que el 6 descaradamente no está en la pila; la opción de enlace aparentemente hace más de su nombre lo sugiere.)
raise(SIGILL)
?