summaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
-rw-r--r--default_options.h3
-rw-r--r--fuzz-wrapfd.h2
-rw-r--r--fuzz.h1
-rw-r--r--fuzz/fuzz-wrapfd.c12
-rw-r--r--svr-chansession.c4
-rw-r--r--svr-session.c21
6 files changed, 43 insertions, 0 deletions
diff --git a/default_options.h b/default_options.h
index 375506d..d6b6d55 100644
--- a/default_options.h
+++ b/default_options.h
@@ -256,6 +256,9 @@ Homedir is prepended unless path begins with / */
/* -T server option overrides */
#define MAX_AUTH_TRIES 10
+/* Delay introduced before closing an unauthenticated session (seconds) */
+#define UNAUTH_CLOSE_DELAY 30
+
/* The default file to store the daemon's process ID, for shutdown
scripts etc. This can be overridden with the -P flag */
#define DROPBEAR_PIDFILE "/var/run/dropbear.pid"
diff --git a/fuzz-wrapfd.h b/fuzz-wrapfd.h
index 6677e62..d0dea88 100644
--- a/fuzz-wrapfd.h
+++ b/fuzz-wrapfd.h
@@ -1,6 +1,7 @@
#ifndef FUZZ_WRAPFD_H
#define FUZZ_WRAPFD_H
+#include "includes.h"
#include "buffer.h"
enum wrapfd_mode {
@@ -21,5 +22,6 @@ int wrapfd_write(int fd, const void* in, size_t count);
int wrapfd_select(int nfds, fd_set *readfds, fd_set *writefds,
fd_set *exceptfds, struct timeval *timeout);
int wrapfd_close(int fd);
+int fuzz_kill(pid_t pid, int sig);
#endif // FUZZ_WRAPFD_H
diff --git a/fuzz.h b/fuzz.h
index 6525e40..4b89e2b 100644
--- a/fuzz.h
+++ b/fuzz.h
@@ -59,6 +59,7 @@ void fuzz_dump(const unsigned char* data, size_t len);
#define write(fd, buf, count) wrapfd_write(fd, buf, count)
#define read(fd, buf, count) wrapfd_read(fd, buf, count)
#define close(fd) wrapfd_close(fd)
+#define kill(pid, sig) fuzz_kill(pid, sig)
#endif // FUZZ_SKIP_WRAP
struct dropbear_fuzz_options {
diff --git a/fuzz/fuzz-wrapfd.c b/fuzz/fuzz-wrapfd.c
index 02f293d..1e2f4f6 100644
--- a/fuzz/fuzz-wrapfd.c
+++ b/fuzz/fuzz-wrapfd.c
@@ -258,3 +258,15 @@ int wrapfd_select(int nfds, fd_set *readfds, fd_set *writefds,
return ret;
}
+int fuzz_kill(pid_t pid, int sig) {
+ if (fuzz.fuzzing) {
+ TRACE(("fuzz_kill ignoring pid %d signal %d", (pid), sig))
+ if (sig >= 0) {
+ return 0;
+ } else {
+ errno = EINVAL;
+ return -1;
+ }
+ }
+ return kill(pid, sig);
+}
diff --git a/svr-chansession.c b/svr-chansession.c
index d090395..1fac918 100644
--- a/svr-chansession.c
+++ b/svr-chansession.c
@@ -423,12 +423,14 @@ out:
/* Send a signal to a session's process as requested by the client*/
static int sessionsignal(const struct ChanSess *chansess) {
+ TRACE(("sessionsignal"))
int sig = 0;
char* signame = NULL;
int i;
if (chansess->pid == 0) {
+ TRACE(("sessionsignal: done no pid"))
/* haven't got a process pid yet */
return DROPBEAR_FAILURE;
}
@@ -446,12 +448,14 @@ static int sessionsignal(const struct ChanSess *chansess) {
m_free(signame);
+ TRACE(("sessionsignal: pid %d signal %d", (int)chansess->pid, sig))
if (sig == 0) {
/* failed */
return DROPBEAR_FAILURE;
}
if (kill(chansess->pid, sig) < 0) {
+ TRACE(("sessionsignal: kill() errored"))
return DROPBEAR_FAILURE;
}
diff --git a/svr-session.c b/svr-session.c
index 63c675c..6898828 100644
--- a/svr-session.c
+++ b/svr-session.c
@@ -215,6 +215,7 @@ void svr_dropbear_exit(int exitcode, const char* format, va_list param) {
char fullmsg[300];
char fromaddr[60];
int i;
+ int add_delay = 0;
#if DROPBEAR_PLUGIN
if ((ses.plugin_session != NULL)) {
@@ -247,13 +248,33 @@ void svr_dropbear_exit(int exitcode, const char* format, va_list param) {
snprintf(fullmsg, sizeof(fullmsg),
"Exit before auth%s: (user '%s', %u fails): %s",
fromaddr, ses.authstate.pw_name, ses.authstate.failcount, exitmsg);
+ add_delay = 1;
} else {
/* before userauth */
snprintf(fullmsg, sizeof(fullmsg), "Exit before auth%s: %s", fromaddr, exitmsg);
+ add_delay = 1;
}
dropbear_log(LOG_INFO, "%s", fullmsg);
+ /* To make it harder for attackers, introduce a delay to keep an
+ * unauthenticated session open a bit longer, thus blocking a connection
+ * slot until after the delay. Without this, while there is a limit on
+ * the amount of attempts an attacker can make at the same time
+ * (MAX_UNAUTH_PER_IP), the time taken by dropbear to handle one attempt
+ * is still short and thus for each of the allowed parallel attempts
+ * many attempts can be chained one after the other. The attempt rate is
+ * then:
+ * "MAX_UNAUTH_PER_IP / <process time of one attempt>".
+ * With the delay, this rate becomes:
+ * "MAX_UNAUTH_PER_IP / UNAUTH_CLOSE_DELAY".
+ */
+ if ((add_delay != 0) && (UNAUTH_CLOSE_DELAY > 0)) {
+ TRACE(("svr_dropbear_exit: start delay of %d seconds", UNAUTH_CLOSE_DELAY));
+ sleep(UNAUTH_CLOSE_DELAY);
+ TRACE(("svr_dropbear_exit: end delay of %d seconds", UNAUTH_CLOSE_DELAY));
+ }
+
#if DROPBEAR_VFORK
/* For uclinux only the main server process should cleanup - we don't want
* forked children doing that */