Panggil syscall Linux dari bahasa scripting

15

Saya ingin memanggil syscall Linux (atau setidaknya libc wrapper) langsung dari bahasa scripting. Saya tidak peduli apa bahasa scripting - itu hanya penting bahwa itu tidak dikompilasi (alasannya pada dasarnya ada hubungannya dengan tidak ingin kompiler di jalur ketergantungan, tapi itu tidak penting). Apakah ada bahasa skrip (shell, Python, Ruby, dll) yang memungkinkan ini?

Secara khusus, ini adalah syscall getrandom .

Astaga
sumber
3
getrandom hanya menarik byte acak dari /dev/urandom. Anda tentu dapat melakukannya dari skrip shell.
steve
@steve memang, kecuali tentu saja /devbelum tersedia. Tapi sulit membayangkan Perl akan!
derobert
Secara kritis, saya ingin ini memblokir sampai kumpulan entropi diinisialisasi, yang membaca dari / dev / urandom sebagai file tidak dilakukan.
joshlf
5
Baca dari /dev/randomsampai terbuka, lalu baca dari /dev/urandom?
Uskup
1
"alasannya pada dasarnya ada hubungannya dengan tidak menginginkan kompiler di jalur dependensi, tapi itu tidak penting" -> Hah? Jika Anda maksud jalur ketergantungan runtime , maka Anda tidak akan dalam hal apa pun. Anda tidak memerlukan kompiler C untuk menjalankan biner yang dikompilasi dari C. Jika Anda bermaksud bahwa Anda tidak ingin bergantung pada kemampuan untuk mengkompilasi hal-hal untuk arsitektur target Anda, karena Anda pikir Anda tidak akan memiliki kemampuan itu, maka itu tidak mungkin Anda dapat membuat Python, Bash, atau bahasa skrip nyata lainnya berjalan di platform itu.
Kevin

Jawaban:

33

Perl memungkinkan ini dengan syscallfungsinya:

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

Dokumentasi juga memberikan contoh penulisan panggilan (2):

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

Tidak bisa mengatakan saya pernah menggunakan fitur ini. Nah, sebelum sekarang untuk mengkonfirmasi contoh memang berfungsi.

Ini tampaknya bekerja dengan 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..

Dan jika Anda tidak memiliki acak di syscall.ph Anda, maka Anda bisa menggunakan nomor itu sebagai gantinya. Ini 318 pada kotak pengujian Debian saya (amd64). Berhati-hatilah karena nomor syscall Linux spesifik untuk arsitektur.

derobert
sumber
2
Perl - palu rencana B!
Thorbjørn Ravn Andersen
28

Dengan Python Anda dapat menggunakan ctypesmodul untuk mengakses fungsi-fungsi sewenang-wenang di pustaka dinamis, termasuk syscall()dari 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)

Jika libc Anda menyertakan getrandom()fungsi wrapper, Anda dapat menyebutnya juga:

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
sumber
Apakah Anda bisa menambahkan contoh memanggil getrandomfungsi libc secara langsung daripada syscall getrandom? Apakah itu mungkin?
joshlf
@ joshlf Tentu saja itu mungkin. Saya mengedit jawaban saya.
cg909
Apakah Anda tahu jika ada cara untuk secara dinamis mencari nilai yang benar dari SYS_getrandomnilai saat runtime (sehingga Anda melakukannya dengan tepat untuk platform saat ini)? Misalnya, dengan mem-parsing /usr/includefile header?
joshlf
Saya tidak mencobanya, tetapi Anda mungkin beruntung dengan pycparser .
cg909
17

Ruby memiliki syscall(num [, args...]) → integerfungsi.

Sebagai contoh:

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

Dengan 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> 
lororget
sumber