summaryrefslogtreecommitdiff
path: root/usr.bin
diff options
context:
space:
mode:
authorMarc Espie <espie@cvs.openbsd.org>2000-11-27 20:35:28 +0000
committerMarc Espie <espie@cvs.openbsd.org>2000-11-27 20:35:28 +0000
commit51da29376372fc8629fb33ed60a2ee42a0335f56 (patch)
tree533c73e1c7bf986e2fc90908d93c892901694bdd /usr.bin
parent735a8e7b2672cc94a7695f09a2252e973ddf4753 (diff)
This does fix some nasty issues: ar field members are NOT null-terminated.
Hence, read_archive must be very careful to parse stuff correctly: don't use str* when mem* are appropriate, copy numeric fields and ensure they're terminated...
Diffstat (limited to 'usr.bin')
-rw-r--r--usr.bin/make/arch.c122
1 files changed, 68 insertions, 54 deletions
diff --git a/usr.bin/make/arch.c b/usr.bin/make/arch.c
index aa11f1a8bbe..d51eb1b8091 100644
--- a/usr.bin/make/arch.c
+++ b/usr.bin/make/arch.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: arch.c,v 1.40 2000/11/27 18:58:10 espie Exp $ */
+/* $OpenBSD: arch.c,v 1.41 2000/11/27 20:35:27 espie Exp $ */
/* $NetBSD: arch.c,v 1.17 1996/11/06 17:58:59 christos Exp $ */
/*
@@ -135,7 +135,7 @@
static char sccsid[] = "@(#)arch.c 8.2 (Berkeley) 1/2/94";
#else
UNUSED
-static char rcsid[] = "$OpenBSD: arch.c,v 1.40 2000/11/27 18:58:10 espie Exp $";
+static char rcsid[] = "$OpenBSD: arch.c,v 1.41 2000/11/27 20:35:27 espie Exp $";
#endif
#endif /* not lint */
@@ -181,6 +181,7 @@ static struct hash_info arch_info = {
static struct arch_member *new_arch_member __P((struct ar_hdr *, const char *));
static TIMESTAMP mtime_of_member __P((struct arch_member *));
+static long field2long __P((const char *, size_t));
static Arch *read_archive __P((const char *, const char *));
#ifdef CLEANUP
@@ -507,16 +508,28 @@ Arch_ParseArchive(linePtr, nodeLst, ctxt)
return (SUCCESS);
}
+/* Helper function: ar fields are not null terminated. */
+static long
+field2long(field, len)
+ const char *field;
+ size_t len;
+{
+ static char enough[32];
+
+ assert(len < sizeof(enough));
+ memcpy(enough, field, len);
+ enough[len] = '\0';
+ return strtol(enough, NULL, 10);
+}
+
static Arch *
read_archive(archive, end)
const char *archive;
const char *end;
{
- FILE *arch; /* Stream to archive */
- char magic[SARMAG];
- Arch *ar;
- struct ar_hdr arh; /* archive-member header for reading archive */
- char *cp;
+ FILE *arch; /* Stream to archive */
+ char magic[SARMAG];
+ Arch *ar;
#ifdef SVR4ARCHIVES
struct SVR4namelist list;
@@ -524,8 +537,6 @@ read_archive(archive, end)
list.fnametab = NULL;
#endif
-#define AR_MAX_NAME_LEN (sizeof(arh.ar_name)-1)
-
/* When we encounter an archive for the first time, we read its
* whole contents, to place it in the cache. */
arch = fopen(archive, "r");
@@ -534,7 +545,7 @@ read_archive(archive, end)
/* Make sure this is an archive we can handle. */
if ((fread(magic, SARMAG, 1, arch) != 1) ||
- (strncmp(magic, ARMAG, SARMAG) != 0)) {
+ (strncmp(magic, ARMAG, SARMAG) != 0)) {
fclose(arch);
return NULL;
}
@@ -542,39 +553,47 @@ read_archive(archive, end)
ar = hash_create_entry(&arch_info, archive, &end);
hash_init(&ar->members, 8, &members_info);
-
- while (fread((char *)&arh, sizeof (struct ar_hdr), 1, arch) == 1) {
- int size; /* Size of archive member */
+ for (;;) {
+ size_t n;
+ struct ar_hdr arh; /* Archive-member header for reading archive */
+ off_t size; /* Size of archive member */
char buffer[MAXPATHLEN+1];
char *memName;
/* Current member name while hashing. */
+ char *cp; /* Useful character pointer */
+
memName = buffer;
- memName[AR_MAX_NAME_LEN] = '\0';
+ n = fread(&arh, 1, sizeof(struct ar_hdr), arch);
- if (strncmp( arh.ar_fmag, ARFMAG, sizeof (arh.ar_fmag)) != 0) {
- /*
- * The header is bogus, so the archive is bad
- * and there's no way we can recover...
- */
- goto badarch;
- } else {
- /*
- * We need to advance the stream's pointer to the start of the
- * next header. Files are padded with newlines to an even-byte
- * boundary, so we need to extract the size of the file from the
- * 'size' field of the header and round it up during the seek.
- */
- arh.ar_size[sizeof(arh.ar_size)-1] = '\0';
- size = (int) strtol(arh.ar_size, NULL, 10);
+ /* Whole archive read ok. */
+ if (n == 0 && feof(arch)) {
+#ifdef SVR4ARCHIVES
+ efree(list.fnametab);
+#endif
+ fclose(arch);
+ return ar;
+ }
+ if (n < sizeof(struct ar_hdr))
+ break;
- (void) strncpy(memName, arh.ar_name, sizeof(arh.ar_name));
- for (cp = &memName[AR_MAX_NAME_LEN]; *cp == ' '; cp--) {
- continue;
- }
+ if (memcmp(arh.ar_fmag, ARFMAG, sizeof(arh.ar_fmag)) != 0) {
+ /* The header is bogus. */
+ break;
+ } else {
+ /* We need to advance the stream's pointer to the start of the
+ * next header. Records are padded with newlines to an even-byte
+ * boundary, so we need to extract the size of the record and
+ * round it up during the seek. */
+ size = (off_t) field2long(arh.ar_size, sizeof(arh.ar_size));
+
+ (void)memcpy(memName, arh.ar_name, AR_NAME_SIZE);
+ /* Find real end of name (strip extranous ' ') */
+ for (cp = memName + AR_NAME_SIZE - 1; *cp == ' ';)
+ cp--;
cp[1] = '\0';
#ifdef SVR4ARCHIVES
- /* SVR4 names are slash terminated. Also svr4 extended AR format.
+ /* SVR4 names are slash terminated. Also svr4 extended AR format.
*/
if (memName[0] == '/') {
/* SVR4 magic mode. */
@@ -594,24 +613,23 @@ read_archive(archive, end)
#endif
#ifdef AR_EFMT1
- /*
- * BSD 4.4 extended AR format: #1/<namelen>, with name as the
- * first <namelen> bytes of the file
- */
- if (strncmp(memName, AR_EFMT1, sizeof(AR_EFMT1) - 1) == 0 &&
+ /* BSD 4.4 extended AR format: #1/<namelen>, with name as the
+ * first <namelen> bytes of the file. */
+ if (memcmp(memName, AR_EFMT1, sizeof(AR_EFMT1) - 1) == 0 &&
isdigit(memName[sizeof(AR_EFMT1) - 1])) {
- unsigned int elen = atoi(&memName[sizeof(AR_EFMT1)-1]);
-
- if (elen > MAXPATHLEN)
- goto badarch;
- if (fread (memName, elen, 1, arch) != 1)
- goto badarch;
+ int elen = atoi(memName + sizeof(AR_EFMT1)-1);
+
+ if (elen <= 0 || elen > MAXPATHLEN)
+ break;
+ memName = buffer;
+ if (fread(memName, elen, 1, arch) != 1)
+ break;
memName[elen] = '\0';
- fseek(arch, -elen, SEEK_CUR);
- if (DEBUG(ARCH) || DEBUG(MAKE)) {
+ if (fseek(arch, -elen, SEEK_CUR) != 0)
+ break;
+ if (DEBUG(ARCH) || DEBUG(MAKE))
printf("ArchStat: Extended format entry for %s\n", memName);
- }
}
#endif
@@ -619,15 +637,11 @@ read_archive(archive, end)
hash_qlookup(&ar->members, memName),
new_arch_member(&arh, memName));
}
- fseek(arch, (size + 1) & ~1, SEEK_CUR);
+ if (fseek(arch, (size + 1) & ~1, SEEK_CUR) != 0)
+ break;
}
fclose(arch);
-
- return ar;
-
-badarch:
- fclose(arch);
hash_delete(&ar->members);
#ifdef SVR4ARCHIVES
efree(list.fnametab);