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) {

Reply via email to