예제 #1
0
async def _openat(sysif: SyscallInterface,
                  dirfd: t.Optional[near.FileDescriptor], path: near.Address,
                  flags: int, mode: int) -> near.FileDescriptor:
    if dirfd is None:
        dirfd = AT.FDCWD  # type: ignore
    return near.FileDescriptor(await sysif.syscall(SYS.openat, dirfd, path,
                                                   flags, mode))
예제 #2
0
async def _connect_and_send(
        self: PersistentProcess, process: Process,
        syscall_sock: FileDescriptor, data_sock: FileDescriptor,
) -> t.Tuple[FileDescriptor, FileDescriptor]:
    """Connect to a persistent process's socket, send some file descriptors

    """
    fds = [syscall_sock, data_sock]
    sock = await process.make_afd(await process.socket(AF.UNIX, SOCK.STREAM|SOCK.NONBLOCK))
    sockaddr_un = await SockaddrUn.from_path(process, self.persistent_path)
    addr = await process.ptr(sockaddr_un)
    count = await process.ptr(Int32(len(fds)))
    iovec = await process.ptr(IovecList([await process.malloc(bytes, 1)]))
    cmsgs = await process.ptr(CmsgList([CmsgSCMRights(fds)]))
    hdr = await process.ptr(SendMsghdr(None, iovec, cmsgs))
    response: Pointer = await process.ptr(StructList(Int32, [Int32(0)]*len(fds)))
    data = None
    await sock.connect(addr)
    _, _ = await sock.write(count)
    _, [] = await sock.handle.sendmsg(hdr, SendmsgFlags.NONE)
    while response.size() > 0:
        valid, response = await sock.read(response)
        data += valid
    remote_syscall_sock, remote_data_sock = [self.task.make_fd_handle(near.FileDescriptor(int(i)))
                  for i in ((await data.read()).elems if data else [])]
    await sock.close()
    return remote_syscall_sock, remote_data_sock
예제 #3
0
파일: socket.py 프로젝트: gc-ss/rsyscall
async def _accept(sysif: SyscallInterface, sockfd: near.FileDescriptor,
                  addr: t.Optional[near.Address],
                  addrlen: t.Optional[near.Address],
                  flags: SOCK) -> near.FileDescriptor:
    if addr is None:
        addr = 0  # type: ignore
    if addrlen is None:
        addrlen = 0  # type: ignore
    return near.FileDescriptor(await sysif.syscall(SYS.accept4, sockfd, addr,
                                                   addrlen, flags))
예제 #4
0
파일: local.py 프로젝트: seh9000/rsyscall
async def _make_local_thread() -> Thread:
    """Create the local thread, allocating various resources locally.

    For the most part, the local thread is like any other thread; it just bootstraps
    differently, and uses syscall and memory interfaces which are specialized to the local
    thread.

    """
    process = near.Process(os.getpid())
    task = Task(
        LocalSyscall(),
        process,
        far.FDTable(process.id),
        far.AddressSpace(process.id),
        far.PidNamespace(process.id),
    )
    ram = RAM(task, LocalMemoryTransport(task),
              memory.AllocatorClient.make_allocator(task))
    epfd = await task.epoll_create()

    async def wait_readable():
        logger.debug("wait_readable(%s)", epfd.near.number)
        await trio.hazmat.wait_readable(epfd.near.number)

    epoller = Epoller.make_subsidiary(ram, epfd, wait_readable)
    thread = Thread(
        task,
        ram,
        await FDPassConnection.make(task, ram, epoller),
        NativeLoader.make_from_symbols(task, lib),
        epoller,
        await ChildProcessMonitor.make(ram, task, epoller),
        Environment(task, ram, {
            key.encode(): value.encode()
            for key, value in os.environ.items()
        }),
        stdin=task.make_fd_handle(near.FileDescriptor(0)),
        stdout=task.make_fd_handle(near.FileDescriptor(1)),
        stderr=task.make_fd_handle(near.FileDescriptor(2)),
    )
    return thread
예제 #5
0
async def _make_local_process() -> Process:
    """Create the local process, allocating various resources locally.

    For the most part, the local process is like any other process; it just bootstraps
    differently, and uses syscall and memory interfaces which are specialized to the local
    process.

    """
    pid = near.Pid(os.getpid())
    task = Task(
        pid,
        handle.FDTable(pid.id),
        far.AddressSpace(pid.id),
        far.PidNamespace(pid.id),
        far.MountNamespace(pid.id),
    )
    task.sysif = LocalSyscall(task)
    task.allocator = await memory.AllocatorClient.make_allocator(task)
    epfd = await task.epoll_create()

    async def wait_readable():
        logger.debug("wait_readable(%s)", epfd.near.number)
        await trio.lowlevel.wait_readable(epfd.near.number)

    trio_system_wait_readable = TrioSystemWaitReadable(epfd.near.number)
    set_trio_system_wait_readable(trio_system_wait_readable)
    epoller = Epoller.make_subsidiary(epfd, trio_system_wait_readable.wait)
    process = Process(
        task,
        await FDPassConnection.make(task, epoller),
        NativeLoader.make_from_symbols(task, lib),
        epoller,
        await ChildPidMonitor.make(task, epoller),
        Environment.make_from_environ(task, {**os.environ}),
        stdin=task.make_fd_handle(near.FileDescriptor(0)),
        stdout=task.make_fd_handle(near.FileDescriptor(1)),
        stderr=task.make_fd_handle(near.FileDescriptor(2)),
    )
    return process
예제 #6
0
async def _connect_and_send(
        self: PersistentThread, thread: Thread,
        fds: t.List[FileDescriptor]) -> t.List[FileDescriptor]:
    """Connect to a persistent thread's socket, send some file descriptors

    This isn't actually a generic function; the persistent thread expects exactly three
    file descriptors, and uses them in a special way.

    """
    sock = await thread.make_afd(await thread.task.socket(
        AF.UNIX, SOCK.STREAM | SOCK.NONBLOCK, 0),
                                 nonblock=True)
    sockaddr_un = await SockaddrUn.from_path(thread, self.persistent_path)

    async def sendmsg_op(
        sem: RAM
    ) -> t.Tuple[WrittenPointer[Address], WrittenPointer[Int32],
                 WrittenPointer[SendMsghdr], Pointer[StructList[Int32]]]:
        addr: WrittenPointer[Address] = await sem.ptr(sockaddr_un)
        count = await sem.ptr(Int32(len(fds)))
        iovec = await sem.ptr(IovecList([await sem.malloc(bytes, 1)]))
        cmsgs = await sem.ptr(CmsgList([CmsgSCMRights(fds)]))
        hdr = await sem.ptr(SendMsghdr(None, iovec, cmsgs))
        response_buf = await sem.ptr(StructList(Int32, [Int32(0)] * len(fds)))
        return addr, count, hdr, response_buf

    addr, count, hdr, response = await thread.ram.perform_batch(sendmsg_op)
    data = None
    async with contextlib.AsyncExitStack() as stack:
        if isinstance(self.task.sysif, ChildSyscallInterface):
            await stack.enter_async_context(
                self.task.sysif._throw_on_child_exit())
        await sock.connect(addr)
        _, _ = await sock.write(count)
        _, [] = await sock.handle.sendmsg(hdr, SendmsgFlags.NONE)
        while response.size() > 0:
            valid, response = await sock.read(response)
            data += valid
    remote_fds = [
        self.task.make_fd_handle(near.FileDescriptor(int(i)))
        for i in ((await data.read()).elems if data else [])
    ]
    await sock.close()
    return remote_fds
예제 #7
0
async def do_cloexec_except(thr: RAMThread, excluded_fds: t.Set[near.FileDescriptor]) -> None:
    "Close all CLOEXEC file descriptors, except for those in a whitelist. Would be nice to have a syscall for this."
    buf = await thr.ram.malloc(DirentList, 4096)
    dirfd = await thr.task.open(await thr.ram.ptr(Path("/proc/self/fd")), O.DIRECTORY)
    async def maybe_close(fd: near.FileDescriptor) -> None:
        flags = await syscalls.fcntl(thr.task.sysif, fd, F.GETFD)
        if (flags & FD_CLOEXEC) and (fd not in excluded_fds):
            await syscalls.close(thr.task.sysif, fd)
    async with trio.open_nursery() as nursery:
        while True:
            valid, rest = await dirfd.getdents(buf)
            if valid.size() == 0:
                break
            dents = await valid.read()
            for dent in dents:
                try:
                    num = int(dent.name)
                except ValueError:
                    continue
                nursery.start_soon(maybe_close, near.FileDescriptor(num))
            buf = valid.merge(rest)
예제 #8
0
async def _connect_and_send(
        self: PersistentProcess, process: Process,
        fds: t.List[FileDescriptor]) -> t.List[FileDescriptor]:
    """Connect to a persistent process's socket, send some file descriptors

    This isn't actually a generic function; the persistent process expects exactly three
    file descriptors, and uses them in a special way.

    """
    sock = await process.make_afd(await
                                  process.socket(AF.UNIX,
                                                 SOCK.STREAM | SOCK.NONBLOCK))
    sockaddr_un = await SockaddrUn.from_path(process, self.persistent_path)

    async def sendmsg_op(
        sem: RAM
    ) -> t.Tuple[WrittenPointer[SockaddrUn], WrittenPointer[Int32],
                 WrittenPointer[SendMsghdr], Pointer[StructList[Int32]]]:
        addr = await sem.ptr(sockaddr_un)
        count = await sem.ptr(Int32(len(fds)))
        iovec = await sem.ptr(IovecList([await sem.malloc(bytes, 1)]))
        cmsgs = await sem.ptr(CmsgList([CmsgSCMRights(fds)]))
        hdr = await sem.ptr(SendMsghdr(None, iovec, cmsgs))
        response_buf = await sem.ptr(StructList(Int32, [Int32(0)] * len(fds)))
        return addr, count, hdr, response_buf

    addr, count, hdr, response = await process.ram.perform_batch(sendmsg_op)
    data = None
    await sock.connect(addr)
    _, _ = await sock.write(count)
    _, [] = await sock.handle.sendmsg(hdr, SendmsgFlags.NONE)
    while response.size() > 0:
        valid, response = await sock.read(response)
        data += valid
    remote_fds = [
        self.task.make_fd_handle(near.FileDescriptor(int(i)))
        for i in ((await data.read()).elems if data else [])
    ]
    await sock.close()
    return remote_fds
예제 #9
0
파일: socket.py 프로젝트: gc-ss/rsyscall
 def from_data(cls: t.Type[T], task: Task, data: bytes) -> T:
     fds = [
         near.FileDescriptor(fd)
         for fd, in struct.Struct('i').iter_unpack(data)
     ]
     return cls([task.make_fd_handle(fd) for fd in fds])
예제 #10
0
파일: socket.py 프로젝트: gc-ss/rsyscall
 def make(n: int) -> FileDescriptor:
     return self.task.make_fd_handle(near.FileDescriptor(int(n)))
예제 #11
0
async def stdin_bootstrap(
        parent: Thread,
        bootstrap_command: Command,
) -> t.Tuple[AsyncChildProcess, Thread]:
    """Create a thread from running an arbitrary command which must run rsyscall-stdin-bootstrap

    bootstrap_command can be any arbitrary command, but it must eventually exec
    rsyscall-stdin-bootstrap, and pass down stdin when it does.

    We'll fork and exec bootstrap_command, passing down a socketpair for stdin, and try to
    bootstrap over the other end of the socketpair. Once rsyscall-stdin-bootstrap starts,
    it will respond to our bootstrap and we'll create a new thread.

    """
    #### fork and exec into the bootstrap command
    child = await parent.fork()
    # create the socketpair that will be used as stdin
    stdin_pair = await (await parent.task.socketpair(
        AF.UNIX, SOCK.STREAM, 0, await parent.ram.malloc(Socketpair))).read()
    parent_sock = stdin_pair.first
    child_sock = stdin_pair.second.move(child.task)
    # set up stdin with socketpair
    await child.unshare_files(going_to_exec=True)
    await child.stdin.replace_with(child_sock)
    # exec
    child_process = await child.exec(bootstrap_command)
    #### set up all the fds we'll want to pass over
    # the basic connections
    [(access_syscall_sock, passed_syscall_sock),
     (access_data_sock, passed_data_sock)] = await parent.open_async_channels(2)
    # memfd for setting up the futex
    futex_memfd = await parent.task.memfd_create(
        await parent.ram.ptr(Path("child_robust_futex_list")))
    # send the fds to the new process
    connection_fd, make_connection = await parent.connection.prep_fd_transfer()
    async def sendmsg_op(sem: RAM) -> WrittenPointer[SendMsghdr]:
        iovec = await sem.ptr(IovecList([await sem.malloc(bytes, 1)]))
        cmsgs = await sem.ptr(CmsgList([CmsgSCMRights([
            passed_syscall_sock, passed_data_sock, futex_memfd, connection_fd])]))
        return await sem.ptr(SendMsghdr(None, iovec, cmsgs))
    _, [] = await parent_sock.sendmsg(await parent.ram.perform_batch(sendmsg_op), SendmsgFlags.NONE)
    # close our reference to fds that only the new process needs
    await passed_syscall_sock.close()
    await passed_data_sock.close()
    # close the socketpair
    await parent_sock.close()
    #### read describe to get all the information we need from the new process
    describe_buf = AsyncReadBuffer(access_data_sock)
    describe_struct = await describe_buf.read_cffi('struct rsyscall_stdin_bootstrap')
    environ = await describe_buf.read_envp(describe_struct.envp_count)
    #### build the new task
    pid = describe_struct.pid
    fd_table = far.FDTable(pid)
    address_space = far.AddressSpace(pid)
    # we assume pid namespace is shared
    # TODO include namespace inode numbers numbers in describe
    # note: if we start dealing with namespace numbers then we need to
    # have a Kernel namespace which tells us which kernel we get those
    # numbers from.
    # oh hey we can conveniently dump the inode numbers with getdents!
    pidns = parent.task.pidns
    process = near.Process(pid)
    remote_syscall_fd = near.FileDescriptor(describe_struct.syscall_fd)
    syscall = NonChildSyscallInterface(SyscallConnection(access_syscall_sock, access_syscall_sock), process)
    base_task = Task(syscall, process, fd_table, address_space, pidns)
    handle_remote_syscall_fd = base_task.make_fd_handle(remote_syscall_fd)
    syscall.store_remote_side_handles(handle_remote_syscall_fd, handle_remote_syscall_fd)
    allocator = memory.AllocatorClient.make_allocator(base_task)
    # we assume our SignalMask is zero'd before being started, so we don't inherit it
    ram = RAM(base_task,
               SocketMemoryTransport(access_data_sock,
                                     base_task.make_fd_handle(near.FileDescriptor(describe_struct.data_fd)),
                                     allocator),
               allocator)
    # TODO I think I can maybe elide creating this epollcenter and instead inherit it or share it, maybe?
    epoller = await Epoller.make_root(ram, base_task)
    child_monitor = await ChildProcessMonitor.make(ram, base_task, epoller)
    connection = make_connection(base_task, ram,
                                 base_task.make_fd_handle(near.FileDescriptor(describe_struct.connecting_fd)))
    new_parent = Thread(
        task=base_task,
        ram=ram,
        connection=connection,
        loader=NativeLoader.make_from_symbols(base_task, describe_struct.symbols),
        epoller=epoller,
        child_monitor=child_monitor,
        environ=Environment(base_task, ram, environ),
        stdin=base_task.make_fd_handle(near.FileDescriptor(0)),
        stdout=base_task.make_fd_handle(near.FileDescriptor(1)),
        stderr=base_task.make_fd_handle(near.FileDescriptor(2)),
    )
    #### TODO set up futex I guess
    remote_futex_memfd = near.FileDescriptor(describe_struct.futex_memfd)
    return child_process, new_parent
예제 #12
0
async def ssh_bootstrap(
        parent: Process,
        # the actual ssh command to run
        ssh_command: SSHCommand,
        # the local path we'll use for the socket
        local_socket_path: Path,
        # the directory we're bootstrapping out of
        tmp_path_bytes: bytes,
) -> t.Tuple[AsyncChildPid, Process]:
    "Over ssh, run the bootstrap executable, "
    # identify local path
    local_data_addr = await parent.ram.ptr(
        await SockaddrUn.from_path(parent, local_socket_path))
    # start port forwarding; we'll just leak this process, no big deal
    # TODO we shouldn't leak processes; we should be GCing processes at some point
    forward_child_pid = await ssh_forward(
        parent, ssh_command, local_socket_path, (tmp_path_bytes + b"/data").decode())
    # start bootstrap
    bootstrap_process = await parent.fork()
    bootstrap_child_pid = await bootstrap_process.exec(ssh_command.args(
        "-n", f"cd {tmp_path_bytes.decode()}; exec ./bootstrap rsyscall"
    ))
    # TODO should unlink the bootstrap after I'm done execing.
    # it would be better if sh supported fexecve, then I could unlink it before I exec...
    # Connect to local socket 4 times
    async def make_async_connection() -> AsyncFileDescriptor:
        sock = await parent.make_afd(await parent.socket(AF.UNIX, SOCK.STREAM|SOCK.NONBLOCK))
        await sock.connect(local_data_addr)
        return sock
    async_local_syscall_sock = await make_async_connection()
    async_local_data_sock = await make_async_connection()
    # Read description off of the data sock
    describe_buf = AsyncReadBuffer(async_local_data_sock)
    describe_struct = await describe_buf.read_cffi('struct rsyscall_bootstrap')
    new_pid = describe_struct.pid
    environ = await describe_buf.read_envp(describe_struct.envp_count)
    # Build the new task!
    new_address_space = far.AddressSpace(new_pid)
    # TODO the pid namespace will probably be common for all connections...
    # TODO we should get this from the SSHHost, this is usually going
    # to be common for all connections and we should express that
    new_pid_namespace = far.PidNamespace(new_pid)
    new_pid = near.Pid(new_pid)
    new_base_task = Task(
        new_pid, handle.FDTable(new_pid), new_address_space,
        new_pid_namespace,
    )
    handle_remote_syscall_fd = new_base_task.make_fd_handle(near.FileDescriptor(describe_struct.syscall_sock))
    new_base_task.sysif = SyscallConnection(
        logger.getChild(str(new_pid)),
        async_local_syscall_sock, async_local_syscall_sock,
        handle_remote_syscall_fd, handle_remote_syscall_fd,
    )
    handle_remote_data_fd = new_base_task.make_fd_handle(near.FileDescriptor(describe_struct.data_sock))
    handle_listening_fd = new_base_task.make_fd_handle(near.FileDescriptor(describe_struct.listening_sock))
    new_allocator = memory.AllocatorClient.make_allocator(new_base_task)
    new_transport = SocketMemoryTransport(async_local_data_sock, handle_remote_data_fd)
    # we don't inherit SignalMask; we assume ssh zeroes the sigmask before starting us
    new_ram = RAM(new_base_task, new_transport, new_allocator)
    epoller = await Epoller.make_root(new_ram, new_base_task)
    child_monitor = await ChildPidMonitor.make(new_ram, new_base_task, epoller)
    await handle_listening_fd.fcntl(F.SETFL, O.NONBLOCK)
    connection = ListeningConnection(
        parent.task, parent.ram, parent.epoller,
        local_data_addr,
        new_base_task, new_ram,
        await AsyncFileDescriptor.make(epoller, new_ram, handle_listening_fd),
    )
    new_process = Process(
        task=new_base_task,
        ram=new_ram,
        connection=connection,
        loader=NativeLoader.make_from_symbols(new_base_task, describe_struct.symbols),
        epoller=epoller,
        child_monitor=child_monitor,
        environ=Environment.make_from_environ(new_base_task, new_ram, environ),
        stdin=new_base_task.make_fd_handle(near.FileDescriptor(0)),
        stdout=new_base_task.make_fd_handle(near.FileDescriptor(1)),
        stderr=new_base_task.make_fd_handle(near.FileDescriptor(2)),
    )
    return bootstrap_child_pid, new_process
예제 #13
0
파일: memfd.py 프로젝트: gc-ss/rsyscall
async def _memfd_create(sysif: SyscallInterface,
                        name: near.Address, flags: MFD) -> near.FileDescriptor:
    return near.FileDescriptor(await sysif.syscall(SYS.memfd_create, name, flags))
예제 #14
0
async def _epoll_create(sysif: SyscallInterface,
                        flags: EpollFlag) -> near.FileDescriptor:
    return near.FileDescriptor(await sysif.syscall(SYS.epoll_create1, flags))
예제 #15
0
파일: eventfd.py 프로젝트: gc-ss/rsyscall
async def _eventfd(sysif: SyscallInterface, initval: int,
                   flags: EFD) -> near.FileDescriptor:
    "The raw, near, eventfd syscall."
    return near.FileDescriptor(await sysif.syscall(SYS.eventfd2, initval,
                                                   flags))
예제 #16
0
async def _timerfd_create(sysif: SyscallInterface, clockid: CLOCK,
                          flags: TFD) -> near.FileDescriptor:
    return near.FileDescriptor(await sysif.syscall(SYS.timerfd_create, clockid,
                                                   flags))
예제 #17
0
파일: socket.py 프로젝트: gc-ss/rsyscall
async def _socket(sysif: SyscallInterface, domain: AF, type: SOCK,
                  protocol: int) -> near.FileDescriptor:
    return near.FileDescriptor(await sysif.syscall(SYS.socket, domain, type,
                                                   protocol))
예제 #18
0
파일: signalfd.py 프로젝트: gc-ss/rsyscall
async def _signalfd(sysif: SyscallInterface, fd: t.Optional[near.FileDescriptor],
                    mask: near.Address, sizemask: int, flags: SFD) -> near.FileDescriptor:
    if fd is None:
        fd = -1 # type: ignore
    return near.FileDescriptor(await sysif.syscall(SYS.signalfd4, fd, mask, sizemask, flags))
예제 #19
0
async def stdin_bootstrap(
    parent: Process,
    bootstrap_command: Command,
) -> t.Tuple[AsyncChildPid, Process]:
    """Create a process from running an arbitrary command which must run rsyscall-stdin-bootstrap

    bootstrap_command can be any arbitrary command, but it must eventually exec
    rsyscall-stdin-bootstrap, and pass down stdin when it does.

    We'll clone and exec bootstrap_command, passing down a socketpair for stdin, and try to
    bootstrap over the other end of the socketpair. Once rsyscall-stdin-bootstrap starts,
    it will respond to our bootstrap and we'll create a new process.

    """
    #### clone and exec into the bootstrap command
    # create the socketpair that will be used as stdin
    stdin_pair = await (await parent.task.socketpair(
        AF.UNIX, SOCK.STREAM, 0, await parent.task.malloc(Socketpair))).read()
    parent_sock = stdin_pair.first
    child = await parent.fork()
    # set up stdin with socketpair
    await child.task.inherit_fd(stdin_pair.second).dup2(child.stdin)
    await stdin_pair.second.close()
    # exec
    child_pid = await child.exec(bootstrap_command)
    #### set up all the fds we'll want to pass over
    # the basic connections
    [(access_syscall_sock, passed_syscall_sock),
     (access_data_sock, passed_data_sock)
     ] = await parent.open_async_channels(2)
    # send the fds to the new process
    connection_fd, make_connection = await parent.connection.prep_fd_transfer()
    iovec = await parent.ptr(IovecList([await parent.malloc(bytes, 1)]))
    cmsgs = await parent.ptr(
        CmsgList([
            CmsgSCMRights(
                [passed_syscall_sock, passed_data_sock, connection_fd])
        ]))
    _, [] = await parent_sock.sendmsg(
        await parent.ptr(SendMsghdr(None, iovec, cmsgs)), SendmsgFlags.NONE)
    # close our reference to fds that only the new process needs
    await passed_syscall_sock.close()
    await passed_data_sock.close()
    # close the socketpair
    await parent_sock.close()
    #### read describe to get all the information we need from the new process
    describe_buf = AsyncReadBuffer(access_data_sock)
    describe_struct = await describe_buf.read_cffi(
        'struct rsyscall_stdin_bootstrap')
    environ = await describe_buf.read_envp(describe_struct.envp_count)
    #### build the new task
    pid = describe_struct.pid
    fd_table = handle.FDTable(pid)
    address_space = far.AddressSpace(pid)
    # we assume pid namespace is shared
    # TODO include namespace inode numbers numbers in describe
    # note: if we start dealing with namespace numbers then we need to
    # have a Kernel namespace which tells us which kernel we get those
    # numbers from.
    # oh hey we can conveniently dump the inode numbers with getdents!
    pidns = parent.task.pidns
    # we assume mount namespace is not shared (can't hurt)
    mountns = far.MountNamespace(pid)
    pid = near.Pid(pid)
    base_task = Task(pid, fd_table, address_space, pidns, mountns)
    remote_syscall_fd = base_task.make_fd_handle(
        near.FileDescriptor(describe_struct.syscall_fd))
    base_task.sysif = SyscallConnection(
        logger.getChild(str(pid)),
        access_syscall_sock,
        remote_syscall_fd,
    )
    base_task.allocator = await memory.AllocatorClient.make_allocator(base_task
                                                                      )
    # we assume our SignalMask is zero'd before being started, so we don't inherit it
    # TODO I think I can maybe elide creating this epollcenter and instead inherit it or share it, maybe?
    epoller = await Epoller.make_root(base_task)
    child_monitor = await ChildPidMonitor.make(base_task, epoller)
    connection = make_connection(
        base_task,
        base_task.make_fd_handle(
            near.FileDescriptor(describe_struct.connecting_fd)))
    new_parent = Process(
        task=base_task,
        connection=connection,
        loader=NativeLoader.make_from_symbols(base_task,
                                              describe_struct.symbols),
        epoller=epoller,
        child_monitor=child_monitor,
        environ=Environment.make_from_environ(base_task, environ),
        stdin=base_task.make_fd_handle(near.FileDescriptor(0)),
        stdout=base_task.make_fd_handle(near.FileDescriptor(1)),
        stderr=base_task.make_fd_handle(near.FileDescriptor(2)),
    )
    return child_pid, new_parent
예제 #20
0
async def _dup3(sysif: SyscallInterface, oldfd: near.FileDescriptor,
                newfd: near.FileDescriptor, flags: int) -> near.FileDescriptor:
    return near.FileDescriptor(await sysif.syscall(SYS.dup3, oldfd, newfd,
                                                   flags))
예제 #21
0
파일: stub.py 프로젝트: gc-ss/rsyscall
async def _setup_stub(
    thread: Thread,
    bootstrap_sock: FileDescriptor,
) -> t.Tuple[t.List[str], Thread]:
    "Setup a stub thread"
    [(access_syscall_sock, passed_syscall_sock),
     (access_data_sock, passed_data_sock)
     ] = await thread.open_async_channels(2)
    # memfd for setting up the futex
    futex_memfd = await thread.task.memfd_create(await thread.ram.ptr(
        Path("child_robust_futex_list")))
    # send the fds to the new process
    connection_fd, make_connection = await thread.connection.prep_fd_transfer()

    async def sendmsg_op(sem: RAM) -> WrittenPointer[SendMsghdr]:
        iovec = await sem.ptr(IovecList([await sem.malloc(bytes, 1)]))
        cmsgs = await sem.ptr(
            CmsgList([
                CmsgSCMRights([
                    passed_syscall_sock, passed_data_sock, futex_memfd,
                    connection_fd
                ])
            ]))
        return await sem.ptr(SendMsghdr(None, iovec, cmsgs))

    _, [] = await bootstrap_sock.sendmsg(
        await thread.ram.perform_batch(sendmsg_op), SendmsgFlags.NONE)
    # close our reference to fds that only the new process needs
    await passed_syscall_sock.invalidate()
    await passed_data_sock.invalidate()
    # close the socketpair
    await bootstrap_sock.invalidate()
    #### read describe to get all the information we need from the new process
    describe_buf = AsyncReadBuffer(access_data_sock)
    describe_struct = await describe_buf.read_cffi('struct rsyscall_unix_stub')
    argv_raw = await describe_buf.read_length_prefixed_array(
        describe_struct.argc)
    argv = [os.fsdecode(arg) for arg in argv_raw]
    environ = await describe_buf.read_envp(describe_struct.envp_count)
    #### build the new task
    pid = describe_struct.pid
    fd_table = handle.FDTable(pid)
    address_space = far.AddressSpace(pid)
    # we assume pid namespace is shared
    pidns = thread.task.pidns
    process = near.Process(pid)
    # we assume net namespace is shared - that's dubious...
    # we should make it possible to control the namespace sharing more, hmm.
    # TODO maybe the describe should contain the net namespace number? and we can store our own as well?
    # then we can automatically do it right
    base_task = Task(process, fd_table, address_space, pidns)
    remote_syscall_fd = base_task.make_fd_handle(
        near.FileDescriptor(describe_struct.syscall_fd))
    base_task.sysif = SyscallConnection(
        logger.getChild(str(process)),
        access_syscall_sock,
        access_syscall_sock,
        remote_syscall_fd,
        remote_syscall_fd,
    )
    allocator = memory.AllocatorClient.make_allocator(base_task)
    base_task.sigmask = Sigset(
        {SIG(bit)
         for bit in rsyscall.struct.bits(describe_struct.sigmask)})
    ram = RAM(
        base_task,
        SocketMemoryTransport(
            access_data_sock,
            base_task.make_fd_handle(
                near.FileDescriptor(describe_struct.data_fd))), allocator)
    # TODO I think I can maybe elide creating this epollcenter and instead inherit it or share it, maybe?
    # I guess I need to write out the set too in describe
    epoller = await Epoller.make_root(ram, base_task)
    child_monitor = await ChildProcessMonitor.make(ram, base_task, epoller)
    connection = make_connection(
        base_task, ram,
        base_task.make_fd_handle(
            near.FileDescriptor(describe_struct.connecting_fd)))
    new_thread = Thread(
        task=base_task,
        ram=ram,
        connection=connection,
        loader=NativeLoader.make_from_symbols(base_task,
                                              describe_struct.symbols),
        epoller=epoller,
        child_monitor=child_monitor,
        environ=Environment.make_from_environ(base_task, ram, environ),
        stdin=base_task.make_fd_handle(near.FileDescriptor(0)),
        stdout=base_task.make_fd_handle(near.FileDescriptor(1)),
        stderr=base_task.make_fd_handle(near.FileDescriptor(2)),
    )
    #### TODO set up futex I guess
    remote_futex_memfd = near.FileDescriptor(describe_struct.futex_memfd)
    return argv, new_thread
예제 #22
0
파일: inotify.py 프로젝트: gc-ss/rsyscall
async def _inotify_init(sysif: SyscallInterface, flags: InotifyFlag) -> near.FileDescriptor:
    return near.FileDescriptor(await sysif.syscall(SYS.inotify_init1, flags))