File: varstore-endianness.patch

package info (click to toggle)
virt-firmware 25.10-2
  • links: PTS, VCS
  • area: main
  • in suites: sid
  • size: 1,016 kB
  • sloc: python: 4,905; sh: 366; makefile: 75
file content (77 lines) | stat: -rw-r--r-- 3,398 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
Author: Michael Tokarev <mjt@tls.msk.ru>
Origin: https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=1121761#5
Bug: https://gitlab.com/kraxel/virt-firmware/-/issues/18
Bug-Debian: https://bugs.debian.org/1121761
Last-Updated: 2025-12-02

There's a bug in virt/firmware/varstore/edk2.py when
reading varstore images, - it uses native endiannes
instead of little-endian.

    def parse_volume(self):
        ...
        (vlen, sig, attr, hlen, csum, xoff, rev, blocks, blksize) = \
            struct.unpack_from("=QLLHHHxBLL", self.filedata, offset + 32)
        logging.debug('vol=%s vlen=0x%x rev=%d blocks=%d*%d (0x%x)',
                      guids.name(guid), vlen, rev,
                      blocks, blksize, blocks * blksize)
        if sig != 0x4856465f:
            logging.error('%s: not a firmware volume', self.filename)
            sys.exit(1)

When reading AAVMF_VARS.fd, on a little-endian system, this results in:

 DEBUG:root:vol=guid:NvData vlen=0xc0000 rev=2 blocks=3*262144 (0xc0000)

The same code and input, when run on s390x, results in:

 DEBUG:root:vol=guid:NvData vlen=0xc0000000000 rev=2 blocks=50331648*1024 (0xc00000000)
 ERROR:root:AAVMF_VARS.fd: not a firmware volume

The unpack_from() call should have "<" (little-endian) as the first symbol
instead of "=" (native-endian), since it is reading an image defined as
having little-endian characteristics.

See two edk2 debci runs, on amd64 (sucessful) and on s390x (failed):
https://ci.debian.net/packages/e/edk2/testing/amd64/66712410/
https://ci.debian.net/packages/e/edk2/testing/s390x/66711962/

There are other places in this file where the same "=" (native) conversion
is used, - these should probably be fixed too.

Attached is a small patch (untested yet) which should fix this.

Thanks,

/mjt

diff --git a/virt/firmware/varstore/edk2.py b/virt/firmware/varstore/edk2.py
index 33b2738..54db6e1 100644
--- a/virt/firmware/varstore/edk2.py
+++ b/virt/firmware/varstore/edk2.py
@@ -62,5 +62,5 @@ class Edk2VarStore:
         guid = guids.parse_bin(self.filedata, offset + 16)
         (vlen, sig, attr, hlen, csum, xoff, rev, blocks, blksize) = \
-            struct.unpack_from("=QLLHHHxBLL", self.filedata, offset + 32)
+            struct.unpack_from("<QLLHHHxBLL", self.filedata, offset + 32)
         logging.debug('vol=%s vlen=0x%x rev=%d blocks=%d*%d (0x%x)',
                       guids.name(guid), vlen, rev,
@@ -76,5 +76,5 @@ class Edk2VarStore:
     def parse_varstore(self, start):
         guid = guids.parse_bin(self.filedata, start)
-        (size, storefmt, state) = struct.unpack_from("=LBB", self.filedata, start + 16)
+        (size, storefmt, state) = struct.unpack_from("<LBB", self.filedata, start + 16)
         logging.debug('varstore=%s size=0x%x format=0x%x state=0x%x',
                       guids.name(guid), size, storefmt, state)
@@ -97,8 +97,8 @@ class Edk2VarStore:
         varlist = efivar.EfiVarList()
         while pos < self.end:
-            (magic, state, attr, count) = struct.unpack_from("=HBxLQ", self.filedata, pos)
+            (magic, state, attr, count) = struct.unpack_from("<HBxLQ", self.filedata, pos)
             if magic != 0x55aa:
                 break
-            (pk, nsize, dsize) = struct.unpack_from("=LLL", self.filedata, pos + 32)
+            (pk, nsize, dsize) = struct.unpack_from("<LLL", self.filedata, pos + 32)
 
             if state == 0x3f: