~mirabilos/klibc/master

« back to all changes in this revision

Viewing changes to usr/utils/cpio.c

  • Committer: Ben Hutchings
  • Date: 2021-04-29 14:02:58 UTC
  • Revision ID: git-v1:9b1c91577aef7f2e72c3aa11a27749160bd278ff
[klibc] cpio: Fix possible integer overflow on 32-bit systems

The maximum name and file sizes in the "new" header format are 32-bit
unsigned values.  However, the I/O functions mostly use long for sizes
and offsets, so that sizes >= 2^31 are handled wrongly on 32-bit
systems.

The current GNU cpio code doesn't seem to have this problem, but the
divergence between this version and that is large enough that I can't
simply cherry-pick a fix for it.

As a short-term fix, in read_in_new_ascii(), fail if c_namesize or
c_filesize is > LONG_MAX.

CVE-2021-31872

Signed-off-by: Ben Hutchings <ben@decadent.org.uk>

Show diffs side-by-side

added added

removed removed

Lines of Context:
17
17
 
18
18
#include <errno.h>
19
19
#include <fcntl.h>
 
20
#include <limits.h>
20
21
#include <malloc.h>
21
22
#include <stdbool.h>
22
23
#include <stdio.h>
904
905
                file_hdr->c_hdr[i] = strtoul(hexbuf, NULL, 16);
905
906
                ah += 8;
906
907
        }
 
908
 
 
909
        /* Sizes > LONG_MAX can currently result in integer overflow
 
910
           in various places.  Fail if name is too large. */
 
911
        if (file_hdr->c_namesize > LONG_MAX) {
 
912
                fprintf(stderr, "%s: name size out of range\n",
 
913
                        progname);
 
914
                exit(1);
 
915
        }
 
916
 
907
917
        /* Read file name from input.  */
908
918
        free(file_hdr->c_name);
909
919
        file_hdr->c_name = (char *)xmalloc(file_hdr->c_namesize);
914
924
           is rounded up to the next long-word, so we might need to drop
915
925
           1-3 bytes.  */
916
926
        tape_skip_padding(in_des, file_hdr->c_namesize + 110);
 
927
 
 
928
        /* Fail if file is too large.  We could check this earlier
 
929
           but it's helpful to report the name. */
 
930
        if (file_hdr->c_filesize > LONG_MAX) {
 
931
                fprintf(stderr, "%s: %s: file size out of range\n",
 
932
                        progname, file_hdr->c_name);
 
933
                exit(1);
 
934
        }
917
935
}
918
936
 
919
937
/* Return 16-bit integer I with the bytes swapped.  */