瀏覽代碼

[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>
tags/v1.20.1
Michael Brown 12 年之前
父節點
當前提交
45e0327987
共有 1 個文件被更改,包括 32 次插入14 次删除
  1. 32
    14
      src/net/tcp/httpcore.c

+ 32
- 14
src/net/tcp/httpcore.c 查看文件

@@ -643,14 +643,16 @@ static void http_step ( struct http_request *http ) {
643 643
 	size_t user_pw_len = ( user ? ( strlen ( user ) + 1 /* ":" */ +
644 644
 					strlen ( password ) ) : 0 );
645 645
 	size_t user_pw_base64_len = base64_encoded_len ( user_pw_len );
646
-	uint8_t user_pw[ user_pw_len + 1 /* NUL */ ];
647
-	char user_pw_base64[ user_pw_base64_len + 1 /* NUL */ ];
648
-	int rc;
649 646
 	int request_len = unparse_uri ( NULL, 0, http->uri,
650 647
 					URI_PATH_BIT | URI_QUERY_BIT );
651
-	char request[ request_len + 1 /* NUL */ ];
652
-	char range[48]; /* Enough for two 64-bit integers in decimal */
648
+	struct {
649
+		uint8_t user_pw[ user_pw_len + 1 /* NUL */ ];
650
+		char user_pw_base64[ user_pw_base64_len + 1 /* NUL */ ];
651
+		char request[ request_len + 1 /* NUL */ ];
652
+		char range[48]; /* Enough for two 64-bit integers in decimal */
653
+	} *dynamic;
653 654
 	int partial;
655
+	int rc;
654 656
 
655 657
 	/* Do nothing if we have already transmitted the request */
656 658
 	if ( ! ( http->flags & HTTP_TX_PENDING ) )
@@ -660,18 +662,27 @@ static void http_step ( struct http_request *http ) {
660 662
 	if ( ! xfer_window ( &http->socket ) )
661 663
 		return;
662 664
 
665
+	/* Allocate dynamic storage */
666
+	dynamic = malloc ( sizeof ( *dynamic ) );
667
+	if ( ! malloc ) {
668
+		rc = -ENOMEM;
669
+		goto err_alloc;
670
+	}
671
+
663 672
 	/* Construct path?query request */
664
-	unparse_uri ( request, sizeof ( request ), http->uri,
673
+	unparse_uri ( dynamic->request, sizeof ( dynamic->request ), http->uri,
665 674
 		      URI_PATH_BIT | URI_QUERY_BIT );
666 675
 
667 676
 	/* Construct authorisation, if applicable */
668 677
 	if ( user ) {
669 678
 		/* Make "user:password" string from decoded fields */
670
-		snprintf ( ( ( char * ) user_pw ), sizeof ( user_pw ),
671
-			   "%s:%s", user, password );
679
+		snprintf ( ( ( char * ) dynamic->user_pw ),
680
+			   sizeof ( dynamic->user_pw ), "%s:%s",
681
+			   user, password );
672 682
 
673 683
 		/* Base64-encode the "user:password" string */
674
-		base64_encode ( user_pw, user_pw_len, user_pw_base64 );
684
+		base64_encode ( dynamic->user_pw, user_pw_len,
685
+				dynamic->user_pw_base64 );
675 686
 	}
676 687
 
677 688
 	/* 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 ) {
682 693
 
683 694
 	/* Determine type of request */
684 695
 	partial = ( http->partial_len != 0 );
685
-	snprintf ( range, sizeof ( range ), "%zd-%zd", http->partial_start,
696
+	snprintf ( dynamic->range, sizeof ( dynamic->range ),
697
+		   "%zd-%zd", http->partial_start,
686 698
 		   ( http->partial_start + http->partial_len - 1 ) );
687 699
 
688 700
 	/* Mark request as transmitted */
@@ -698,7 +710,7 @@ static void http_step ( struct http_request *http ) {
698 710
 				  ( ( http->flags & HTTP_HEAD_ONLY ) ?
699 711
 				    "HEAD" : "GET" ),
700 712
 				  ( http->uri->path ? "" : "/" ),
701
-				  request, host,
713
+				  dynamic->request, host,
702 714
 				  ( http->uri->port ?
703 715
 				    ":" : "" ),
704 716
 				  ( http->uri->port ?
@@ -706,14 +718,20 @@ static void http_step ( struct http_request *http ) {
706 718
 				  ( ( http->flags & HTTP_KEEPALIVE ) ?
707 719
 				    "Connection: Keep-Alive\r\n" : "" ),
708 720
 				  ( partial ? "Range: bytes=" : "" ),
709
-				  ( partial ? range : "" ),
721
+				  ( partial ? dynamic->range : "" ),
710 722
 				  ( partial ? "\r\n" : "" ),
711 723
 				  ( user ?
712 724
 				    "Authorization: Basic " : "" ),
713
-				  ( user ? user_pw_base64 : "" ),
725
+				  ( user ? dynamic->user_pw_base64 : "" ),
714 726
 				  ( user ? "\r\n" : "" ) ) ) != 0 ) {
715
-		http_close ( http, rc );
727
+		goto err_xfer;
716 728
 	}
729
+
730
+ err_xfer:
731
+	free ( dynamic );
732
+ err_alloc:
733
+	if ( rc != 0 )
734
+		http_close ( http, rc );
717 735
 }
718 736
 
719 737
 /**

Loading…
取消
儲存