Вызов системного вызова Linux с языка сценариев

15

Я хочу вызвать системный вызов Linux (или, по крайней мере, оболочку libc) напрямую из языка сценариев. Мне все равно, какой язык сценариев - просто важно, чтобы он не компилировался (причина в основном связана с нежеланием компилятора в пути зависимости, но это ни здесь, ни там). Существуют ли языки сценариев (shell, Python, Ruby и т. Д.), Которые позволяют это?

В частности, это системный вызов getrandom.

joshlf
источник
3
getrandom просто извлекает случайные байты из /dev/urandom. Конечно, вы можете сделать это из сценария оболочки.
Стив
@steve действительно, если, конечно, /devеще не доступен. Но тогда трудно представить, что Perl будет!
derobert
Критически, я хочу, чтобы это блокировалось до тех пор, пока не будет инициализирован пул энтропии, чего не делает чтение из / dev / urandom как файла.
joshlf
5
Читать с, /dev/randomпока он не разблокируется, затем читать с /dev/urandom?
епископ
1
«причина в основном в том, что не нужен компилятор в пути зависимости, но это ни здесь, ни там» -> А? Если вы имеете в виду путь зависимости времени выполнения , то ни в коем случае не будете. Вам не нужен компилятор C для запуска двоичного файла, скомпилированного из C. Если вы имеете в виду, что не хотите зависеть от возможности компилировать вещи для вашей целевой архитектуры, потому что вы думаете, что у вас не будет этой способности, тогда он маловероятно, что на этой платформе вы сможете запустить Python, Bash или любой другой настоящий язык сценариев.
Кевин,

Ответы:

33

Perl позволяет это с помощью своей syscallфункции:

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

В документации также приведен пример вызова write (2):

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

Не могу сказать, что когда- либо использовал эту функцию. Ну, прежде чем сейчас подтвердить пример действительно работает.

Это похоже на работу с 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..

И если у вас нет getrandom в вашем syscall.ph, то вы можете использовать номер вместо этого. Это 318 на моей коробке тестирования Debian (amd64). Помните, что номера системных вызовов Linux зависят от архитектуры.

derobert
источник
2
Perl - план Б молоток!
Торбьерн Равн Андерсен
28

В Python вы можете использовать ctypesмодуль для доступа к произвольным функциям в динамических библиотеках, в том числе syscall()из 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)

Если в вашем libc есть getrandom()функция-обертка, вы также можете вызвать ее:

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
источник
Есть ли шанс, что вы могли бы добавить пример вызова getrandomфункции libc напрямую, а не системный вызов getrandom? Это возможно?
joshlf
@joshlf Конечно, это возможно. Я отредактировал свой ответ.
cg909
Знаете ли вы, есть ли способ динамически искать правильное значение SYS_getrandomзначения во время выполнения (чтобы вы поняли это правильно для текущей платформы)? Например, путем разбора /usr/includeзаголовочных файлов?
Joshlf
Я не пробовал, но вам может повезти с pycparser .
cg909
17

Руби имеет syscall(num [, args...]) → integerфункцию.

Например:

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

С 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
источник