ldap/servers/slapd/abandon.c | 3 ++-
ldap/servers/slapd/connection.c | 2 +-
ldap/servers/slapd/opshared.c | 20 ++++++++++++++------
ldap/servers/slapd/pagedresults.c | 27 +++++++++++++++++++++------
ldap/servers/slapd/proto-slap.h | 2 +-
ldap/servers/slapd/slap.h | 16 ++++++++++++----
6 files changed, 51 insertions(+), 19 deletions(-)
New commits:
commit 16088c1548396cf6ea7e2e7d5a6fc11ae17dd644
Author: Noriko Hosoi <nhosoi(a)totoro.usersys.redhat.com>
Date: Wed Oct 24 13:59:42 2012 -0700
Bug 866623 - RHDS crash when attempting to free an invalid pointer
https://bugzilla.redhat.com/show_bug.cgi?id=866623
Bug Description: When a simple-paged-results search is abandoned,
it calls pagedresults_cleanup and cleans up the search result set
stashed in the connection object. The abandoned fact is not stored
any place. Thus if the further operation expecting the search
result set is issued, it crould crash the server.
Fix Description: This patch introduces ABANDONED flag and sets it
if the simple paged results search is abandoned. Any further ops
on the search are skipped.
This patch is also adding a check if the given page size is 0 in
the simple-paged-results control or not. If it is 0, treat is as
an abandoned operation.
diff --git a/ldap/servers/slapd/abandon.c b/ldap/servers/slapd/abandon.c
index 8870364..5271981 100644
--- a/ldap/servers/slapd/abandon.c
+++ b/ldap/servers/slapd/abandon.c
@@ -152,7 +152,8 @@ do_abandon( Slapi_PBlock *pb )
0 );
}
- if (pagedresults_cleanup(pb->pb_conn, 0 /* already locked */)) {
+ if (pagedresults_cleanup(pb->pb_conn, PAGEDRESULTS_ABANDONED,
+ 0 /* already locked */)) {
/* Cleaned up paged result connection */
slapi_log_access( LDAP_DEBUG_STATS, "conn=%" NSPRIu64 " op=%d
ABANDON"
" targetop=Simple Paged Results\n",
diff --git a/ldap/servers/slapd/connection.c b/ldap/servers/slapd/connection.c
index cabfe71..1dbd493 100644
--- a/ldap/servers/slapd/connection.c
+++ b/ldap/servers/slapd/connection.c
@@ -201,7 +201,7 @@ connection_cleanup(Connection *conn)
/* destroy any sasl context */
sasl_dispose((sasl_conn_t**)&conn->c_sasl_conn);
/* PAGED_RESULTS */
- pagedresults_cleanup(conn, 0 /* do not need to lock inside */);
+ pagedresults_cleanup(conn, PAGEDRESULTS_CLEANALL, 0 /* do not need to lock inside */);
/* free the connection socket buffer */
connection_free_private_buffer(conn);
diff --git a/ldap/servers/slapd/opshared.c b/ldap/servers/slapd/opshared.c
index dffc2a5..b213342 100644
--- a/ldap/servers/slapd/opshared.c
+++ b/ldap/servers/slapd/opshared.c
@@ -422,9 +422,17 @@ op_shared_search (Slapi_PBlock *pb, int send_result)
&pagesize, &curr_search_count);
if (LDAP_SUCCESS == rc) {
unsigned int opnote = SLAPI_OP_NOTE_SIMPLEPAGED;
- if (pagedresults_check_or_set_processing(pb->pb_conn)) {
- send_ldap_result(pb, LDAP_UNWILLING_TO_PERFORM,
- NULL, "Simple Paged Results Search already in
progress on this connection", 0, NULL);
+ int myrc = pagedresults_check_or_set_processing(pb->pb_conn);
+ if ((0 == pagesize) || (myrc & CONN_FLAG_PAGEDRESULTS_ABANDONED)) {
+ send_ldap_result(pb, LDAP_UNWILLING_TO_PERFORM, NULL,
+ "Simple Paged Results Search is abandoned",
+ 0, NULL);
+ goto free_and_return_nolock;
+ } else if (myrc) {
+ send_ldap_result(pb, LDAP_UNWILLING_TO_PERFORM, NULL,
+ "Simple Paged Results Search is "
+ "already in progress on this connection",
+ 0, NULL);
goto free_and_return_nolock;
}
pr_reset_processing = 1; /* need to reset after we are done with this op
*/
@@ -535,7 +543,7 @@ op_shared_search (Slapi_PBlock *pb, int send_result)
}
if (slapi_sdn_compare(basesdn, sdn)) {
slapi_sdn_free(&basesdn);
- basesdn = operation_get_target_spec(pb->pb_op);
+ basesdn = operation_get_target_spec(pb->pb_op);
slapi_sdn_free(&basesdn);
basesdn = slapi_sdn_dup(sdn);
operation_set_target_spec (pb->pb_op, basesdn);
@@ -660,7 +668,7 @@ op_shared_search (Slapi_PBlock *pb, int send_result)
pagedresults_set_search_result_set_size_estimate(pb->pb_conn, estimate);
next_be = NULL; /* to break the loop */
if (curr_search_count == -1) {
- pagedresults_cleanup(pb->pb_conn, 1 /* need to lock */);
+ pagedresults_cleanup(pb->pb_conn, 0, 1 /* need to lock */);
}
} else {
/* be_suffix null means that we are searching the default backend
@@ -811,7 +819,7 @@ op_shared_search (Slapi_PBlock *pb, int send_result)
slapi_pblock_set( pb, SLAPI_SEARCH_RESULT_SET, NULL );
next_be = NULL; /* to break the loop */
if (curr_search_count == -1) {
- pagedresults_cleanup(pb->pb_conn, 1 /* need to lock */);
+ pagedresults_cleanup(pb->pb_conn, 0, 1 /* need to lock */);
}
}
diff --git a/ldap/servers/slapd/pagedresults.c b/ldap/servers/slapd/pagedresults.c
index c77ec27..ff2b81f 100644
--- a/ldap/servers/slapd/pagedresults.c
+++ b/ldap/servers/slapd/pagedresults.c
@@ -217,7 +217,11 @@ pagedresults_set_search_result(Connection *conn, void *sr, int
locked)
int rc = -1;
if (conn) {
if (!locked) PR_Lock(conn->c_mutex);
- conn->c_search_result_set = sr;
+ /* In case abandoned (CONN_FLAG_PAGEDRESULTS_PROCESSING is reset),
+ * stop setting the search result set. */
+ if (conn->c_flags & CONN_FLAG_PAGEDRESULTS_PROCESSING) {
+ conn->c_search_result_set = sr;
+ }
if (!locked) PR_Unlock(conn->c_mutex);
rc = 0;
}
@@ -370,7 +374,7 @@ pagedresults_set_timelimit(Connection *conn, time_t timelimit)
* 1: simple paged result and successfully abandoned
*/
int
-pagedresults_cleanup(Connection *conn, int needlock)
+pagedresults_cleanup(Connection *conn, int flags, int needlock)
{
int rc = 0;
@@ -389,7 +393,15 @@ pagedresults_cleanup(Connection *conn, int needlock)
}
conn->c_search_result_count = 0;
conn->c_timelimit = 0;
- conn->c_flags &= ~CONN_FLAG_PAGEDRESULTS_PROCESSING;
+ if (flags == PAGEDRESULTS_CLEANALL) {
+ conn->c_flags &= ~CONN_FLAG_PAGEDRESULTS_ALL;
+ } else {
+ conn->c_flags &= ~CONN_FLAG_PAGEDRESULTS_PROCESSING;
+ if (flags == PAGEDRESULTS_ABANDONED) {
+ conn->c_flags |= CONN_FLAG_PAGEDRESULTS_ABANDONED;
+ }
+ }
+
if (needlock) {
PR_Unlock(conn->c_mutex);
}
@@ -407,9 +419,12 @@ pagedresults_check_or_set_processing(Connection *conn)
int ret = 0;
if (conn) {
PR_Lock(conn->c_mutex);
- ret = conn->c_flags&CONN_FLAG_PAGEDRESULTS_PROCESSING;
- /* if ret is true, the following doesn't do anything */
- conn->c_flags |= CONN_FLAG_PAGEDRESULTS_PROCESSING;
+ ret = conn->c_flags & (CONN_FLAG_PAGEDRESULTS_PROCESSING |
+ CONN_FLAG_PAGEDRESULTS_ABANDONED);
+ /* if ret is true, don't set the flag. */
+ if (!ret) {
+ conn->c_flags |= CONN_FLAG_PAGEDRESULTS_PROCESSING;
+ }
PR_Unlock(conn->c_mutex);
}
return ret;
diff --git a/ldap/servers/slapd/proto-slap.h b/ldap/servers/slapd/proto-slap.h
index 1c48793..2162c2f 100644
--- a/ldap/servers/slapd/proto-slap.h
+++ b/ldap/servers/slapd/proto-slap.h
@@ -1398,7 +1398,7 @@ int pagedresults_set_unindexed(Connection *conn);
int pagedresults_get_sort_result_code(Connection *conn);
int pagedresults_set_sort_result_code(Connection *conn, int code);
int pagedresults_set_timelimit(Connection *conn, time_t timelimit);
-int pagedresults_cleanup(Connection *conn, int needlock);
+int pagedresults_cleanup(Connection *conn, int flags, int needlock);
int pagedresults_check_or_set_processing(Connection *conn);
int pagedresults_reset_processing(Connection *conn);
diff --git a/ldap/servers/slapd/slap.h b/ldap/servers/slapd/slap.h
index c01e590..4d3a9e2 100644
--- a/ldap/servers/slapd/slap.h
+++ b/ldap/servers/slapd/slap.h
@@ -1446,12 +1446,16 @@ typedef struct conn {
* sent with server side sorting
*/
-#define CONN_FLAG_PAGEDRESULTS_UNINDEXED 128 /* If the search is unindexed,
+#define CONN_FLAG_PAGEDRESULTS_UNINDEXED 128/* If the search is unindexed,
* store the info in c_flags
*/
-#define CONN_FLAG_PAGEDRESULTS_PROCESSING 256 /* there is an operation
- * processing a pagedresults search
- */
+#define CONN_FLAG_PAGEDRESULTS_PROCESSING 256/* there is an operation
+ * processing a pagedresults search
+ */
+#define CONN_FLAG_PAGEDRESULTS_ABANDONED 512/* paged results op is abandoned */
+#define CONN_FLAG_PAGEDRESULTS_ALL (CONN_FLAG_PAGEDRESULTS_UNINDEXED| \
+ CONN_FLAG_PAGEDRESULTS_PROCESSING| \
+ CONN_FLAG_PAGEDRESULTS_ABANDONED)
#define CONN_GET_SORT_RESULT_CODE (-1)
#define START_TLS_OID "1.3.6.1.4.1.1466.20037"
@@ -2319,4 +2323,8 @@ extern char *attr_dataversion;
/* copied from replication/repl5.h */
#define RUV_STORAGE_ENTRY_UNIQUEID "ffffffff-ffffffff-ffffffff-ffffffff"
+/* Flags for pagedresults_cleanup */
+#define PAGEDRESULTS_ABANDONED 1
+#define PAGEDRESULTS_CLEANALL 2
+
#endif /* _slap_h_ */