summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--guix/narinfo.scm67
-rw-r--r--guix/substitutes.scm11
-rw-r--r--tests/substitute.scm26
3 files changed, 71 insertions, 33 deletions
diff --git a/guix/narinfo.scm b/guix/narinfo.scm
index a149d9a9017..49f7c14bb37 100644
--- a/guix/narinfo.scm
+++ b/guix/narinfo.scm
@@ -1,5 +1,5 @@
1;;; GNU Guix --- Functional package management for GNU 1;;; GNU Guix --- Functional package management for GNU
2;;; Copyright © 2013-2022 Ludovic Courtès <ludo@gnu.org> 2;;; Copyright © 2013-2022, 2026 Ludovic Courtès <ludo@gnu.org>
3;;; Copyright © 2014 Nikita Karetnikov <nikita@karetnikov.org> 3;;; Copyright © 2014 Nikita Karetnikov <nikita@karetnikov.org>
4;;; Copyright © 2018 Kyle Meyer <kyle@kyleam.com> 4;;; Copyright © 2018 Kyle Meyer <kyle@kyleam.com>
5;;; 5;;;
@@ -25,6 +25,8 @@
25 #:use-module (guix base64) 25 #:use-module (guix base64)
26 #:use-module (guix records) 26 #:use-module (guix records)
27 #:use-module (guix diagnostics) 27 #:use-module (guix diagnostics)
28 #:autoload (guix store) (valid-path-syntax?
29 valid-path-basename-syntax?)
28 #:use-module (gcrypt hash) 30 #:use-module (gcrypt hash)
29 #:use-module (gcrypt pk-crypto) 31 #:use-module (gcrypt pk-crypto)
30 #:use-module (rnrs bytevectors) 32 #:use-module (rnrs bytevectors)
@@ -140,32 +142,39 @@ must contain the original contents of a narinfo file."
140 signature) 142 signature)
141 "Return a new <narinfo> object." 143 "Return a new <narinfo> object."
142 (define len (length urls)) 144 (define len (length urls))
143 (%make-narinfo path cache-url 145 (let ((references (string-tokenize references))
144 ;; Handle the case where URL is a relative URL. 146 (deriver (match deriver
145 (map (lambda (url)
146 (or (string->uri url)
147 (string->uri
148 (if (string-suffix? "/" cache-url)
149 (string-append cache-url url)
150 (string-append cache-url "/" url)))))
151 urls)
152 compressions
153 (match file-sizes
154 (() (make-list len #f))
155 ((lst ...) (map string->number lst)))
156 (match file-hashes
157 (() (make-list len #f))
158 ((lst ...) (map string->number lst)))
159 nar-hash
160 (and=> nar-size string->number)
161 (string-tokenize references)
162 (match deriver
163 ((or #f "") #f) 147 ((or #f "") #f)
164 (_ deriver)) 148 (_ deriver))))
165 system 149 ;; Return #f if PATH, REFERENCES, or DERIVER is malformed.
166 (false-if-exception 150 (and (valid-path-syntax? path)
167 (and=> signature narinfo-signature->canonical-sexp)) 151 (every valid-path-basename-syntax? references)
168 str))) 152 (or (not deriver)
153 (valid-path-basename-syntax? deriver))
154 (%make-narinfo path cache-url
155 ;; Handle the case where URL is a relative URL.
156 (map (lambda (url)
157 (or (string->uri url)
158 (string->uri
159 (if (string-suffix? "/" cache-url)
160 (string-append cache-url url)
161 (string-append cache-url "/" url)))))
162 urls)
163 compressions
164 (match file-sizes
165 (() (make-list len #f))
166 ((lst ...) (map string->number lst)))
167 (match file-hashes
168 (() (make-list len #f))
169 ((lst ...) (map string->number lst)))
170 nar-hash
171 (and=> nar-size string->number)
172 references
173 deriver
174 system
175 (false-if-exception
176 (and=> signature narinfo-signature->canonical-sexp))
177 str)))))
169 178
170(define fields->alist 179(define fields->alist
171 ;; The narinfo format is really just like recutils. 180 ;; The narinfo format is really just like recutils.
@@ -176,6 +185,8 @@ must contain the original contents of a narinfo file."
176 "Read a narinfo from PORT. If URL is true, it must be a string used to 185 "Read a narinfo from PORT. If URL is true, it must be a string used to
177build full URIs from relative URIs found while reading PORT. When SIZE is 186build full URIs from relative URIs found while reading PORT. When SIZE is
178true, read at most SIZE bytes from PORT; otherwise, read as much as possible. 187true, read at most SIZE bytes from PORT; otherwise, read as much as possible.
188Return #f if the narinfo that was read is not syntactically valid, for
189instance if it contains invalid store file names.
179 190
180No authentication and authorization checks are performed here!" 191No authentication and authorization checks are performed here!"
181 (let ((str (utf8->string (if size 192 (let ((str (utf8->string (if size
@@ -253,8 +264,8 @@ unauthorized party~%"
253 (call-with-output-string (cut write-narinfo narinfo <>))) 264 (call-with-output-string (cut write-narinfo narinfo <>)))
254 265
255(define (string->narinfo str cache-uri) 266(define (string->narinfo str cache-uri)
256 "Return the narinfo represented by STR. Assume CACHE-URI as the base URI of 267 "Return the narinfo represented by STR or #f if it is not syntactically
257the cache STR originates form." 268valid. Assume CACHE-URI as the base URI of the cache STR originates form."
258 (call-with-input-string str (cut read-narinfo <> cache-uri))) 269 (call-with-input-string str (cut read-narinfo <> cache-uri)))
259 270
260(define (equivalent-narinfo? narinfo1 narinfo2) 271(define (equivalent-narinfo? narinfo1 narinfo2)
diff --git a/guix/substitutes.scm b/guix/substitutes.scm
index df4677ab7d4..b2a79c2a48d 100644
--- a/guix/substitutes.scm
+++ b/guix/substitutes.scm
@@ -193,7 +193,8 @@ indicates that PATH is unavailable at CACHE-URL."
193 193
194(define (narinfo-from-file file url) 194(define (narinfo-from-file file url)
195 "Attempt to read a narinfo from FILE, using URL as the cache URL. Return #f 195 "Attempt to read a narinfo from FILE, using URL as the cache URL. Return #f
196if file doesn't exist, and the narinfo otherwise." 196if file doesn't exist or if the narinfo read is not syntactically valid--e.g.,
197it contains invalid store file names--and return the narinfo otherwise."
197 (catch 'system-error 198 (catch 'system-error
198 (lambda () 199 (lambda ()
199 (call-with-input-file file 200 (call-with-input-file file
@@ -239,8 +240,7 @@ if file doesn't exist, and the narinfo otherwise."
239 ;; belong to the next response. 240 ;; belong to the next response.
240 (if (= code 200) ; hit 241 (if (= code 200) ; hit
241 (let ((narinfo (read-narinfo port url #:size len))) 242 (let ((narinfo (read-narinfo port url #:size len)))
242 (if (string=? (dirname (narinfo-path narinfo)) 243 (if narinfo
243 (%store-prefix))
244 (begin 244 (begin
245 (cache-narinfo! url (narinfo-path narinfo) narinfo ttl) 245 (cache-narinfo! url (narinfo-path narinfo) narinfo ttl)
246 (cons narinfo result)) 246 (cons narinfo result))
@@ -324,7 +324,10 @@ for PATH."
324 ;; A cached positive lookup 324 ;; A cached positive lookup
325 (if (obsolete? date now ttl) 325 (if (obsolete? date now ttl)
326 (values #f #f) 326 (values #f #f)
327 (values #t (string->narinfo value cache-uri)))) 327 (let ((narinfo (string->narinfo value cache-uri)))
328 (if narinfo
329 (values #t narinfo)
330 (values #f #f)))))
328 (('narinfo ('version v) _ ...) 331 (('narinfo ('version v) _ ...)
329 (values #f #f)) 332 (values #f #f))
330 ((? eof-object?) ;corrupt file 333 ((? eof-object?) ;corrupt file
diff --git a/tests/substitute.scm b/tests/substitute.scm
index 6837e7e868e..8f32bfa7281 100644
--- a/tests/substitute.scm
+++ b/tests/substitute.scm
@@ -1,6 +1,6 @@
1;;; GNU Guix --- Functional package management for GNU 1;;; GNU Guix --- Functional package management for GNU
2;;; Copyright © 2014 Nikita Karetnikov <nikita@karetnikov.org> 2;;; Copyright © 2014 Nikita Karetnikov <nikita@karetnikov.org>
3;;; Copyright © 2014-2015, 2017-2019, 2021-2023 Ludovic Courtès <ludo@gnu.org> 3;;; Copyright © 2014-2015, 2017-2019, 2021-2023, 2026 Ludovic Courtès <ludo@gnu.org>
4;;; 4;;;
5;;; This file is part of GNU Guix. 5;;; This file is part of GNU Guix.
6;;; 6;;;
@@ -333,6 +333,30 @@ Deriver: aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa-foo.drv")
333 (lambda () 333 (lambda ()
334 (guix-substitute "--query"))))))))) 334 (guix-substitute "--query")))))))))
335 335
336(test-equal "query narinfo that contains invalid store path"
337 ;; The signature covers the StorePath/NarHash/References tuple, so it is
338 ;; valid, but the 'StorePath' field is invalid (contains forbidden
339 ;; characters).
340 ""
341
342 (let ((prefix (string-append "StorePath: " (%store-prefix)
343 "/aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa-foo/../../../etc/passwd
344NarHash: sha256:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
345References: bar baz\n")))
346 (with-narinfo (string-append prefix
347 "Signature: " (signature-field prefix) "
348URL: example.nar
349Compression: none
350NarSize: 42
351Deriver: foo.drv")
352 (string-trim-both
353 (with-output-to-string
354 (lambda ()
355 (with-input-from-string (string-append "have " (%store-prefix)
356 "/aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa-foo")
357 (lambda ()
358 (guix-substitute "--query")))))))))
359
336(test-equal "query narinfo signed with authorized key" 360(test-equal "query narinfo signed with authorized key"
337 (string-append (%store-prefix) "/aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa-foo") 361 (string-append (%store-prefix) "/aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa-foo")
338 362