Additional precautions against potential buffer overruns. b=307259 r=darin sr=dveditz

This commit is contained in:
dbaron%dbaron.org 2005-09-13 17:38:20 +00:00
Родитель 58b8c56727
Коммит a0d15a3adb
2 изменённых файлов: 60 добавлений и 59 удалений

Просмотреть файл

@ -170,8 +170,10 @@ PRInt32 nsStandardURL::
nsSegmentEncoder::EncodeSegmentCount(const char *str, nsSegmentEncoder::EncodeSegmentCount(const char *str,
const URLSegment &seg, const URLSegment &seg,
PRInt16 mask, PRInt16 mask,
nsAFlatCString &result) nsAFlatCString &result,
PRBool &appended)
{ {
appended = PR_FALSE;
if (!str) if (!str)
return 0; return 0;
PRInt32 len = 0; PRInt32 len = 0;
@ -203,11 +205,14 @@ nsSegmentEncoder::EncodeSegmentCount(const char *str,
PRUint32 initLen = result.Length(); PRUint32 initLen = result.Length();
// now perform any required escaping // now perform any required escaping
if (NS_EscapeURL(str + pos, len, mask | escapeFlags, result)) if (NS_EscapeURL(str + pos, len, mask | escapeFlags, result)) {
len = result.Length() - initLen; len = result.Length() - initLen;
appended = PR_TRUE;
}
else if (str == encBuf.get()) { else if (str == encBuf.get()) {
result += encBuf; // append only!! result += encBuf; // append only!!
len = encBuf.Length(); len = encBuf.Length();
appended = PR_TRUE;
} }
} }
return len; return len;
@ -219,13 +224,11 @@ nsSegmentEncoder::EncodeSegment(const nsASingleFragmentCString &str,
nsAFlatCString &result) nsAFlatCString &result)
{ {
const char *text; const char *text;
PRUint32 resultLen = result.Length(); PRBool encoded;
EncodeSegmentCount(str.BeginReading(text), URLSegment(0, str.Length()), mask, result); EncodeSegmentCount(str.BeginReading(text), URLSegment(0, str.Length()), mask, result, encoded);
// since EncodeSegmentCount appends to result, we must check whether its length grew if (encoded)
if (result.Length() > resultLen)
return result; return result;
else return str;
return str;
} }
PRBool nsStandardURL:: PRBool nsStandardURL::
@ -395,14 +398,14 @@ nsStandardURL::NormalizeIDN(const nsCSubstring &host, nsCString &result)
PRBool isACE; PRBool isACE;
if (gIDN && if (gIDN &&
NS_SUCCEEDED(gIDN->IsACE(host, &isACE)) && isACE && NS_SUCCEEDED(gIDN->IsACE(host, &isACE)) && isACE &&
NS_SUCCEEDED(ACEtoUTF8(host, result))) { NS_SUCCEEDED(ACEtoDisplayIDN(host, result))) {
mHostEncoding = eEncoding_UTF8; mHostEncoding = eEncoding_UTF8;
return PR_TRUE; return PR_TRUE;
} }
} }
else { else {
mHostEncoding = eEncoding_UTF8; mHostEncoding = eEncoding_UTF8;
if (gIDN && NS_SUCCEEDED(NormalizeUTF8(host, result))) { if (gIDN && NS_SUCCEEDED(UTF8toDisplayIDN(host, result))) {
// normalization could result in an ASCII only hostname // normalization could result in an ASCII only hostname
if (IsASCII(result)) if (IsASCII(result))
mHostEncoding = eEncoding_ASCII; mHostEncoding = eEncoding_ASCII;
@ -429,10 +432,10 @@ nsStandardURL::CoalescePath(netCoalesceFlags coalesceFlag, char *path)
} }
PRUint32 PRUint32
nsStandardURL::AppendSegmentToBuf(char *buf, PRUint32 i, const char *str, URLSegment &seg, const nsCString *escapedStr) nsStandardURL::AppendSegmentToBuf(char *buf, PRUint32 i, const char *str, URLSegment &seg, const nsCString *escapedStr, PRBool useEscaped)
{ {
if (seg.mLen > 0) { if (seg.mLen > 0) {
if (escapedStr && !escapedStr->IsEmpty()) { if (useEscaped) {
seg.mLen = escapedStr->Length(); seg.mLen = escapedStr->Length();
memcpy(buf + i, escapedStr->get(), seg.mLen); memcpy(buf + i, escapedStr->get(), seg.mLen);
} }
@ -464,16 +467,10 @@ nsStandardURL::BuildNormalizedSpec(const char *spec)
// buffers for holding escaped url segments (these will remain empty unless // buffers for holding escaped url segments (these will remain empty unless
// escaping is required). // escaping is required).
nsCAutoString encUsername; nsCAutoString encUsername, encPassword, encHost, encDirectory,
nsCAutoString encPassword; encBasename, encExtension, encParam, encQuery, encRef;
nsCAutoString encHost; PRBool useEncUsername, useEncPassword, useEncHost, useEncDirectory,
PRBool useEncHost; useEncBasename, useEncExtension, useEncParam, useEncQuery, useEncRef;
nsCAutoString encDirectory;
nsCAutoString encBasename;
nsCAutoString encExtension;
nsCAutoString encParam;
nsCAutoString encQuery;
nsCAutoString encRef;
// //
// escape each URL segment, if necessary, and calculate approximate normalized // escape each URL segment, if necessary, and calculate approximate normalized
@ -490,14 +487,14 @@ nsStandardURL::BuildNormalizedSpec(const char *spec)
// appropriate encoding. // appropriate encoding.
{ {
GET_SEGMENT_ENCODER(encoder); GET_SEGMENT_ENCODER(encoder);
approxLen += encoder.EncodeSegmentCount(spec, mUsername, esc_Username, encUsername); approxLen += encoder.EncodeSegmentCount(spec, mUsername, esc_Username, encUsername, useEncUsername);
approxLen += encoder.EncodeSegmentCount(spec, mPassword, esc_Password, encPassword); approxLen += encoder.EncodeSegmentCount(spec, mPassword, esc_Password, encPassword, useEncPassword);
approxLen += encoder.EncodeSegmentCount(spec, mDirectory, esc_Directory, encDirectory); approxLen += encoder.EncodeSegmentCount(spec, mDirectory, esc_Directory, encDirectory, useEncDirectory);
approxLen += encoder.EncodeSegmentCount(spec, mBasename, esc_FileBaseName, encBasename); approxLen += encoder.EncodeSegmentCount(spec, mBasename, esc_FileBaseName, encBasename, useEncBasename);
approxLen += encoder.EncodeSegmentCount(spec, mExtension, esc_FileExtension, encExtension); approxLen += encoder.EncodeSegmentCount(spec, mExtension, esc_FileExtension, encExtension, useEncExtension);
approxLen += encoder.EncodeSegmentCount(spec, mParam, esc_Param, encParam); approxLen += encoder.EncodeSegmentCount(spec, mParam, esc_Param, encParam, useEncParam);
approxLen += encoder.EncodeSegmentCount(spec, mQuery, esc_Query, encQuery); approxLen += encoder.EncodeSegmentCount(spec, mQuery, esc_Query, encQuery, useEncQuery);
approxLen += encoder.EncodeSegmentCount(spec, mRef, esc_Ref, encRef); approxLen += encoder.EncodeSegmentCount(spec, mRef, esc_Ref, encRef, useEncRef);
} }
// do not escape the hostname, if IPv6 address literal, mHost will // do not escape the hostname, if IPv6 address literal, mHost will
@ -532,21 +529,15 @@ nsStandardURL::BuildNormalizedSpec(const char *spec)
// append authority // append authority
if (mUsername.mLen > 0) { if (mUsername.mLen > 0) {
i = AppendSegmentToBuf(buf, i, spec, mUsername, &encUsername); i = AppendSegmentToBuf(buf, i, spec, mUsername, &encUsername, useEncUsername);
if (mPassword.mLen >= 0) { if (mPassword.mLen >= 0) {
buf[i++] = ':'; buf[i++] = ':';
i = AppendSegmentToBuf(buf, i, spec, mPassword, &encPassword); i = AppendSegmentToBuf(buf, i, spec, mPassword, &encPassword, useEncPassword);
} }
buf[i++] = '@'; buf[i++] = '@';
} }
if (mHost.mLen > 0) { if (mHost.mLen > 0) {
if (useEncHost) { i = AppendSegmentToBuf(buf, i, spec, mHost, &encHost, useEncHost);
mHost.mPos = i;
mHost.mLen = encHost.Length();
i = AppendToBuf(buf, i, encHost.get(), mHost.mLen);
}
else
i = AppendSegmentToBuf(buf, i, spec, mHost);
net_ToLowerCase(buf + mHost.mPos, mHost.mLen); net_ToLowerCase(buf + mHost.mPos, mHost.mLen);
if (mPort != -1 && mPort != mDefaultPort) { if (mPort != -1 && mPort != mDefaultPort) {
nsCAutoString portbuf; nsCAutoString portbuf;
@ -580,7 +571,7 @@ nsStandardURL::BuildNormalizedSpec(const char *spec)
// record corrected (file)path starting position // record corrected (file)path starting position
mPath.mPos = mFilepath.mPos = i - leadingSlash; mPath.mPos = mFilepath.mPos = i - leadingSlash;
i = AppendSegmentToBuf(buf, i, spec, mDirectory, &encDirectory); i = AppendSegmentToBuf(buf, i, spec, mDirectory, &encDirectory, useEncDirectory);
// the directory must end with a '/' // the directory must end with a '/'
if (buf[i-1] != '/') { if (buf[i-1] != '/') {
@ -588,7 +579,7 @@ nsStandardURL::BuildNormalizedSpec(const char *spec)
mDirectory.mLen++; mDirectory.mLen++;
} }
i = AppendSegmentToBuf(buf, i, spec, mBasename, &encBasename); i = AppendSegmentToBuf(buf, i, spec, mBasename, &encBasename, useEncBasename);
// make corrections to directory segment if leadingSlash // make corrections to directory segment if leadingSlash
if (leadingSlash) { if (leadingSlash) {
@ -601,22 +592,22 @@ nsStandardURL::BuildNormalizedSpec(const char *spec)
if (mExtension.mLen >= 0) { if (mExtension.mLen >= 0) {
buf[i++] = '.'; buf[i++] = '.';
i = AppendSegmentToBuf(buf, i, spec, mExtension, &encExtension); i = AppendSegmentToBuf(buf, i, spec, mExtension, &encExtension, useEncExtension);
} }
// calculate corrected filepath length // calculate corrected filepath length
mFilepath.mLen = i - mFilepath.mPos; mFilepath.mLen = i - mFilepath.mPos;
if (mParam.mLen >= 0) { if (mParam.mLen >= 0) {
buf[i++] = ';'; buf[i++] = ';';
i = AppendSegmentToBuf(buf, i, spec, mParam, &encParam); i = AppendSegmentToBuf(buf, i, spec, mParam, &encParam, useEncParam);
} }
if (mQuery.mLen >= 0) { if (mQuery.mLen >= 0) {
buf[i++] = '?'; buf[i++] = '?';
i = AppendSegmentToBuf(buf, i, spec, mQuery, &encQuery); i = AppendSegmentToBuf(buf, i, spec, mQuery, &encQuery, useEncQuery);
} }
if (mRef.mLen >= 0) { if (mRef.mLen >= 0) {
buf[i++] = '#'; buf[i++] = '#';
i = AppendSegmentToBuf(buf, i, spec, mRef, &encRef); i = AppendSegmentToBuf(buf, i, spec, mRef, &encRef, useEncRef);
} }
// calculate corrected path length // calculate corrected path length
mPath.mLen = i - mPath.mPos; mPath.mLen = i - mPath.mPos;
@ -859,7 +850,7 @@ nsStandardURL::PrefsChanged(nsIPrefBranch *prefs, const char *pref)
} }
/* static */ nsresult /* static */ nsresult
nsStandardURL::ACEtoUTF8(const nsCSubstring &host, nsCString &result) nsStandardURL::ACEtoDisplayIDN(const nsCSubstring &host, nsCString &result)
{ {
if (gShowPunycode || !IsInWhitelist(host)) { if (gShowPunycode || !IsInWhitelist(host)) {
result = host; result = host;
@ -870,7 +861,7 @@ nsStandardURL::ACEtoUTF8(const nsCSubstring &host, nsCString &result)
} }
/* static */ nsresult /* static */ nsresult
nsStandardURL::NormalizeUTF8(const nsCSubstring &host, nsCString &result) nsStandardURL::UTF8toDisplayIDN(const nsCSubstring &host, nsCString &result)
{ {
if (gShowPunycode || !IsInWhitelist(host)) if (gShowPunycode || !IsInWhitelist(host))
return gIDN->ConvertUTF8toACE(host, result); return gIDN->ConvertUTF8toACE(host, result);
@ -1221,18 +1212,20 @@ nsStandardURL::SetUserPass(const nsACString &input)
nsCAutoString buf; nsCAutoString buf;
if (usernameLen > 0) { if (usernameLen > 0) {
GET_SEGMENT_ENCODER(encoder); GET_SEGMENT_ENCODER(encoder);
PRBool ignoredOut;
usernameLen = encoder.EncodeSegmentCount(userpass.get(), usernameLen = encoder.EncodeSegmentCount(userpass.get(),
URLSegment(usernamePos, URLSegment(usernamePos,
usernameLen), usernameLen),
esc_Username | esc_AlwaysCopy, esc_Username | esc_AlwaysCopy,
buf); buf, ignoredOut);
if (passwordLen >= 0) { if (passwordLen >= 0) {
buf.Append(':'); buf.Append(':');
passwordLen = encoder.EncodeSegmentCount(userpass.get(), passwordLen = encoder.EncodeSegmentCount(userpass.get(),
URLSegment(passwordPos, URLSegment(passwordPos,
passwordLen), passwordLen),
esc_Password | esc_Password |
esc_AlwaysCopy, buf); esc_AlwaysCopy, buf,
ignoredOut);
} }
if (mUsername.mLen < 0) if (mUsername.mLen < 0)
buf.Append('@'); buf.Append('@');
@ -2183,9 +2176,11 @@ nsStandardURL::SetQuery(const nsACString &input)
// encode query if necessary // encode query if necessary
nsCAutoString buf; nsCAutoString buf;
PRBool encoded;
GET_SEGMENT_ENCODER(encoder); GET_SEGMENT_ENCODER(encoder);
encoder.EncodeSegmentCount(query, URLSegment(0, queryLen), esc_Query, buf); encoder.EncodeSegmentCount(query, URLSegment(0, queryLen), esc_Query,
if (!buf.IsEmpty()) { buf, encoded);
if (encoded) {
query = buf.get(); query = buf.get();
queryLen = buf.Length(); queryLen = buf.Length();
} }
@ -2241,9 +2236,11 @@ nsStandardURL::SetRef(const nsACString &input)
// encode ref if necessary // encode ref if necessary
nsCAutoString buf; nsCAutoString buf;
PRBool encoded;
GET_SEGMENT_ENCODER(encoder); GET_SEGMENT_ENCODER(encoder);
encoder.EncodeSegmentCount(ref, URLSegment(0, refLen), esc_Ref, buf); encoder.EncodeSegmentCount(ref, URLSegment(0, refLen), esc_Ref,
if (!buf.IsEmpty()) { buf, encoded);
if (encoded) {
ref = buf.get(); ref = buf.get();
refLen = buf.Length(); refLen = buf.Length();
} }
@ -2311,17 +2308,20 @@ nsStandardURL::SetFileName(const nsACString &input)
} }
else { else {
nsCAutoString newFilename; nsCAutoString newFilename;
PRBool ignoredOut;
GET_SEGMENT_ENCODER(encoder); GET_SEGMENT_ENCODER(encoder);
basename.mLen = encoder.EncodeSegmentCount(filename, basename, basename.mLen = encoder.EncodeSegmentCount(filename, basename,
esc_FileBaseName | esc_FileBaseName |
esc_AlwaysCopy, esc_AlwaysCopy,
newFilename); newFilename,
ignoredOut);
if (extension.mLen >= 0) { if (extension.mLen >= 0) {
newFilename.Append('.'); newFilename.Append('.');
extension.mLen = encoder.EncodeSegmentCount(filename, extension, extension.mLen = encoder.EncodeSegmentCount(filename, extension,
esc_FileExtension | esc_FileExtension |
esc_AlwaysCopy, esc_AlwaysCopy,
newFilename); newFilename,
ignoredOut);
} }
if (mBasename.mLen < 0) { if (mBasename.mLen < 0) {

Просмотреть файл

@ -124,7 +124,8 @@ public: /* internal -- HPUX compiler can't handle this being private */
PRInt32 EncodeSegmentCount(const char *str, PRInt32 EncodeSegmentCount(const char *str,
const URLSegment &segment, const URLSegment &segment,
PRInt16 mask, PRInt16 mask,
nsAFlatCString &buf); nsAFlatCString &buf,
PRBool& appended);
// Encode the given string if necessary, and return a reference to // Encode the given string if necessary, and return a reference to
// the encoded string. Returns a reference to |buf| if encoding // the encoded string. Returns a reference to |buf| if encoding
@ -159,7 +160,7 @@ private:
PRBool NormalizeIDN(const nsCSubstring &host, nsCString &result); PRBool NormalizeIDN(const nsCSubstring &host, nsCString &result);
void CoalescePath(netCoalesceFlags coalesceFlag, char *path); void CoalescePath(netCoalesceFlags coalesceFlag, char *path);
PRUint32 AppendSegmentToBuf(char *, PRUint32, const char *, URLSegment &, const nsCString *esc=nsnull); PRUint32 AppendSegmentToBuf(char *, PRUint32, const char *, URLSegment &, const nsCString *esc=nsnull, PRBool useEsc = PR_FALSE);
PRUint32 AppendToBuf(char *, PRUint32, const char *, PRUint32); PRUint32 AppendToBuf(char *, PRUint32, const char *, PRUint32);
nsresult BuildNormalizedSpec(const char *spec); nsresult BuildNormalizedSpec(const char *spec);
@ -219,8 +220,8 @@ private:
static void PrefsChanged(nsIPrefBranch *prefs, const char *pref); static void PrefsChanged(nsIPrefBranch *prefs, const char *pref);
// IDN routines // IDN routines
static nsresult ACEtoUTF8(const nsCSubstring &in, nsCString &out); static nsresult ACEtoDisplayIDN(const nsCSubstring &in, nsCString &out);
static nsresult NormalizeUTF8(const nsCSubstring &in, nsCString &out); static nsresult UTF8toDisplayIDN(const nsCSubstring &in, nsCString &out);
static PRBool IsInWhitelist(const nsCSubstring &host); static PRBool IsInWhitelist(const nsCSubstring &host);
// mSpec contains the normalized version of the URL spec (UTF-8 encoded). // mSpec contains the normalized version of the URL spec (UTF-8 encoded).