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
Родитель 03df34dd12
Коммит e7099d7048
2 изменённых файлов: 60 добавлений и 59 удалений

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

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

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

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