david/ipxe
david
/
ipxe
Archived
1
0
Fork 0

[http] Avoid using stack-allocated memory in http_step()

http_step() allocates a potentially large block of storage (since the
URI can be arbitrarily long), and can be invoked as part of an already
deep call stack via xfer_window_changed().

Signed-off-by: Michael Brown <mcb30@ipxe.org>
This commit is contained in:
Michael Brown 2012-04-23 23:26:29 +01:00
parent a026a27f04
commit 45e0327987
1 changed files with 32 additions and 14 deletions

View File

@ -643,14 +643,16 @@ static void http_step ( struct http_request *http ) {
size_t user_pw_len = ( user ? ( strlen ( user ) + 1 /* ":" */ + size_t user_pw_len = ( user ? ( strlen ( user ) + 1 /* ":" */ +
strlen ( password ) ) : 0 ); strlen ( password ) ) : 0 );
size_t user_pw_base64_len = base64_encoded_len ( user_pw_len ); size_t user_pw_base64_len = base64_encoded_len ( user_pw_len );
uint8_t user_pw[ user_pw_len + 1 /* NUL */ ];
char user_pw_base64[ user_pw_base64_len + 1 /* NUL */ ];
int rc;
int request_len = unparse_uri ( NULL, 0, http->uri, int request_len = unparse_uri ( NULL, 0, http->uri,
URI_PATH_BIT | URI_QUERY_BIT ); URI_PATH_BIT | URI_QUERY_BIT );
char request[ request_len + 1 /* NUL */ ]; struct {
char range[48]; /* Enough for two 64-bit integers in decimal */ uint8_t user_pw[ user_pw_len + 1 /* NUL */ ];
char user_pw_base64[ user_pw_base64_len + 1 /* NUL */ ];
char request[ request_len + 1 /* NUL */ ];
char range[48]; /* Enough for two 64-bit integers in decimal */
} *dynamic;
int partial; int partial;
int rc;
/* Do nothing if we have already transmitted the request */ /* Do nothing if we have already transmitted the request */
if ( ! ( http->flags & HTTP_TX_PENDING ) ) if ( ! ( http->flags & HTTP_TX_PENDING ) )
@ -660,18 +662,27 @@ static void http_step ( struct http_request *http ) {
if ( ! xfer_window ( &http->socket ) ) if ( ! xfer_window ( &http->socket ) )
return; return;
/* Allocate dynamic storage */
dynamic = malloc ( sizeof ( *dynamic ) );
if ( ! malloc ) {
rc = -ENOMEM;
goto err_alloc;
}
/* Construct path?query request */ /* Construct path?query request */
unparse_uri ( request, sizeof ( request ), http->uri, unparse_uri ( dynamic->request, sizeof ( dynamic->request ), http->uri,
URI_PATH_BIT | URI_QUERY_BIT ); URI_PATH_BIT | URI_QUERY_BIT );
/* Construct authorisation, if applicable */ /* Construct authorisation, if applicable */
if ( user ) { if ( user ) {
/* Make "user:password" string from decoded fields */ /* Make "user:password" string from decoded fields */
snprintf ( ( ( char * ) user_pw ), sizeof ( user_pw ), snprintf ( ( ( char * ) dynamic->user_pw ),
"%s:%s", user, password ); sizeof ( dynamic->user_pw ), "%s:%s",
user, password );
/* Base64-encode the "user:password" string */ /* Base64-encode the "user:password" string */
base64_encode ( user_pw, user_pw_len, user_pw_base64 ); base64_encode ( dynamic->user_pw, user_pw_len,
dynamic->user_pw_base64 );
} }
/* Force a HEAD request if we have nowhere to send any received data */ /* Force a HEAD request if we have nowhere to send any received data */
@ -682,7 +693,8 @@ static void http_step ( struct http_request *http ) {
/* Determine type of request */ /* Determine type of request */
partial = ( http->partial_len != 0 ); partial = ( http->partial_len != 0 );
snprintf ( range, sizeof ( range ), "%zd-%zd", http->partial_start, snprintf ( dynamic->range, sizeof ( dynamic->range ),
"%zd-%zd", http->partial_start,
( http->partial_start + http->partial_len - 1 ) ); ( http->partial_start + http->partial_len - 1 ) );
/* Mark request as transmitted */ /* Mark request as transmitted */
@ -698,7 +710,7 @@ static void http_step ( struct http_request *http ) {
( ( http->flags & HTTP_HEAD_ONLY ) ? ( ( http->flags & HTTP_HEAD_ONLY ) ?
"HEAD" : "GET" ), "HEAD" : "GET" ),
( http->uri->path ? "" : "/" ), ( http->uri->path ? "" : "/" ),
request, host, dynamic->request, host,
( http->uri->port ? ( http->uri->port ?
":" : "" ), ":" : "" ),
( http->uri->port ? ( http->uri->port ?
@ -706,14 +718,20 @@ static void http_step ( struct http_request *http ) {
( ( http->flags & HTTP_KEEPALIVE ) ? ( ( http->flags & HTTP_KEEPALIVE ) ?
"Connection: Keep-Alive\r\n" : "" ), "Connection: Keep-Alive\r\n" : "" ),
( partial ? "Range: bytes=" : "" ), ( partial ? "Range: bytes=" : "" ),
( partial ? range : "" ), ( partial ? dynamic->range : "" ),
( partial ? "\r\n" : "" ), ( partial ? "\r\n" : "" ),
( user ? ( user ?
"Authorization: Basic " : "" ), "Authorization: Basic " : "" ),
( user ? user_pw_base64 : "" ), ( user ? dynamic->user_pw_base64 : "" ),
( user ? "\r\n" : "" ) ) ) != 0 ) { ( user ? "\r\n" : "" ) ) ) != 0 ) {
http_close ( http, rc ); goto err_xfer;
} }
err_xfer:
free ( dynamic );
err_alloc:
if ( rc != 0 )
http_close ( http, rc );
} }
/** /**