示例#1
0
 def __init__(self, task: Task, ram: RAM,
              environment: t.Dict[bytes, bytes]) -> None:
     self.data = environment
     self.sh = Command(Path("/bin/sh"), ['sh'], {})
     self.tmpdir = Path(self.get("TMPDIR", "/tmp"))
     self.path = ExecutablePathCache(task, ram,
                                     self.get("PATH", "").split(":"))
示例#2
0
async def start_recursor(nursery, parent: Thread, path: Path,
                                  ipv4_sockets: t.List[t.Tuple[handle.FileDescriptor, handle.FileDescriptor]],
                                  ipv6_sockets: t.List[t.Tuple[handle.FileDescriptor, handle.FileDescriptor]],
                                  root_hints: dns.zone.Zone=None) -> Powerdns:
    pdns_recursor = Command(Path("/home/sbaugh/.local/src/pdns/pdns/recursordist/pdns_recursor"), ['pdns_recursor'], {})
    thread = await parent.fork()

    ipv4s = {str(i+1): (udp.move(thread.task), tcp.move(thread.task))
             for i, (udp, tcp) in enumerate(ipv4_sockets)}
    ipv6s = {"::"+str(i+1): (udp.move(thread.task), tcp.move(thread.task))
             for i, (udp, tcp) in enumerate(ipv6_sockets)}
    addresses = {**ipv4s, **ipv6s}
    await thread.unshare_files(going_to_exec=True)
    config = {
        "config-dir": os.fsdecode(path),
        "socket-dir": os.fsdecode(path),
        # more logging
        "loglevel": "9",
        "log-common-errors": "yes",
        "quiet": "no",
        "trace": "yes",
        "dont-query": "",
        "logging-facility": "0",
        # relevant stuff
        "local-address": ",".join(addresses),
        "allow-from": "127.0.0.0/8",
        "local-address-udp-fds": ",".join([f"{i}={await fd.as_argument()}" for i, (fd, _) in addresses.items()]),
        "local-address-tcp-fds": ",".join([f"{i}={await fd.as_argument()}" for i, (_, fd) in addresses.items()]),
    }
    if root_hints is not None:
        config["hint-file"] = os.fsdecode(await thread.spit(path/'root.hints', root_hints.to_text()))
    child = await thread.exec(pdns_recursor.args(*[f"--{name}={value}" for name, value in config.items()]))
    nursery.start_soon(child.check)
    return Powerdns()
示例#3
0
文件: miredo.py 项目: catern/rsyscall
async def make_tun(process: Process, name: str, reqsock: FileDescriptor) -> t.Tuple[FileDescriptor, int]:
    # open /dev/net/tun
    tun_fd = await process.task.open(await process.ptr(Path("/dev/net/tun")), O.RDWR)
    # register TUN interface name for this /dev/net/tun fd
    ifreq = await process.ptr(Ifreq(name, flags=IFF.TUN))
    await tun_fd.ioctl(TUNSETIFF, ifreq)
    # use reqsock to look up the interface index of the TUN interface by name (reusing the previous Ifreq)
    await reqsock.ioctl(SIOC.GIFINDEX, ifreq)
    tun_index = (await ifreq.read()).ifindex
    return tun_fd, tun_index
示例#4
0
 async def send_email(self, from_: str, to: str, subject: str, msg: str) -> None:
     thread = await self.thread.fork()
     await thread.unshare_files()
     fd = await thread.task.memfd_create(await thread.ram.ptr(Path('message')))
     msg = f'From: {from_}\nSubject: {subject}\nTo: {to}\n\n' + msg
     await thread.spit(fd, msg)
     await fd.lseek(0, SEEK.SET)
     await thread.stdin.replace_with(fd)
     child = await thread.exec(self.sendmail.args('-t'))
     await child.check()
示例#5
0
async def start_miredo(nursery, miredo_exec: MiredoExecutables,
                       thread: Thread) -> Miredo:
    inet_sock = await thread.task.socket(AF.INET, SOCK.DGRAM)
    await inet_sock.bind(await thread.ram.ptr(SockaddrIn(0, 0)))
    # set a bunch of sockopts
    one = await thread.ram.ptr(Int32(1))
    await inet_sock.setsockopt(SOL.IP, IP.RECVERR, one)
    await inet_sock.setsockopt(SOL.IP, IP.PKTINFO, one)
    await inet_sock.setsockopt(SOL.IP, IP.MULTICAST_TTL, one)
    # hello fragments my old friend
    await inet_sock.setsockopt(SOL.IP, IP.MTU_DISCOVER, await
                               thread.ram.ptr(Int32(IP.PMTUDISC_DONT)))
    ns_thread = await thread.fork()
    await ns_thread.unshare(CLONE.NEWNET | CLONE.NEWUSER)
    # create icmp6 fd so miredo can relay pings
    icmp6_fd = await ns_thread.task.socket(AF.INET6, SOCK.RAW, IPPROTO.ICMPV6)

    # create the TUN interface
    tun_fd = await ns_thread.task.open(
        await ns_thread.ram.ptr(Path("/dev/net/tun")), O.RDWR)
    ptr = await thread.ram.ptr(netif.Ifreq(b'teredo', flags=netif.IFF_TUN))
    await tun_fd.ioctl(netif.TUNSETIFF, ptr)
    # create reqsock for ifreq operations in this network namespace
    reqsock = await ns_thread.task.socket(AF.INET, SOCK.STREAM)
    await reqsock.ioctl(netif.SIOCGIFINDEX, ptr)
    tun_index = (await ptr.read()).ifindex
    # create socketpair for communication between privileged process and teredo client
    privproc_pair = await (await ns_thread.task.socketpair(
        AF.UNIX, SOCK.STREAM, 0, await
        ns_thread.ram.malloc(Socketpair))).read()

    privproc_thread = await ns_thread.fork()
    await add_to_ambient(privproc_thread, {CAP.NET_ADMIN})
    privproc_child = await exec_miredo_privproc(miredo_exec, privproc_thread,
                                                privproc_pair.first, tun_index)
    nursery.start_soon(privproc_child.check)

    # TODO lock down the client thread, it's talking on the network and isn't audited...
    # should clear out the mount namespace
    # iterate through / and umount(MNT_DETACH) everything that isn't /nix
    # ummm and let's use UMOUNT_NOFOLLOW too
    # ummm no let's just only umount directories
    client_thread = await ns_thread.fork(CLONE.NEWPID)
    await client_thread.unshare(CLONE.NEWNET | CLONE.NEWNS)
    await client_thread.unshare_user()
    client_child = await exec_miredo_run_client(miredo_exec, client_thread,
                                                inet_sock, tun_fd, reqsock,
                                                icmp6_fd, privproc_pair.second,
                                                "teredo.remlab.net")
    nursery.start_soon(client_child.check)

    # we keep the ns thread around so we don't have to mess with setns
    return Miredo(ns_thread)
示例#6
0
async def start_powerdns(nursery, parent: Thread, path: Path, zone: dns.zone.Zone,
                                  # tuple is (udpfd, listening tcpfd)
                                  ipv4_sockets: t.List[t.Tuple[handle.FileDescriptor, handle.FileDescriptor]],
                                  ipv6_sockets: t.List[t.Tuple[handle.FileDescriptor, handle.FileDescriptor]],
) -> Powerdns:
    pdns_server = Command(Path("/home/sbaugh/.local/src/pdns/pdns/pdns_server"), ['pdns_server'], {})
    # pdns_server = await parent.environ.which("pdns_server")
    thread = await parent.fork()

    # we pretend to pass addresses like 0.0.0.1 etc
    # we add one so we don't pass 0.0.0.0 and make powerdns think it's bound to everything
    ipv4s = {str(i+1): (udp.move(thread.task), tcp.move(thread.task))
             for i, (udp, tcp) in enumerate(ipv4_sockets)}
    ipv6s = {str(i+1): (udp.move(thread.task), tcp.move(thread.task))
             for i, (udp, tcp) in enumerate(ipv6_sockets)}
    await thread.unshare_files(going_to_exec=True)
    config = {
        "config-dir": os.fsdecode(path),
        # TODO control-console seems to be a feature where it will listen on stdin or something?
        # we should use that instead of this socketdir
        "socket-dir": os.fsdecode(path),
        # more logging
        "loglevel": "9",
        "log-dns-queries": "yes",
        # backend
        "launch": "bind",
        "bind-config": os.fsdecode(await thread.spit(path/"named.conf",
            'zone "%s" { file "%s"; };' % (
                zone.origin.to_text(),
                os.fsdecode(await thread.spit(path/"zone", zone.to_text()))))),
        "enable-lua-records": "yes",
        # relevant stuff
        "local-address": ",".join(ipv4s),
        "local-address-udp-fds": ",".join([f"{i}={await fd.as_argument()}" for i, (fd, _) in ipv4s.items()]),
        "local-address-tcp-fds": ",".join([f"{i}={await fd.as_argument()}" for i, (_, fd) in ipv4s.items()]),
        "local-ipv6": ",".join(ipv6s),
        "local-ipv6-udp-fds": ",".join([f"{i}={await fd.as_argument()}" for i, (fd, _) in ipv6s.items()]),
        "local-ipv6-tcp-fds": ",".join([f"{i}={await fd.as_argument()}" for i, (_, fd) in ipv6s.items()]),
    }
    print(config['local-address-udp-fds'])
    child = await thread.exec(pdns_server.args(*[f"--{name}={value}" for name, value in config.items()]))
    nursery.start_soon(child.check)
    return Powerdns()
示例#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 write_user_mappings(thr: RAMThread, uid: int, gid: int,
                              in_namespace_uid: int=None, in_namespace_gid: int=None) -> None:
    """Set up a new user namespace with single-user {uid,gid}_map

    These are the only valid mappings for unprivileged user namespaces.
    """
    if in_namespace_uid is None:
        in_namespace_uid = uid
    if in_namespace_gid is None:
        in_namespace_gid = gid
    procself = Path("/proc/self")

    uid_map = await thr.task.open(await thr.ram.ptr(procself/"uid_map"), O.WRONLY)
    await uid_map.write(await thr.ram.ptr(f"{in_namespace_uid} {uid} 1\n".encode()))
    await uid_map.close()

    setgroups = await thr.task.open(await thr.ram.ptr(procself/"setgroups"), O.WRONLY)
    await setgroups.write(await thr.ram.ptr(b"deny"))
    await setgroups.close()

    gid_map = await thr.task.open(await thr.ram.ptr(procself/"gid_map"), O.WRONLY)
    await gid_map.write(await thr.ram.ptr(f"{in_namespace_gid} {gid} 1\n".encode()))
    await gid_map.close()
示例#9
0
 async def which(self, name: str) -> Command:
     "Locate an executable with this name on PATH; throw ExecutableNotFound on failure"
     try:
         path = self.name_to_path[name]
     except KeyError:
         nameptr = await self.ram.ptr(Path(name))
         # do the lookup for 64 paths at a time, that seems like a good batching number
         for paths in chunks(self.paths, 64):
             thunks = [
                 functools.partial(self._check, path, nameptr)
                 for path in paths
             ]
             results = await run_all(thunks)  # type: ignore
             for path, result in zip(paths, results):
                 if result:
                     # path is set as the loop variable; python has no scope
                     # so we can just break out and use it.
                     break
             if result:
                 break
         else:
             raise ExecutableNotFound(name)
         self.name_to_path[name] = path
     return Command(path / name, [name], {})
示例#10
0
 def __init__(self, task: Task, ram: RAM, paths: t.List[str]) -> None:
     self.task = task
     self.ram = ram
     self.paths = [Path(path) for path in paths]
     self.fds: t.Dict[Path, t.Optional[FileDescriptor]] = {}
     self.name_to_path: t.Dict[str, Path] = {}