php.net |  support |  documentation |  report a bug |  advanced search |  search howto |  statistics |  random bug |  login
Bug #57297 oci8 uses wrong permanent connection (ORA-00942)
Submitted: 2006-10-16 06:55 UTC Modified: 2006-10-18 10:23 UTC
From: jfbustarret at tf1 dot fr Assigned:
Status: Closed Package: oci8 (PECL)
PHP Version: 5.1.6 OS: Linux
Private report: No CVE-ID: None
Welcome back! If you're the original bug submitter, here's where you can edit the bug or add additional notes.
If you forgot your password, you can retrieve your password here.
Password:
Status:
Package:
Bug Type:
Summary:
From: jfbustarret at tf1 dot fr
New email:
PHP Version: OS:

 

 [2006-10-16 06:55 UTC] jfbustarret at tf1 dot fr
Description:
------------
On an apache webserver hosting various websites & connecting to various databases, we randomly get ORA-00942 errors (table or view does not exist).
It looks like the oci8 mixes up persistent connections & uses one with the wrong credentials.

Disabling persistent connections (oci8.max_persistent=0) solves the problem. Playing with ping_interval & persistent_timeout does not.

oci8 version : 1.2.2 ($Revision: 1.269.2.16.2.21 $)
Oracle client version : 9.2
PHP Version : 5.1.6 with hardening patch

Reproduce code:
---------------
No reproduce code. The errors are random (random times, random sql requests, random websites).


Patches

Pull Requests

History

AllCommentsChangesGit/SVN commitsRelated reports
 [2006-10-16 09:01 UTC] tony2001 at phpclub dot net
Can't reproduce.
 [2006-10-17 10:07 UTC] jfbustarret at tf1 dot fr
I did add debug messages in oci8.c

diff -rup oci8-1.2.2/oci8.c oci8-1.2.2.debug/oci8.c
--- oci8-1.2.2/oci8.c   2006-08-24 14:05:19.000000000 +0200
+++ oci8-1.2.2.debug/oci8.c     2006-10-17 15:26:59.000000000 +0200
@@ -666,7 +666,7 @@ PHP_MINFO_FUNCTION(oci)

        php_info_print_table_start();
        php_info_print_table_row(2, "OCI8 Support", "enabled");
-       php_info_print_table_row(2, "Version", "1.2.1");
+       php_info_print_table_row(2, "Version", "1.2.2.debug");
        php_info_print_table_row(2, "Revision", "$Revision: 1.269.2.16.2.21 $");

        sprintf(buf, "%ld", OCI_G(num_persistent));
@@ -1106,12 +1106,13 @@ php_oci_connection *php_oci_do_connect_e

                                                        /* okay, the connection is open and the server is still alive */
                                                        connection->used_this_request = 1;
-                                                       smart_str_free_ex(&hashed_details, 0);
                                                        if (zend_list_find(connection->rsrc_id, &rsrc_type) && (rsrc_type == le_pconnection) && zend_list_addref(connection->rsrc_id) == SUCCESS) {
                                                                /* do nothing */
                                                        } else {
                                                                connection->rsrc_id = zend_list_insert(connection, le_pconnection);
                                                        }
+                                                       php_error_docref(NULL TSRMLS_CC, E_WARNING, "found persistent connection for %s : %s (rsrc_id %d)\n", hashed_details.c, connection->hash_key, connection->rsrc_id);
+                                                       smart_str_free_ex(&hashed_details, 0);
                                                        return connection;
                                                }
                                        }

These debug message show different persistent connections using the same rsrc_id :
Oct 17 16:00:35  [error] 2880 - www.olweb.fr - Environnement - Warning PHP : ociplogon() [<a href='function.ociplogon'>function.ociplogon</a>]: found persistent connection for oci8___[user1]__1442677164__[database].world__8710 : oci8___[user1]__1442677164__[database].world__8710 (rsrc_id 56)
Oct 17 16:00:35  [error] 2880 - www.olweb.fr - Environnement - Warning PHP : ociplogon() [<a href='function.ociplogon'>function.ociplogon</a>]: found persistent connection for oci8___[user2]__2782104700__[database].world__8710 : oci8___[user2]__2782104700__[database].world__8710 (rsrc_id 56)

After this rsrc_id mixup, the db requests for the second connection use the first one.
 [2006-10-17 10:14 UTC] tony2001 at phpclub dot net
That doesn't help much in reproducing it.
 [2006-10-17 11:24 UTC] jfbustarret at tf1 dot fr
Tell me what you think of this scenario :

pconnect user1 => rsrc_id1
statement_free (or lob_free) => rsrc_id1 is removed from the list (zend_list_delete), but the persistent connection still exists and points to rsrc_id1
pconnect user2 => rsrc_id1 (zend_list_insert returns the first available)

The next pconnect user1 returns rsrc_id1, checks that it is a persistent connection (which it is, but it points to user2), and returns rsrc_id1. Hence the mixup.

Suggested fix : remove zend_list_delete(xxx->connection->rsrc_id) from php_oci_lob_free and php_oci_statement_free (which might have an impact on PECL bug #5571 (oci_new_connect() not closed by oci_close()))

I'll test the fix tomorrow.
 [2006-10-17 11:38 UTC] jfbustarret at tf1 dot fr
Reproduce code :

<?php
ini_set("display_errors", "On");
$server = "...";
$passwd1 = $user1 = "...";
$passwd2 = $user2 = "...";
$table1 = "...";

$conn1 = OCIPLogon($user1, $passwd1, $server);
$stmt = OCIParse($conn1, "select * from $table1");
OCIExecute($stmt);
$erra=OCIError($conn1);
if (!empty($erra['message']))
        print "Error: ${erra['code']} ${erra['message']}";
OCIFreeStatement($stmt);
$conn1 = OCIPLogon($user2, $passwd2, $server);
$stmt = OCIParse($conn1, "select * from $table1");
OCIExecute($stmt);
$erra=OCIError($conn1);
if (!empty($erra['message']))
        print "Error: ${erra['code']} ${erra['message']}";

Displays :

Warning: ociexecute(): ORA-00942: table or view does not exist in /mnt/home_distant/jfb/testoci.php on line 17

Expected result :

no error
 [2006-10-17 11:40 UTC] jfbustarret at tf1 dot fr
My mistake. The code was wrong...
 [2006-10-17 13:12 UTC] tony2001 at phpclub dot net
No bug -> bogus.
 [2006-10-18 03:15 UTC] jfbustarret at tf1 dot fr
The bug is not bogus. Only my reproduce code is.

Current oci8 does not garantee that different persistent connctions have different rsrc_id. This means that requests can use a connection with wrong credentials.

I'll try to write a new reproduce code and/or a fix.
 [2006-10-18 03:16 UTC] jfbustarret at tf1 dot fr
reopening
 [2006-10-18 05:11 UTC] tony2001 at phpclub dot net
>Current oci8 does not garantee that different persistent
>connctions have different rsrc_id. 
Wrong.

If you're unable to provide the reproduce code - the report is bogus.
 [2006-10-18 05:11 UTC] jfbustarret at tf1 dot fr
New reproduce code :

<?php
ini_set("display_errors", "On");
$server = "...";
$passwd1 = $user1 = "...";
$passwd2 = $user2 = "...";
$passwd3 = $user3 = "...";
$table1 = "...";
$table3 = "...";

// generate a random rsrc_id offset
$conn3 = OCIPLogon($user3, $passwd3, $server);
for ($i=1; $i<rand(1,2); $i++) {
        $stmt = OCIParse($conn3, "select * from $table3");
        OCIExecute($stmt);
}

// conn1 will sometimes get conn2->rsrc_id
$conn2 = OCIPLogon($user2, $passwd2, $server);
$conn1 = OCIPLogon($user1, $passwd1, $server);

// this will be randomly executed with user1 or user2 credentials
$stmt = OCIParse($conn1, "select * from $table1");
OCIExecute($stmt);

You have to call this multiple times through the HTTP server (apache in my case).
The script should not generate an error, but randomly displays :
<b>Warning</b>:  ociexecute() [<a href='function.ociexecute'>function.ociexecute</a>]: ORA-00942: table or view does not exist in <b>/data/www/exploit/htdocs/testoci.php</b> on line <b>23</b>

My understanding of the bug is that EG(regular_list) & all ressource ids are reset between requests. EG(persistent_list) is not reset, and connections store invalid rsrc_ids from previous requests. Shouldn't all persistent connections rsrc_ids be reset between requests ?
 [2006-10-18 05:58 UTC] jfbustarret at tf1 dot fr
Reverting to the oci8 version 1.1 way of using rsrc_id seems to solve the problem (reproduce code works without error, no error on the production platform for the last 30 minutes - 1 or 2 errors/minute before).

--- oci8-1.2.2/oci8.c   2006-08-24 14:05:19.000000000 +0200
+++ oci8-1.2.2-jfb/oci8.c       2006-10-18 11:16:34.000000000 +0200
@@ -1107,11 +1107,7 @@ php_oci_connection *php_oci_do_connect_e
                                                        /* okay, the connection is open and the server is still alive */
                                                        connection->used_this_request = 1;
                                                        smart_str_free_ex(&hashed_details, 0);
-                                                       if (zend_list_find(connection->rsrc_id, &rsrc_type) && (rsrc_type == le_pconnection) && zend_list_addref(connection->rsrc_id) == SUCCESS) {
-                                                               /* do nothing */
-                                                       } else {
-                                                               connection->rsrc_id = zend_list_insert(connection, le_pconnection);
-                                                       }
+                                                       connection->rsrc_id = zend_list_insert(connection, le_pconnection);
                                                        return connection;
                                                }
                                        }

Thanks for your help.
 [2006-10-18 06:03 UTC] tony2001 at phpclub dot net
Please get the latest 5.2 snapshot, apply this patch:
http://tony2001.phpclub.net/dev/tmp/pecl_bug9061.diff
(cd php-...; patch -p0 < /path/to/pecl_bug9061.diff)
and check if you still can reproduce it.
 [2006-10-18 09:59 UTC] jfbustarret at tf1 dot fr
Patch applied on PHP 5.1.6/oci8 1.2.2.

It crashes on :
hash_key_len = tmp ? strlen(tmp->hash_key) : 0;
(gdb) print *tmp
$3 = {env = 0x2, charset = 33656, server = 0x0, svc = 0x838f424, session = 0x838ed5c, err = 0x847ca58, errcode = 24, descriptors = 0x8480820, is_open = 0,
  is_attached = 0, is_persistent = 0, used_this_request = 0, needs_commit = 0, rsrc_id = 0, idle_expiry = 47, next_ping = 65537,
  hash_key = 0xb28863f1 <Address 0xb28863f1 out of bounds>}

After applying this after your patch, it works :

@@ -1108,9 +1108,9 @@ php_oci_connection *php_oci_do_connect_e
                                                        /* okay, the connection is open and the server is still alive */
                                                        connection->used_this_request = 1;
                                                        tmp = (php_oci_connection *)zend_list_find(connection->rsrc_id, &rsrc_type);
-                                                       hash_key_len = tmp ? strlen(tmp->hash_key) : 0;
+                                                       hash_key_len = tmp && rsrc_type == le_pconnection ? strlen(tmp->hash_key) : 0;

-                                                       if (tmp != NULL && rsrc_type == le_pconnection && hash_key_len == hashed_details.len &&
+                                                       if (hash_key_len > 0 && hash_key_len == hashed_details.len &&
                                                                memcmp(tmp->hash_key, hashed_details.c, hashed_details.len) == 0 && zend_list_addref(connection->rsrc_id) == SUCCESS) {
                                                                /* do nothing */
                                                        } else {
 [2006-10-18 10:08 UTC] tony2001 at phpclub dot net
So it crashes or it works?
 [2006-10-18 10:14 UTC] jfbustarret at tf1 dot fr
- It crashes with your patch

- It works fine (no crashes, no ORA-00942) with your patch AND my last patch (rsrc_type == le_pconnection moved before strlen(tmp->hash_key))
 [2006-10-18 10:23 UTC] tony2001 at phpclub dot net
This bug has been fixed in CVS.

In case this was a documentation problem, the fix will show up at the
end of next Sunday (CET) on pecl.php.net.

In case this was a pecl.php.net website problem, the change will show
up on the website in short time.
 
Thank you for the report, and for helping us make PECL better.


 
PHP Copyright © 2001-2024 The PHP Group
All rights reserved.
Last updated: Thu Dec 26 10:01:29 2024 UTC