Ted Unangst wrote:
> This splits gzip into two processes, such that the heavy lifting is done in a
> process with even fewer privileges. The idea is the child decompresses the
> data and feeds it to the parent over a pipe. There's also a control pipe used
> for some metadata that needs to be passed up.
>
> early version, i'm not sure it's entirely reliable. it does seem to decompress
> some test files, however.
Does anybody really know what time it is?
Does anybody really care?
>
>
> Index: gzopen.c
> ===================================================================
> RCS file: /cvs/src/usr.bin/compress/gzopen.c,v
> retrieving revision 1.34
> diff -u -p -r1.34 gzopen.c
> --- gzopen.c 3 Sep 2016 12:29:30 -0000 1.34
> +++ gzopen.c 3 Sep 2016 15:04:26 -0000
> @@ -92,6 +92,8 @@ struct gz_stream {
> u_int32_t z_hlen; /* length of the gz header */
> u_int64_t z_total_in; /* # bytes in */
> u_int64_t z_total_out; /* # bytes out */
> + int z_pipe[2];
> + int z_ctlpipe[2];
> } gz_stream;
>
> static const u_char gz_magic[2] = {0x1f, 0x8b}; /* gzip magic header */
> @@ -100,10 +102,13 @@ static u_int32_t get_int32(gz_stream *);
> static int get_header(gz_stream *, char *, int);
> static int get_byte(gz_stream *);
>
> +static void childcopier(gz_stream *, char *, int);
> +
> void *
> gz_ropen(int fd, char *name, int gotmagic)
> {
> gz_stream *s;
> + int ok;
>
> if (fd < 0)
> return NULL;
> @@ -126,20 +131,31 @@ gz_ropen(int fd, char *name, int gotmagi
> s->z_crc = crc32(0L, Z_NULL, 0);
> s->z_mode = 'r';
>
> - if (inflateInit2(&(s->z_stream), -MAX_WBITS) != Z_OK) {
> - free (s);
> + if (pipe(s->z_pipe) || pipe(s->z_ctlpipe))
> return NULL;
> - }
> - s->z_stream.next_in = s->z_buf;
> - s->z_stream.avail_out = Z_BUFSIZE;
>
> errno = 0;
> s->z_fd = fd;
>
> - /* read the .gz header */
> - if (get_header(s, name, gotmagic) != 0) {
> - gz_close(s, NULL, NULL, NULL);
> - s = NULL;
> + switch(fork()) {
> + case -1:
> + free(s);
> + return NULL;
> + case 0:
> + close(s->z_pipe[1]);
> + close(s->z_ctlpipe[1]);
> + childcopier(s, name, gotmagic);
> + break;
> + default:
> + close(s->z_pipe[0]);
> + close(s->z_ctlpipe[0]);
> + break;
> + }
> +
> + if (read(s->z_ctlpipe[1], &ok, sizeof(ok)) != sizeof(ok) ||
> + ok != 0) {
> + free(s);
> + return NULL;
> }
>
> return s;
> @@ -260,6 +276,26 @@ int
> gz_read(void *cookie, char *buf, int len)
> {
> gz_stream *s = (gz_stream*)cookie;
> + int amt;
> + int ok;
> +
> + amt = read(s->z_pipe[1], buf, len);
> + if (amt == -1)
> + return -1;
> +
> + if (amt > 0)
> + return amt;
> +
> + if (read(s->z_ctlpipe[1], &ok, sizeof(ok)) != sizeof(ok) ||
> + ok != 0) {
> + return -1;
> + }
> +}
> +
> +int
> +do_gz_read(void *cookie, char *buf, int len)
> +{
> + gz_stream *s = (gz_stream*)cookie;
> u_char *start = buf; /* starting point for crc computation */
> int error = Z_OK;
>
> @@ -330,6 +366,62 @@ bad:
> return (-1);
> }
>
> +static void
> +childcopier(gz_stream *s, char *name, int gotmagic)
> +{
> + struct z_info info;
> + char tmpbuffer[Z_BUFSIZE];
> + int one = 1;
> + int zero = 0;
> + int amt;
> +
> + if (pledge("stdio", NULL) == -1)
> + goto die;
> +
> + if (inflateInit2(&(s->z_stream), -MAX_WBITS) != Z_OK) {
> + goto die;
> + }
> + s->z_stream.next_in = s->z_buf;
> + s->z_stream.avail_out = Z_BUFSIZE;
> +
> + /* read the .gz header */
> + if (get_header(s, name, gotmagic) != 0) {
> + goto die;
> + }
> +
> + write(s->z_ctlpipe[0], &zero, sizeof(zero));
> +
> + while (1) {
> + amt = do_gz_read(s, tmpbuffer, sizeof(tmpbuffer));
> + if (amt == -1)
> + goto die;
> + if (amt == 0)
> + break;
> + while (amt > 0) {
> + int x = write(s->z_pipe[0], tmpbuffer, amt);
> + if (x < 1)
> + goto die;
> + amt -= x;
> + }
> + }
> + close(s->z_pipe[0]);
> + write(s->z_ctlpipe[0], &zero, sizeof(zero));
> +
> + info.mtime = s->z_time;
> + info.crc = s->z_crc;
> + info.hlen = s->z_hlen;
> + info.total_in = s->z_total_in;
> + info.total_out = s->z_total_out;
> +
> + write(s->z_ctlpipe[0], &info, sizeof(info));
> +
> + _exit(0);
> +
> +die:
> + write(s->z_ctlpipe[0], &one, sizeof(one));
> + _exit(1);
> +}
> +
> #ifndef SMALL
> static int
> put_int32(gz_stream *s, u_int32_t x)
> @@ -493,37 +585,35 @@ gz_close(void *cookie, struct z_info *in
> return -1;
>
> #ifndef SMALL
> - if (s->z_mode == 'w' && (err = gz_flush (s, Z_FINISH)) == Z_OK) {
> - if ((err = put_int32 (s, s->z_crc)) == Z_OK) {
> - s->z_hlen += sizeof(int32_t);
> - if ((err = put_int32 (s, s->z_stream.total_in)) == Z_OK)
> + if (s->z_mode == 'w') {
> + if ((err = gz_flush (s, Z_FINISH)) == Z_OK) {
> + if ((err = put_int32 (s, s->z_crc)) == Z_OK) {
> s->z_hlen += sizeof(int32_t);
> + if ((err = put_int32 (s, s->z_stream.total_in))
> == Z_OK)
> + s->z_hlen += sizeof(int32_t);
> + }
> }
> - }
> -#endif
> - if (!err && s->z_stream.state != NULL) {
> - if (s->z_mode == 'w')
> -#ifndef SMALL
> + if (!err && s->z_stream.state != NULL)
> err = deflateEnd(&s->z_stream);
> -#else
> - err = -1;
> -#endif
> - else if (s->z_mode == 'r')
> - err = inflateEnd(&s->z_stream);
> - }
> + if (info != NULL) {
> + info->mtime = s->z_time;
> + info->crc = s->z_crc;
> + info->hlen = s->z_hlen;
> + if (s->z_mode == 'r') {
> + info->total_in = s->z_total_in;
> + info->total_out = s->z_total_out;
> + } else {
> + info->total_in = s->z_stream.total_in;
> + info->total_out = s->z_stream.total_out;
> + }
>
> - if (info != NULL) {
> - info->mtime = s->z_time;
> - info->crc = s->z_crc;
> - info->hlen = s->z_hlen;
> - if (s->z_mode == 'r') {
> - info->total_in = s->z_total_in;
> - info->total_out = s->z_total_out;
> - } else {
> - info->total_in = s->z_stream.total_in;
> - info->total_out = s->z_stream.total_out;
> }
> -
> + } else
> +#endif
> + if (s->z_mode == 'r') {
> + if (info != NULL)
> + if (read(s->z_ctlpipe[1], info, sizeof(*info)) !=
> sizeof(*info))
> + err = -1;
> }
>
> setfile(name, s->z_fd, sb);
> @@ -536,4 +626,3 @@ gz_close(void *cookie, struct z_info *in
>
> return err;
> }
> -
> Index: main.c
> ===================================================================
> RCS file: /cvs/src/usr.bin/compress/main.c,v
> retrieving revision 1.94
> diff -u -p -r1.94 main.c
> --- main.c 3 Sep 2016 13:26:50 -0000 1.94
> +++ main.c 3 Sep 2016 15:04:26 -0000
> @@ -166,7 +166,7 @@ main(int argc, char *argv[])
> char outfile[PATH_MAX], _infile[PATH_MAX], suffix[16];
> int bits, ch, error, rc, cflag, oflag;
>
> - if (pledge("stdio rpath wpath cpath fattr chown", NULL) == -1)
> + if (pledge("stdio rpath wpath cpath fattr chown proc", NULL) == -1)
> err(1, "pledge");
>
> bits = cflag = oflag = 0;
> @@ -332,7 +332,7 @@ main(int argc, char *argv[])
> argv += optind;
>
> if (cflag || testmode || (!oflag && argc == 0))
> - if (pledge("stdio rpath", NULL) == -1)
> + if (pledge("stdio rpath proc", NULL) == -1)
> err(1, "pledge");
>
> if (argc == 0) {