Llamar a un syscall de Linux desde un lenguaje de script


15

Quiero llamar a un syscall de Linux (o al menos el contenedor libc) directamente desde un lenguaje de script. No me importa qué lenguaje de secuencias de comandos: es importante que no se compile (la razón básicamente tiene que ver con no querer un compilador en la ruta de dependencia, pero eso no es ni aquí ni allá). ¿Hay algún lenguaje de script (shell, Python, Ruby, etc.) que permita esto?

En particular, es el syscall getrandom.


3
getrandom simplemente extrae bytes aleatorios de /dev/urandom. Ciertamente puedes hacerlo desde un script de shell.
Steve

@steve, a menos que, por supuesto, /devaún no esté disponible. ¡Pero entonces difícil de imaginar sería Perl!
derobert

Críticamente, quiero que esto se bloquee hasta que se inicialice el grupo de entropía, lo que no se puede leer desde / dev / urandom como archivo.
joshlf

55
¿Leer desde /dev/randomhasta que se desbloquea y luego leer /dev/urandom?
obispo

1
"La razón básicamente tiene que ver con no querer un compilador en la ruta de dependencia, pero eso no es ni aquí ni allá" -> ¿Eh? Si te refieres a la ruta de dependencia de tiempo de ejecución , entonces no lo harás en ningún caso. No necesita un compilador de C para ejecutar un binario que se compiló de C. Si quiere decir que no quiere depender de la capacidad de compilar cosas para su arquitectura de destino, porque cree que no tendrá esa capacidad, entonces es poco probable que pueda ejecutar Python, Bash o cualquier otro lenguaje de script real en esa plataforma.
Kevin

Respuestas:


33

Perl permite esto con su syscallfunción:

$ perldoc -f syscall
    syscall NUMBER, LIST
            Calls the system call specified as the first element of the list,
            passing the remaining elements as arguments to the system call. If
⋮

La documentación también da un ejemplo de llamar a write (2):

require 'syscall.ph';        # may need to run h2ph
my $s = "hi there\n";
syscall(SYS_write(), fileno(STDOUT), $s, length $s);

Sin embargo, no puedo decir que alguna vez haya usado esta función. Bueno, antes de ahora para confirmar el ejemplo sí funciona.

Esto parece funcionar con getrandom:

$ perl -E 'require "syscall.ph"; $v = " "x8; syscall(SYS_getrandom(), $v, length $v, 0); print $v' | xxd
00000000: 5790 8a6d 714f 8dbe                      W..mqO..

Y si no tiene getrandom en su syscall.ph, entonces podría usar el número en su lugar. Es 318 en mi cuadro de prueba de Debian (amd64). Tenga en cuenta que los números de syscall de Linux son específicos de la arquitectura.


2
Perl - el plan B martillo!
Thorbjørn Ravn Andersen

28

En Python puede usar el ctypesmódulo para acceder a funciones arbitrarias en bibliotecas dinámicas, incluso syscall()desde libc:

import ctypes

SYS_getrandom = 318 # You need to check the syscall number for your target architecture

libc = ctypes.CDLL(None)
_getrandom_syscall = libc.syscall
_getrandom_syscall.restypes = ctypes.c_int
_getrandom_syscall.argtypes = ctypes.c_int, ctypes.POINTER(ctypes.c_char), ctypes.c_size_t, ctypes.c_uint

def getrandom(size, flags=0):
    buf = (ctypes.c_char * size)()
    result = _getrandom_syscall(SYS_getrandom, buf, size, flags)
    if result < 0:
        raise OSError(ctypes.get_errno(), 'getrandom() failed')
    return bytes(buf)

Si su libc incluye la getrandom()función de contenedor, también puede llamarla:

import ctypes

libc = ctypes.CDLL(None)
_getrandom = libc.getrandom
_getrandom.restypes = ctypes.c_int
_getrandom.argtypes = ctypes.POINTER(ctypes.c_char), ctypes.c_size_t, ctypes.c_uint

def getrandom(size, flags=0):
    buf = (ctypes.c_char * size)()
    result = _getrandom(buf, size, flags)
    if result < 0:
        raise OSError(ctypes.get_errno(), 'getrandom() failed')
    return bytes(buf)

¿ getrandomHay alguna posibilidad de que pueda agregar un ejemplo de llamada a la función libc directamente en lugar de la llamada al sistema getrandom? ¿Es eso posible?
joshlf

@joshlf Por supuesto que es posible. Edité mi respuesta.
cg909

¿Sabes si hay una manera de buscar dinámicamente el valor correcto del SYS_getrandomvalor en tiempo de ejecución (para que lo hagas bien en la plataforma actual)? Por ejemplo, analizando /usr/includearchivos de encabezado?
joshlf

No lo intenté, pero es posible que tengas suerte con Pycparser .
cg909

17

Ruby tiene una syscall(num [, args...]) → integerfunción.

Por ejemplo:

irb(main):010:0> syscall 1, 1, "hello\n", 6
hello
=> 6

Con getrandom():

irb(main):001:0> a = "aaaaaaaa"
=> "aaaaaaaa"
irb(main):002:0> syscall 318,a,8,0
=> 8
irb(main):003:0> a
=> "\x9Cq\xBE\xD6|\x87\u0016\xC6"
irb(main):004:0> 
Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.