mirror of
https://gitlab.torproject.org/tpo/core/tor.git
synced 2025-02-23 14:40:51 +01:00
r13788@catbus: nickm | 2007-07-16 14:26:25 -0400
Patch from croup: rewrite the logic of get_next_token() to do the right thing with input that ends at weird places, or aligns with block boundaries after mmap. should fix bug 455. Needs fuzzing. svn:r10847
This commit is contained in:
parent
6e9f1f76f2
commit
ad45ddfb07
5 changed files with 103 additions and 90 deletions
|
@ -42,7 +42,9 @@ Changes in version 0.2.0.3-alpha - 2007-??-??
|
||||||
- Fix a crash bug in directory authorities when we re-number the
|
- Fix a crash bug in directory authorities when we re-number the
|
||||||
routerlist while inserting a new router. [Bugfix on 0.1.2.x]
|
routerlist while inserting a new router. [Bugfix on 0.1.2.x]
|
||||||
- Fix a crash bug when router descriptors end at a 4096-byte boundary
|
- Fix a crash bug when router descriptors end at a 4096-byte boundary
|
||||||
on disk. [Bugfix on 0.1.2.x]
|
on disk. [Bugfix on 0.1.2.x]
|
||||||
|
- Rewrite directory tokenization code to never run off the end of
|
||||||
|
a string. Fixes bug 455. Patch from croup. [Bugfix on 0.1.2.x]
|
||||||
|
|
||||||
o Minor bugfixes (core protocol):
|
o Minor bugfixes (core protocol):
|
||||||
- When sending destroy cells from a circuit's origin, don't include
|
- When sending destroy cells from a circuit's origin, don't include
|
||||||
|
|
|
@ -1730,7 +1730,6 @@ tor_threads_init(void)
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* On Windows, WSAEWOULDBLOCK is not always correct: when you see it,
|
* On Windows, WSAEWOULDBLOCK is not always correct: when you see it,
|
||||||
* you need to ask the socket for its actual errno. Also, you need to
|
* you need to ask the socket for its actual errno. Also, you need to
|
||||||
|
|
|
@ -403,6 +403,21 @@ strcmpstart(const char *s1, const char *s2)
|
||||||
return strncmp(s1, s2, n);
|
return strncmp(s1, s2, n);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** Compare the s1_len-byte string <b>s1</b> with <b>s2</b>,
|
||||||
|
* without depending on a terminating nul in s1. Sorting order is first by
|
||||||
|
* length, then lexically; return values are as for strcmp.
|
||||||
|
*/
|
||||||
|
int
|
||||||
|
strcmp_len(const char *s1, const char *s2, size_t s1_len)
|
||||||
|
{
|
||||||
|
size_t s2_len = strlen(s2);
|
||||||
|
if (s1_len < s2_len)
|
||||||
|
return -1;
|
||||||
|
if (s1_len > s2_len)
|
||||||
|
return 1;
|
||||||
|
return memcmp(s1, s2, s2_len);
|
||||||
|
}
|
||||||
|
|
||||||
/** Compares the first strlen(s2) characters of s1 with s2. Returns as for
|
/** Compares the first strlen(s2) characters of s1 with s2. Returns as for
|
||||||
* strcasecmp.
|
* strcasecmp.
|
||||||
*/
|
*/
|
||||||
|
@ -505,7 +520,8 @@ eat_whitespace_no_nl(const char *s)
|
||||||
return s;
|
return s;
|
||||||
}
|
}
|
||||||
|
|
||||||
/** DOCDOC */
|
/** As eat_whitespace_no_nl, but stop at <b>eos</b> whether we have
|
||||||
|
* found a non-whitespace character or not. */
|
||||||
const char *
|
const char *
|
||||||
eat_whitespace_eos_no_nl(const char *s, const char *eos)
|
eat_whitespace_eos_no_nl(const char *s, const char *eos)
|
||||||
{
|
{
|
||||||
|
@ -537,7 +553,8 @@ find_whitespace(const char *s)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/** DOCDOC */
|
/** As find_whitespace, but stop at <b>eos</b> whether we have found a
|
||||||
|
* whitespace or not. */
|
||||||
const char *
|
const char *
|
||||||
find_whitespace_eos(const char *s, const char *eos)
|
find_whitespace_eos(const char *s, const char *eos)
|
||||||
{
|
{
|
||||||
|
@ -556,10 +573,9 @@ find_whitespace_eos(const char *s, const char *eos)
|
||||||
++s;
|
++s;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return NULL;
|
return s;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/** Return true iff the 'len' bytes at 'mem' are all zero. */
|
/** Return true iff the 'len' bytes at 'mem' are all zero. */
|
||||||
int
|
int
|
||||||
tor_mem_is_zero(const char *mem, size_t len)
|
tor_mem_is_zero(const char *mem, size_t len)
|
||||||
|
|
|
@ -155,6 +155,8 @@ void tor_strupper(char *s) ATTR_NONNULL((1));
|
||||||
int tor_strisprint(const char *s) ATTR_PURE ATTR_NONNULL((1));
|
int tor_strisprint(const char *s) ATTR_PURE ATTR_NONNULL((1));
|
||||||
int tor_strisnonupper(const char *s) ATTR_PURE ATTR_NONNULL((1));
|
int tor_strisnonupper(const char *s) ATTR_PURE ATTR_NONNULL((1));
|
||||||
int strcmpstart(const char *s1, const char *s2) ATTR_PURE ATTR_NONNULL((1,2));
|
int strcmpstart(const char *s1, const char *s2) ATTR_PURE ATTR_NONNULL((1,2));
|
||||||
|
int strcmp_len(const char *s1, const char *s2, size_t len)
|
||||||
|
ATTR_PURE ATTR_NONNULL((1,2));
|
||||||
int strcasecmpstart(const char *s1, const char *s2)
|
int strcasecmpstart(const char *s1, const char *s2)
|
||||||
ATTR_PURE ATTR_NONNULL((1,2));
|
ATTR_PURE ATTR_NONNULL((1,2));
|
||||||
int strcmpend(const char *s1, const char *s2) ATTR_PURE ATTR_NONNULL((1,2));
|
int strcmpend(const char *s1, const char *s2) ATTR_PURE ATTR_NONNULL((1,2));
|
||||||
|
|
|
@ -2345,8 +2345,8 @@ token_check_object(const char *kwd,
|
||||||
static directory_token_t *
|
static directory_token_t *
|
||||||
get_next_token(const char **s, const char *eos, token_rule_t *table)
|
get_next_token(const char **s, const char *eos, token_rule_t *table)
|
||||||
{
|
{
|
||||||
const char *next, *obstart;
|
const char *next, *eol, *obstart;
|
||||||
int i, j, done, allocated;
|
int i, j, allocated, obname_len;
|
||||||
directory_token_t *tok;
|
directory_token_t *tok;
|
||||||
obj_syntax o_syn = NO_OBJ;
|
obj_syntax o_syn = NO_OBJ;
|
||||||
char ebuf[128];
|
char ebuf[128];
|
||||||
|
@ -2364,61 +2364,55 @@ get_next_token(const char **s, const char *eos, token_rule_t *table)
|
||||||
tok = tor_malloc_zero(sizeof(directory_token_t));
|
tok = tor_malloc_zero(sizeof(directory_token_t));
|
||||||
tok->tp = _ERR;
|
tok->tp = _ERR;
|
||||||
|
|
||||||
*s = eat_whitespace_eos(*s, eos);
|
/* Set *s to first token, eol to end-of-line, next to after first token */
|
||||||
if (*s == eos) {
|
*s = eat_whitespace_eos(*s, eos); /* eat multi-line whitespace */
|
||||||
tok->tp = _EOF;
|
eol = memchr(*s, '\n', eos-*s);
|
||||||
return tok;
|
if (!eol)
|
||||||
}
|
eol = eos;
|
||||||
next = find_whitespace_eos(*s, eos);
|
next = find_whitespace_eos(*s, eol);
|
||||||
if (!next) {
|
|
||||||
tok->error = tor_strdup("Unexpected EOF"); return tok;
|
if (!strcmp_len(*s, "opt", next-*s)) {
|
||||||
}
|
|
||||||
/* It's a keyword... but which one? */
|
|
||||||
if (!strncmp("opt", *s, next-*s)) {
|
|
||||||
/* Skip past an "opt" at the start of the line. */
|
/* Skip past an "opt" at the start of the line. */
|
||||||
*s = eat_whitespace_eos(next, eos);
|
*s = eat_whitespace_eos_no_nl(next, eol);
|
||||||
next = find_whitespace_eos(*s, eos);
|
next = find_whitespace_eos(*s, eol);
|
||||||
if (!next) {
|
} else if (*s == eos) { /* If no "opt", and end-of-line, line is invalid */
|
||||||
RET_ERR("opt without keyword");
|
RET_ERR("Unexpected EOF");
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Search the table for the appropriate entry. (I tried a binary search
|
/* Search the table for the appropriate entry. (I tried a binary search
|
||||||
* instead, but it wasn't any faster.) */
|
* instead, but it wasn't any faster.) */
|
||||||
for (i = 0; table[i].t ; ++i) {
|
for (i = 0; table[i].t ; ++i) {
|
||||||
if (!strncmp(table[i].t, *s, next-*s)) {
|
if (!strcmp_len(*s, table[i].t, next-*s)) {
|
||||||
/* We've found the keyword. */
|
/* We've found the keyword. */
|
||||||
kwd = table[i].t;
|
kwd = table[i].t;
|
||||||
tok->tp = table[i].v;
|
tok->tp = table[i].v;
|
||||||
o_syn = table[i].os;
|
o_syn = table[i].os;
|
||||||
if (table[i].concat_args) {
|
*s = eat_whitespace_eos_no_nl(next, eol);
|
||||||
/* The keyword takes the line as a single argument */
|
next = find_whitespace_eos(*s, eol);
|
||||||
*s = eat_whitespace_no_nl(next);
|
if (1 || *s < eol) { /* make sure there are arguments to store */
|
||||||
next = strchr(*s, '\n');
|
/* XXXX020 actually, we go ahead whether there are arguments or not,
|
||||||
if (!next)
|
* so that tok->args is always set if we want arguments. */
|
||||||
RET_ERR("Unexpected EOF");
|
if (table[i].concat_args) {
|
||||||
tok->args = tor_malloc(sizeof(char*));
|
/* The keyword takes the line as a single argument */
|
||||||
tok->args[0] = tor_strndup(*s,next-*s);
|
tok->args = tor_malloc(sizeof(char*));
|
||||||
tok->n_args = 1;
|
tok->args[0] = tor_strndup(*s,eol-*s); /* Grab everything on line */
|
||||||
*s = eat_whitespace_eos_no_nl(next+1, eos);
|
tok->n_args = 1;
|
||||||
} else {
|
} else {
|
||||||
/* This keyword takes multiple arguments. */
|
/* This keyword takes multiple arguments. */
|
||||||
j = 0;
|
j = 0;
|
||||||
done = (*next == '\n');
|
allocated = 16;
|
||||||
allocated = 32;
|
tok->args = tor_malloc(sizeof(char*)*allocated);
|
||||||
tok->args = tor_malloc(sizeof(char*)*32);
|
while (*s < eol) { /* While not at eol, store the next token */
|
||||||
*s = eat_whitespace_eos_no_nl(next, eos);
|
if (j == allocated) {
|
||||||
while (**s != '\n' && !done) {
|
allocated *= 2;
|
||||||
next = find_whitespace(*s);
|
tok->args = tor_realloc(tok->args,sizeof(char*)*allocated);
|
||||||
if (*next == '\n')
|
}
|
||||||
done = 1;
|
tok->args[j++] = tor_strndup(*s, next-*s);
|
||||||
if (j == allocated) {
|
*s = eat_whitespace_eos_no_nl(next, eol); /* eat intra-line ws */
|
||||||
allocated *= 2;
|
next = find_whitespace_eos(*s, eol); /* find end of token at *s */
|
||||||
tok->args = tor_realloc(tok->args,sizeof(char*)*allocated);
|
|
||||||
}
|
}
|
||||||
tok->args[j++] = tor_strndup(*s,next-*s);
|
tok->n_args = j;
|
||||||
*s = eat_whitespace_eos_no_nl(next+1, eos);
|
|
||||||
}
|
}
|
||||||
tok->n_args = j;
|
|
||||||
}
|
}
|
||||||
if (tok->n_args < table[i].min_args) {
|
if (tok->n_args < table[i].min_args) {
|
||||||
tor_snprintf(ebuf, sizeof(ebuf), "Too few arguments to %s", kwd);
|
tor_snprintf(ebuf, sizeof(ebuf), "Too few arguments to %s", kwd);
|
||||||
|
@ -2427,63 +2421,63 @@ get_next_token(const char **s, const char *eos, token_rule_t *table)
|
||||||
tor_snprintf(ebuf, sizeof(ebuf), "Too many arguments to %s", kwd);
|
tor_snprintf(ebuf, sizeof(ebuf), "Too many arguments to %s", kwd);
|
||||||
RET_ERR(ebuf);
|
RET_ERR(ebuf);
|
||||||
}
|
}
|
||||||
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (tok->tp == _ERR) {
|
|
||||||
|
if (tok->tp == _ERR) { /* No keyword matched; call it an "opt". */
|
||||||
tok->tp = K_OPT;
|
tok->tp = K_OPT;
|
||||||
*s = eat_whitespace_eos_no_nl(next, eos);
|
|
||||||
next = strchr(*s,'\n');
|
|
||||||
if (!next)
|
|
||||||
RET_ERR("Unexpected EOF");
|
|
||||||
tok->args = tor_malloc(sizeof(char*));
|
tok->args = tor_malloc(sizeof(char*));
|
||||||
tok->args[0] = tor_strndup(*s,next-*s);
|
tok->args[0] = tor_strndup(*s, eol-*s);
|
||||||
tok->n_args = 1;
|
tok->n_args = 1;
|
||||||
*s = eat_whitespace_eos_no_nl(next+1, eos);
|
|
||||||
o_syn = OBJ_OK;
|
o_syn = OBJ_OK;
|
||||||
}
|
}
|
||||||
*s = eat_whitespace_eos(*s, eos);
|
|
||||||
if (strcmpstart(*s, "-----BEGIN ")) {
|
/* Check whether there's an object present */
|
||||||
|
*s = eat_whitespace_eos(eol, eos); /* Scan from end of first line */
|
||||||
|
eol = memchr(*s, '\n', eos-*s);
|
||||||
|
if (!eol || eol-*s<11 || strcmpstart(*s, "-----BEGIN ")) /* No object. */
|
||||||
goto check_object;
|
goto check_object;
|
||||||
}
|
|
||||||
obstart = *s;
|
obstart = *s; /* Set obstart to start of object spec */
|
||||||
*s += 11; /* length of "-----BEGIN ". */
|
if (*s+11 >= eol-5 || memchr(*s+11,'\0',eol-*s-16) || /* no short lines, */
|
||||||
next = strchr(*s, '\n');
|
strcmp_len(eol-5, "-----", 5)) { /* nuls or invalid endings */
|
||||||
if (next-*s < 6 || strcmpstart(next-5, "-----\n")) {
|
|
||||||
RET_ERR("Malformed object: bad begin line");
|
RET_ERR("Malformed object: bad begin line");
|
||||||
}
|
}
|
||||||
tok->object_type = tor_strndup(*s, next-*s-5);
|
tok->object_type = tor_strndup(*s+11, eol-*s-16);
|
||||||
*s = next+1;
|
obname_len = eol-*s-16; /* store objname length here to avoid a strlen() */
|
||||||
|
*s = eol+1; /* Set *s to possible start of object data (could be eos) */
|
||||||
|
|
||||||
|
/* Go to the end of the object */
|
||||||
next = tor_memstr(*s, eos-*s, "-----END ");
|
next = tor_memstr(*s, eos-*s, "-----END ");
|
||||||
if (!next) {
|
if (!next) {
|
||||||
RET_ERR("Malformed object: missing end line");
|
RET_ERR("Malformed object: missing object end line");
|
||||||
}
|
}
|
||||||
if (!strcmp(tok->object_type, "RSA PUBLIC KEY")) {
|
eol = memchr(next, '\n', eos-next);
|
||||||
if (strcmpstart(next, "-----END RSA PUBLIC KEY-----\n"))
|
if (!eol) /* end-of-line marker, or eos if there's no '\n' */
|
||||||
RET_ERR("Malformed object: mismatched end line");
|
eol = eos;
|
||||||
next = memchr(next, '\n', eos-next);
|
/* Validate the ending tag, which should be 9 + NAME + 5 + eol */
|
||||||
if (!next)
|
if (eol-next != 9+obname_len+5 ||
|
||||||
RET_ERR("Couldn't parse public key.");
|
strcmp_len(next+9, tok->object_type, obname_len) ||
|
||||||
++next;
|
strcmp_len(eol-5, "-----", 5)) {
|
||||||
|
snprintf(ebuf, sizeof(ebuf), "Malformed object: mismatched end tag %s",
|
||||||
|
tok->object_type);
|
||||||
|
ebuf[sizeof(ebuf)-1] = '\0';
|
||||||
|
RET_ERR(ebuf);
|
||||||
|
}
|
||||||
|
if (!strcmp(tok->object_type, "RSA PUBLIC KEY")) { /* If it's a key... */
|
||||||
tok->key = crypto_new_pk_env();
|
tok->key = crypto_new_pk_env();
|
||||||
if (crypto_pk_read_public_key_from_string(tok->key, obstart, next-obstart))
|
if (crypto_pk_read_public_key_from_string(tok->key, obstart, eol-obstart))
|
||||||
RET_ERR("Couldn't parse public key.");
|
RET_ERR("Couldn't parse public key.");
|
||||||
*s = next;
|
} else { /* If it's something else, try to base64-decode it */
|
||||||
} else {
|
int r;
|
||||||
tok->object_body = tor_malloc(next-*s); /* really, this is too much RAM. */
|
tok->object_body = tor_malloc(next-*s); /* really, this is too much RAM. */
|
||||||
i = base64_decode(tok->object_body, next-*s, *s, next-*s);
|
r = base64_decode(tok->object_body, next-*s, *s, next-*s);
|
||||||
if (i<0) {
|
if (r<0)
|
||||||
RET_ERR("Malformed object: bad base64-encoded data");
|
RET_ERR("Malformed object: bad base64-encoded data");
|
||||||
}
|
tok->object_size = r;
|
||||||
tok->object_size = i;
|
|
||||||
*s = next + 9; /* length of "-----END ". */
|
|
||||||
i = strlen(tok->object_type);
|
|
||||||
if (strncmp(*s, tok->object_type, i) || strcmpstart(*s+i, "-----\n")) {
|
|
||||||
RET_ERR("Malformed object: mismatched end tag");
|
|
||||||
}
|
|
||||||
*s += i+6;
|
|
||||||
}
|
}
|
||||||
|
*s = eol;
|
||||||
|
|
||||||
check_object:
|
check_object:
|
||||||
tok = token_check_object(kwd, tok, o_syn);
|
tok = token_check_object(kwd, tok, o_syn);
|
||||||
|
|
Loading…
Add table
Reference in a new issue