diff options
| -rw-r--r-- | guix/narinfo.scm | 67 | ||||
| -rw-r--r-- | guix/substitutes.scm | 11 | ||||
| -rw-r--r-- | tests/substitute.scm | 26 |
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 |
| 177 | build full URIs from relative URIs found while reading PORT. When SIZE is | 186 | build full URIs from relative URIs found while reading PORT. When SIZE is |
| 178 | true, read at most SIZE bytes from PORT; otherwise, read as much as possible. | 187 | true, read at most SIZE bytes from PORT; otherwise, read as much as possible. |
| 188 | Return #f if the narinfo that was read is not syntactically valid, for | ||
| 189 | instance if it contains invalid store file names. | ||
| 179 | 190 | ||
| 180 | No authentication and authorization checks are performed here!" | 191 | No 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 |
| 257 | the cache STR originates form." | 268 | valid. 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 |
| 196 | if file doesn't exist, and the narinfo otherwise." | 196 | if file doesn't exist or if the narinfo read is not syntactically valid--e.g., |
| 197 | it 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 | ||
| 344 | NarHash: sha256:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa | ||
| 345 | References: bar baz\n"))) | ||
| 346 | (with-narinfo (string-append prefix | ||
| 347 | "Signature: " (signature-field prefix) " | ||
| 348 | URL: example.nar | ||
| 349 | Compression: none | ||
| 350 | NarSize: 42 | ||
| 351 | Deriver: 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 | ||
