Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Make syscall in Python

I want to make syscall in Python and the function is not in libc, is there a way to do it in Python?

More specifically, I want to call getdents, whose manpage says

Note: There are no glibc wrappers for these system calls;

All existing related solutions I found on the web uses ctypes with libc.so: for example.

Please don't question why I want to use getdents directly, I have a very specific reason to do that, and it would be distracting to discuss in this question. Thank you.

like image 271
Kan Li Avatar asked May 04 '16 15:05

Kan Li


People also ask

Does Python have system calls?

syscall() is a small library function that invokes the system call whose assembly language interface has the specified number with the specified arguments. Employing syscall() is useful, for example, when invoking a system call that has no wrapper function in the C library.

What is system call Python?

Processing arguments import sys # argv is a list of strings containing the commandline params # argv[0] is always the name of the invoked command for arg in sys.argv: print arg argc = len(sys.argv) fork import os # fork creates a child process.

Can kernel call syscall?

In Linux, you can call almost all system calls if you can find their kernel export (do cat /proc/kallsysms | grep sys_ for an example). There is a minor "trick" to get around a protection in most syscalls (those which accept a user mode *), by setting the data segment (KERNEL_DS).


1 Answers

Libc exposes a function to invoke "custom" syscalls: long syscall(long number, ...);

syscall() is a small library function that invokes the system call whose assembly language interface has the specified number with the specified arguments. Employing syscall() is useful, for example, when invoking a system call that has no wrapper function in the C library.

Just access this function like any foreign function:

import ctypes  libc = ctypes.CDLL(None) syscall = libc.syscall 

e.g.

syscall(39)  # 39 = getpid, but you get the gist 

Or to translate the example in the man page:

import os, ctypes  off_t = ctypes.c_long  # YMMV __NR_getdents = 78  # YMMV  class linux_dirent(ctypes.Structure):     _fields_ = [         ('d_ino', ctypes.c_long),         ('d_off', off_t),         ('d_reclen', ctypes.c_ushort),         ('d_name', ctypes.c_char)     ]  _getdents = ctypes.CDLL(None).syscall _getdents.restype = ctypes.c_int _getdents.argtypes = ctypes.c_long, ctypes.c_uint, ctypes.POINTER(ctypes.c_char), ctypes.c_uint  fd = os.open('/tmp/', os.O_RDONLY | os.O_DIRECTORY)  buf = ctypes.ARRAY(ctypes.c_char, 1024)() while True:     nread = _getdents(__NR_getdents, fd, buf, len(buf))     if nread == -1:         raise OSError('getdents')     elif nread == 0:         break      pos = 0     while pos < nread:         d = linux_dirent.from_buffer(buf, pos)          name = buf[pos + linux_dirent.d_name.offset : pos + d.d_reclen]         name = name[:name.index('\0')]         print 'name:', name          pos += d.d_reclen 
like image 70
kay Avatar answered Oct 11 '22 17:10

kay