[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[PATCH] crash with callbacks


I got a libssh crash (((((
0.6.3 as well as master

Imagine following situation:
Init session #1...
Do something in session #1...
Init session #2...
Destroy session #1...
Do something in session #2... crash!

The reason is
LIBSSH_THREAD void *ssh_log_userdata;
in
libssh\src\log.c
stores a pointer to OLD (destroyed) session #1

My patch fixes this. Example code also attached.
Feel free to make more suitable fixes =)

Attachment: 0001-fix-crash-with-callbacks.patch
Description: 0001-fix-crash-with-callbacks.patch

#include <iostream>
#include <string>
#include <memory>

#include <libssh/libssh.h>
#include <libssh/callbacks.h>

namespace
{
    void log_callback(ssh_session /*session*/, int /*priority*/, const char* message, void* /*userdata*/)
    {
        std::cout << "SSH message: ";
        std::cout << message << std::endl;
    }

    struct my_ssh_wrap
    {
        ssh_session m_session;
        ssh_channel m_channel;
        ssh_callbacks_struct m_callbacs;

        my_ssh_wrap(const std::string& host, const std::string& port, const std::string& login, const std::string& password):
            m_session(ssh_new()),
            m_channel(NULL)
        {
            std::cout << "SSH library: ";
            std::cout << ssh_copyright() << std::endl;

            if (NULL == m_session) {
                throw std::runtime_error("ssh_new");
            }

            m_callbacs.userdata = this;
            m_callbacs.auth_function = 0;
            m_callbacs.log_function = &log_callback;
            m_callbacs.connect_status_function = 0;
            m_callbacs.global_request_function = 0;

            ssh_callbacks_init(&m_callbacs);

            if (SSH_OK != ssh_set_callbacks(m_session, &m_callbacs)) {
                throw std::runtime_error("ssh_set_callbacks");
            }

            int log_verbosity = SSH_LOG_PROTOCOL;

            ssh_options_set(m_session, SSH_OPTIONS_HOST, host.c_str());
            ssh_options_set(m_session, SSH_OPTIONS_PORT_STR, port.c_str());
            ssh_options_set(m_session, SSH_OPTIONS_USER, login.c_str());
            ssh_options_set(m_session, SSH_OPTIONS_LOG_VERBOSITY, &log_verbosity);

            if (SSH_OK != ssh_connect(m_session)) {
                throw std::runtime_error("ssh_connect");
            }

            std::cout << "SSH version: ";
            std::cout << ssh_get_version(m_session) << std::endl;

            if (const char* server_banner = ssh_get_serverbanner(m_session)) {
                std::cout << "SSH server banner: ";
                std::cout << server_banner << std::endl;
            }

            if (SSH_OK != ssh_userauth_password(m_session, NULL, password.c_str())) {
                throw std::runtime_error("ssh_userauth_password");
            }

            if (NULL == (m_channel = ssh_channel_new(m_session))) {
                throw std::runtime_error("ssh_channel_new");
            }

            if (SSH_OK != ssh_channel_open_session(m_channel)) {
                throw std::runtime_error("ssh_channel_open_session");
            }

            if (SSH_OK != ssh_channel_request_pty_size(m_channel, "ansi", 500, 500)) {
                throw std::runtime_error("ssh_channel_request_pty");
            }

            if (SSH_OK != ssh_channel_request_shell(m_channel)) {
                throw std::runtime_error("ssh_channel_request_shell");
            }
        }

        ~my_ssh_wrap()
        {
            if (m_channel) {
                ssh_channel_close(m_channel);
                ssh_channel_free(m_channel);
            }
            if (m_session) {
                ssh_disconnect(m_session);
                ssh_free(m_session);
            }
        }

        void write(const std::string& data)
        {
            std::cout << "SSH write: ";
            std::cout << data << std::endl;
            int count = ssh_channel_write(m_channel, data.c_str(), data.size());
            if (count < 0) {
                throw std::runtime_error("ssh_channel_write");
            }
            std::cout << count;
            std::cout << " bytes written" << std::endl;
        }

        std::string read(int timeout)
        {
            char buffer[1024];
            std::string result;
            const int absolute_timeout = timeout * 1000 + static_cast<int>(GetTickCount());
            do {
                int count = ssh_channel_read_timeout(m_channel, buffer, sizeof(buffer), 0, 100);
                if (count < 0) {
                    throw std::runtime_error("ssh_channel_read");
                } else if (count > 0) {
                    std::cout << count;
                    std::cout << " bytes red" << std::endl;
                    result.append(buffer, count);
                }
            } while (absolute_timeout - static_cast<int>(GetTickCount()) > 0);
            return result;
        }

        void scp(const std::string& data)
        {
            ssh_scp scp = ssh_scp_new(m_session, SSH_SCP_WRITE, ".");
            if (NULL == scp) {
                throw std::runtime_error("ssh_scp_new");
            }

            if (SSH_OK != ssh_scp_init(scp)) {
                throw std::runtime_error("ssh_scp_init");
            }

            if (SSH_OK != ssh_scp_push_file(scp, "command.sh", data.size(), 0755)) {
                throw std::runtime_error("ssh_scp_push_file");
            }

            if (SSH_OK != ssh_scp_write(scp, data.c_str(), data.size())) {
                throw std::runtime_error("ssh_scp_write");
            }

            ssh_scp_free(scp);
        }
    };

    void dialog_shared(std::shared_ptr<my_ssh_wrap> session)
    {
        std::cout << session->read(1) << std::endl;

        session->write("stty -echo\n");
        std::cout << session->read(1) << std::endl;

        session->write("uname\n");
        std::cout << session->read(1) << std::endl;

        session->write("echo 1\n");
        std::cout << session->read(1) << std::endl;
    }

    void dialog1(std::shared_ptr<my_ssh_wrap> session)
    {
        dialog_shared(session);

        session->scp("...first command...");
        session->write("sh command.sh\n");
        std::cout << session->read(10) << std::endl;
    }

    void dialog2(std::shared_ptr<my_ssh_wrap> session)
    {
        dialog_shared(session);

        session->scp("...second command...");
        session->write("sh command.sh\n");
        std::cout << session->read(10) << std::endl;
    }
}

int main(int argc, const char **argv)
{
    std::shared_ptr<my_ssh_wrap> session1, session2;
    try
    {
        if(argc!=5)
        {
            std::cout << "Wrong usage" << std::endl;
            return 1;
        }

        session1 = std::make_shared<my_ssh_wrap>(argv[1], argv[2], argv[3], argv[4]);
        dialog1(session1);

        session2 = std::make_shared<my_ssh_wrap>(argv[1], argv[2], argv[3], argv[4]);
        session1.reset();
        dialog2(session2);
    }
    catch (const std::exception& e)
    {
        std::cout << "Error during connection: ";
        std::cout << e.what() << std::endl;
    }
    return 0;
}

Follow-Ups:
Re: [PATCH] crash with callbacksAndreas Schneider <asn@xxxxxxxxxxxxxx>
Archive administrator: postmaster@lists.cynapses.org