Fix logical bug in the bzip2 reading code, which results in bogus EIO
returned on a perfectly valid bzip2 stream whose decompressed size is multiple of read-ahead buffer size. Reproduce the problem is easy: create some power-of-two sized file (truncate -s 1m file will do), bzip2 it and try to load it as md_image from loader. See how it fails. The bug doesn't affect gzip code (which most of bzip2-reading code was copied from) probably due to the fact that libgzip doesn't report Z_STREAM_END with the last block, but requires extra call to inflate() to retrieve it and has some extra data in the input stream at that time. However, apply similar fix to gzipfs.c just in the case the API will change in the future to do what bzip2 code does. Add some ifdef'ed code to enable testing bzipfs.c from witin normal FreeBSD environment as opposed to the restricted loader one, so that one can use gdb and whatnot. Sponsored by: Sippy Software, Inc., http://www.sippysoft.com/ MFC in: 7 days
This commit is contained in:
parent
83073fcba3
commit
056c1a0528
Notes:
svn2git
2020-12-20 02:59:44 +00:00
svn path=/head/; revision=174741
@ -28,7 +28,23 @@
|
||||
#include <sys/cdefs.h>
|
||||
__FBSDID("$FreeBSD$");
|
||||
|
||||
#ifndef REGRESSION
|
||||
#include "stand.h"
|
||||
#else
|
||||
#include <sys/errno.h>
|
||||
#include <sys/fcntl.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/unistd.h>
|
||||
|
||||
struct open_file {
|
||||
int f_flags; /* see F_* below */
|
||||
void *f_fsdata; /* file system specific data */
|
||||
};
|
||||
#define F_READ 0x0001 /* file opened for reading */
|
||||
#define EOFFSET (ELAST+8) /* relative seek not supported */
|
||||
static inline u_int min(u_int a, u_int b) { return (a < b ? a : b); }
|
||||
#define panic(x, y) abort()
|
||||
#endif
|
||||
|
||||
#include <sys/stat.h>
|
||||
#include <string.h>
|
||||
@ -41,6 +57,7 @@ struct bz_file
|
||||
int bzf_rawfd;
|
||||
bz_stream bzf_bzstream;
|
||||
char bzf_buf[BZ_BUFSIZE];
|
||||
int bzf_endseen;
|
||||
};
|
||||
|
||||
static int bzf_fill(struct bz_file *z);
|
||||
@ -50,6 +67,7 @@ static int bzf_read(struct open_file *f, void *buf, size_t size, size_t *resid);
|
||||
static off_t bzf_seek(struct open_file *f, off_t offset, int where);
|
||||
static int bzf_stat(struct open_file *f, struct stat *sb);
|
||||
|
||||
#ifndef REGRESSION
|
||||
struct fs_ops bzipfs_fsops = {
|
||||
"bzip",
|
||||
bzf_open,
|
||||
@ -60,6 +78,7 @@ struct fs_ops bzipfs_fsops = {
|
||||
bzf_stat,
|
||||
null_readdir
|
||||
};
|
||||
#endif
|
||||
|
||||
#if 0
|
||||
void *
|
||||
@ -220,7 +239,7 @@ bzf_read(struct open_file *f, void *buf, size_t size, size_t *resid)
|
||||
bzf->bzf_bzstream.next_out = buf; /* where and how much */
|
||||
bzf->bzf_bzstream.avail_out = size;
|
||||
|
||||
while (bzf->bzf_bzstream.avail_out) {
|
||||
while (bzf->bzf_bzstream.avail_out && bzf->bzf_endseen == 0) {
|
||||
if ((bzf->bzf_bzstream.avail_in == 0) && (bzf_fill(bzf) == -1)) {
|
||||
printf("bzf_read: fill error\n");
|
||||
return(EIO);
|
||||
@ -234,6 +253,7 @@ bzf_read(struct open_file *f, void *buf, size_t size, size_t *resid)
|
||||
|
||||
error = BZ2_bzDecompress(&bzf->bzf_bzstream); /* decompression pass */
|
||||
if (error == BZ_STREAM_END) { /* EOF, all done */
|
||||
bzf->bzf_endseen = 1;
|
||||
break;
|
||||
}
|
||||
if (error != BZ_OK) { /* argh, decompression error */
|
||||
@ -301,3 +321,27 @@ bz_internal_error(int errorcode)
|
||||
{
|
||||
panic("bzipfs: critical error %d in bzip2 library occured\n", errorcode);
|
||||
}
|
||||
|
||||
#ifdef REGRESSION
|
||||
/* Small test case, open and decompress test.bz2 */
|
||||
int main()
|
||||
{
|
||||
struct open_file f;
|
||||
char buf[1024];
|
||||
size_t resid;
|
||||
int err;
|
||||
|
||||
memset(&f, '\0', sizeof(f));
|
||||
f.f_flags = F_READ;
|
||||
err = bzf_open("test", &f);
|
||||
if (err != 0)
|
||||
exit(1);
|
||||
do {
|
||||
err = bzf_read(&f, buf, sizeof(buf), &resid);
|
||||
} while (err == 0 && resid != sizeof(buf));
|
||||
|
||||
if (err != 0)
|
||||
exit(2);
|
||||
exit(0);
|
||||
}
|
||||
#endif
|
||||
|
@ -41,6 +41,7 @@ struct z_file
|
||||
off_t zf_dataoffset;
|
||||
z_stream zf_zstream;
|
||||
char zf_buf[Z_BUFSIZE];
|
||||
int zf_endseen;
|
||||
};
|
||||
|
||||
static int zf_fill(struct z_file *z);
|
||||
@ -252,7 +253,7 @@ zf_read(struct open_file *f, void *buf, size_t size, size_t *resid)
|
||||
zf->zf_zstream.next_out = buf; /* where and how much */
|
||||
zf->zf_zstream.avail_out = size;
|
||||
|
||||
while (zf->zf_zstream.avail_out) {
|
||||
while (zf->zf_zstream.avail_out && zf->zf_endseen == 0) {
|
||||
if ((zf->zf_zstream.avail_in == 0) && (zf_fill(zf) == -1)) {
|
||||
printf("zf_read: fill error\n");
|
||||
return(EIO);
|
||||
@ -266,6 +267,7 @@ zf_read(struct open_file *f, void *buf, size_t size, size_t *resid)
|
||||
|
||||
error = inflate(&zf->zf_zstream, Z_SYNC_FLUSH); /* decompression pass */
|
||||
if (error == Z_STREAM_END) { /* EOF, all done */
|
||||
zf->zf_endseen = 1;
|
||||
break;
|
||||
}
|
||||
if (error != Z_OK) { /* argh, decompression error */
|
||||
|
Loading…
Reference in New Issue
Block a user