summaryrefslogtreecommitdiffstats
path: root/src/image/gzip.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/image/gzip.c')
-rw-r--r--src/image/gzip.c116
1 files changed, 62 insertions, 54 deletions
diff --git a/src/image/gzip.c b/src/image/gzip.c
index 98376e113..17ccd2492 100644
--- a/src/image/gzip.c
+++ b/src/image/gzip.c
@@ -24,10 +24,10 @@
FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#include <stdlib.h>
+#include <string.h>
#include <errno.h>
#include <assert.h>
#include <ipxe/deflate.h>
-#include <ipxe/uaccess.h>
#include <ipxe/image.h>
#include <ipxe/zlib.h>
#include <ipxe/gzip.h>
@@ -46,85 +46,94 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
* @ret rc Return status code
*/
static int gzip_extract ( struct image *image, struct image *extracted ) {
- struct gzip_header header;
- struct gzip_extra_header extra;
- struct gzip_crc_header crc;
- struct gzip_footer footer;
- struct deflate_chunk in;
- unsigned int strings;
- size_t offset;
+ const struct gzip_header *header;
+ const struct gzip_extra_header *extra;
+ const struct gzip_crc_header *crc;
+ const struct gzip_footer *footer;
+ const void *data;
+ size_t extra_len;
+ size_t string_len;
size_t len;
- off_t nul;
+ unsigned int strings;
int rc;
/* Sanity check */
- assert ( image->len >= ( sizeof ( header ) + sizeof ( footer ) ) );
+ assert ( image->len >= ( sizeof ( *header ) + sizeof ( *footer ) ) );
+ data = image->data;
+ len = image->len;
/* Extract footer */
- len = ( image->len - sizeof ( footer ) );
- copy_from_user ( &footer, image->data, len, sizeof ( footer ) );
+ assert ( len >= sizeof ( *footer ) );
+ len -= sizeof ( *footer );
+ footer = ( data + len );
/* Extract fixed header */
- copy_from_user ( &header, image->data, 0, sizeof ( header ) );
- offset = sizeof ( header );
- assert ( offset <= ( image->len - sizeof ( footer ) ) );
+ assert ( len >= sizeof ( *header ) );
+ header = data;
+ data += sizeof ( *header );
+ len -= sizeof ( *header );
/* Skip extra header, if present */
- if ( header.flags & GZIP_FL_EXTRA ) {
- copy_from_user ( &extra, image->data, offset,
- sizeof ( extra ) );
- offset += sizeof ( extra );
- offset += le16_to_cpu ( extra.len );
- if ( offset > len ) {
- DBGC ( image, "GZIP %p overlength extra header\n",
- image );
+ if ( header->flags & GZIP_FL_EXTRA ) {
+ if ( len < sizeof ( *extra ) ) {
+ DBGC ( image, "GZIP %s overlength extra header\n",
+ image->name );
return -EINVAL;
}
+ extra = data;
+ data += sizeof ( *extra );
+ len -= sizeof ( *extra );
+ extra_len = le16_to_cpu ( extra->len );
+ if ( len < extra_len ) {
+ DBGC ( image, "GZIP %s overlength extra header\n",
+ image->name );
+ return -EINVAL;
+ }
+ data += extra_len;
+ len -= extra_len;
}
- assert ( offset <= ( image->len - sizeof ( footer ) ) );
/* Skip name and/or comment, if present */
strings = 0;
- if ( header.flags & GZIP_FL_NAME )
+ if ( header->flags & GZIP_FL_NAME )
strings++;
- if ( header.flags & GZIP_FL_COMMENT )
+ if ( header->flags & GZIP_FL_COMMENT )
strings++;
while ( strings-- ) {
- nul = memchr_user ( image->data, offset, 0, ( len - offset ) );
- if ( nul < 0 ) {
- DBGC ( image, "GZIP %p overlength name/comment\n",
- image );
+ string_len = strnlen ( data, len );
+ if ( string_len == len ) {
+ DBGC ( image, "GZIP %s overlength name/comment\n",
+ image->name );
return -EINVAL;
}
- offset = ( nul + 1 /* NUL */ );
+ data += ( string_len + 1 /* NUL */ );
+ len -= ( string_len + 1 /* NUL */ );
}
- assert ( offset <= ( image->len - sizeof ( footer ) ) );
/* Skip CRC, if present */
- if ( header.flags & GZIP_FL_HCRC ) {
- offset += sizeof ( crc );
- if ( offset > len ) {
- DBGC ( image, "GZIP %p overlength CRC header\n",
- image );
+ if ( header->flags & GZIP_FL_HCRC ) {
+ if ( len < sizeof ( *crc ) ) {
+ DBGC ( image, "GZIP %s overlength CRC header\n",
+ image->name );
return -EINVAL;
}
+ data += sizeof ( *crc );
+ len -= sizeof ( *crc );
}
- /* Initialise input chunk */
- deflate_chunk_init ( &in, userptr_add ( image->data, offset ), 0, len );
-
/* Presize extracted image */
if ( ( rc = image_set_len ( extracted,
- le32_to_cpu ( footer.len ) ) ) != 0 ) {
- DBGC ( image, "GZIP %p could not presize: %s\n",
- image, strerror ( rc ) );
+ le32_to_cpu ( footer->len ) ) ) != 0 ) {
+ DBGC ( image, "GZIP %s could not presize: %s\n",
+ image->name, strerror ( rc ) );
return rc;
}
/* Decompress image (expanding if necessary) */
- if ( ( rc = zlib_deflate ( DEFLATE_RAW, &in, extracted ) ) != 0 ) {
- DBGC ( image, "GZIP %p could not decompress: %s\n",
- image, strerror ( rc ) );
+ if ( ( rc = zlib_deflate ( DEFLATE_RAW, data, len,
+ extracted ) ) != 0 ) {
+ DBGC ( image, "GZIP %s could not decompress: %s\n",
+ image->name, strerror ( rc ) );
return rc;
}
@@ -138,20 +147,19 @@ static int gzip_extract ( struct image *image, struct image *extracted ) {
* @ret rc Return status code
*/
static int gzip_probe ( struct image *image ) {
- struct gzip_header header;
- struct gzip_footer footer;
+ const struct gzip_header *header;
+ const struct gzip_footer *footer;
/* Sanity check */
- if ( image->len < ( sizeof ( header ) + sizeof ( footer ) ) ) {
- DBGC ( image, "GZIP %p image too short\n", image );
+ if ( image->len < ( sizeof ( *header ) + sizeof ( *footer ) ) ) {
+ DBGC ( image, "GZIP %s image too short\n", image->name );
return -ENOEXEC;
}
+ header = image->data;
/* Check magic header */
- copy_from_user ( &header.magic, image->data, 0,
- sizeof ( header.magic ) );
- if ( header.magic != cpu_to_be16 ( GZIP_MAGIC ) ) {
- DBGC ( image, "GZIP %p invalid magic\n", image );
+ if ( header->magic != cpu_to_be16 ( GZIP_MAGIC ) ) {
+ DBGC ( image, "GZIP %s invalid magic\n", image->name );
return -ENOEXEC;
}