diff --git a/common-session.c b/common-session.c index d820d64e2d116989ca8643c1574c5692b9a872ac..a225b2162582200a90fe1d23c772e6f50a25c8b2 100644 --- a/common-session.c +++ b/common-session.c @@ -240,6 +240,15 @@ void session_loop(void(*loophandler)()) { /* Not reached */ } +static void cleanup_buf(buffer **buf) { + if (!*buf) { + return; + } + buf_burn(*buf); + buf_free(*buf); + *buf = NULL; +} + /* clean up a session on exit */ void session_cleanup() { @@ -256,19 +265,31 @@ void session_cleanup() { } chancleanup(); - - /* Cleaning up keys must happen after other cleanup - functions which might queue packets */ - if (ses.session_id) { - buf_burn(ses.session_id); - buf_free(ses.session_id); - ses.session_id = NULL; - } - if (ses.hash) { - buf_burn(ses.hash); - buf_free(ses.hash); - ses.hash = NULL; + + /* Most dropbear functions are unsafe to run after this point */ +#ifdef DROPBEAR_CLEANUP + /* listeners call cleanup functions, this should occur before + other session state is freed. */ + remove_all_listeners(); + + while (!isempty(&ses.writequeue)) { + buf_free(dequeue(&ses.writequeue)); } + + m_free(ses.remoteident); + m_free(ses.authstate.pw_dir); + m_free(ses.authstate.pw_name); + m_free(ses.authstate.pw_shell); + m_free(ses.authstate.pw_passwd); + m_free(ses.authstate.username); +#endif + + cleanup_buf(&ses.session_id); + cleanup_buf(&ses.hash); + cleanup_buf(&ses.payload); + cleanup_buf(&ses.readbuf); + cleanup_buf(&ses.writepayload); + m_burn(ses.keys, sizeof(struct key_context)); m_free(ses.keys); diff --git a/listener.c b/listener.c index dd90c6bfe73aa6669f7c03b8afdad0ae9bfd81f8..a7f07304d3e5ed3e201225e465d50d85fb2f7836 100644 --- a/listener.c +++ b/listener.c @@ -161,5 +161,14 @@ void remove_listener(struct Listener* listener) { } ses.listeners[listener->index] = NULL; m_free(listener); +} +void remove_all_listeners(void) { + unsigned int i; + for (i = 0; i < ses.listensize; i++) { + if (ses.listeners[i]) { + remove_listener(ses.listeners[i]); + } + } + m_free(ses.listeners); } diff --git a/listener.h b/listener.h index 317665f5a62104bf51ce35666ac728be408281ad..b531ed6db824cbc1e1aa112677da5852af473442 100644 --- a/listener.h +++ b/listener.h @@ -60,4 +60,6 @@ struct Listener * get_listener(int type, void* typedata, void remove_listener(struct Listener* listener); +void remove_all_listeners(void); + #endif /* DROPBEAR_LISTENER_H */ diff --git a/svr-chansession.c b/svr-chansession.c index 5bed8fc7d2fbc3c8270785cbf7c857da8f7904d4..5f9f56d52fd967a98d122e5f763f8f372c9d1acc 100644 --- a/svr-chansession.c +++ b/svr-chansession.c @@ -787,9 +787,11 @@ static int ptycommand(struct Channel *channel, struct ChanSess *chansess) { TRACE(("back to normal sigchld")) /* Revert to normal sigchld handling */ + /* if (signal(SIGCHLD, SIG_DFL) == SIG_ERR) { dropbear_exit("signal() error"); } + */ /* redirect stdin/stdout/stderr */ close(chansess->master); @@ -1005,9 +1007,11 @@ void svr_chansessinitialise() { sa_chld.sa_handler = sesssigchild_handler; sa_chld.sa_flags = SA_NOCLDSTOP; sigemptyset(&sa_chld.sa_mask); + /* if (sigaction(SIGCHLD, &sa_chld, NULL) < 0) { dropbear_exit("signal() error"); } + */ } diff --git a/svr-session.c b/svr-session.c index 343cb30ccaeae1652bdd2216075d93b39822367d..2b8a9560c8ab6aa16c7c2a258280196ef3810e4a 100644 --- a/svr-session.c +++ b/svr-session.c @@ -78,10 +78,13 @@ static const struct ChanType *svr_chantypes[] = { }; static void -svr_session_cleanup(void) -{ +svr_session_cleanup(void) { /* free potential public key options */ svr_pubkey_options_cleanup(); + + m_free(svr_ses.addrstring); + m_free(svr_ses.childpids); + m_free(svr_ses.remotehost); } static void @@ -150,6 +153,7 @@ void svr_session(int sock, int childpipe) { void svr_dropbear_exit(int exitcode, const char* format, va_list param) { char fmtbuf[300]; + int i; if (!sessinitdone) { /* before session init */ @@ -183,6 +187,15 @@ void svr_dropbear_exit(int exitcode, const char* format, va_list param) { session_cleanup(); } + if (svr_opts.hostkey) { + sign_key_free(svr_opts.hostkey); + svr_opts.hostkey = NULL; + } + for (i = 0; i < DROPBEAR_MAX_PORTS; i++) { + m_free(svr_opts.addresses[i]); + m_free(svr_opts.ports[i]); + } + exit(exitcode); } diff --git a/sysoptions.h b/sysoptions.h index bec72461d8e41991bb7c43ea5d96330f9cd60f9f..03f4076e39bbe37afb8536ef9d90b10ab480b718 100644 --- a/sysoptions.h +++ b/sysoptions.h @@ -256,6 +256,9 @@ #define DROPBEAR_LISTEN_BACKLOG MAX_CHANNELS #endif +/* free memory before exiting */ +#define DROPBEAR_CLEANUP + /* Use this string since some implementations might special-case it */ #define DROPBEAR_KEEPALIVE_STRING "keepalive@openssh.com"