file-systems: Do not read superblocks past the end of a device.

Fixes <http://bugs.gnu.org/25573>.
Reported by Alex Kost <alezost@gmail.com>.

* gnu/build/file-systems.scm (seek*): New procedure.
(read-superblock): Use it instead of 'seek' and ensure it returns
OFFSET.
This commit is contained in:
Ludovic Courtès 2017-01-31 21:52:46 +01:00
parent 69f2b3bdf9
commit 2fe4ceee18
No known key found for this signature in database
GPG key ID: 090B11993D9AEBB5

View file

@ -1,5 +1,5 @@
;;; GNU Guix --- Functional package management for GNU ;;; GNU Guix --- Functional package management for GNU
;;; Copyright © 2014, 2015, 2016 Ludovic Courtès <ludo@gnu.org> ;;; Copyright © 2014, 2015, 2016, 2017 Ludovic Courtès <ludo@gnu.org>
;;; Copyright © 2016, 2017 David Craven <david@craven.ch> ;;; Copyright © 2016, 2017 David Craven <david@craven.ch>
;;; ;;;
;;; This file is part of GNU Guix. ;;; This file is part of GNU Guix.
@ -72,22 +72,33 @@ (define (bind-mount source target)
"Bind-mount SOURCE at TARGET." "Bind-mount SOURCE at TARGET."
(mount source target "" MS_BIND)) (mount source target "" MS_BIND))
(define (seek* fd/port offset whence)
"Like 'seek' but return -1 instead of throwing to 'system-error' upon
EINVAL. This makes it easier to catch cases like OFFSET being too large for
FD/PORT."
(catch 'system-error
(lambda ()
(seek fd/port offset whence))
(lambda args
(if (= EINVAL (system-error-errno args))
-1
(apply throw args)))))
(define (read-superblock device offset size magic?) (define (read-superblock device offset size magic?)
"Read a superblock of SIZE from OFFSET and DEVICE. Return the raw "Read a superblock of SIZE from OFFSET and DEVICE. Return the raw
superblock on success, and #f if no valid superblock was found. MAGIC? superblock on success, and #f if no valid superblock was found. MAGIC?
takes a bytevector and returns #t when it's a valid superblock." takes a bytevector and returns #t when it's a valid superblock."
(call-with-input-file device (call-with-input-file device
(lambda (port) (lambda (port)
(seek port offset SEEK_SET) (and (= offset (seek* port offset SEEK_SET))
(let ((block (make-bytevector size)))
(let ((block (make-bytevector size))) (match (get-bytevector-n! port block 0 (bytevector-length block))
(match (get-bytevector-n! port block 0 (bytevector-length block)) ((? eof-object?)
((? eof-object?) #f)
#f) ((? number? len)
((? number? len) (and (= len (bytevector-length block))
(and (= len (bytevector-length block)) (and (magic? block)
(and (magic? block) block)))))))))
block))))))))
(define (sub-bytevector bv start size) (define (sub-bytevector bv start size)
"Return a copy of the SIZE bytes of BV starting from offset START." "Return a copy of the SIZE bytes of BV starting from offset START."