~ruther/guix-local

2fe4ceee18f8687de8520d28dbfefc7bc3a7e084 — Ludovic Courtès 9 years ago 69f2b3b
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.
1 files changed, 22 insertions(+), 11 deletions(-)

M gnu/build/file-systems.scm
M gnu/build/file-systems.scm => gnu/build/file-systems.scm +22 -11
@@ 1,5 1,5 @@
;;; 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>
;;;
;;; This file is part of GNU Guix.


@@ 72,22 72,33 @@
  "Bind-mount SOURCE at TARGET."
  (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?)
  "Read a superblock of SIZE from OFFSET and DEVICE.  Return the raw
superblock on success, and #f if no valid superblock was found.  MAGIC?
takes a bytevector and returns #t when it's a valid superblock."
  (call-with-input-file device
    (lambda (port)
      (seek port offset SEEK_SET)

      (let ((block (make-bytevector size)))
        (match (get-bytevector-n! port block 0 (bytevector-length block))
          ((? eof-object?)
           #f)
          ((? number? len)
           (and (= len (bytevector-length block))
                (and (magic? block)
                     block))))))))
      (and (= offset (seek* port offset SEEK_SET))
           (let ((block (make-bytevector size)))
             (match (get-bytevector-n! port block 0 (bytevector-length block))
               ((? eof-object?)
                #f)
               ((? number? len)
                (and (= len (bytevector-length block))
                     (and (magic? block)
                          block)))))))))

(define (sub-bytevector bv start size)
  "Return a copy of the SIZE bytes of BV starting from offset START."