1
0
mirror of https://github.com/nmap/nmap.git synced 2025-12-15 04:09:01 +00:00

Use const and avoid strdup in fingerprint parsing

This commit is contained in:
dmiller
2022-09-13 16:10:05 +00:00
parent f44f255da3
commit 9a494348c5
4 changed files with 72 additions and 78 deletions

142
osscan.cc
View File

@@ -189,9 +189,9 @@ static int AVal_match(const FingerTest *reference, const FingerTest *fprint, con
/* Check for sortedness. */ /* Check for sortedness. */
if (prev_ref != reference->results.end()) if (prev_ref != reference->results.end())
assert(strcmp(prev_ref->attribute, current_ref->attribute) < 0); assert(*prev_ref < *current_ref);
if (prev_fp != fprint->results.end()) if (prev_fp != fprint->results.end())
assert(strcmp(prev_fp->attribute, current_fp->attribute) < 0); assert(*prev_fp < *current_fp);
d = strcmp(current_ref->attribute, current_fp->attribute); d = strcmp(current_ref->attribute, current_fp->attribute);
if (d == 0) { if (d == 0) {
@@ -546,17 +546,27 @@ error:
return -1; return -1;
} }
static std::vector<struct AVal> str2AVal(const char *str) { // Like strchr, but don't go past end. Nulls not handled specially.
static const char *strchr_p(const char *str, const char *end, char c) {
assert(str && end >= str);
for (const char *q = str; q < end; q++) {
if (*q == c)
return q;
}
return NULL;
}
static std::vector<struct AVal> str2AVal(const char *str, const char *end) {
int i = 1; int i = 1;
int count = 1; int count = 1;
const char *q = str, *p=str; const char *q = str, *p=str;
std::vector<struct AVal> AVs; std::vector<struct AVal> AVs;
if (!*str) if (!*str || str == end)
return std::vector<struct AVal>(); return std::vector<struct AVal>();
/* count the AVals */ /* count the AVals */
while ((q = strchr(q, '%'))) { while ((q = strchr_p(q, end, '%'))) {
count++; count++;
q++; q++;
} }
@@ -565,20 +575,20 @@ static std::vector<struct AVal> str2AVal(const char *str) {
for (i = 0; i < count; i++) { for (i = 0; i < count; i++) {
struct AVal av; struct AVal av;
q = strchr(p, '='); q = strchr_p(p, end, '=');
if (!q) { if (!q) {
fatal("Parse error with AVal string (%s) in nmap-os-db file", str); fatal("Parse error with AVal string (%s) in nmap-os-db file", str);
} }
av.attribute = string_pool_substr(p, q); av.attribute = string_pool_substr(p, q);
p = q+1; p = q+1;
if (i < count - 1) { if (i < count - 1) {
q = strchr(p, '%'); q = strchr_p(p, end, '%');
if (!q) { if (!q) {
fatal("Parse error with AVal string (%s) in nmap-os-db file", str); fatal("Parse error with AVal string (%s) in nmap-os-db file", str);
} }
av.value = string_pool_substr(p, q); av.value = string_pool_substr(p, q);
} else { } else {
av.value = string_pool_insert(p); av.value = string_pool_substr(p, end);
} }
p = q + 1; p = q + 1;
AVs.push_back(av); AVs.push_back(av);
@@ -800,30 +810,30 @@ const char *fp2ascii(const FingerPrint *FP) {
/* Parse a 'Class' line found in the fingerprint file into the current /* Parse a 'Class' line found in the fingerprint file into the current
FP. Classno is the number of 'class' lines found so far in the FP. Classno is the number of 'class' lines found so far in the
current fingerprint. The function quits if there is a parse error */ current fingerprint. The function quits if there is a parse error */
static void parse_classline(FingerPrint *FP, char *thisline, int lineno) { static void parse_classline(FingerPrint *FP, const char *thisline, const char *lineend, int lineno) {
const char *begin, *end; const char *begin, *end;
struct OS_Classification os_class; struct OS_Classification os_class;
if (!thisline || strncmp(thisline, "Class ", 6) != 0) if (!thisline || lineend - thisline < 6 || strncmp(thisline, "Class ", 6) != 0)
fatal("Bogus line #%d (%s) passed to %s()", lineno, thisline, __func__); fatal("Bogus line #%d (%.*s) passed to %s()", lineno, (int)(lineend - thisline), thisline, __func__);
/* First let's get the vendor name. */ /* First let's get the vendor name. */
begin = thisline + 6; begin = thisline + 6;
end = strchr(begin, '|'); end = strchr_p(begin, lineend, '|');
if (end == NULL) if (end == NULL)
fatal("Parse error on line %d of fingerprint: %s\n", lineno, thisline); fatal("Parse error on line %d of fingerprint: %s\n", lineno, thisline);
os_class.OS_Vendor = string_pool_substr_strip(begin, end); os_class.OS_Vendor = string_pool_substr_strip(begin, end);
/* Next comes the OS family. */ /* Next comes the OS family. */
begin = end + 1; begin = end + 1;
end = strchr(begin, '|'); end = strchr_p(begin, lineend, '|');
if (end == NULL) if (end == NULL)
fatal("Parse error on line %d of fingerprint: %s\n", lineno, thisline); fatal("Parse error on line %d of fingerprint: %s\n", lineno, thisline);
os_class.OS_Family = string_pool_substr_strip(begin, end); os_class.OS_Family = string_pool_substr_strip(begin, end);
/* And now the the OS generation. */ /* And now the the OS generation. */
begin = end + 1; begin = end + 1;
end = strchr(begin, '|'); end = strchr_p(begin, lineend, '|');
if (end == NULL) if (end == NULL)
fatal("Parse error on line %d of fingerprint: %s\n", lineno, thisline); fatal("Parse error on line %d of fingerprint: %s\n", lineno, thisline);
/* OS generation is handled specially: instead of an empty string it's /* OS generation is handled specially: instead of an empty string it's
@@ -835,15 +845,14 @@ static void parse_classline(FingerPrint *FP, char *thisline, int lineno) {
else else
os_class.OS_Generation = NULL; os_class.OS_Generation = NULL;
/* And finally the device type. We look for '\0' instead of '|'. */ /* And finally the device type. */
begin = end + 1; begin = end + 1;
end = strchr(begin, '\0'); os_class.Device_Type = string_pool_substr_strip(begin, lineend);
os_class.Device_Type = string_pool_substr_strip(begin, end);
FP->match.OS_class.push_back(os_class); FP->match.OS_class.push_back(os_class);
} }
static void parse_cpeline(FingerPrint *FP, char *thisline, int lineno) { static void parse_cpeline(FingerPrint *FP, const char *thisline, const char *lineend, int lineno) {
const char *cpe; const char *cpe;
if (FP->match.OS_class.empty()) if (FP->match.OS_class.empty())
@@ -851,12 +860,12 @@ static void parse_cpeline(FingerPrint *FP, char *thisline, int lineno) {
OS_Classification& osc = FP->match.OS_class.back(); OS_Classification& osc = FP->match.OS_class.back();
if (thisline == NULL || strncmp(thisline, "CPE ", 4) != 0) if (thisline == NULL || lineend - thisline < 4 || strncmp(thisline, "CPE ", 4) != 0)
fatal("Bogus line #%d (%s) passed to %s()", lineno, thisline, __func__); fatal("Bogus line #%d (%.*s) passed to %s()", lineno, (int)(lineend - thisline), thisline, __func__);
/* The cpe part may be followed by whitespace-separated flags (like "auto"), /* The cpe part may be followed by whitespace-separated flags (like "auto"),
which we ignore. */ which we ignore. */
cpe = string_pool_strip_word(thisline + 4); cpe = string_pool_strip_word(thisline + 4, lineend);
assert(cpe != NULL); assert(cpe != NULL);
osc.cpe.push_back(cpe); osc.cpe.push_back(cpe);
} }
@@ -868,11 +877,11 @@ static void parse_cpeline(FingerPrint *FP, char *thisline, int lineno) {
which some partial fingerpritns are OK. */ which some partial fingerpritns are OK. */
/* This function is not currently used by Nmap, but it is present here because /* This function is not currently used by Nmap, but it is present here because
it is used by fingerprint utilities that link with Nmap object files. */ it is used by fingerprint utilities that link with Nmap object files. */
FingerPrint *parse_single_fingerprint(const char *fprint_orig) { FingerPrint *parse_single_fingerprint(const char *fprint) {
int lineno = 0; int lineno = 0;
char *p, *q; const char *p, *q;
char *thisline, *nextline; const char *thisline, *nextline;
char *fprint = strdup(fprint_orig); /* Make a copy we can futz with */ const char * const end = strchr(fprint, '\0');
FingerPrint *FP; FingerPrint *FP;
FP = new FingerPrint; FP = new FingerPrint;
@@ -880,73 +889,61 @@ FingerPrint *parse_single_fingerprint(const char *fprint_orig) {
thisline = fprint; thisline = fprint;
do /* 1 line at a time */ { do /* 1 line at a time */ {
nextline = strchr(thisline, '\n'); nextline = strchr_p(thisline, end, '\n');
if (nextline) if (!nextline)
*nextline++ = '\0'; nextline = end;
/* printf("Preparing to handle next line: %s\n", thisline); */ /* printf("Preparing to handle next line: %s\n", thisline); */
while (*thisline && isspace((int) (unsigned char) *thisline)) while (thisline < nextline && isspace((int) (unsigned char) *thisline))
thisline++; thisline++;
if (!*thisline) { if (thisline >= nextline) {
fatal("Parse error on line %d of fingerprint: %s", lineno, nextline); fatal("Parse error on line %d of fingerprint\n", lineno);
} }
if (strncmp(thisline, "Fingerprint ", 12) == 0) { if (strncmp(thisline, "Fingerprint ", 12) == 0) {
/* Ignore a second Fingerprint line if it appears. */ /* Ignore a second Fingerprint line if it appears. */
if (FP->match.OS_name == NULL) { if (FP->match.OS_name == NULL) {
p = thisline + 12; p = thisline + 12;
while (*p && isspace((int) (unsigned char) *p)) while (p < nextline && isspace((int) (unsigned char) *p))
p++; p++;
q = strchr(p, '\n'); q = nextline ? nextline : end;
if (!q) while (q > p && isspace((int) (unsigned char) *q))
q = p + strlen(p); q--;
while (q > p && isspace((int) (unsigned char) *(--q)))
;
FP->match.OS_name = (char *) cp_alloc(q - p + 2); FP->match.OS_name = cp_strndup(p, q - p);
memcpy(FP->match.OS_name, p, q - p + 1);
FP->match.OS_name[q - p + 1] = '\0';
} }
} else if (strncmp(thisline, "MatchPoints", 11) == 0) { } else if (strncmp(thisline, "MatchPoints", 11) == 0) {
p = thisline + 11; p = thisline + 11;
if (*p && !isspace((int) (unsigned char) *p)) while (p < nextline && isspace((int) (unsigned char) *p))
fatal("Parse error on line %d of fingerprint: %s\n", lineno, thisline);
while (*p && isspace((int) (unsigned char) *p))
p++; p++;
if (*p != '\0') if (p != nextline)
fatal("Parse error on line %d of fingerprint: %s\n", lineno, thisline); fatal("Parse error on line %d of fingerprint: %.*s\n", lineno, (int)(nextline - thisline), thisline);
} else if (strncmp(thisline, "Class ", 6) == 0) { } else if (strncmp(thisline, "Class ", 6) == 0) {
parse_classline(FP, thisline, lineno); parse_classline(FP, thisline, nextline, lineno);
} else if (strncmp(thisline, "CPE ", 4) == 0) { } else if (strncmp(thisline, "CPE ", 4) == 0) {
parse_cpeline(FP, thisline, lineno); parse_cpeline(FP, thisline, nextline, lineno);
} else if ((q = strchr(thisline, '('))) { } else if ((q = strchr_p(thisline, nextline, '('))) {
FingerTest test; FingerTest test;
*q = '\0'; test.name = string_pool_substr(thisline, q);
test.name = string_pool_insert(thisline);
p = q+1; p = q+1;
*q = '('; q = strchr_p(p, nextline, ')');
q = strchr(p, ')');
if (!q) { if (!q) {
fatal("Parse error on line %d of fingerprint: %s\n", lineno, thisline); fatal("Parse error on line %d of fingerprint: %.*s\n", lineno, (int)(nextline - thisline), thisline);
} }
*q = '\0'; test.results = str2AVal(p, q);
test.results = str2AVal(p);
FP->tests.push_back(test); FP->tests.push_back(test);
} else { } else {
fatal("Parse error line #%d of fingerprint: %s", lineno, thisline); fatal("Parse error on line %d of fingerprint: %.*s\n", lineno, (int)(nextline - thisline), thisline);
} }
thisline = nextline; /* Time to handle the next line, if there is one */ thisline = nextline; /* Time to handle the next line, if there is one */
lineno++; lineno++;
} while (thisline && *thisline); } while (thisline && thisline < end);
/* Free the temporary fingerprint copy. */
free(fprint);
return FP; return FP;
} }
@@ -962,7 +959,7 @@ FingerPrintDB *parse_fingerprint_file(const char *fname) {
DB = new FingerPrintDB; DB = new FingerPrintDB;
char *p, *q; /* OH YEAH!!!! */ const char *p, *q; /* OH YEAH!!!! */
fp = fopen(fname, "r"); fp = fopen(fname, "r");
if (!fp) if (!fp)
@@ -976,9 +973,9 @@ top:
continue; continue;
fparse: fparse:
if (strncasecmp(line, "FingerPrint", 11) == 0) { if (strncmp(line, "Fingerprint", 11) == 0) {
parsingMatchPoints = false; parsingMatchPoints = false;
} else if (strncasecmp(line, "MatchPoints", 11) == 0) { } else if (strncmp(line, "MatchPoints", 11) == 0) {
if (DB->MatchPoints) if (DB->MatchPoints)
fatal("Found MatchPoints directive on line %d of %s even though it has previously been seen in the file", lineno, fname); fatal("Found MatchPoints directive on line %d of %s even though it has previously been seen in the file", lineno, fname);
parsingMatchPoints = true; parsingMatchPoints = true;
@@ -1008,9 +1005,7 @@ fparse:
if (q < p) if (q < p)
fatal("Parse error on line %d of fingerprint: %s", lineno, line); fatal("Parse error on line %d of fingerprint: %s", lineno, line);
current->match.OS_name = (char *) cp_alloc(q - p + 2); current->match.OS_name = cp_strndup(p, q - p + 1);
memcpy(current->match.OS_name, p, q - p + 1);
current->match.OS_name[q - p + 1] = '\0';
} }
current->match.line = lineno; current->match.line = lineno;
@@ -1023,12 +1018,14 @@ fparse:
if (*line == '\n') if (*line == '\n')
break; break;
if (!strncmp(line, "FingerPrint ",12)) { q = strchr(line, '\n');
if (!strncmp(line, "Fingerprint ",12)) {
goto fparse; goto fparse;
} else if (strncmp(line, "Class ", 6) == 0) { } else if (strncmp(line, "Class ", 6) == 0) {
parse_classline(current, line, lineno); parse_classline(current, line, q, lineno);
} else if (strncmp(line, "CPE ", 4) == 0) { } else if (strncmp(line, "CPE ", 4) == 0) {
parse_cpeline(current, line, lineno); parse_cpeline(current, line, q, lineno);
} else { } else {
FingerTest test; FingerTest test;
p = line; p = line;
@@ -1037,17 +1034,14 @@ fparse:
error("Parse error on line %d of nmap-os-db file: %s", lineno, line); error("Parse error on line %d of nmap-os-db file: %s", lineno, line);
goto top; goto top;
} }
*q = '\0'; test.name = string_pool_substr(p, q);
test.name = string_pool_insert(p);
p = q+1; p = q+1;
*q = '(';
q = strchr(p, ')'); q = strchr(p, ')');
if (!q) { if (!q) {
error("Parse error on line %d of nmap-os-db file: %s", lineno, line); error("Parse error on line %d of nmap-os-db file: %s", lineno, line);
goto top; goto top;
} }
*q = '\0'; test.results = str2AVal(p, q);
test.results = str2AVal(p);
current->tests.push_back(test); current->tests.push_back(test);
} }
} }

View File

@@ -114,7 +114,7 @@ struct FingerMatch {
/* For IPv6 matches, the number of fingerprints that contributed to this /* For IPv6 matches, the number of fingerprints that contributed to this
* classification group */ * classification group */
unsigned short numprints; unsigned short numprints;
char *OS_name; const char *OS_name;
std::vector<OS_Classification> OS_class; std::vector<OS_Classification> OS_class;
FingerMatch() { FingerMatch() {

View File

@@ -128,13 +128,13 @@ const char *string_pool_substr_strip(const char *s, const char *t) {
return string_pool_substr(s, t); return string_pool_substr(s, t);
} }
const char *string_pool_strip_word(const char *s) { const char *string_pool_strip_word(const char *s, const char *end) {
const char *t; const char *t;
while (isspace((int) (unsigned char) *s)) while (isspace((int) (unsigned char) *s))
s++; s++;
t = s; t = s;
while (*t != '\0' && !isspace((int) (unsigned char) *t)) while (t < end && *t != '\0' && !isspace((int) (unsigned char) *t))
t++; t++;
if (s == t) if (s == t)

View File

@@ -80,6 +80,6 @@ const char *string_pool_substr_strip(const char *s, const char *t);
/* Skip over whitespace to find the beginning of a word, then read until the /* Skip over whitespace to find the beginning of a word, then read until the
next whitespace character. Returns NULL if only whitespace is found. */ next whitespace character. Returns NULL if only whitespace is found. */
const char *string_pool_strip_word(const char *s); const char *string_pool_strip_word(const char *s, const char *end);
#endif // STRING_POOL_H #endif // STRING_POOL_H