Appeler un syscall Linux à partir d'un langage de script

15

Je veux appeler un syscall Linux (ou au moins le wrapper libc) directement à partir d'un langage de script. Peu m'importe le langage de script - il est juste important qu'il ne soit pas compilé (la raison a essentiellement à voir avec le fait de ne pas vouloir de compilateur dans le chemin de dépendance, mais ce n'est ni ici ni là). Existe-t-il des langages de script (shell, Python, Ruby, etc.) qui permettent cela?

En particulier, c'est le syscall getrandom.

joshlf
la source
3
getrandom extrait simplement des octets aléatoires de /dev/urandom. Vous pouvez certainement le faire à partir d'un script shell.
steve
@steve en effet, à moins bien sûr qu'il /devne soit pas encore disponible. Mais alors difficile d'imaginer que Perl le serait!
derobert
De manière critique, je veux que cela se bloque jusqu'à ce que le pool d'entropie soit initialisé, ce que la lecture de / dev / urandom en tant que fichier ne fait pas.
joshlf
5
Lire /dev/randomjusqu'à ce qu'il se débloque, puis lire /dev/urandom?
évêque
1
"La raison est essentiellement de ne pas vouloir de compilateur dans le chemin de dépendance, mais ce n'est ni ici ni là-bas" -> Huh? Si vous voulez dire le chemin de dépendance d' exécution , vous ne le ferez en aucun cas. Vous n'avez pas besoin d'un compilateur C pour exécuter un binaire qui a été compilé à partir de C. Si vous voulez dire que vous ne voulez pas dépendre de la capacité de compiler des choses pour votre architecture cible, parce que vous pensez que vous n'aurez pas cette capacité, alors il il est peu probable que vous puissiez faire fonctionner Python, Bash ou tout autre langage de script réel sur cette plate-forme.
Kevin

Réponses:

33

Perl permet cela avec sa syscallfonction:

$ 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 documentation donne également un exemple d'appel de write (2):

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

Je ne peux pas dire que j'aie jamais utilisé cette fonctionnalité. Eh bien, avant tout à l'heure, pour confirmer l'exemple fonctionne effectivement.

Cela semble fonctionner avec 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..

Et si vous n'avez pas getrandom dans votre syscall.ph, vous pouvez utiliser le numéro à la place. C'est 318 sur ma boîte de test Debian (amd64). Sachez que les numéros d'appel système Linux sont spécifiques à l'architecture.

derobert
la source
2
Perl - le marteau du plan B!
Thorbjørn Ravn Andersen
28

En Python, vous pouvez utiliser le ctypesmodule pour accéder à des fonctions arbitraires dans des bibliothèques dynamiques, y compris à syscall()partir de 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 votre libc inclut la getrandom()fonction wrapper, vous pouvez également l'appeler:

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
la source
getrandomY a- getrandomt- il une chance que vous puissiez ajouter un exemple d'appel direct de la fonction libc plutôt que de l'appel système ? Est-ce possible?
joshlf
@joshlf Bien sûr, c'est possible. J'ai édité ma réponse.
cg909
Savez-vous s'il existe un moyen de rechercher dynamiquement la valeur correcte de la SYS_getrandomvaleur au moment de l'exécution (afin de l'obtenir correctement pour la plate-forme actuelle)? Par exemple, en analysant /usr/includeles fichiers d'en-tête?
joshlf
Je ne l'ai pas essayé, mais vous pourriez avoir de la chance avec pycparser .
cg909
17

Ruby a une syscall(num [, args...]) → integerfonction.

Par exemple:

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

Avec 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
la source