소스 검색

[build] Round up SUBx deltas

The zbin compressor fixup utility rounds down file sizes before
calculating their difference.  This produces incorrect values and may
cause truncated gPXE images to be loaded at boot.

The following example explains the problem:
ilen    = 48 bytes     (uncompressed input file)
olen    = 17 bytes     (compressed output file)
divisor = 16 bytes     (paragraph granularity)
fixmeup = 3 paragraphs (value to fix up)

olen / divisor - ilen / divisor
= 1 - 3
= -2 paragraphs  (old delta calculation)

( align ( olen, divisor ) - align ( ilen, divisor ) ) / divisor
= 2 - 3
= -1 paragraphs  (new delta calculation)

If we perform the SUBx operation with old delta:
fixmeup + -2 = 1 paragraph gets loaded by the prefix

With the new delta:
fixmeup + -1 = 2 paragraphs get loaded by the prefix

The old delta calculation removes the last paragraph; the prefix will
load a truncated copy of gPXE into memory.  We need to load 2
paragraphs since olen is 17 bytes.  Loading only 1 paragraph (16
bytes) would truncate the last byte.

Signed-off-by: Michael Brown <mcb30@etherboot.org>
tags/v0.9.8
Stefan Hajnoczi 15 년 전
부모
커밋
b149a99302
1개의 변경된 파일10개의 추가작업 그리고 7개의 파일을 삭제
  1. 10
    7
      src/util/zbin.c

+ 10
- 7
src/util/zbin.c 파일 보기

@@ -57,6 +57,10 @@ struct zinfo_file {
57 57
 	unsigned int num_entries;
58 58
 };
59 59
 
60
+static unsigned long align ( unsigned long value, unsigned long align ) {
61
+	return ( ( value + align - 1 ) & ~( align - 1 ) );
62
+}
63
+
60 64
 static int read_file ( const char *filename, void **buf, size_t *len ) {
61 65
 	FILE *file;
62 66
 	struct stat stat;
@@ -140,14 +144,13 @@ static int process_zinfo_copy ( struct input_file *input,
140 144
 	struct zinfo_copy *copy = &zinfo->copy;
141 145
 	size_t offset = copy->offset;
142 146
 	size_t len = copy->len;
143
-	unsigned int align = copy->align;
144 147
 
145 148
 	if ( ( offset + len ) > input->len ) {
146 149
 		fprintf ( stderr, "Input buffer overrun on copy\n" );
147 150
 		return -1;
148 151
 	}
149 152
 
150
-	output->len = ( ( output->len + align - 1 ) & ~( align - 1 ) );
153
+	output->len = align ( output->len, copy->align );
151 154
 	if ( ( output->len + len ) > output->max_len ) {
152 155
 		fprintf ( stderr, "Output buffer overrun on copy\n" );
153 156
 		return -1;
@@ -170,7 +173,6 @@ static int process_zinfo_pack ( struct input_file *input,
170 173
 	struct zinfo_pack *pack = &zinfo->pack;
171 174
 	size_t offset = pack->offset;
172 175
 	size_t len = pack->len;
173
-	unsigned int align = pack->align;
174 176
 	unsigned long packed_len;
175 177
 
176 178
 	if ( ( offset + len ) > input->len ) {
@@ -178,7 +180,7 @@ static int process_zinfo_pack ( struct input_file *input,
178 180
 		return -1;
179 181
 	}
180 182
 
181
-	output->len = ( ( output->len + align - 1 ) & ~( align - 1 ) );
183
+	output->len = align ( output->len, pack->align );
182 184
 	if ( output->len > output->max_len ) {
183 185
 		fprintf ( stderr, "Output buffer overrun on pack\n" );
184 186
 		return -1;
@@ -222,8 +224,9 @@ static int process_zinfo_subtract ( struct input_file *input,
222 224
 	}
223 225
 
224 226
 	target = ( output->buf + offset );
225
-	delta = ( ( output->len / subtract->divisor ) -
226
-		  ( input->len / subtract->divisor ) );
227
+	delta = ( ( align ( output->len, subtract->divisor ) -
228
+		    align ( input->len, subtract->divisor ) )
229
+		  / subtract->divisor );
227 230
 
228 231
 	switch ( datasize ) {
229 232
 	case 1: {
@@ -251,7 +254,7 @@ static int process_zinfo_subtract ( struct input_file *input,
251 254
 	}
252 255
 
253 256
 	if ( DEBUG ) {
254
-		fprintf ( stderr, "SUBx [%#zx,%#zx) (%#lx+(%#lx/%#lx)-(%#lx/%#lx)) = %#lx\n",
257
+		fprintf ( stderr, "SUBx [%#zx,%#zx) (%#lx+(%#lx/%#x)-(%#lx/%#x)) = %#lx\n",
255 258
 			  offset, ( offset + datasize ), old, output->len, subtract->divisor,
256 259
 			  input->len, subtract->divisor, new );
257 260
 	}

Loading…
취소
저장