about summary refs log tree commit diff
path: root/blacklisting/check-env.pl
blob: f334ef04cb1e045a7b44b68a16632c66de5e65d5 (plain) (blame)
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
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
#! /usr/bin/perl -w -I /home/eelco/.nix-profile/lib/site_perl

use strict;
use XML::LibXML;
#use XML::Simple;

my $blacklistFN = shift @ARGV;
die unless defined $blacklistFN;
my $userEnv = shift @ARGV;
die unless defined $userEnv;


# Read the blacklist.
my $parser = XML::LibXML->new();
my $blacklist = $parser->parse_file($blacklistFN)->getDocumentElement;

#print $blacklist->toString() , "\n";


# Get all the elements of the user environment.
my $userEnvElems = `nix-store --query --references '$userEnv'`;
die "cannot query user environment elements" if $? != 0;
my @userEnvElems = split ' ', $userEnvElems;


my %storePathHashes;


# Function for evaluating conditions.
sub evalCondition {
    my $storePaths = shift;
    my $condition = shift;

    my $name = $condition->getName;
    
    if ($name eq "containsSource") {
        my $hash = $condition->attributes->getNamedItem("hash")->getValue;
        foreach my $path (keys %{$storePathHashes{$hash}}) {
            # !!! use a hash for $storePaths
            foreach my $path2 (@{$storePaths}) {
                return 1 if $path eq $path2;
            }
        }
        return 0;
    }

    elsif ($name eq "and") {
        my $result = 1;
        foreach my $node ($condition->getChildNodes) {
            if ($node->nodeType == XML_ELEMENT_NODE) {
                $result &= evalCondition($storePaths, $node);
            }
        }
        return $result;
    }

    elsif ($name eq "true") {
        return 1;
    }

    elsif ($name eq "false") {
        return 0;
    }

    else {
        die "unknown element `$name'";
    }
}


sub evalOr {
    my $storePaths = shift;
    my $nodes = shift;

    my $result = 0;
    foreach my $node (@{$nodes}) {
        if ($node->nodeType == XML_ELEMENT_NODE) {
            $result |= evalCondition($storePaths, $node);
        }
    }
    
    return $result;
}


# Iterate over all elements, check them.
foreach my $userEnvElem (@userEnvElems) {

    # Get the deriver of this path.
    my $deriver = `nix-store --query --deriver '$userEnvElem'`;
    die "cannot query deriver" if $? != 0;
    chomp $deriver;

    if ($deriver eq "unknown-deriver") {
#        print "  deriver unknown, cannot check sources\n";
        next;
    }

    print "CHECKING $userEnvElem\n";


    # Get the requisites of the deriver.
    my $requisites = `nix-store --query --requisites --include-outputs '$deriver'`;
    die "cannot query requisites" if $? != 0;
    my @requisites = split ' ', $requisites;


    # Get the hashes of the requisites.
    my $hashes = `nix-store --query --hash @requisites`;
    die "cannot query hashes" if $? != 0;
    my @hashes = split ' ', $hashes;
    for (my $i = 0; $i < scalar @requisites; $i++) {
        die unless $i < scalar @hashes;
        my $hash = $hashes[$i];
        $storePathHashes{$hash} = {} unless defined $storePathHashes{$hash};
        my $r = $storePathHashes{$hash}; # !!! fix
        $$r{$requisites[$i]} = 1;
    }


    # Evaluate each blacklist item.
    foreach my $item ($blacklist->getChildrenByTagName("item")) {
        my $itemId = $item->getAttributeNode("id")->getValue;
        print "  CHECKING FOR $itemId\n";

        my $condition = ($item->getChildrenByTagName("condition"))[0];
        die unless $condition;

        # Evaluate the condition.
        my @foo = $condition->getChildNodes();
        if (evalOr(\@requisites, \@foo)) {
            # Oops, condition triggered.
            my $reason = ($item->getChildrenByTagName("reason"))[0]->getChildNodes->to_literal;
            $reason =~ s/\s+/ /g;
            $reason =~ s/^\s+//g;

            print "    VULNERABLE TO `$itemId': $reason\n";
        }
    }
}