Chamar um syscall do Linux a partir de uma linguagem de script

15

Quero chamar um syscall do Linux (ou pelo menos o wrapper libc) diretamente de uma linguagem de script. Eu não me importo com a linguagem de script - é importante que não seja compilada (o motivo basicamente tem a ver com não querer um compilador no caminho da dependência, mas isso não é aqui nem ali). Existem linguagens de script (shell, Python, Ruby, etc) que permitem isso?

Em particular, é o syscall getrandom .

joshlf
fonte
3
O getrandom simplesmente extrai bytes aleatórios de /dev/urandom. Certamente você pode fazer isso a partir de um script de shell.
steve
@ Steve de fato, a menos que, /devé claro, ainda não esteja disponível. Mas então difícil imaginar Perl seria!
derobert
Criticamente, eu quero que isso bloqueie até que o pool de entropia seja inicializado, o que a leitura de / dev / urandom como um arquivo não faz.
joshlf
5
Leia /dev/randomaté que ele seja desbloqueado e depois leia /dev/urandom?
bispo
1
"o motivo basicamente tem a ver com não querer um compilador no caminho da dependência, mas isso não está aqui nem ali" -> Hein? Se você quer dizer o caminho da dependência do tempo de execução , não será o caso. Você não precisa de um compilador C para executar um binário compilado a partir de C. Se você quer dizer que não deseja depender da capacidade de compilar coisas para sua arquitetura de destino, porque acha que não terá essa capacidade, é improvável que você consiga executar o Python, o Bash ou qualquer outra linguagem de script real nessa plataforma.
26717 Kevin

Respostas:

33

O Perl permite isso com sua syscallfunção:

$ 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
⋮

A documentação também fornece um exemplo de chamada write (2):

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

Não posso dizer que usei esse recurso. Bem, antes de confirmar agora o exemplo realmente funciona.

Parece funcionar com 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..

E se você não tiver o getrandom no seu syscall.ph, poderá usar o número. É 318 na minha caixa de teste Debian (amd64). Cuidado que os números de syscall do Linux são específicos da arquitetura.

derobert
fonte
2
Perl - o plano B martelo!
Thorbjørn Ravn Andersen
28

No Python, você pode usar o ctypesmódulo para acessar funções arbitrárias em bibliotecas dinâmicas, incluindo a syscall()partir da 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)

Se sua libc inclui a getrandom()função wrapper, você também pode chamá-la:

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)
cg909
fonte
Alguma chance de você adicionar um exemplo de chamar a getrandomfunção libc diretamente, em vez de syscall getrandom? Isso é possível?
joshlf
@joshlf Claro que é possível. Eu editei minha resposta.
cg909
Você sabe se existe uma maneira de procurar dinamicamente o valor correto do SYS_getrandomvalor em tempo de execução (para que você acerte na plataforma atual)? Por exemplo, analisando os /usr/includearquivos de cabeçalho?
joshlf
Eu não tentei, mas você pode ter sorte com o pycparser .
cg909
17

Ruby tem uma syscall(num [, args...]) → integerfunção.

Por exemplo:

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

Com 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> 
lgeorget
fonte