* In the checker, do traversals of the dependency graph explicitly. A

conditional expression in the blacklist can specify when to
  continue/stop a traversal.  For example, in

    <condition>
      <within>
        <traverse>
          <not><hasAttr name='outputHash' value='.+' /></not>
        </traverse>
        <hasAttr name='outputHash' value='ef1cb003448b4a53517b8f25adb12452' />
      </within>
    </condition>

  we traverse the dependency graph, not following the dependencies of
  `fetchurl' derivations (as indicated by the presence of an
  `outputHash' attribute - this is a bit ugly).  The resulting set of
  paths is scanned for a fetch of a file with the given hash, in this
  case, the hash of zlib-1.2.1.tar.gz (which has a security bug).  The
  intent is that a dependency on zlib is not a problem if it is in a
  `fetchurl' derivation, since that's build-time only.  (Other
  build-time uses of zlib *might* be a problem, e.g., static linking.)
This commit is contained in:
Eelco Dolstra 2005-03-07 16:26:05 +00:00
parent bfbc55cbc6
commit 97c93526da
2 changed files with 168 additions and 61 deletions

View file

@ -1,32 +1,28 @@
<blacklist> <blacklist>
<!--
<item id='openssl-0.9.7d-obsolete'> <item id='openssl-0.9.7d-obsolete'>
<condition> <condition>
<containsSource <within>
hash="sha256:1xf1749gdfw9f50mxa5rsnmwiwrb5mi0kg4siw8a73jykdp2i6ii" <traverse><true /></traverse>
origin="openssl-0.9.7d.tar.gz" /> <hasAttr name='outputHash' value='1b49e90fc8a75c3a507c0a624529aca5' />
</within>
</condition> </condition>
<reason> <reason>
Race condition in CRL checking code. Upgrade to 0.9.7e. Race condition in CRL checking code. Upgrade to 0.9.7e.
</reason> </reason>
<severity class="all" level="low" /> <severity class="all" level="low" />
</item> </item>
-->
<item id='zlib-1.2.1-security' type='security'> <item id='zlib-1.2.1-security' type='security'>
<condition> <condition>
<containsSource <within>
hash="sha256:1xf1749gdfw9f50mxa5rsnmwiwrb5mi0kg4siw8a73jykdp2i6ii"
origin="openssl-0.9.7d.tar.gz" />
<!-- <within>
<traverse> <traverse>
<not><hasName name='*.tar.*' /></not> <not><hasAttr name='outputHash' value='.+' /></not>
</traverse> </traverse>
<hasAttr name='md5' value='ef1cb003448b4a53517b8f25adb12452' /> <hasAttr name='outputHash' value='ef1cb003448b4a53517b8f25adb12452' />
</within> --> </within>
</condition> </condition>
<reason> <reason>
Zlib 1.2.1 is vulnerable to a denial-of-service condition. See Zlib 1.2.1 is vulnerable to a denial-of-service condition. See

View file

@ -26,40 +26,86 @@ my @userEnvElems = split ' ', $userEnvElems;
my %storePathHashes; my %storePathHashes;
# Function for evaluating conditions. sub getElemNodes {
sub evalCondition { my $node = shift;
my $storePaths = shift; my @elems = ();
my $condition = shift; foreach my $node ($node->getChildNodes) {
push @elems, $node if $node->nodeType == XML_ELEMENT_NODE;
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 @elems;
return 0;
} }
elsif ($name eq "and") {
my $result = 1; my %referencesCache;
foreach my $node ($condition->getChildNodes) { sub getReferences {
if ($node->nodeType == XML_ELEMENT_NODE) { my $path = shift;
$result &= evalCondition($storePaths, $node); return $referencesCache{$path} if defined $referencesCache{$path};
}
} my $references = `nix-store --query --references '$path'`;
return $result; die "cannot query references" if $? != 0;
$referencesCache{$path} = [split ' ', $references];
return $referencesCache{$path};
} }
elsif ($name eq "true") {
return 1; my %attrsCache;
sub getAttr {
my $path = shift;
my $name = shift;
my $key = "$path/$name";
return $referencesCache{$key} if defined $referencesCache{$key};
my $value = `nix-store --query --binding '$name' '$path' 2> /dev/null`;
$value = "" if $? != 0; # !!!
chomp $value;
$referencesCache{$key} = $value;
return $value;
} }
elsif ($name eq "false") {
return 0; sub evalCondition;
sub traverse {
my $done = shift;
my $set = shift;
my $path = shift;
my $stopCondition = shift;
return if defined $done->{$path};
$done->{$path} = 1;
$set->{$path} = 1;
# print " in $path\n";
if (!evalCondition({$path => 1}, $stopCondition)) {
# print " STOPPING in $path\n";
return;
}
# Get the requisites of the deriver.
foreach my $reference (@{getReferences $path}) {
traverse($done, $set, $reference, $stopCondition);
}
}
sub evalSet {
my $inSet = shift;
my $expr = shift;
my $name = $expr->getName;
if ($name eq "traverse") {
my $stopCondition = (getElemNodes $expr)[0];
my $done = { };
my $set = { };
foreach my $path (keys %{$inSet}) {
traverse($done, $set, $path, $stopCondition);
}
return $set;
} }
else { else {
@ -68,16 +114,81 @@ sub evalCondition {
} }
# Function for evaluating conditions.
sub evalCondition {
my $storePaths = shift;
my $condition = shift;
my $elemName = $condition->getName;
if ($elemName eq "containsSource") {
my $hash = $condition->attributes->getNamedItem("hash")->getValue;
foreach my $path (keys %{$storePathHashes{$hash}}) {
return 1 if defined $storePaths->{$path};
}
return 0;
}
elsif ($elemName eq "hasName") {
my $nameRE = $condition->attributes->getNamedItem("name")->getValue;
foreach my $path (keys %{$storePaths}) {
return 1 if $path =~ /$nameRE/;
}
return 0;
}
elsif ($elemName eq "hasAttr") {
my $name = $condition->attributes->getNamedItem("name")->getValue;
my $valueRE = $condition->attributes->getNamedItem("value")->getValue;
foreach my $path (keys %{$storePaths}) {
if ($path =~ /\.drv$/) {
my $value = getAttr($path, $name);
# print " $path $name $value\n";
return 1 if $value =~ /$valueRE/;
}
}
return 0;
}
elsif ($elemName eq "and") {
my $result = 1;
foreach my $node (getElemNodes $condition) {
$result &= evalCondition($storePaths, $node);
}
return $result;
}
elsif ($elemName eq "not") {
return !evalCondition($storePaths, (getElemNodes $condition)[0]);
}
elsif ($elemName eq "within") {
my @elems = getElemNodes $condition;
my $set = evalSet($storePaths, $elems[0]);
return evalCondition($set, $elems[1]);
}
elsif ($elemName eq "true") {
return 1;
}
elsif ($elemName eq "false") {
return 0;
}
else {
die "unknown element `$elemName'";
}
}
sub evalOr { sub evalOr {
my $storePaths = shift; my $storePaths = shift;
my $nodes = shift; my $nodes = shift;
my $result = 0; my $result = 0;
foreach my $node (@{$nodes}) { foreach my $node (@{$nodes}) {
if ($node->nodeType == XML_ELEMENT_NODE) {
$result |= evalCondition($storePaths, $node); $result |= evalCondition($storePaths, $node);
} }
}
return $result; return $result;
} }
@ -100,22 +211,22 @@ foreach my $userEnvElem (@userEnvElems) {
# Get the requisites of the deriver. # Get the requisites of the deriver.
my $requisites = `nix-store --query --requisites --include-outputs '$deriver'`; # my $requisites = `nix-store --query --requisites --include-outputs '$deriver'`;
die "cannot query requisites" if $? != 0; # die "cannot query requisites" if $? != 0;
my @requisites = split ' ', $requisites; # my @requisites = split ' ', $requisites;
# Get the hashes of the requisites. # Get the hashes of the requisites.
my $hashes = `nix-store --query --hash @requisites`; # my $hashes = `nix-store --query --hash @requisites`;
die "cannot query hashes" if $? != 0; # die "cannot query hashes" if $? != 0;
my @hashes = split ' ', $hashes; # my @hashes = split ' ', $hashes;
for (my $i = 0; $i < scalar @requisites; $i++) { # for (my $i = 0; $i < scalar @requisites; $i++) {
die unless $i < scalar @hashes; # die unless $i < scalar @hashes;
my $hash = $hashes[$i]; # my $hash = $hashes[$i];
$storePathHashes{$hash} = {} unless defined $storePathHashes{$hash}; # $storePathHashes{$hash} = {} unless defined $storePathHashes{$hash};
my $r = $storePathHashes{$hash}; # !!! fix # my $r = $storePathHashes{$hash}; # !!! fix
$$r{$requisites[$i]} = 1; # $$r{$requisites[$i]} = 1;
} # }
# Evaluate each blacklist item. # Evaluate each blacklist item.
@ -127,8 +238,8 @@ foreach my $userEnvElem (@userEnvElems) {
die unless $condition; die unless $condition;
# Evaluate the condition. # Evaluate the condition.
my @foo = $condition->getChildNodes(); my @elems = getElemNodes $condition;
if (evalOr(\@requisites, \@foo)) { if (evalOr({$deriver => 1}, \@elems)) {
# Oops, condition triggered. # Oops, condition triggered.
my $reason = ($item->getChildrenByTagName("reason"))[0]->getChildNodes->to_literal; my $reason = ($item->getChildrenByTagName("reason"))[0]->getChildNodes->to_literal;
$reason =~ s/\s+/ /g; $reason =~ s/\s+/ /g;