A modern Music Player Daemon based on Rockbox open source high quality audio player
libadwaita audio rust zig deno mpris rockbox mpd

rockbox: fix iriver firmware validation for larger bootloaders

It turns out the code for the firmware size validation was incorrectly
using the total length of the firmware file to check if it was too big
for the flash rom which caused it to incorrectly flag larger bootloaders
as too big even though they would still fit.

As it happens this situation can only really arise after mkboot has been
run on the decoded firmware image. Because mkboot writes the actual binary
size to the ESTFBINR header we will be using that to check if the firmware
image is too large for the flash rom.

Now because this information is embedded in the decrypted / encrypted
region we have to collect it as the region is processed so the validation
is also moved to after the data processing loop.

Change-Id: I8bfead73812fe4e59f08fbbe8956790604dcb4e2

+103 -25
+47 -10
tools/fwpatcher/iriver.c
··· 101 101 FILE * outfile = NULL; 102 102 int i = -1; 103 103 unsigned char headerdata[512]; 104 - unsigned long dwLength1, dwLength2, dwLength3, fp = 0; 104 + unsigned int dwLength1, dwLength2, dwLength3, fp = 0; 105 + unsigned int minsize, maxsize, sizes[2]; 105 106 unsigned char blockdata[16+16]; 106 107 unsigned char out[16]; 107 108 unsigned char newmunge; ··· 138 139 dwLength3 = headerdata[8] | (headerdata[9]<<8) | 139 140 (headerdata[10]<<16) | (headerdata[11]<<24); 140 141 141 - if( dwLength1 < firmware_minsize[ i ] || 142 - dwLength1 > firmware_maxsize[ i ] || 143 - dwLength2 < firmware_minsize[ i ] || 144 - dwLength2 > dwLength1 || 142 + if( dwLength2 > dwLength1 || 145 143 dwLength3 > dwLength1 || 146 144 dwLength2>>9 != dwLength3 || 147 145 dwLength2+dwLength3+512 != dwLength1 ) ··· 151 149 goto error; 152 150 }; 153 151 152 + minsize = firmware_minsize[i]; 153 + maxsize = firmware_maxsize[i]; 154 + sizes[0] = sizes[1] = 0; 155 + 154 156 pChecksums = ppChecksums = (unsigned char *)( malloc( dwLength3 ) ); 155 157 156 158 if( modify ) ··· 177 179 ck += out[i]; 178 180 } 179 181 182 + if (fp <= 32) 183 + sizes[fp / 16 - 1] = (out[0] << 24) | 184 + (out[1] << 16) | 185 + (out[2] << 8) | 186 + (out[3] << 0); 187 + 180 188 if( fp > ESTF_SIZE || stripmode != STRIP_HEADER_CHECKSUM_ESTF ) 181 189 { 182 190 fwrite( out+4, 1, 12, outfile ); ··· 202 210 } 203 211 else 204 212 s+=16; 213 + }; 214 + 215 + if( sizes[0] < minsize || 216 + sizes[1] < minsize || 217 + sizes[0] > maxsize || 218 + sizes[1] > maxsize ) 219 + { 220 + fprintf( stderr, "This doesn't look like a valid encrypted " 221 + "iHP firmware - reason: ESTFBINR 'length' data\n" ); 222 + goto error; 205 223 }; 206 224 207 225 if( fp != dwLength2 ) ··· 269 287 FILE * outfile = NULL; 270 288 int i = -1; 271 289 unsigned char headerdata[512]; 272 - unsigned long dwLength1, dwLength2, dwLength3, fp = 0; 290 + unsigned int dwLength1, dwLength2, dwLength3, fp = 0; 291 + unsigned int minsize, maxsize, sizes[2]; 273 292 unsigned char blockdata[16+16]; 274 293 unsigned char out[16]; 275 294 unsigned char newmunge; ··· 313 332 dwLength3 = headerdata[8] | (headerdata[9]<<8) | 314 333 (headerdata[10]<<16) | (headerdata[11]<<24); 315 334 316 - if( dwLength1 < firmware_minsize[i] || 317 - dwLength1 > firmware_maxsize[i] || 318 - dwLength2 < firmware_minsize[i] || 319 - dwLength2 > dwLength1 || 335 + if( dwLength2 > dwLength1 || 320 336 dwLength3 > dwLength1 || 321 337 dwLength2+dwLength3+512 != dwLength1 ) 322 338 { ··· 325 341 goto error; 326 342 }; 327 343 344 + minsize = firmware_minsize[i]; 345 + maxsize = firmware_maxsize[i]; 346 + sizes[0] = sizes[1] = 0; 347 + 328 348 pChecksums = ppChecksums = (unsigned char *)( malloc( dwLength3 ) ); 329 349 330 350 fwrite( headerdata, 512, 1, outfile ); ··· 335 355 ( lenread = fread( blockdata+16, 1, 16, infile ) ) == 16 ) 336 356 { 337 357 fp += 16; 358 + 359 + if (fp <= 32) 360 + sizes[fp / 16 - 1] = (blockdata[28] << 24) | 361 + (blockdata[29] << 16) | 362 + (blockdata[30] << 8) | 363 + (blockdata[31] << 0); 364 + 338 365 for( i=0; i<16; ++i ) 339 366 { 340 367 newmunge = blockdata[16+((12+i)&0xf)] ^ blockdata[i]; ··· 353 380 } 354 381 else 355 382 s+=16; 383 + }; 384 + 385 + if( sizes[0] < minsize || 386 + sizes[1] < minsize || 387 + sizes[0] > maxsize || 388 + sizes[1] > maxsize ) 389 + { 390 + fprintf( stderr, "This doesn't look like a valid decoded iHP" 391 + " firmware - reason: ESTFBINR 'length' data\n" ); 392 + goto error; 356 393 }; 357 394 358 395 if( fp != dwLength2 )
+56 -15
tools/iriver.c
··· 103 103 FILE * outfile = NULL; 104 104 int i = -1; 105 105 unsigned char headerdata[512]; 106 - unsigned long dwLength1, dwLength2, dwLength3, fp = 0; 106 + unsigned int dwLength1, dwLength2, dwLength3, fp = 0; 107 + unsigned int minsize, maxsize, sizes[2]; 107 108 unsigned char blockdata[16+16]; 108 109 unsigned char out[16]; 109 110 unsigned char newmunge; ··· 143 144 dwLength3 = headerdata[8] | (headerdata[9]<<8) | 144 145 (headerdata[10]<<16) | (headerdata[11]<<24); 145 146 146 - if( dwLength1 < firmware_minsize[ i ] || 147 - dwLength1 > firmware_maxsize[ i ] || 148 - dwLength2 < firmware_minsize[ i ] || 149 - dwLength2 > dwLength1 || 147 + if( dwLength2 > dwLength1 || 150 148 dwLength3 > dwLength1 || 151 149 dwLength2>>9 != dwLength3 || 152 150 dwLength2+dwLength3+512 != dwLength1 ) ··· 158 156 return -3; 159 157 }; 160 158 159 + minsize = firmware_minsize[i]; 160 + maxsize = firmware_maxsize[i]; 161 + sizes[0] = sizes[1] = 0; 162 + 161 163 pChecksums = ppChecksums = (unsigned char *)( malloc( dwLength3 ) ); 162 164 163 165 if( modify ) ··· 183 185 blockdata[i] = newmunge; 184 186 ck += out[i]; 185 187 } 188 + 189 + if (fp <= 32) 190 + sizes[fp / 16 - 1] = (out[0] << 24) | 191 + (out[1] << 16) | 192 + (out[2] << 8) | 193 + (out[3] << 0); 186 194 187 195 if( fp > ESTF_SIZE || stripmode != STRIP_HEADER_CHECKSUM_ESTF ) 188 196 { ··· 211 219 s+=16; 212 220 }; 213 221 222 + if( sizes[0] < minsize || 223 + sizes[1] < minsize || 224 + sizes[0] > maxsize || 225 + sizes[1] > maxsize ) 226 + { 227 + fprintf( stderr, "This doesn't look like a valid encrypted " 228 + "iHP firmware - reason: ESTFBINR 'length' data\n" ); 229 + fclose(infile); 230 + fclose(outfile); 231 + return -4; 232 + }; 233 + 214 234 if( fp != dwLength2 ) 215 235 { 216 236 fprintf( stderr, "This doesn't look like a valid encrypted " 217 237 "iHP firmware - reason: 'length2' mismatch\n" ); 218 238 fclose(infile); 219 239 fclose(outfile); 220 - return -4; 240 + return -5; 221 241 }; 222 242 223 243 fp = 0; ··· 234 254 "iHP firmware - reason: Checksum mismatch!" ); 235 255 fclose(infile); 236 256 fclose(outfile); 237 - return -5; 257 + return -6; 238 258 }; 239 259 ppChecksums += lenread; 240 260 }; ··· 245 265 "iHP firmware - reason: 'length3' mismatch\n" ); 246 266 fclose(infile); 247 267 fclose(outfile); 248 - return -6; 268 + return -7; 249 269 }; 250 270 251 271 ··· 276 296 FILE * outfile = NULL; 277 297 int i = -1; 278 298 unsigned char headerdata[512]; 279 - unsigned long dwLength1, dwLength2, dwLength3, fp = 0; 299 + unsigned int dwLength1, dwLength2, dwLength3, fp = 0; 300 + unsigned int minsize, maxsize, sizes[2]; 280 301 unsigned char blockdata[16+16]; 281 302 unsigned char out[16]; 282 303 unsigned char newmunge; ··· 321 342 dwLength3 = headerdata[8] | (headerdata[9]<<8) | 322 343 (headerdata[10]<<16) | (headerdata[11]<<24); 323 344 324 - if( dwLength1 < firmware_minsize[i] || 325 - dwLength1 > firmware_maxsize[i] || 326 - dwLength2 < firmware_minsize[i] || 327 - dwLength2 > dwLength1 || 345 + if( dwLength2 > dwLength1 || 328 346 dwLength3 > dwLength1 || 329 347 dwLength2+dwLength3+512 != dwLength1 ) 330 348 { ··· 335 353 return -3; 336 354 }; 337 355 356 + minsize = firmware_minsize[i]; 357 + maxsize = firmware_maxsize[i]; 358 + sizes[0] = sizes[1] = 0; 359 + 338 360 pChecksums = ppChecksums = (unsigned char *)( malloc( dwLength3 ) ); 339 361 340 362 fwrite( headerdata, 512, 1, outfile ); ··· 345 367 ( lenread = fread( blockdata+16, 1, 16, infile ) ) == 16 ) 346 368 { 347 369 fp += 16; 370 + 371 + if (fp <= 32) 372 + sizes[fp / 16 - 1] = (blockdata[28] << 24) | 373 + (blockdata[29] << 16) | 374 + (blockdata[30] << 8) | 375 + (blockdata[31] << 0); 376 + 348 377 for( i=0; i<16; ++i ) 349 378 { 350 379 newmunge = blockdata[16+((12+i)&0xf)] ^ blockdata[i]; ··· 365 394 s+=16; 366 395 }; 367 396 397 + if( sizes[0] < minsize || 398 + sizes[1] < minsize || 399 + sizes[0] > maxsize || 400 + sizes[1] > maxsize ) 401 + { 402 + fprintf( stderr, "This doesn't look like a valid decoded iHP" 403 + " firmware - reason: ESTFBINR 'length' data\n" ); 404 + fclose(infile); 405 + fclose(outfile); 406 + return -4; 407 + }; 408 + 368 409 if( fp != dwLength2 ) 369 410 { 370 411 fprintf( stderr, "This doesn't look like a valid decoded " 371 412 "iHP firmware - reason: 'length1' mismatch\n" ); 372 413 fclose(infile); 373 414 fclose(outfile); 374 - return -4; 415 + return -5; 375 416 }; 376 417 377 418 /* write out remainder w/out applying descrambler */ ··· 392 433 "iHP firmware - reason: 'length2' mismatch\n" ); 393 434 fclose(infile); 394 435 fclose(outfile); 395 - return -5; 436 + return -6; 396 437 }; 397 438 398 439 fprintf( stderr, "File encoded successfully and checksum table built!\n" );