[PECL-CVS] [pecl-web_services-oauth] master: Merge pull request #40 from php/memory-safety-audit

[email protected] (Rasmus Lerdorf via GitHub) Sun, 5 Apr 2026 03:02:35 +0000
Newsgroups php.pecl.cvs
Message-ID <[email protected]>
Author: Rasmus Lerdorf (rlerdorf)
Committer: GitHub (web-flow)
Pusher: rlerdorf
Date: 2026-04-05T04:02:32+01:00

Commit: https://github.com/php/pecl-web_services-oauth/commit/a528c9fc8529f3db40525cac36714c1f0ac8019a
Raw diff: https://github.com/php/pecl-web_services-oauth/commit/a528c9fc8529f3db40525cac36714c1f0ac8019a.diff

Merge pull request #40 from php/memory-safety-audit

memory audit fixes

Changed paths:
  M  oauth.c
  M  provider.c


Diff:

diff --git a/oauth.c b/oauth.c
index f1c1c35..f05a95b 100644
--- a/oauth.c
+++ b/oauth.c
@@ -158,10 +158,6 @@ static void so_object_free_storage(zend_object *obj) /* {{{ */
 		soo->debug_info = NULL;
 	}
 
-	smart_string_free(&soo->headers_in);
-	if (soo->headers_out.c) {
-		smart_string_free(&soo->headers_out);
-	}
 	if(Z_TYPE(soo->debugArr) != IS_UNDEF) {
 		zval_ptr_dtor(&soo->debugArr);
 	}
@@ -172,6 +168,23 @@ static void so_object_free_storage(zend_object *obj) /* {{{ */
 	if (soo->timestamp) {
 		efree(soo->timestamp);
 	}
+	if (soo->multipart_files || soo->multipart_params) {
+		int mi;
+		for (mi = 0; mi < soo->multipart_files_num; mi++) {
+			if (soo->multipart_files) {
+				efree(soo->multipart_files[mi]);
+			}
+			if (soo->multipart_params) {
+				efree(soo->multipart_params[mi]);
+			}
+		}
+		if (soo->multipart_files) {
+			efree(soo->multipart_files);
+		}
+		if (soo->multipart_params) {
+			efree(soo->multipart_params);
+		}
+	}
 
 }
 /* }}} */
@@ -482,8 +495,8 @@ int oauth_http_build_query(php_so_object *soo, smart_string *s, HashTable *args,
 						soo->multipart_params = erealloc(soo->multipart_params, sizeof(char *) * (soo->multipart_files_num + 1));
 
 						convert_to_string_ex(cur_val);
-						soo->multipart_files[soo->multipart_files_num] = Z_STRVAL_P(cur_val);
-						soo->multipart_params[soo->multipart_files_num] = ZSTR_VAL(cur_key);
+						soo->multipart_files[soo->multipart_files_num] = estrdup(Z_STRVAL_P(cur_val));
+						soo->multipart_params[soo->multipart_files_num] = estrdup(ZSTR_VAL(cur_key));
 
 						++soo->multipart_files_num;
 						/* we don't add multipart files to the params */
@@ -1127,15 +1140,16 @@ long make_req_curl(php_so_object *soo, const char *url, const smart_string *payl
 		}
 
 		for(i=0; i < soo->multipart_files_num; i++) {
-			char *type = NULL, *filename = NULL, *postval, *postval_orig;
+			char *type = NULL, *filename = NULL, *postval, *postval_orig, *param_name;
 			curl_mimepart *part;
 
 			/* swiped from ext/curl/interface.c to help with consistency */
 			postval_orig = postval = estrdup(soo->multipart_files[i]);
+			param_name = soo->multipart_params[i];
 
-			if (postval[0] == '@' && soo->multipart_params[i][0] == '@') {
+			if (postval[0] == '@' && param_name[0] == '@') {
 				/* :< (chomp) @ */
-				++soo->multipart_params[i];
+				++param_name;
 				++postval;
 
 				if((type = (char *) php_memnstr(postval, ";type=", sizeof(";type=") - 1, postval + strlen(soo->multipart_files[i]) - 1))) {
@@ -1161,7 +1175,7 @@ long make_req_curl(php_so_object *soo, const char *url, const smart_string *payl
 					efree(postval_orig);
 					goto cleanup;
 				}
-				mres = curl_mime_name(part, soo->multipart_params[i]);
+				mres = curl_mime_name(part, param_name);
 				if (mres == CURLE_OK) mres = curl_mime_filedata(part, postval);
 				if (mres == CURLE_OK && filename) mres = curl_mime_filename(part, filename + sizeof(";filename=") - 1);
 				if (mres == CURLE_OK) mres = curl_mime_type(part, type ? type + sizeof(";type=") - 1 : "application/octet-stream");
@@ -1180,7 +1194,7 @@ long make_req_curl(php_so_object *soo, const char *url, const smart_string *payl
 					efree(postval_orig);
 					goto cleanup;
 				}
-				mres = curl_mime_name(part, soo->multipart_params[i]);
+				mres = curl_mime_name(part, param_name);
 				if (mres == CURLE_OK) mres = curl_mime_data(part, postval, CURL_ZERO_TERMINATED);
 				if (mres != CURLE_OK) {
 					char *em;
@@ -1199,12 +1213,13 @@ long make_req_curl(php_so_object *soo, const char *url, const smart_string *payl
 		int i;
 
 		for(i=0; i < soo->multipart_files_num; i++) {
-			char *type = NULL, *filename = NULL, *postval, *postval_orig;
+			char *type = NULL, *filename = NULL, *postval, *postval_orig, *param_name;
 
 			postval_orig = postval = estrdup(soo->multipart_files[i]);
+			param_name = soo->multipart_params[i];
 
-			if (postval[0] == '@' && soo->multipart_params[i][0] == '@') {
-				++soo->multipart_params[i];
+			if (postval[0] == '@' && param_name[0] == '@') {
+				++param_name;
 				++postval;
 
 				if((type = (char *) php_memnstr(postval, ";type=", sizeof(";type=") - 1, postval + strlen(soo->multipart_files[i]) - 1))) {
@@ -1225,24 +1240,24 @@ long make_req_curl(php_so_object *soo, const char *url, const smart_string *payl
 
 				if (filename) {
 					curl_formadd(&ff, &lf,
-								 CURLFORM_COPYNAME, soo->multipart_params[i],
-								 CURLFORM_NAMELENGTH, (long)strlen(soo->multipart_params[i]),
+								 CURLFORM_COPYNAME, param_name,
+								 CURLFORM_NAMELENGTH, (long)strlen(param_name),
 								 CURLFORM_FILENAME, filename + sizeof(";filename=") - 1,
 								 CURLFORM_CONTENTTYPE, type ? type + sizeof(";type=") - 1 : "application/octet-stream",
 								 CURLFORM_FILE, postval,
 								 CURLFORM_END);
 				} else {
 					curl_formadd(&ff, &lf,
-								 CURLFORM_COPYNAME, soo->multipart_params[i],
-								 CURLFORM_NAMELENGTH, (long)strlen(soo->multipart_params[i]),
+								 CURLFORM_COPYNAME, param_name,
+								 CURLFORM_NAMELENGTH, (long)strlen(param_name),
 								 CURLFORM_CONTENTTYPE, type ? type + sizeof(";type=") - 1 : "application/octet-stream",
 								 CURLFORM_FILE, postval,
 								 CURLFORM_END);
 				}
 			} else {
 				curl_formadd(&ff, &lf,
-							 CURLFORM_COPYNAME, soo->multipart_params[i],
-							 CURLFORM_NAMELENGTH, (long)strlen(soo->multipart_params[i]),
+							 CURLFORM_COPYNAME, param_name,
+							 CURLFORM_NAMELENGTH, (long)strlen(param_name),
 							 CURLFORM_COPYCONTENTS, postval,
 							 CURLFORM_CONTENTSLENGTH, (long)strlen(postval),
 							 CURLFORM_END);
@@ -1713,16 +1728,32 @@ static long oauth_fetch(php_so_object *soo, const char *url, const char *method,
 #if OAUTH_USE_CURL
 			case OAUTH_REQENGINE_CURL:
 				http_response_code = make_req_curl(soo, surl.c, &payload, final_http_method, &rheaders);
-				if (soo->multipart_files_num) {
-					efree(soo->multipart_files);
-					efree(soo->multipart_params);
-					soo->multipart_files_num = 0;
-					soo->is_multipart = 0;
-				}
 				break;
 #endif
 		}
 
+		if (soo->multipart_files || soo->multipart_params) {
+			int mi;
+			for (mi = 0; mi < soo->multipart_files_num; mi++) {
+				if (soo->multipart_files) {
+					efree(soo->multipart_files[mi]);
+				}
+				if (soo->multipart_params) {
+					efree(soo->multipart_params[mi]);
+				}
+			}
+			if (soo->multipart_files) {
+				efree(soo->multipart_files);
+				soo->multipart_files = NULL;
+			}
+			if (soo->multipart_params) {
+				efree(soo->multipart_params);
+				soo->multipart_params = NULL;
+			}
+			soo->multipart_files_num = 0;
+			soo->is_multipart = 0;
+		}
+
 		is_redirect = HTTP_IS_REDIRECT(http_response_code);
 
 		if(soo->debug) {
diff --git a/provider.c b/provider.c
index da09647..295af02 100644
--- a/provider.c
+++ b/provider.c
@@ -195,7 +195,11 @@ static void oauth_provider_set_std_params(zval *provider_obj, HashTable *sbs_var
 static inline int oauth_provider_set_param_value(HashTable *ht, char *key, zval *val) /* {{{ */
 {
 	Z_TRY_ADDREF_P(val);
-	return zend_hash_str_update(ht, key, strlen(key), val) != NULL;
+	if (zend_hash_str_update(ht, key, strlen(key), val) == NULL) {
+		Z_TRY_DELREF_P(val);
+		return FAILURE;
+	}
+	return SUCCESS;
 }
 /* }}} */
 
@@ -206,17 +210,25 @@ static int oauth_provider_parse_auth_header(php_oauth_provider *sop, char *auth_
 	HashPosition hpos;
 	zend_string *regex = zend_string_init(OAUTH_REGEX, sizeof(OAUTH_REGEX) - 1, 0);
 #if PHP_VERSION_ID >= 70400
-	zend_string *s_auth_header = zend_string_init(auth_header, strlen(auth_header), 0);
+	zend_string *s_auth_header;
 #endif
 	size_t decoded_len;
 
-	if(!auth_header || strncasecmp(auth_header, "oauth", 4) || !sop) {
+	if(!auth_header || strncasecmp(auth_header, "oauth ", 6) || !sop) {
+		zend_string_release(regex);
 		return FAILURE;
 	}
 	/* pass "OAuth " */
-	auth_header += 5;
+	auth_header += 6;
+
+#if PHP_VERSION_ID >= 70400
+	s_auth_header = zend_string_init(auth_header, strlen(auth_header), 0);
+#endif
 
 	if ((pce = pcre_get_compiled_regex_cache(regex)) == NULL) {
+#if PHP_VERSION_ID >= 70400
+		zend_string_release(s_auth_header);
+#endif
 		zend_string_release(regex);
 		return FAILURE;
 	}
@@ -246,6 +258,11 @@ static int oauth_provider_parse_auth_header(php_oauth_provider *sop, char *auth_
 	);
 
 	if (0 == Z_LVAL(return_value)) {
+		zval_ptr_dtor(&return_value);
+		zval_ptr_dtor(&subpats);
+#if PHP_VERSION_ID >= 70400
+		zend_string_release(s_auth_header);
+#endif
 		return FAILURE;
 	}
 
@@ -271,16 +288,26 @@ static int oauth_provider_parse_auth_header(php_oauth_provider *sop, char *auth_
 			tmp = estrndup(Z_STRVAL_P(current_val), Z_STRLEN_P(current_val));
 			decoded_len = php_url_decode(tmp, Z_STRLEN_P(current_val));
 			ZVAL_STRINGL(&decoded_val, tmp, decoded_len);
+			efree(tmp);
 
-			if (oauth_provider_set_param_value(sop->oauth_params, Z_STRVAL_P(current_param), &decoded_val)==FAILURE) {
+			if (oauth_provider_set_param_value(sop->oauth_params, Z_STRVAL_P(current_param), &decoded_val) == FAILURE) {
+				zval_ptr_dtor(&decoded_val);
+				zval_ptr_dtor(&return_value);
+				zval_ptr_dtor(&subpats);
+#if PHP_VERSION_ID >= 70400
+				zend_string_release(s_auth_header);
+#endif
 				return FAILURE;
 			}
-			Z_DELREF(decoded_val);
+			zval_ptr_dtor(&decoded_val);
 		}
 	} while (SUCCESS==zend_hash_move_forward_ex(Z_ARRVAL(subpats), &hpos));
 
 	zval_ptr_dtor(&return_value);
 	zval_ptr_dtor(&subpats);
+#if PHP_VERSION_ID >= 70400
+	zend_string_release(s_auth_header);
+#endif
 
 	return SUCCESS;
 }
@@ -318,6 +345,9 @@ static void oauth_provider_register_cb(INTERNAL_FUNCTION_PARAMETERS, int type) /
 			tgt_cb = &sop->tsnonce_handler;
 			break;
 		default:
+			zval_ptr_dtor(&cb->fcall_info->function_name);
+			efree(cb->fcall_info);
+			efree(cb);
 			php_error_docref(NULL, E_ERROR, "Invalid callback type for OAuthProvider");
 			return;
 	}