1 |
PATCH-P1-FIX: Fix incorrect linked list handling |
2 |
|
3 |
More information can be found below. |
4 |
|
5 |
Maintainer: Kristyna Streitova <kstreitova@suse.com> |
6 |
|
7 |
From 4797ea0b772d5f4c5889bc552424132806f46e93 Mon Sep 17 00:00:00 2001 |
8 |
From: Nisha Gopalakrishnan <nisha.gopalakrishnan@oracle.com> |
9 |
Date: Mon, 21 Jul 2014 21:21:15 +0530 |
10 |
Subject: [PATCH] BUG#17512527: LIST HANDLING INCORRECT IN |
11 |
MYSQL_PRUNE_STMT_LIST() |
12 |
|
13 |
Analysis: |
14 |
--------- |
15 |
Invalid memory access maybe observed when using prepared statements if: |
16 |
a) The mysql client connection is lost after statement preparation |
17 |
is complete and |
18 |
b) There is at least one statement which is in initialized state but |
19 |
not prepared yet. |
20 |
|
21 |
When the client detects a closed connection, it calls end_server() |
22 |
to shutdown the connection. As part of the clean up, the |
23 |
mysql_prune_stmt_list() removes the statements which has transitioned |
24 |
beyond the initialized state and retains only the statements which |
25 |
are in a initialized state. During this processing, the initialized |
26 |
statements are moved from 'mysql->stmts' to a temporary 'pruned_list'. |
27 |
When moving the first 'INIT_DONE' element to the pruned_list, |
28 |
'element->next' is set to NULL. Hence the rest of the list is never |
29 |
traversed and the statements which have transitioned beyond the |
30 |
initialized state are never invalidated. |
31 |
|
32 |
When the mysql_stmt_close() is called for the statement which is not |
33 |
invalidated; the statements list is updated in order to remove the |
34 |
statement. This would end up accessing freed memory(freed by the |
35 |
mysql_stmt_close() for a previous statement in the list). |
36 |
|
37 |
Fix: |
38 |
--- |
39 |
mysql_prune_stmt_list() called list_add() incorrectly to create a |
40 |
temporary list. The use case of list_add() is to add a single |
41 |
element to the front of the doubly linked list. |
42 |
mysql_prune_stmt_list() called list_add() by passing an entire |
43 |
list as the 'element'. |
44 |
|
45 |
mysql_prune_stmt_list() now uses list_delete() to remove the |
46 |
statement which has transitioned beyond the initialized phase. |
47 |
Thus the statement list would contain only elements where the |
48 |
the state of the statement is initialized. |
49 |
|
50 |
Note: Run the test with valgrind-mysqltest and leak-check=full |
51 |
option to see the invalid memory access. |
52 |
--- |
53 |
|
54 |
diff --git a/sql-common/client.c b/sql-common/client.c |
55 |
index eefb8a8..012292f 100644 |
56 |
--- a/sql-common/client.c |
57 |
+++ b/sql-common/client.c |
58 |
@@ -3985,12 +3985,15 @@ static void mysql_close_free(MYSQL *mysql) |
59 |
*/ |
60 |
static void mysql_prune_stmt_list(MYSQL *mysql) |
61 |
{ |
62 |
- LIST *element= mysql->stmts; |
63 |
- LIST *pruned_list= 0; |
64 |
+ LIST *pruned_list= NULL; |
65 |
|
66 |
- for (; element; element= element->next) |
67 |
+ while(mysql->stmts) |
68 |
{ |
69 |
- MYSQL_STMT *stmt= (MYSQL_STMT *) element->data; |
70 |
+ LIST *element= mysql->stmts; |
71 |
+ MYSQL_STMT *stmt; |
72 |
+ |
73 |
+ mysql->stmts= list_delete(element, element); |
74 |
+ stmt= (MYSQL_STMT *) element->data; |
75 |
if (stmt->state != MYSQL_STMT_INIT_DONE) |
76 |
{ |
77 |
stmt->mysql= 0; |