Commit:    1751d5fabeff466f08da560caa6f92222ade5a82
Author:    Anthony Ferrara <ircmax...@gmail.com>         Sat, 6 Oct 2012 
10:38:41 -0400
Parents:   25b2d364e995fc070ae16ee34f60d25148413769
Branches:  master

Link:       
http://git.php.net/?p=php-src.git;a=commitdiff;h=1751d5fabeff466f08da560caa6f92222ade5a82

Log:
Really fix leaks, add test cases to prove it...

Changed paths:
  M  ext/standard/password.c
  M  ext/standard/tests/password/password_bcrypt_errors.phpt
  M  ext/standard/tests/password/password_hash_error.phpt
  M  ext/standard/tests/password/password_needs_rehash.phpt


Diff:
diff --git a/ext/standard/password.c b/ext/standard/password.c
index af42a6f..9667fdc 100644
--- a/ext/standard/password.c
+++ b/ext/standard/password.c
@@ -245,9 +245,12 @@ PHP_FUNCTION(password_needs_rehash)
                                
                                if (options && zend_symtable_find(options, 
"cost", sizeof("cost"), (void **) &option_buffer) == SUCCESS) {
                                        if (Z_TYPE_PP(option_buffer) != 
IS_LONG) {
-                                               
convert_to_long_ex(option_buffer);
-                                               new_cost = 
Z_LVAL_PP(option_buffer);
-                                               zval_ptr_dtor(option_buffer);
+                                               zval *cast_option_buffer;
+                                               ALLOC_ZVAL(cast_option_buffer);
+                                               
INIT_PZVAL_COPY(cast_option_buffer, *option_buffer);
+                                               
convert_to_long(cast_option_buffer);
+                                               new_cost = 
Z_LVAL_P(cast_option_buffer);
+                                               zval_dtor(cast_option_buffer);
                                        } else {
                                                new_cost = 
Z_LVAL_PP(option_buffer);
                                        }
@@ -323,9 +326,12 @@ PHP_FUNCTION(password_hash)
        
                        if (options && zend_symtable_find(options, "cost", 5, 
(void **) &option_buffer) == SUCCESS) {
                                if (Z_TYPE_PP(option_buffer) != IS_LONG) {
-                                       convert_to_long_ex(option_buffer);
-                                       cost = Z_LVAL_PP(option_buffer);
-                                       zval_ptr_dtor(option_buffer);
+                                       zval *cast_option_buffer;
+                                       ALLOC_ZVAL(cast_option_buffer);
+                                       INIT_PZVAL_COPY(cast_option_buffer, 
*option_buffer);
+                                       convert_to_long(cast_option_buffer);
+                                       cost = Z_LVAL_P(cast_option_buffer);
+                                       zval_dtor(cast_option_buffer);
                                } else {
                                        cost = Z_LVAL_PP(option_buffer);
                                }
@@ -353,27 +359,27 @@ PHP_FUNCTION(password_hash)
                int buffer_len_int = 0;
                size_t buffer_len;
                switch (Z_TYPE_PP(option_buffer)) {
-                       case IS_NULL:
                        case IS_STRING:
+                               buffer = estrndup(Z_STRVAL_PP(option_buffer), 
Z_STRLEN_PP(option_buffer));
+                               buffer_len_int = Z_STRLEN_PP(option_buffer);
+                               break;
                        case IS_LONG:
                        case IS_DOUBLE:
-                       case IS_BOOL:
-                       case IS_OBJECT:
-                               if (Z_TYPE_PP(option_buffer) == IS_STRING) {
-                                       buffer = Z_STRVAL_PP(option_buffer);
-                                       buffer_len_int = 
Z_STRLEN_PP(option_buffer);
+                       case IS_OBJECT: {
+                               zval *cast_option_buffer;
+                               ALLOC_ZVAL(cast_option_buffer);
+                               INIT_PZVAL_COPY(cast_option_buffer, 
*option_buffer);
+                               convert_to_string(cast_option_buffer);
+                               if (Z_TYPE_P(cast_option_buffer) == IS_STRING) {
+                                       buffer = 
estrndup(Z_STRVAL_P(cast_option_buffer), Z_STRLEN_P(cast_option_buffer));
+                                       buffer_len_int = 
Z_STRLEN_P(cast_option_buffer);
+                                       zval_dtor(cast_option_buffer);
                                        break;
-                               } else {
-                                       SEPARATE_ZVAL(option_buffer);
-                                       convert_to_string_ex(option_buffer);
-                                       if (Z_TYPE_PP(option_buffer) == 
IS_STRING) {
-                                               buffer = 
Z_STRVAL_PP(option_buffer);
-                                               buffer_len_int = 
Z_STRLEN_PP(option_buffer);
-                                               zval_ptr_dtor(option_buffer);
-                                               break;
-                                       }
-                                       zval_ptr_dtor(option_buffer);
                                }
+                               zval_dtor(cast_option_buffer);
+                       }
+                       case IS_BOOL:
+                       case IS_NULL:
                        case IS_RESOURCE:
                        case IS_ARRAY:
                        default:
@@ -383,17 +389,20 @@ PHP_FUNCTION(password_hash)
                }
                if (buffer_len_int < 0) {
                        efree(hash_format);
+                       efree(buffer);
                        php_error_docref(NULL TSRMLS_CC, E_WARNING, "Supplied 
salt is too long");
                }
                buffer_len = (size_t) buffer_len_int;
                if (buffer_len < required_salt_len) {
                        efree(hash_format);
+                       efree(buffer);
                        php_error_docref(NULL TSRMLS_CC, E_WARNING, "Provided 
salt is too short: %lu expecting %lu", (unsigned long) buffer_len, (unsigned 
long) required_salt_len);
                        RETURN_NULL();
                } else if (0 == php_password_salt_is_alphabet(buffer, 
buffer_len)) {
                        salt = safe_emalloc(required_salt_len, 1, 1);
                        if (php_password_salt_to64(buffer, buffer_len, 
required_salt_len, salt) == FAILURE) {
                                efree(hash_format);
+                               efree(buffer);
                                efree(salt);
                                php_error_docref(NULL TSRMLS_CC, E_WARNING, 
"Provided salt is too short: %lu", (unsigned long) buffer_len);
                                RETURN_NULL();
@@ -404,6 +413,7 @@ PHP_FUNCTION(password_hash)
                        memcpy(salt, buffer, (int) required_salt_len);
                        salt_len = required_salt_len;
                }
+               efree(buffer);
        } else {
                salt = safe_emalloc(required_salt_len, 1, 1);
                if (php_password_make_salt(required_salt_len, salt TSRMLS_CC) 
== FAILURE) {
diff --git a/ext/standard/tests/password/password_bcrypt_errors.phpt 
b/ext/standard/tests/password/password_bcrypt_errors.phpt
index f36d11f..2548c9a 100644
--- a/ext/standard/tests/password/password_bcrypt_errors.phpt
+++ b/ext/standard/tests/password/password_bcrypt_errors.phpt
@@ -12,6 +12,10 @@ var_dump(password_hash("foo", PASSWORD_BCRYPT, array("salt" 
=> "foo")));
 
 var_dump(password_hash("foo", PASSWORD_BCRYPT, array("salt" => 
"123456789012345678901")));
 
+var_dump(password_hash("foo", PASSWORD_BCRYPT, array("salt" => 123)));
+
+var_dump(password_hash("foo", PASSWORD_BCRYPT, array("cost" => "foo")));
+
 ?>
 --EXPECTF--
 Warning: password_hash(): Invalid bcrypt cost parameter specified: 3 in %s on 
line %d
@@ -26,3 +30,10 @@ NULL
 Warning: password_hash(): Provided salt is too short: 21 expecting 22 in %s on 
line %d
 NULL
 
+Warning: password_hash(): Provided salt is too short: 3 expecting 22 in %s on 
line %d
+NULL
+
+Warning: password_hash(): Invalid bcrypt cost parameter specified: 0 in %s on 
line %d
+NULL
+
+
diff --git a/ext/standard/tests/password/password_hash_error.phpt 
b/ext/standard/tests/password/password_hash_error.phpt
index 695a6c4..952250c 100644
--- a/ext/standard/tests/password/password_hash_error.phpt
+++ b/ext/standard/tests/password/password_hash_error.phpt
@@ -18,6 +18,9 @@ var_dump(password_hash(array(), PASSWORD_BCRYPT));
 
 var_dump(password_hash("123", PASSWORD_BCRYPT, array("salt" => array())));
 
+/* Non-string salt, checking for memory leaks */
+var_dump(password_hash('123', PASSWORD_BCRYPT, array('salt' => 1234)));
+
 ?>
 --EXPECTF--
 Warning: password_hash() expects at least 2 parameters, 0 given in %s on line 
%d
@@ -41,3 +44,5 @@ NULL
 Warning: password_hash(): Non-string salt parameter supplied in %s on line %d
 NULL
 
+Warning: password_hash(): Provided salt is too short: 4 expecting 22 in %s on 
line %d
+NULL
diff --git a/ext/standard/tests/password/password_needs_rehash.phpt 
b/ext/standard/tests/password/password_needs_rehash.phpt
index 2fc3983..734729e 100644
--- a/ext/standard/tests/password/password_needs_rehash.phpt
+++ b/ext/standard/tests/password/password_needs_rehash.phpt
@@ -26,6 +26,11 @@ 
var_dump(password_needs_rehash('$2y$10$MTIzNDU2Nzg5MDEyMzQ1Nej0NmcAWSLR.oP7XOR9H
 $cost = str_pad(PASSWORD_BCRYPT_DEFAULT_COST, 2, '0', STR_PAD_LEFT);
 
var_dump(password_needs_rehash('$2y$'.$cost.'$MTIzNDU2Nzg5MDEyMzQ1Nej0NmcAWSLR.oP7XOR9HD/vjUuOj100y',
 PASSWORD_BCRYPT));
 
+// Should Issue Needs Rehash, Since Foo is cast to 0...
+var_dump(password_needs_rehash('$2y$10$MTIzNDU2Nzg5MDEyMzQ1Nej0NmcAWSLR.oP7XOR9HD/vjUuOj100y',
 PASSWORD_BCRYPT, array('cost' => 'foo')));
+
+
+
 echo "OK!";
 ?>
 --EXPECT--
@@ -36,4 +41,5 @@ bool(false)
 bool(true)
 bool(true)
 bool(false)
+bool(true)
 OK!


--
PHP CVS Mailing List (http://www.php.net/)
To unsubscribe, visit: http://www.php.net/unsub.php

Reply via email to