1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
#pragma once
///@file

#include "lix/libstore/build/local-derivation-goal.hh"
#include "lix/libstore/gc-store.hh"
#include "lix/libstore/local-store.hh"
#include "lix/libutil/processes.hh"
#include <unistd.h>

namespace nix {

/**
 * Linux-specific implementation of LocalStore
 */
class LinuxLocalStore : public LocalStore
{
public:
    LinuxLocalStore(LocalStoreConfig config) : Store(config), LocalStore(config) {}
    LinuxLocalStore(const std::string scheme, std::string path, LocalStoreConfig config)
        : LinuxLocalStore(config)
    {
        throw UnimplementedError("LinuxLocalStore");
    }

private:

    kj::Promise<Result<void>> findPlatformRoots(UncheckedRoots & unchecked) override;
};

/**
 * Linux-specific implementation of LocalDerivationGoal
 */
class LinuxLocalDerivationGoal : public LocalDerivationGoal
{
public:
    using LocalDerivationGoal::LocalDerivationGoal;

    ~LinuxLocalDerivationGoal();

    // NOTE these are all C strings because macos doesn't have constexpr std::string
    // constructors, and std::string_view is a pain to turn into std::strings again.
    static constexpr const char * PASTA_NS_IFNAME = "eth0";
    static constexpr const char * PASTA_HOST_IPV4 = "169.254.1.1";
    static constexpr const char * PASTA_CHILD_IPV4 = "169.254.1.2";
    static constexpr const char * PASTA_IPV4_NETMASK = "16";
    // randomly chosen 6to4 prefix, mapping the same ipv4ll as above.
    // even if this id is used on the daemon host there should not be
    // any collisions since ipv4ll should never be addressed by ipv6.
    static constexpr const char * PASTA_HOST_IPV6 = "64:ff9b:1:4b8e:472e:a5c8:a9fe:0101";
    static constexpr const char * PASTA_CHILD_IPV6 = "64:ff9b:1:4b8e:472e:a5c8:a9fe:0102";

private:
    /*
     * Destroy the cgroup otherwise another build
     * may grab the current UID which is used in the cgroup name
     * and then mess with a cgroup we might be reading statistics from.
     */
    void cleanupHookFinally() override;

    Pid pastaPid;

    /**
     * Create a special accessor that can access paths that were built within the sandbox's
     * chroot.
     */
    std::optional<ref<FSAccessor>> getChrootDirAwareFSAccessor() override;

    void fillBuilderConfig(build::Request::Builder request) override;

    /**
     * Create and populate chroot
     */
    void prepareSandbox() override;

    /**
     * Start child process in new namespaces,
     * create /etc/passwd and /etc/group based on discovered uid/gid
     */
    Pid startChild(AutoCloseFD setupFD, AutoCloseFD logPTY) override;

    /**
     * Kill all processes by build user.
     */
    void killSandbox(bool getStatus) override;

    bool supportsUidRange() override
    {
        return true;
    }

    std::string rewriteResolvConf(std::string fromHost);

    /**
     * Whether to run the build in a private network namespace.
     */
    bool privateNetwork() const
    {
        return derivationType.value().isSandboxed();
    }

    /**
     * Whether to run pasta for network-endowed derivations. Running pasta
     * currently requires actively waiting for its net-ns setup to finish.
     */
    bool runPasta()
    {
        if (!_runPasta) {
            // don't launch pasta unless we have a tun device. in a build sandbox we
            // commonly do not, and trying to run pasta anyway naturally won't work.
            _runPasta = !privateNetwork() && settings.pastaPath != "" && pathExists("/dev/net/tun");
        }
        return *_runPasta;
    }
    std::optional<bool> _runPasta;
};
}