Fossil SCM
Make <code>style_set_base_href_suffix()</code> safe for misuse: if the resulting suffix contains unescaped quotes then escape them. <var>$base_href_suffix</var> is intended for interpolation inside of the quoted href attribute. This check-in should address the case when a user of malfunctioning browser (which mishandles quoting) is tricked by an adversary to visit a specially crafted hyperlink.
Commit
d97752f30b40a495de6f7954b58ec64e1454e55f354ff6fd6e0369beeb679044
Parent
05e3fa76bee4003…
2 files changed
+30
+7
-3
+30
| --- src/encode.c | ||
| +++ src/encode.c | ||
| @@ -205,10 +205,40 @@ | ||
| 205 | 205 | ** by this routine. |
| 206 | 206 | */ |
| 207 | 207 | char *urlize(const char *z, int n){ |
| 208 | 208 | return EncodeHttp(z, n, 0); |
| 209 | 209 | } |
| 210 | + | |
| 211 | +/* | |
| 212 | +** If input string does not contain quotes (niether ' nor ") | |
| 213 | +** then return the argument itself. Otherwise return a newly allocated | |
| 214 | +** copy of input with all quotes %-escaped. | |
| 215 | +*/ | |
| 216 | +const char* escape_quotes(const char *zIn){ | |
| 217 | + char *zRet, *zOut; | |
| 218 | + size_t i, n = 0; | |
| 219 | + for(i=0; zIn[i]; i++){ | |
| 220 | + if( zIn[i]== '"' || zIn[i]== '\'' ) n++; | |
| 221 | + } | |
| 222 | + if( !n ) return zIn; | |
| 223 | + zRet = zOut = fossil_malloc( i + 2*n + 1 ); | |
| 224 | + for(i=0; zIn[i]; i++){ | |
| 225 | + if( zIn[i]=='"' ){ | |
| 226 | + *(zOut++) = '%'; | |
| 227 | + *(zOut++) = '2'; | |
| 228 | + *(zOut++) = '2'; | |
| 229 | + }else if( zIn[i]=='\'' ){ | |
| 230 | + *(zOut++) = '%'; | |
| 231 | + *(zOut++) = '2'; | |
| 232 | + *(zOut++) = '7'; | |
| 233 | + }else{ | |
| 234 | + *(zOut++) = zIn[i]; | |
| 235 | + } | |
| 236 | + } | |
| 237 | + *zOut = 0; | |
| 238 | + return zRet; | |
| 239 | +} | |
| 210 | 240 | |
| 211 | 241 | /* |
| 212 | 242 | ** Convert a single HEX digit to an integer |
| 213 | 243 | */ |
| 214 | 244 | static int AsciiToHex(int c){ |
| 215 | 245 |
| --- src/encode.c | |
| +++ src/encode.c | |
| @@ -205,10 +205,40 @@ | |
| 205 | ** by this routine. |
| 206 | */ |
| 207 | char *urlize(const char *z, int n){ |
| 208 | return EncodeHttp(z, n, 0); |
| 209 | } |
| 210 | |
| 211 | /* |
| 212 | ** Convert a single HEX digit to an integer |
| 213 | */ |
| 214 | static int AsciiToHex(int c){ |
| 215 |
| --- src/encode.c | |
| +++ src/encode.c | |
| @@ -205,10 +205,40 @@ | |
| 205 | ** by this routine. |
| 206 | */ |
| 207 | char *urlize(const char *z, int n){ |
| 208 | return EncodeHttp(z, n, 0); |
| 209 | } |
| 210 | |
| 211 | /* |
| 212 | ** If input string does not contain quotes (niether ' nor ") |
| 213 | ** then return the argument itself. Otherwise return a newly allocated |
| 214 | ** copy of input with all quotes %-escaped. |
| 215 | */ |
| 216 | const char* escape_quotes(const char *zIn){ |
| 217 | char *zRet, *zOut; |
| 218 | size_t i, n = 0; |
| 219 | for(i=0; zIn[i]; i++){ |
| 220 | if( zIn[i]== '"' || zIn[i]== '\'' ) n++; |
| 221 | } |
| 222 | if( !n ) return zIn; |
| 223 | zRet = zOut = fossil_malloc( i + 2*n + 1 ); |
| 224 | for(i=0; zIn[i]; i++){ |
| 225 | if( zIn[i]=='"' ){ |
| 226 | *(zOut++) = '%'; |
| 227 | *(zOut++) = '2'; |
| 228 | *(zOut++) = '2'; |
| 229 | }else if( zIn[i]=='\'' ){ |
| 230 | *(zOut++) = '%'; |
| 231 | *(zOut++) = '2'; |
| 232 | *(zOut++) = '7'; |
| 233 | }else{ |
| 234 | *(zOut++) = zIn[i]; |
| 235 | } |
| 236 | } |
| 237 | *zOut = 0; |
| 238 | return zRet; |
| 239 | } |
| 240 | |
| 241 | /* |
| 242 | ** Convert a single HEX digit to an integer |
| 243 | */ |
| 244 | static int AsciiToHex(int c){ |
| 245 |
+7
-3
| --- src/style.c | ||
| +++ src/style.c | ||
| @@ -408,24 +408,28 @@ | ||
| 408 | 408 | } |
| 409 | 409 | |
| 410 | 410 | /* Use this for the $base_href_suffix variable if it is not NULL. |
| 411 | 411 | ** If it is NULL then use g.zRelReqURI |
| 412 | 412 | */ |
| 413 | -static char *local_zBaseHrefSuffix = 0; | |
| 413 | +static const char *local_zBaseHrefSuffix = 0; | |
| 414 | 414 | |
| 415 | 415 | /* |
| 416 | 416 | ** Set the desired $base_href_suffix to something other than g.zRelReqURI |
| 417 | 417 | */ |
| 418 | 418 | void style_set_base_href_suffix(const char *zFormat, ...){ |
| 419 | - fossil_free(local_zBaseHrefSuffix); | |
| 419 | + fossil_free( (char*)local_zBaseHrefSuffix ); | |
| 420 | 420 | if( zFormat==0 ){ |
| 421 | 421 | local_zBaseHrefSuffix = 0; |
| 422 | 422 | }else{ |
| 423 | + char *z; | |
| 423 | 424 | va_list ap; |
| 425 | + | |
| 424 | 426 | va_start(ap, zFormat); |
| 425 | - local_zBaseHrefSuffix = vmprintf(zFormat, ap); | |
| 427 | + z = vmprintf(zFormat, ap); | |
| 426 | 428 | va_end(ap); |
| 429 | + local_zBaseHrefSuffix = escape_quotes( z ); | |
| 430 | + if( local_zBaseHrefSuffix!=z ) fossil_free( z ); | |
| 427 | 431 | } |
| 428 | 432 | } |
| 429 | 433 | |
| 430 | 434 | /* |
| 431 | 435 | ** Create a TH1 variable containing the URL for the stylesheet. |
| 432 | 436 |
| --- src/style.c | |
| +++ src/style.c | |
| @@ -408,24 +408,28 @@ | |
| 408 | } |
| 409 | |
| 410 | /* Use this for the $base_href_suffix variable if it is not NULL. |
| 411 | ** If it is NULL then use g.zRelReqURI |
| 412 | */ |
| 413 | static char *local_zBaseHrefSuffix = 0; |
| 414 | |
| 415 | /* |
| 416 | ** Set the desired $base_href_suffix to something other than g.zRelReqURI |
| 417 | */ |
| 418 | void style_set_base_href_suffix(const char *zFormat, ...){ |
| 419 | fossil_free(local_zBaseHrefSuffix); |
| 420 | if( zFormat==0 ){ |
| 421 | local_zBaseHrefSuffix = 0; |
| 422 | }else{ |
| 423 | va_list ap; |
| 424 | va_start(ap, zFormat); |
| 425 | local_zBaseHrefSuffix = vmprintf(zFormat, ap); |
| 426 | va_end(ap); |
| 427 | } |
| 428 | } |
| 429 | |
| 430 | /* |
| 431 | ** Create a TH1 variable containing the URL for the stylesheet. |
| 432 |
| --- src/style.c | |
| +++ src/style.c | |
| @@ -408,24 +408,28 @@ | |
| 408 | } |
| 409 | |
| 410 | /* Use this for the $base_href_suffix variable if it is not NULL. |
| 411 | ** If it is NULL then use g.zRelReqURI |
| 412 | */ |
| 413 | static const char *local_zBaseHrefSuffix = 0; |
| 414 | |
| 415 | /* |
| 416 | ** Set the desired $base_href_suffix to something other than g.zRelReqURI |
| 417 | */ |
| 418 | void style_set_base_href_suffix(const char *zFormat, ...){ |
| 419 | fossil_free( (char*)local_zBaseHrefSuffix ); |
| 420 | if( zFormat==0 ){ |
| 421 | local_zBaseHrefSuffix = 0; |
| 422 | }else{ |
| 423 | char *z; |
| 424 | va_list ap; |
| 425 | |
| 426 | va_start(ap, zFormat); |
| 427 | z = vmprintf(zFormat, ap); |
| 428 | va_end(ap); |
| 429 | local_zBaseHrefSuffix = escape_quotes( z ); |
| 430 | if( local_zBaseHrefSuffix!=z ) fossil_free( z ); |
| 431 | } |
| 432 | } |
| 433 | |
| 434 | /* |
| 435 | ** Create a TH1 variable containing the URL for the stylesheet. |
| 436 |