| 1 | #include <linux/zutil.h> | 
|---|
| 2 | #include <linux/errno.h> | 
|---|
| 3 | #include <linux/slab.h> | 
|---|
| 4 | #include <linux/vmalloc.h> | 
|---|
| 5 |  | 
|---|
| 6 | /* Utility function: initialize zlib, unpack binary blob, clean up zlib, | 
|---|
| 7 | * return len or negative error code. | 
|---|
| 8 | */ | 
|---|
| 9 | int zlib_inflate_blob(void *gunzip_buf, unsigned int sz, | 
|---|
| 10 | const void *buf, unsigned int len) | 
|---|
| 11 | { | 
|---|
| 12 | const u8 *zbuf = buf; | 
|---|
| 13 | struct z_stream_s *strm; | 
|---|
| 14 | int rc; | 
|---|
| 15 |  | 
|---|
| 16 | rc = -ENOMEM; | 
|---|
| 17 | strm = kmalloc(sizeof(*strm), GFP_KERNEL); | 
|---|
| 18 | if (strm == NULL) | 
|---|
| 19 | goto gunzip_nomem1; | 
|---|
| 20 | strm->workspace = kmalloc(zlib_inflate_workspacesize(), GFP_KERNEL); | 
|---|
| 21 | if (strm->workspace == NULL) | 
|---|
| 22 | goto gunzip_nomem2; | 
|---|
| 23 |  | 
|---|
| 24 | /* gzip header (1f,8b,08... 10 bytes total + possible asciz filename) | 
|---|
| 25 | * expected to be stripped from input | 
|---|
| 26 | */ | 
|---|
| 27 | strm->next_in = zbuf; | 
|---|
| 28 | strm->avail_in = len; | 
|---|
| 29 | strm->next_out = gunzip_buf; | 
|---|
| 30 | strm->avail_out = sz; | 
|---|
| 31 |  | 
|---|
| 32 | rc = zlib_inflateInit2(strm, windowBits: -MAX_WBITS); | 
|---|
| 33 | if (rc == Z_OK) { | 
|---|
| 34 | rc = zlib_inflate(strm, Z_FINISH); | 
|---|
| 35 | /* after Z_FINISH, only Z_STREAM_END is "we unpacked it all" */ | 
|---|
| 36 | if (rc == Z_STREAM_END) | 
|---|
| 37 | rc = sz - strm->avail_out; | 
|---|
| 38 | else | 
|---|
| 39 | rc = -EINVAL; | 
|---|
| 40 | zlib_inflateEnd(strm); | 
|---|
| 41 | } else | 
|---|
| 42 | rc = -EINVAL; | 
|---|
| 43 |  | 
|---|
| 44 | kfree(objp: strm->workspace); | 
|---|
| 45 | gunzip_nomem2: | 
|---|
| 46 | kfree(objp: strm); | 
|---|
| 47 | gunzip_nomem1: | 
|---|
| 48 | return rc; /* returns Z_OK (0) if successful */ | 
|---|
| 49 | } | 
|---|
| 50 |  | 
|---|