* 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:
		
							parent
							
								
									bfbc55cbc6
								
							
						
					
					
						commit
						97c93526da
					
				
					 2 changed files with 168 additions and 61 deletions
				
			
		|  | @ -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 | ||||||
|  |  | ||||||
|  | @ -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; | ||||||
|  |     } | ||||||
|  |     return @elems; | ||||||
|  | } | ||||||
| 
 | 
 | ||||||
|     my $name = $condition->getName; |  | ||||||
| 
 | 
 | ||||||
|     if ($name eq "containsSource") { | my %referencesCache; | ||||||
|         my $hash = $condition->attributes->getNamedItem("hash")->getValue; | sub getReferences { | ||||||
|         foreach my $path (keys %{$storePathHashes{$hash}}) { |     my $path = shift; | ||||||
|             # !!! use a hash for $storePaths |     return $referencesCache{$path} if defined $referencesCache{$path}; | ||||||
|             foreach my $path2 (@{$storePaths}) { |      | ||||||
|                 return 1 if $path eq $path2; |     my $references = `nix-store --query --references '$path'`; | ||||||
|             } |     die "cannot query references" if $? != 0; | ||||||
|  |     $referencesCache{$path} = [split ' ', $references]; | ||||||
|  |      | ||||||
|  |     return $referencesCache{$path}; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | 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; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | 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 0; |         return $set; | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     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 { |     else { | ||||||
|  | @ -68,15 +114,80 @@ 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; | ||||||
|  |  | ||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue