iPXE
gzip.c
Go to the documentation of this file.
1 /*
2  * Copyright (C) 2021 Michael Brown <mbrown@fensystems.co.uk>.
3  *
4  * This program is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU General Public License as
6  * published by the Free Software Foundation; either version 2 of the
7  * License, or any later version.
8  *
9  * This program is distributed in the hope that it will be useful, but
10  * WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12  * General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program; if not, write to the Free Software
16  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
17  * 02110-1301, USA.
18  *
19  * You can also choose to distribute this program under the terms of
20  * the Unmodified Binary Distribution Licence (as given in the file
21  * COPYING.UBDL), provided that you have satisfied its requirements.
22  */
23 
24 FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
25 
26 #include <stdlib.h>
27 #include <errno.h>
28 #include <assert.h>
29 #include <ipxe/deflate.h>
30 #include <ipxe/uaccess.h>
31 #include <ipxe/image.h>
32 #include <ipxe/zlib.h>
33 #include <ipxe/gzip.h>
34 
35 /** @file
36  *
37  * gzip compressed images
38  *
39  */
40 
41 /**
42  * Extract gzip image
43  *
44  * @v image Image
45  * @v extracted Extracted image
46  * @ret rc Return status code
47  */
48 static int gzip_extract ( struct image *image, struct image *extracted ) {
49  struct gzip_header header;
50  struct gzip_extra_header extra;
51  struct gzip_crc_header crc;
52  struct gzip_footer footer;
53  struct deflate_chunk in;
54  unsigned int strings;
55  size_t offset;
56  size_t len;
57  off_t nul;
58  int rc;
59 
60  /* Sanity check */
61  assert ( image->len >= ( sizeof ( header ) + sizeof ( footer ) ) );
62 
63  /* Extract footer */
64  len = ( image->len - sizeof ( footer ) );
65  copy_from_user ( &footer, image->data, len, sizeof ( footer ) );
66 
67  /* Extract fixed header */
68  copy_from_user ( &header, image->data, 0, sizeof ( header ) );
69  offset = sizeof ( header );
70  assert ( offset <= ( image->len - sizeof ( footer ) ) );
71 
72  /* Skip extra header, if present */
73  if ( header.flags & GZIP_FL_EXTRA ) {
75  sizeof ( extra ) );
76  offset += sizeof ( extra );
77  offset += le16_to_cpu ( extra.len );
78  if ( offset > len ) {
79  DBGC ( image, "GZIP %p overlength extra header\n",
80  image );
81  return -EINVAL;
82  }
83  }
84  assert ( offset <= ( image->len - sizeof ( footer ) ) );
85 
86  /* Skip name and/or comment, if present */
87  strings = 0;
88  if ( header.flags & GZIP_FL_NAME )
89  strings++;
91  strings++;
92  while ( strings-- ) {
93  nul = memchr_user ( image->data, offset, 0, ( len - offset ) );
94  if ( nul < 0 ) {
95  DBGC ( image, "GZIP %p overlength name/comment\n",
96  image );
97  return -EINVAL;
98  }
99  offset = ( nul + 1 /* NUL */ );
100  }
101  assert ( offset <= ( image->len - sizeof ( footer ) ) );
102 
103  /* Skip CRC, if present */
104  if ( header.flags & GZIP_FL_HCRC ) {
105  offset += sizeof ( crc );
106  if ( offset > len ) {
107  DBGC ( image, "GZIP %p overlength CRC header\n",
108  image );
109  return -EINVAL;
110  }
111  }
112 
113  /* Initialise input chunk */
114  deflate_chunk_init ( &in, userptr_add ( image->data, offset ), 0, len );
115 
116  /* Presize extracted image */
117  if ( ( rc = image_set_len ( extracted,
118  le32_to_cpu ( footer.len ) ) ) != 0 ) {
119  DBGC ( image, "GZIP %p could not presize: %s\n",
120  image, strerror ( rc ) );
121  return rc;
122  }
123 
124  /* Decompress image (expanding if necessary) */
125  if ( ( rc = zlib_deflate ( DEFLATE_RAW, &in, extracted ) ) != 0 ) {
126  DBGC ( image, "GZIP %p could not decompress: %s\n",
127  image, strerror ( rc ) );
128  return rc;
129  }
130 
131  return 0;
132 }
133 
134 /**
135  * Probe gzip image
136  *
137  * @v image gzip image
138  * @ret rc Return status code
139  */
140 static int gzip_probe ( struct image *image ) {
141  struct gzip_header header;
142  struct gzip_footer footer;
143 
144  /* Sanity check */
145  if ( image->len < ( sizeof ( header ) + sizeof ( footer ) ) ) {
146  DBGC ( image, "GZIP %p image too short\n", image );
147  return -ENOEXEC;
148  }
149 
150  /* Check magic header */
151  copy_from_user ( &header.magic, image->data, 0,
152  sizeof ( header.magic ) );
153  if ( header.magic != cpu_to_be16 ( GZIP_MAGIC ) ) {
154  DBGC ( image, "GZIP %p invalid magic\n", image );
155  return -ENOEXEC;
156  }
157 
158  return 0;
159 }
160 
161 /** gzip image type */
162 struct image_type gzip_image_type __image_type ( PROBE_NORMAL ) = {
163  .name = "gzip",
164  .probe = gzip_probe,
165  .extract = gzip_extract,
166  .exec = image_extract_exec,
167 };
#define cpu_to_be16(value)
Definition: byteswap.h:109
#define EINVAL
Invalid argument.
Definition: errno.h:428
struct arbelprm_rc_send_wqe rc
Definition: arbel.h:14
uint16_t crc
CRC-16.
Definition: gzip.h:58
userptr_t data
Raw file image.
Definition: image.h:41
__be32 in[4]
Definition: CIB_PRM.h:35
gzip extra header
Definition: gzip.h:50
#define le32_to_cpu(value)
Definition: byteswap.h:113
#define GZIP_FL_NAME
File name is present.
Definition: gzip.h:44
Error codes.
off_t memchr_user(userptr_t userptr, off_t offset, int c, size_t len)
Find character in user buffer.
uint8_t extra
Signature extra byte.
Definition: smbios.h:17
#define ENOEXEC
Exec format error.
Definition: errno.h:519
static __always_inline void copy_from_user(void *dest, userptr_t src, off_t src_off, size_t len)
Copy data from user buffer.
Definition: uaccess.h:337
#define GZIP_FL_HCRC
CRC header is present.
Definition: gzip.h:38
#define DBGC(...)
Definition: compiler.h:505
An executable image type.
Definition: image.h:76
#define PROBE_NORMAL
Normal image probe priority.
Definition: image.h:137
An executable image.
Definition: image.h:24
struct image_type gzip_image_type __image_type(PROBE_NORMAL)
gzip image type
Access to external ("user") memory.
gzip header
Definition: gzip.h:16
char * name
Name of this image type.
Definition: image.h:78
A chunk of data.
Definition: deflate.h:241
userptr_t userptr_add(userptr_t userptr, off_t offset)
Add offset to user pointer.
Assertions.
gzip CRC header
Definition: gzip.h:56
assert((readw(&hdr->flags) &(GTF_reading|GTF_writing))==0)
zlib compressed images
gzip compressed images
Executable images.
static userptr_t size_t offset
Offset of the first segment within the content.
Definition: deflate.h:259
#define GZIP_FL_EXTRA
Extra header is present.
Definition: gzip.h:41
static int gzip_probe(struct image *image)
Probe gzip image.
Definition: gzip.c:140
uint8_t flags
Flags.
Definition: ena.h:92
int zlib_deflate(enum deflate_format format, struct deflate_chunk *in, struct image *extracted)
Extract compressed data to image.
Definition: zlib.c:48
char * strerror(int errno)
Retrieve string representation of error number.
Definition: strerror.c:78
size_t len
Length of raw file image.
Definition: image.h:43
#define GZIP_MAGIC
Magic ID.
Definition: gzip.h:32
FILE_LICENCE(GPL2_OR_LATER_OR_UBDL)
static int gzip_extract(struct image *image, struct image *extracted)
Extract gzip image.
Definition: gzip.c:48
#define le16_to_cpu(value)
Definition: byteswap.h:112
signed long off_t
Definition: stdint.h:8
int image_set_len(struct image *image, size_t len)
Set image length.
Definition: image.c:201
Raw DEFLATE data (no header or footer)
Definition: deflate.h:19
uint32_t len
Length.
Definition: ena.h:14
struct ena_aq_header header
Header.
Definition: ena.h:12
#define GZIP_FL_COMMENT
File comment is present.
Definition: gzip.h:47
DEFLATE decompression algorithm.
int image_extract_exec(struct image *image)
Extract and execute image.
Definition: archive.c:110