The branch, master has been updated
       via  33f10d0 s3:smbd: avoid invalid lock_order panic triggered by 
"CTDB_SRVID_RELEASE_IP"
       via  9677fae s3:lib/ctdbd_conn: let release_ip_handler return bool
       via  52ccb40 s3:smbd: maintain smbd_server_connection->status
       via  58c71be s3:smbd: simplify exit_server_common()
      from  913b2a1 clitar: don't panic, propagate talloc errors upwards

http://gitweb.samba.org/?p=samba.git;a=shortlog;h=master


- Log -----------------------------------------------------------------
commit 33f10d06baf44e31d558bc5bd926c886915322cc
Author: Stefan Metzmacher <me...@samba.org>
Date:   Thu Feb 13 15:36:27 2014 +0100

    s3:smbd: avoid invalid lock_order panic triggered by "CTDB_SRVID_RELEASE_IP"
    
    If smbd_server_connection_terminate("CTDB_SRVID_RELEASE_IP") is triggered 
from
    within ctdbd_migrate(), we got a smb_panic complaining about invalid
    lock_order, as ctdbd_migrate is called from dbwrap_fetch_locked().
    
    Bug: https://bugzilla.samba.org/show_bug.cgi?id=10444
    Signed-off-by: Stefan Metzmacher <me...@samba.org>
    Reviewed-by: Volker Lendecke <v...@samba.org>
    
    Autobuild-User(master): Stefan Metzmacher <me...@samba.org>
    Autobuild-Date(master): Fri Feb 21 14:51:51 CET 2014 on sn-devel-104

commit 9677fae6aab26d2bf0884dc31516d2dcd8840c03
Author: Stefan Metzmacher <me...@samba.org>
Date:   Mon Feb 17 11:57:52 2014 +0100

    s3:lib/ctdbd_conn: let release_ip_handler return bool
    
    If it returns true the passed ip address matched and we
    let a nested ctdb operation fail with NT_STATUS_ADDRESS_CLOSED.
    
    Signed-off-by: Stefan Metzmacher <me...@samba.org>
    Reviewed-by: Volker Lendecke <v...@samba.org>

commit 52ccb40d595fc80bfa53b0b9cd75ffb902369681
Author: Stefan Metzmacher <me...@samba.org>
Date:   Mon Feb 17 12:01:12 2014 +0100

    s3:smbd: maintain smbd_server_connection->status
    
    If this isn't NT_STATUS_OK, we skip any io on the socket.
    
    This avoids possible problems during shutdown.
    
    Signed-off-by: Stefan Metzmacher <me...@samba.org>
    Reviewed-by: Volker Lendecke <v...@samba.org>

commit 58c71bee40bb91868fc69d8f7fa640db0e33efae
Author: Stefan Metzmacher <me...@samba.org>
Date:   Mon Feb 17 12:05:42 2014 +0100

    s3:smbd: simplify exit_server_common()
    
    Signed-off-by: Stefan Metzmacher <me...@samba.org>
    Reviewed-by: Volker Lendecke <v...@samba.org>

-----------------------------------------------------------------------

Summary of changes:
 source3/include/ctdbd_conn.h |    2 +-
 source3/lib/ctdbd_conn.c     |   36 +++++++++++++++++---
 source3/smbd/globals.h       |    1 +
 source3/smbd/process.c       |   72 +++++++++++++++++++++++++++++++++++++++--
 source3/smbd/server_exit.c   |   17 +++++++--
 source3/smbd/smb2_server.c   |   16 +++++++++
 6 files changed, 129 insertions(+), 15 deletions(-)


Changeset truncated at 500 lines:

diff --git a/source3/include/ctdbd_conn.h b/source3/include/ctdbd_conn.h
index ce5c8ba..0f85229 100644
--- a/source3/include/ctdbd_conn.h
+++ b/source3/include/ctdbd_conn.h
@@ -76,7 +76,7 @@ NTSTATUS ctdbd_traverse(uint32_t db_id,
 NTSTATUS ctdbd_register_ips(struct ctdbd_connection *conn,
                            const struct sockaddr_storage *server,
                            const struct sockaddr_storage *client,
-                           void (*release_ip_handler)(const char *ip_addr,
+                           bool (*release_ip_handler)(const char *ip_addr,
                                                       void *private_data),
                            void *private_data);
 
diff --git a/source3/lib/ctdbd_conn.c b/source3/lib/ctdbd_conn.c
index 6ab4bbe..4d90324 100644
--- a/source3/lib/ctdbd_conn.c
+++ b/source3/lib/ctdbd_conn.c
@@ -59,7 +59,7 @@ struct ctdbd_connection {
        struct ctdb_packet_context *pkt;
        struct tevent_fd *fde;
 
-       void (*release_ip_handler)(const char *ip_addr, void *private_data);
+       bool (*release_ip_handler)(const char *ip_addr, void *private_data);
        void *release_ip_priv;
 };
 
@@ -428,10 +428,23 @@ static NTSTATUS ctdb_read_req(struct ctdbd_connection 
*conn, uint32_t reqid,
 
                if ((conn->release_ip_handler != NULL)
                    && (msg->srvid == CTDB_SRVID_RELEASE_IP)) {
+                       bool ret;
+
                        /* must be dispatched immediately */
                        DEBUG(10, ("received CTDB_SRVID_RELEASE_IP\n"));
-                       conn->release_ip_handler((const char *)msg->data,
-                                                conn->release_ip_priv);
+                       ret = conn->release_ip_handler((const char *)msg->data,
+                                                      conn->release_ip_priv);
+                       if (ret) {
+                               /*
+                                * We need to release the ip,
+                                * so return an error to the upper layers.
+                                *
+                                * We make sure we don't trigger this again.
+                                */
+                               conn->release_ip_handler = NULL;
+                               conn->release_ip_priv = NULL;
+                               return NT_STATUS_ADDRESS_CLOSED;
+                       }
                        TALLOC_FREE(hdr);
                        goto next_pkt;
                }
@@ -630,10 +643,21 @@ static NTSTATUS ctdb_handle_message(uint8_t *buf, size_t 
length,
 
        if ((conn->release_ip_handler != NULL)
            && (msg->srvid == CTDB_SRVID_RELEASE_IP)) {
+               bool ret;
+
                /* must be dispatched immediately */
                DEBUG(10, ("received CTDB_SRVID_RELEASE_IP\n"));
-               conn->release_ip_handler((const char *)msg->data,
-                                        conn->release_ip_priv);
+               ret = conn->release_ip_handler((const char *)msg->data,
+                                              conn->release_ip_priv);
+               if (ret) {
+                       /*
+                        * We need to release the ip.
+                        *
+                        * We make sure we don't trigger this again.
+                        */
+                       conn->release_ip_handler = NULL;
+                       conn->release_ip_priv = NULL;
+               }
                TALLOC_FREE(buf);
                return NT_STATUS_OK;
        }
@@ -1692,7 +1716,7 @@ static void smbd_ctdb_canonicalize_ip(const struct 
sockaddr_storage *in,
 NTSTATUS ctdbd_register_ips(struct ctdbd_connection *conn,
                            const struct sockaddr_storage *_server,
                            const struct sockaddr_storage *_client,
-                           void (*release_ip_handler)(const char *ip_addr,
+                           bool (*release_ip_handler)(const char *ip_addr,
                                                       void *private_data),
                            void *private_data)
 {
diff --git a/source3/smbd/globals.h b/source3/smbd/globals.h
index 94111b6..bae3ed0 100644
--- a/source3/smbd/globals.h
+++ b/source3/smbd/globals.h
@@ -633,6 +633,7 @@ struct user_struct {
 };
 
 struct smbd_server_connection {
+       NTSTATUS status;
        int sock;
        const struct tsocket_address *local_address;
        const struct tsocket_address *remote_address;
diff --git a/source3/smbd/process.c b/source3/smbd/process.c
index f5ca2f9..41b3611 100644
--- a/source3/smbd/process.c
+++ b/source3/smbd/process.c
@@ -152,6 +152,13 @@ bool srv_send_smb(struct smbd_server_connection *sconn, 
char *buffer,
        ssize_t ret;
        char *buf_out = buffer;
 
+       if (!NT_STATUS_IS_OK(sconn->status)) {
+               /*
+                * we're not supposed to do any io
+                */
+               return true;
+       }
+
        smbd_lock_socket(sconn);
 
        if (do_signing) {
@@ -2445,6 +2452,15 @@ static void smbd_server_connection_handler(struct 
tevent_context *ev,
        struct smbd_server_connection *conn = talloc_get_type(private_data,
                                              struct smbd_server_connection);
 
+       if (!NT_STATUS_IS_OK(conn->status)) {
+               /*
+                * we're not supposed to do any io
+                */
+               TEVENT_FD_NOT_READABLE(conn->smb1.fde);
+               TEVENT_FD_NOT_WRITEABLE(conn->smb1.fde);
+               return;
+       }
+
        if (flags & TEVENT_FD_WRITE) {
                smbd_server_connection_write_handler(conn);
                return;
@@ -2463,6 +2479,15 @@ static void smbd_server_echo_handler(struct 
tevent_context *ev,
        struct smbd_server_connection *conn = talloc_get_type(private_data,
                                              struct smbd_server_connection);
 
+       if (!NT_STATUS_IS_OK(conn->status)) {
+               /*
+                * we're not supposed to do any io
+                */
+               TEVENT_FD_NOT_READABLE(conn->smb1.echo_handler.trusted_fde);
+               TEVENT_FD_NOT_WRITEABLE(conn->smb1.echo_handler.trusted_fde);
+               return;
+       }
+
        if (flags & TEVENT_FD_WRITE) {
                smbd_server_connection_write_handler(conn);
                return;
@@ -2478,13 +2503,32 @@ static void smbd_server_echo_handler(struct 
tevent_context *ev,
 
 struct smbd_release_ip_state {
        struct smbd_server_connection *sconn;
+       struct tevent_immediate *im;
        char addr[INET6_ADDRSTRLEN];
 };
 
+static void smbd_release_ip_immediate(struct tevent_context *ctx,
+                                     struct tevent_immediate *im,
+                                     void *private_data)
+{
+       struct smbd_release_ip_state *state =
+               talloc_get_type_abort(private_data,
+               struct smbd_release_ip_state);
+
+       if (!NT_STATUS_EQUAL(state->sconn->status, NT_STATUS_ADDRESS_CLOSED)) {
+               /*
+                * smbd_server_connection_terminate() already triggered ?
+                */
+               return;
+       }
+
+       smbd_server_connection_terminate(state->sconn, "CTDB_SRVID_RELEASE_IP");
+}
+
 /****************************************************************************
 received when we should release a specific IP
 ****************************************************************************/
-static void release_ip(const char *ip, void *priv)
+static bool release_ip(const char *ip, void *priv)
 {
        struct smbd_release_ip_state *state =
                talloc_get_type_abort(priv,
@@ -2492,6 +2536,11 @@ static void release_ip(const char *ip, void *priv)
        const char *addr = state->addr;
        const char *p = addr;
 
+       if (!NT_STATUS_IS_OK(state->sconn->status)) {
+               /* avoid recursion */
+               return false;
+       }
+
        if (strncmp("::ffff:", addr, 7) == 0) {
                p = addr + 7;
        }
@@ -2518,11 +2567,22 @@ static void release_ip(const char *ip, void *priv)
                 * triggered and has implication on our process model,
                 * we can just use smbd_server_connection_terminate()
                 * (also for SMB1).
+                *
+                * We don't call smbd_server_connection_terminate() directly
+                * as we might be called from within ctdbd_migrate(),
+                * we need to defer our action to the next event loop
                 */
-               smbd_server_connection_terminate(state->sconn,
-                                                "CTDB_SRVID_RELEASE_IP");
-               return;
+               tevent_schedule_immediate(state->im, state->sconn->ev_ctx,
+                                         smbd_release_ip_immediate, state);
+
+               /*
+                * Make sure we don't get any io on the connection.
+                */
+               state->sconn->status = NT_STATUS_ADDRESS_CLOSED;
+               return true;
        }
+
+       return false;
 }
 
 static NTSTATUS smbd_register_ips(struct smbd_server_connection *sconn,
@@ -2542,6 +2602,10 @@ static NTSTATUS smbd_register_ips(struct 
smbd_server_connection *sconn,
                return NT_STATUS_NO_MEMORY;
        }
        state->sconn = sconn;
+       state->im = tevent_create_immediate(state);
+       if (state->im == NULL) {
+               return NT_STATUS_NO_MEMORY;
+       }
        if (print_sockaddr(state->addr, sizeof(state->addr), srv) == NULL) {
                return NT_STATUS_NO_MEMORY;
        }
diff --git a/source3/smbd/server_exit.c b/source3/smbd/server_exit.c
index 18a1a46..357c69a 100644
--- a/source3/smbd/server_exit.c
+++ b/source3/smbd/server_exit.c
@@ -99,13 +99,22 @@ static void exit_server_common(enum server_exit_reason how,
 
        change_to_root_user();
 
-       if (sconn && sconn->smb1.negprot.auth_context) {
-               TALLOC_FREE(sconn->smb1.negprot.auth_context);
-       }
-
        if (sconn) {
                NTSTATUS status;
 
+               if (NT_STATUS_IS_OK(sconn->status)) {
+                       switch (how) {
+                       case SERVER_EXIT_ABNORMAL:
+                               sconn->status = NT_STATUS_INTERNAL_ERROR;
+                               break;
+                       case SERVER_EXIT_NORMAL:
+                               sconn->status = NT_STATUS_LOCAL_DISCONNECT;
+                               break;
+                       }
+               }
+
+               TALLOC_FREE(sconn->smb1.negprot.auth_context);
+
                if (lp_log_writeable_files_on_exit()) {
                        bool found = false;
                        files_forall(sconn, log_writeable_file_fn, &found);
diff --git a/source3/smbd/smb2_server.c b/source3/smbd/smb2_server.c
index fe42ac9..5e6bfd9 100644
--- a/source3/smbd/smb2_server.c
+++ b/source3/smbd/smb2_server.c
@@ -2841,6 +2841,13 @@ static NTSTATUS smbd_smb2_request_next_incoming(struct 
smbd_server_connection *s
        size_t max_send_queue_len;
        size_t cur_send_queue_len;
 
+       if (!NT_STATUS_IS_OK(sconn->status)) {
+               /*
+                * we're not supposed to do any io
+                */
+               return NT_STATUS_OK;
+       }
+
        if (state->req != NULL) {
                /*
                 * if there is already a tstream_readv_pdu
@@ -3087,6 +3094,15 @@ static NTSTATUS smbd_smb2_io_handler(struct 
smbd_server_connection *sconn,
        NTSTATUS status;
        NTTIME now;
 
+       if (!NT_STATUS_IS_OK(sconn->status)) {
+               /*
+                * we're not supposed to do any io
+                */
+               TEVENT_FD_NOT_READABLE(sconn->smb2.fde);
+               TEVENT_FD_NOT_WRITEABLE(sconn->smb2.fde);
+               return NT_STATUS_OK;
+       }
+
        if (fde_flags & TEVENT_FD_WRITE) {
                status = smbd_smb2_flush_send_queue(sconn);
                if (!NT_STATUS_IS_OK(status)) {


-- 
Samba Shared Repository

Reply via email to