From b5cde260487eae86db1661a53e5e5e0823936aab Mon Sep 17 00:00:00 2001 From: Konstantin Demin Date: Tue, 9 Jan 2024 03:40:01 +0300 Subject: [PATCH] dropbear: cherry-pick upstream patches critical fixes: - libtommath: possible integer overflow (CVE-2023-36328) - implement Strict KEX mode (CVE-2023-48795) various fixes: - fix DROPBEAR_DSS and DROPBEAR_RSA config options - y2038 issues - remove SO_LINGER socket option - make banner reading failure non-fatal - fix "noremotetcp" behavior - don't try to shutdown a pty - fix test for multiuser kernels adds new features: - option to bind to interface - allow inetd with non-syslog - ignore unsupported command line options with dropbearkey Signed-off-by: Konstantin Demin --- package/network/services/dropbear/Makefile | 1 - .../001-add-if-DROPBEAR_RSA-guards.patch | 104 +++++++++ .../patches/002-fix-y2038-issues.patch | 198 ++++++++++++++++ .../patches/003-fix-DROPBEAR_DSS.patch | 25 ++ ...rs-s-own-gid-in-pty-permission-check.patch | 24 ++ .../patches/005-const-parameter-mp_int.patch | 123 ++++++++++ ...pbearkey-add-missing-break-in-switch.patch | 21 ++ ...7-fix-building-only-client-or-server.patch | 29 +++ ...e-rsa-signatures-when-no-rsa-hostkey.patch | 94 ++++++++ ...-rather-than-fprintf-in-segv-handler.patch | 27 +++ .../patches/010-remove-SO_LINGER.patch | 39 ++++ .../011-add-option-to-bind-to-interface.patch | 147 ++++++++++++ ...add-ifdef-guards-for-SO_BINDTODEVICE.patch | 50 ++++ ...ake-banner-reading-failure-non-fatal.patch | 74 ++++++ ...nore-unsupported-command-line-option.patch | 60 +++++ ...ommath-fix-possible-integer-overflow.patch | 121 ++++++++++ ...-svr-tcpfwd-Fix-noremotetcp-behavior.patch | 35 +++ .../017-Don-t-try-to-shutdown-a-pty.patch | 32 +++ ...-dropbearkey-add-alias-to-ssh-keygen.patch | 33 +++ .../019-Allow-inetd-with-non-syslog.patch | 34 +++ .../020-Fix-test-for-multiuser-kernels.patch | 33 +++ .../021-Implement-Strict-KEX-mode.patch | 216 ++++++++++++++++++ ...nkey-fix-use-of-rsa-sha2-256-pubkeys.patch | 2 +- 23 files changed, 1520 insertions(+), 2 deletions(-) create mode 100644 package/network/services/dropbear/patches/001-add-if-DROPBEAR_RSA-guards.patch create mode 100644 package/network/services/dropbear/patches/002-fix-y2038-issues.patch create mode 100644 package/network/services/dropbear/patches/003-fix-DROPBEAR_DSS.patch create mode 100644 package/network/services/dropbear/patches/004-allow-users-s-own-gid-in-pty-permission-check.patch create mode 100644 package/network/services/dropbear/patches/005-const-parameter-mp_int.patch create mode 100644 package/network/services/dropbear/patches/006-dropbearkey-add-missing-break-in-switch.patch create mode 100644 package/network/services/dropbear/patches/007-fix-building-only-client-or-server.patch create mode 100644 package/network/services/dropbear/patches/008-disable-rsa-signatures-when-no-rsa-hostkey.patch create mode 100644 package/network/services/dropbear/patches/009-use-write-rather-than-fprintf-in-segv-handler.patch create mode 100644 package/network/services/dropbear/patches/010-remove-SO_LINGER.patch create mode 100644 package/network/services/dropbear/patches/011-add-option-to-bind-to-interface.patch create mode 100644 package/network/services/dropbear/patches/012-add-ifdef-guards-for-SO_BINDTODEVICE.patch create mode 100644 package/network/services/dropbear/patches/013-make-banner-reading-failure-non-fatal.patch create mode 100644 package/network/services/dropbear/patches/014-dropbearkey-ignore-unsupported-command-line-option.patch create mode 100644 package/network/services/dropbear/patches/015-libtommath-fix-possible-integer-overflow.patch create mode 100644 package/network/services/dropbear/patches/016-src-svr-tcpfwd-Fix-noremotetcp-behavior.patch create mode 100644 package/network/services/dropbear/patches/017-Don-t-try-to-shutdown-a-pty.patch create mode 100644 package/network/services/dropbear/patches/018-dropbearkey-add-alias-to-ssh-keygen.patch create mode 100644 package/network/services/dropbear/patches/019-Allow-inetd-with-non-syslog.patch create mode 100644 package/network/services/dropbear/patches/020-Fix-test-for-multiuser-kernels.patch create mode 100644 package/network/services/dropbear/patches/021-Implement-Strict-KEX-mode.patch diff --git a/package/network/services/dropbear/Makefile b/package/network/services/dropbear/Makefile index 5339bbd108..d0b0e01646 100644 --- a/package/network/services/dropbear/Makefile +++ b/package/network/services/dropbear/Makefile @@ -114,7 +114,6 @@ DB_OPT_COMMON = \ DEFAULT_PATH|"$(TARGET_INIT_PATH)" \ !!LOCAL_IDENT|"SSH-2.0-dropbear" \ DROPBEAR_CLI_NETCAT|0 \ - !!DROPBEAR_DSS|0 \ DROPBEAR_DSS|0 \ DO_MOTD|0 \ diff --git a/package/network/services/dropbear/patches/001-add-if-DROPBEAR_RSA-guards.patch b/package/network/services/dropbear/patches/001-add-if-DROPBEAR_RSA-guards.patch new file mode 100644 index 0000000000..ad1a20c520 --- /dev/null +++ b/package/network/services/dropbear/patches/001-add-if-DROPBEAR_RSA-guards.patch @@ -0,0 +1,104 @@ +From 36a03132634a17c667c0fac0a8e1519b3d1b71c6 Mon Sep 17 00:00:00 2001 +From: Matt Johnston +Date: Mon, 28 Nov 2022 21:12:23 +0800 +Subject: Add #if DROPBEAR_RSA guards + +Fixes building with DROPBEAR_RSA disabled. +Closes #197 +--- + signkey.c | 8 +++++++- + signkey.h | 2 ++ + sysoptions.h | 5 +---- + 3 files changed, 10 insertions(+), 5 deletions(-) + +--- a/signkey.c ++++ b/signkey.c +@@ -120,6 +120,7 @@ enum signkey_type signkey_type_from_name + /* Special case for rsa-sha2-256. This could be generalised if more + signature names are added that aren't 1-1 with public key names */ + const char* signature_name_from_type(enum signature_type type, unsigned int *namelen) { ++#if DROPBEAR_RSA + #if DROPBEAR_RSA_SHA256 + if (type == DROPBEAR_SIGNATURE_RSA_SHA256) { + if (namelen) { +@@ -136,11 +137,13 @@ const char* signature_name_from_type(enu + return SSH_SIGNKEY_RSA; + } + #endif ++#endif /* DROPBEAR_RSA */ + return signkey_name_from_type((enum signkey_type)type, namelen); + } + + /* Returns DROPBEAR_SIGNATURE_NONE if none match */ + enum signature_type signature_type_from_name(const char* name, unsigned int namelen) { ++#if DROPBEAR_RSA + #if DROPBEAR_RSA_SHA256 + if (namelen == strlen(SSH_SIGNATURE_RSA_SHA256) + && memcmp(name, SSH_SIGNATURE_RSA_SHA256, namelen) == 0) { +@@ -153,10 +156,11 @@ enum signature_type signature_type_from_ + return DROPBEAR_SIGNATURE_RSA_SHA1; + } + #endif ++#endif /* DROPBEAR_RSA */ + return (enum signature_type)signkey_type_from_name(name, namelen); + } + +-/* Returns the signature type from a key type. Must not be called ++/* Returns the signature type from a key type. Must not be called + with RSA keytype */ + enum signature_type signature_type_from_signkey(enum signkey_type keytype) { + #if DROPBEAR_RSA +@@ -167,6 +171,7 @@ enum signature_type signature_type_from_ + } + + enum signkey_type signkey_type_from_signature(enum signature_type sigtype) { ++#if DROPBEAR_RSA + #if DROPBEAR_RSA_SHA256 + if (sigtype == DROPBEAR_SIGNATURE_RSA_SHA256) { + return DROPBEAR_SIGNKEY_RSA; +@@ -177,6 +182,7 @@ enum signkey_type signkey_type_from_sign + return DROPBEAR_SIGNKEY_RSA; + } + #endif ++#endif /* DROPBEAR_RSA */ + assert((int)sigtype < (int)DROPBEAR_SIGNKEY_NUM_NAMED); + return (enum signkey_type)sigtype; + } +--- a/signkey.h ++++ b/signkey.h +@@ -79,12 +79,14 @@ enum signature_type { + DROPBEAR_SIGNATURE_SK_ED25519 = DROPBEAR_SIGNKEY_SK_ED25519, + #endif + #endif ++#if DROPBEAR_RSA + #if DROPBEAR_RSA_SHA1 + DROPBEAR_SIGNATURE_RSA_SHA1 = 100, /* ssh-rsa signature (sha1) */ + #endif + #if DROPBEAR_RSA_SHA256 + DROPBEAR_SIGNATURE_RSA_SHA256 = 101, /* rsa-sha2-256 signature. has a ssh-rsa key */ + #endif ++#endif /* DROPBEAR_RSA */ + DROPBEAR_SIGNATURE_NONE = DROPBEAR_SIGNKEY_NONE, + }; + +--- a/sysoptions.h ++++ b/sysoptions.h +@@ -137,7 +137,7 @@ + + /* Debian doesn't define this in system headers */ + #if !defined(LTM_DESC) && (DROPBEAR_ECC) +-#define LTM_DESC ++#define LTM_DESC + #endif + + #define DROPBEAR_ECC_256 (DROPBEAR_ECC) +@@ -151,9 +151,6 @@ + * signing operations slightly slower. */ + #define DROPBEAR_RSA_BLINDING 1 + +-#ifndef DROPBEAR_RSA_SHA1 +-#define DROPBEAR_RSA_SHA1 DROPBEAR_RSA +-#endif + #ifndef DROPBEAR_RSA_SHA256 + #define DROPBEAR_RSA_SHA256 DROPBEAR_RSA + #endif diff --git a/package/network/services/dropbear/patches/002-fix-y2038-issues.patch b/package/network/services/dropbear/patches/002-fix-y2038-issues.patch new file mode 100644 index 0000000000..0654e3b98b --- /dev/null +++ b/package/network/services/dropbear/patches/002-fix-y2038-issues.patch @@ -0,0 +1,198 @@ +From ec2215726cffb976019d08ebf569edd2229e9dba Mon Sep 17 00:00:00 2001 +From: Matt Johnston +Date: Thu, 1 Dec 2022 11:34:43 +0800 +Subject: Fix y2038 issues with time_t conversion + +These changes were identified by building with and without +-D_TIME_BITS=64 -D_FILE_OFFSET_BITS=64 +on 32-bit arm, logging warnings to files. +-Wconversion was added to CFLAGS in both builds. + +Then a "diff -I Wconversion log1 log2" shows new warnings that appear +with the 64-bit time_t. There are a few false positives that have been +fixed for quietness. + +struct logininfo and struct wtmp are still problematic, those will +need to be handled by libc. +--- + common-session.c | 43 +++++++++++++++++++++++++++---------------- + dbutil.c | 2 +- + loginrec.c | 2 ++ + loginrec.h | 4 ++-- + runopts.h | 4 ++-- + svr-auth.c | 2 +- + 6 files changed, 35 insertions(+), 22 deletions(-) + +--- a/common-session.c ++++ b/common-session.c +@@ -519,15 +519,24 @@ static void send_msg_keepalive() { + ses.last_packet_time_idle = old_time_idle; + } + ++/* Returns the difference in seconds, clamped to LONG_MAX */ ++static long elapsed(time_t now, time_t prev) { ++ time_t del = now - prev; ++ if (del > LONG_MAX) { ++ return LONG_MAX; ++ } ++ return (long)del; ++} ++ + /* Check all timeouts which are required. Currently these are the time for + * user authentication, and the automatic rekeying. */ + static void checktimeouts() { + + time_t now; + now = monotonic_now(); +- ++ + if (IS_DROPBEAR_SERVER && ses.connect_time != 0 +- && now - ses.connect_time >= AUTH_TIMEOUT) { ++ && elapsed(now, ses.connect_time) >= AUTH_TIMEOUT) { + dropbear_close("Timeout before auth"); + } + +@@ -537,45 +546,47 @@ static void checktimeouts() { + } + + if (!ses.kexstate.sentkexinit +- && (now - ses.kexstate.lastkextime >= KEX_REKEY_TIMEOUT ++ && (elapsed(now, ses.kexstate.lastkextime) >= KEX_REKEY_TIMEOUT + || ses.kexstate.datarecv+ses.kexstate.datatrans >= KEX_REKEY_DATA)) { + TRACE(("rekeying after timeout or max data reached")) + send_msg_kexinit(); + } +- ++ + if (opts.keepalive_secs > 0 && ses.authstate.authdone) { + /* Avoid sending keepalives prior to auth - those are + not valid pre-auth packet types */ + + /* Send keepalives if we've been idle */ +- if (now - ses.last_packet_time_any_sent >= opts.keepalive_secs) { ++ if (elapsed(now, ses.last_packet_time_any_sent) >= opts.keepalive_secs) { + send_msg_keepalive(); + } + + /* Also send an explicit keepalive message to trigger a response + if the remote end hasn't sent us anything */ +- if (now - ses.last_packet_time_keepalive_recv >= opts.keepalive_secs +- && now - ses.last_packet_time_keepalive_sent >= opts.keepalive_secs) { ++ if (elapsed(now, ses.last_packet_time_keepalive_recv) >= opts.keepalive_secs ++ && elapsed(now, ses.last_packet_time_keepalive_sent) >= opts.keepalive_secs) { + send_msg_keepalive(); + } + +- if (now - ses.last_packet_time_keepalive_recv ++ if (elapsed(now, ses.last_packet_time_keepalive_recv) + >= opts.keepalive_secs * DEFAULT_KEEPALIVE_LIMIT) { + dropbear_exit("Keepalive timeout"); + } + } + +- if (opts.idle_timeout_secs > 0 +- && now - ses.last_packet_time_idle >= opts.idle_timeout_secs) { ++ if (opts.idle_timeout_secs > 0 ++ && elapsed(now, ses.last_packet_time_idle) >= opts.idle_timeout_secs) { + dropbear_close("Idle timeout"); + } + } + +-static void update_timeout(long limit, long now, long last_event, long * timeout) { +- TRACE2(("update_timeout limit %ld, now %ld, last %ld, timeout %ld", +- limit, now, last_event, *timeout)) ++static void update_timeout(long limit, time_t now, time_t last_event, long * timeout) { ++ TRACE2(("update_timeout limit %ld, now %llu, last %llu, timeout %ld", ++ limit, ++ (unsigned long long)now, ++ (unsigned long long)last_event, *timeout)) + if (last_event > 0 && limit > 0) { +- *timeout = MIN(*timeout, last_event+limit-now); ++ *timeout = MIN(*timeout, elapsed(now, last_event) + limit); + TRACE2(("new timeout %ld", *timeout)) + } + } +@@ -584,7 +595,7 @@ static long select_timeout() { + /* determine the minimum timeout that might be required, so + as to avoid waking when unneccessary */ + long timeout = KEX_REKEY_TIMEOUT; +- long now = monotonic_now(); ++ time_t now = monotonic_now(); + + if (!ses.kexstate.sentkexinit) { + update_timeout(KEX_REKEY_TIMEOUT, now, ses.kexstate.lastkextime, &timeout); +@@ -596,7 +607,7 @@ static long select_timeout() { + } + + if (ses.authstate.authdone) { +- update_timeout(opts.keepalive_secs, now, ++ update_timeout(opts.keepalive_secs, now, + MAX(ses.last_packet_time_keepalive_recv, ses.last_packet_time_keepalive_sent), + &timeout); + } +--- a/dbutil.c ++++ b/dbutil.c +@@ -724,7 +724,7 @@ void gettime_wrapper(struct timespec *no + /* Fallback for everything else - this will sometimes go backwards */ + gettimeofday(&tv, NULL); + now->tv_sec = tv.tv_sec; +- now->tv_nsec = 1000*tv.tv_usec; ++ now->tv_nsec = 1000*(long)tv.tv_usec; + } + + /* second-resolution monotonic timestamp */ +--- a/loginrec.c ++++ b/loginrec.c +@@ -459,6 +459,7 @@ line_abbrevname(char *dst, const char *s + void + set_utmp_time(struct logininfo *li, struct utmp *ut) + { ++ /* struct utmp in glibc isn't y2038 safe yet */ + # ifdef HAVE_STRUCT_UTMP_UT_TV + ut->ut_tv.tv_sec = li->tv_sec; + ut->ut_tv.tv_usec = li->tv_usec; +@@ -1272,6 +1273,7 @@ lastlog_construct(struct logininfo *li, + (void)line_stripname(last->ll_line, li->line, sizeof(last->ll_line)); + strlcpy(last->ll_host, li->hostname, + MIN_SIZEOF(last->ll_host, li->hostname)); ++ /* struct lastlog in glibc isn't y2038 safe yet */ + last->ll_time = li->tv_sec; + } + +--- a/loginrec.h ++++ b/loginrec.h +@@ -139,8 +139,8 @@ struct logininfo { + /* struct timeval (sys/time.h) isn't always available, if it isn't we'll + * use time_t's value as tv_sec and set tv_usec to 0 + */ +- unsigned int tv_sec; +- unsigned int tv_usec; ++ time_t tv_sec; ++ suseconds_t tv_usec; + union login_netinfo hostaddr; /* caller's host address(es) */ + }; /* struct logininfo */ + +--- a/runopts.h ++++ b/runopts.h +@@ -39,8 +39,8 @@ typedef struct runopts { + int listen_fwd_all; + #endif + unsigned int recv_window; +- time_t keepalive_secs; /* Time between sending keepalives. 0 is off */ +- time_t idle_timeout_secs; /* Exit if no traffic is sent/received in this time */ ++ long keepalive_secs; /* Time between sending keepalives. 0 is off */ ++ long idle_timeout_secs; /* Exit if no traffic is sent/received in this time */ + int usingsyslog; + + #ifndef DISABLE_ZLIB +--- a/svr-auth.c ++++ b/svr-auth.c +@@ -389,7 +389,7 @@ void send_msg_userauth_failure(int parti + Beware of integer overflow if increasing these values */ + const unsigned int mindelay = 250000000; + const unsigned int vardelay = 100000000; +- unsigned int rand_delay; ++ suseconds_t rand_delay; + struct timespec delay; + + gettime_wrapper(&delay); diff --git a/package/network/services/dropbear/patches/003-fix-DROPBEAR_DSS.patch b/package/network/services/dropbear/patches/003-fix-DROPBEAR_DSS.patch new file mode 100644 index 0000000000..6789800e12 --- /dev/null +++ b/package/network/services/dropbear/patches/003-fix-DROPBEAR_DSS.patch @@ -0,0 +1,25 @@ +From c043efb47c3173072fa636ca0da0d19875d4511f Mon Sep 17 00:00:00 2001 +From: Matt Johnston +Date: Tue, 6 Dec 2022 22:34:11 +0800 +Subject: Fix so DROPBEAR_DSS is only forced for fuzzing + +Regression from 787391ea3b5af2acf5e3c83372510f0c79477ad7, +was missing fuzzing conditional +--- + sysoptions.h | 2 ++ + 1 file changed, 2 insertions(+) + +--- a/sysoptions.h ++++ b/sysoptions.h +@@ -380,9 +380,11 @@ + #endif + + /* Fuzzing expects all key types to be enabled */ ++#if DROPBEAR_FUZZ + #if defined(DROPBEAR_DSS) + #undef DROPBEAR_DSS + #endif + #define DROPBEAR_DSS 1 ++#endif + + /* no include guard for this file */ diff --git a/package/network/services/dropbear/patches/004-allow-users-s-own-gid-in-pty-permission-check.patch b/package/network/services/dropbear/patches/004-allow-users-s-own-gid-in-pty-permission-check.patch new file mode 100644 index 0000000000..bcb43aed2a --- /dev/null +++ b/package/network/services/dropbear/patches/004-allow-users-s-own-gid-in-pty-permission-check.patch @@ -0,0 +1,24 @@ +From 860721558837441ab45019858e710a2625ffa46e Mon Sep 17 00:00:00 2001 +From: Matt Johnston +Date: Wed, 7 Dec 2022 13:04:10 +0800 +Subject: Allow users's own gid in pty permission check + +This allows non-root Dropbear to work even without devpts gid=5 mount +option on Linux. +--- + sshpty.c | 4 +++- + 1 file changed, 3 insertions(+), 1 deletion(-) + +--- a/sshpty.c ++++ b/sshpty.c +@@ -380,7 +380,9 @@ pty_setowner(struct passwd *pw, const ch + tty_name, strerror(errno)); + } + +- if (st.st_uid != pw->pw_uid || st.st_gid != gid) { ++ /* Allow either "tty" gid or user's own gid. On Linux with openpty() ++ * this varies depending on the devpts mount options */ ++ if (st.st_uid != pw->pw_uid || !(st.st_gid == gid || st.st_gid == pw->pw_gid)) { + if (chown(tty_name, pw->pw_uid, gid) < 0) { + if (errno == EROFS && + (st.st_uid == pw->pw_uid || st.st_uid == 0)) { diff --git a/package/network/services/dropbear/patches/005-const-parameter-mp_int.patch b/package/network/services/dropbear/patches/005-const-parameter-mp_int.patch new file mode 100644 index 0000000000..0d23c9c416 --- /dev/null +++ b/package/network/services/dropbear/patches/005-const-parameter-mp_int.patch @@ -0,0 +1,123 @@ +From 01415ef8269e594a647f67ea0729ca8b590679de Mon Sep 17 00:00:00 2001 +From: Francois Perrad +Date: Thu, 22 Dec 2022 10:19:54 +0100 +Subject: const parameter mp_int + +--- + bignum.c | 2 +- + bignum.h | 2 +- + buffer.c | 2 +- + buffer.h | 2 +- + dbrandom.c | 2 +- + dbrandom.h | 2 +- + dbutil.c | 2 +- + dbutil.h | 2 +- + genrsa.c | 4 ++-- + 9 files changed, 10 insertions(+), 10 deletions(-) + +--- a/bignum.c ++++ b/bignum.c +@@ -93,7 +93,7 @@ void bytes_to_mp(mp_int *mp, const unsig + + /* hash the ssh representation of the mp_int mp */ + void hash_process_mp(const struct ltc_hash_descriptor *hash_desc, +- hash_state *hs, mp_int *mp) { ++ hash_state *hs, const mp_int *mp) { + buffer * buf; + + buf = buf_new(512 + 20); /* max buffer is a 4096 bit key, +--- a/bignum.h ++++ b/bignum.h +@@ -33,6 +33,6 @@ void m_mp_alloc_init_multi(mp_int **mp, + void m_mp_free_multi(mp_int **mp, ...) ATTRIB_SENTINEL; + void bytes_to_mp(mp_int *mp, const unsigned char* bytes, unsigned int len); + void hash_process_mp(const struct ltc_hash_descriptor *hash_desc, +- hash_state *hs, mp_int *mp); ++ hash_state *hs, const mp_int *mp); + + #endif /* DROPBEAR_BIGNUM_H_ */ +--- a/buffer.c ++++ b/buffer.c +@@ -299,7 +299,7 @@ void buf_putbytes(buffer *buf, const uns + + /* for our purposes we only need positive (or 0) numbers, so will + * fail if we get negative numbers */ +-void buf_putmpint(buffer* buf, mp_int * mp) { ++void buf_putmpint(buffer* buf, const mp_int * mp) { + size_t written; + unsigned int len, pad = 0; + TRACE2(("enter buf_putmpint")) +--- a/buffer.h ++++ b/buffer.h +@@ -65,7 +65,7 @@ void buf_putint(buffer* buf, unsigned in + void buf_putstring(buffer* buf, const char* str, unsigned int len); + void buf_putbufstring(buffer *buf, const buffer* buf_str); + void buf_putbytes(buffer *buf, const unsigned char *bytes, unsigned int len); +-void buf_putmpint(buffer* buf, mp_int * mp); ++void buf_putmpint(buffer* buf, const mp_int * mp); + int buf_getmpint(buffer* buf, mp_int* mp); + unsigned int buf_getint(buffer* buf); + +--- a/dbrandom.c ++++ b/dbrandom.c +@@ -347,7 +347,7 @@ void genrandom(unsigned char* buf, unsig + * rand must be an initialised *mp_int for the result. + * the result rand satisfies: 0 < rand < max + * */ +-void gen_random_mpint(mp_int *max, mp_int *rand) { ++void gen_random_mpint(const mp_int *max, mp_int *rand) { + + unsigned char *randbuf = NULL; + unsigned int len = 0; +--- a/dbrandom.h ++++ b/dbrandom.h +@@ -30,6 +30,6 @@ + void seedrandom(void); + void genrandom(unsigned char* buf, unsigned int len); + void addrandom(const unsigned char * buf, unsigned int len); +-void gen_random_mpint(mp_int *max, mp_int *rand); ++void gen_random_mpint(const mp_int *max, mp_int *rand); + + #endif /* DROPBEAR_RANDOM_H_ */ +--- a/dbutil.c ++++ b/dbutil.c +@@ -442,7 +442,7 @@ void printhex(const char * label, const + } + } + +-void printmpint(const char *label, mp_int *mp) { ++void printmpint(const char *label, const mp_int *mp) { + buffer *buf = buf_new(1000); + buf_putmpint(buf, mp); + fprintf(stderr, "%d bits ", mp_count_bits(mp)); +--- a/dbutil.h ++++ b/dbutil.h +@@ -53,7 +53,7 @@ void dropbear_trace3(const char* format, + void dropbear_trace4(const char* format, ...) ATTRIB_PRINTF(1,2); + void dropbear_trace5(const char* format, ...) ATTRIB_PRINTF(1,2); + void printhex(const char * label, const unsigned char * buf, int len); +-void printmpint(const char *label, mp_int *mp); ++void printmpint(const char *label, const mp_int *mp); + void debug_start_net(void); + extern int debug_trace; + #endif +--- a/genrsa.c ++++ b/genrsa.c +@@ -34,7 +34,7 @@ + #if DROPBEAR_RSA + + static void getrsaprime(mp_int* prime, mp_int *primeminus, +- mp_int* rsa_e, unsigned int size_bytes); ++ const mp_int* rsa_e, unsigned int size_bytes); + + /* mostly taken from libtomcrypt's rsa key generation routine */ + dropbear_rsa_key * gen_rsa_priv_key(unsigned int size) { +@@ -89,7 +89,7 @@ dropbear_rsa_key * gen_rsa_priv_key(unsi + + /* return a prime suitable for p or q */ + static void getrsaprime(mp_int* prime, mp_int *primeminus, +- mp_int* rsa_e, unsigned int size_bytes) { ++ const mp_int* rsa_e, unsigned int size_bytes) { + + unsigned char *buf; + int trials; diff --git a/package/network/services/dropbear/patches/006-dropbearkey-add-missing-break-in-switch.patch b/package/network/services/dropbear/patches/006-dropbearkey-add-missing-break-in-switch.patch new file mode 100644 index 0000000000..c7011021c1 --- /dev/null +++ b/package/network/services/dropbear/patches/006-dropbearkey-add-missing-break-in-switch.patch @@ -0,0 +1,21 @@ +From 39d955c49f31fc155e885447ee2be61c869d8c2d Mon Sep 17 00:00:00 2001 +From: Matt Johnston +Date: Tue, 3 Jan 2023 22:05:14 +0800 +Subject: Add missing break in switch + +Has no effect on execution, the fallthrough does nothing +Closes #208 +--- + dropbearkey.c | 1 + + 1 file changed, 1 insertion(+) + +--- a/dropbearkey.c ++++ b/dropbearkey.c +@@ -139,6 +139,7 @@ static void check_signkey_bits(enum sign + dropbear_exit("DSS keys have a fixed size of 1024 bits\n"); + exit(EXIT_FAILURE); + } ++ break; + #endif + default: + (void)0; /* quiet, compiler. ecdsa handles checks itself */ diff --git a/package/network/services/dropbear/patches/007-fix-building-only-client-or-server.patch b/package/network/services/dropbear/patches/007-fix-building-only-client-or-server.patch new file mode 100644 index 0000000000..5fcfaad180 --- /dev/null +++ b/package/network/services/dropbear/patches/007-fix-building-only-client-or-server.patch @@ -0,0 +1,29 @@ +From 7a53c7f0f4b3eb23e002819553cb45558642c01d Mon Sep 17 00:00:00 2001 +From: Matt Johnston +Date: Wed, 4 Jan 2023 20:32:23 +0800 +Subject: Fix building only client or server + +Regressed when -Wundef was added + +Fixes #210 +--- + sysoptions.h | 8 ++++++++ + 1 file changed, 8 insertions(+) + +--- a/sysoptions.h ++++ b/sysoptions.h +@@ -10,6 +10,14 @@ + #define LOCAL_IDENT "SSH-2.0-dropbear_" DROPBEAR_VERSION + #define PROGNAME "dropbear" + ++#ifndef DROPBEAR_CLIENT ++#define DROPBEAR_CLIENT 0 ++#endif ++ ++#ifndef DROPBEAR_SERVER ++#define DROPBEAR_SERVER 0 ++#endif ++ + /* Spec recommends after one hour or 1 gigabyte of data. One hour + * is a bit too verbose, so we try 8 hours */ + #ifndef KEX_REKEY_TIMEOUT diff --git a/package/network/services/dropbear/patches/008-disable-rsa-signatures-when-no-rsa-hostkey.patch b/package/network/services/dropbear/patches/008-disable-rsa-signatures-when-no-rsa-hostkey.patch new file mode 100644 index 0000000000..4f675234ff --- /dev/null +++ b/package/network/services/dropbear/patches/008-disable-rsa-signatures-when-no-rsa-hostkey.patch @@ -0,0 +1,94 @@ +From a113381c12a2da3c9b7bd594f47a1b2657bdfdf2 Mon Sep 17 00:00:00 2001 +From: Matt Johnston +Date: Sun, 12 Feb 2023 22:44:32 +0800 +Subject: Disable rsa signatures when no rsa hostkey + +Otherwise Dropbear will offer RSA as a hostkey signature option, but the +session will exit with an assertion or NULL pointer dereference once +that algorithm is negotiated. + +This likely regressed in 2020.79 when signature vs key type enums were +split, for rsa-sha256. + +Fixes #219 on github +--- + svr-runopts.c | 21 +++++++++++---------- + 1 file changed, 11 insertions(+), 10 deletions(-) + +--- a/svr-runopts.c ++++ b/svr-runopts.c +@@ -505,11 +505,11 @@ static void addportandaddress(const char + svr_opts.portcount++; + } + +-static void disablekey(int type) { ++static void disablekey(enum signature_type type) { + int i; + TRACE(("Disabling key type %d", type)) + for (i = 0; sigalgs[i].name != NULL; i++) { +- if (sigalgs[i].val == type) { ++ if ((int)sigalgs[i].val == (int)type) { + sigalgs[i].usable = 0; + break; + } +@@ -624,7 +624,8 @@ void load_all_hostkeys() { + + #if DROPBEAR_RSA + if (!svr_opts.delay_hostkey && !svr_opts.hostkey->rsakey) { +- disablekey(DROPBEAR_SIGNKEY_RSA); ++ disablekey(DROPBEAR_SIGNATURE_RSA_SHA256); ++ disablekey(DROPBEAR_SIGNATURE_RSA_SHA1); + } else { + any_keys = 1; + } +@@ -632,7 +633,7 @@ void load_all_hostkeys() { + + #if DROPBEAR_DSS + if (!svr_opts.delay_hostkey && !svr_opts.hostkey->dsskey) { +- disablekey(DROPBEAR_SIGNKEY_DSS); ++ disablekey(DROPBEAR_SIGNATURE_DSS); + } else { + any_keys = 1; + } +@@ -666,35 +667,35 @@ void load_all_hostkeys() { + #if DROPBEAR_ECC_256 + if (!svr_opts.hostkey->ecckey256 + && (!svr_opts.delay_hostkey || loaded_any_ecdsa || ECDSA_DEFAULT_SIZE != 256 )) { +- disablekey(DROPBEAR_SIGNKEY_ECDSA_NISTP256); ++ disablekey(DROPBEAR_SIGNATURE_ECDSA_NISTP256); + } + #endif + #if DROPBEAR_ECC_384 + if (!svr_opts.hostkey->ecckey384 + && (!svr_opts.delay_hostkey || loaded_any_ecdsa || ECDSA_DEFAULT_SIZE != 384 )) { +- disablekey(DROPBEAR_SIGNKEY_ECDSA_NISTP384); ++ disablekey(DROPBEAR_SIGNATURE_ECDSA_NISTP384); + } + #endif + #if DROPBEAR_ECC_521 + if (!svr_opts.hostkey->ecckey521 + && (!svr_opts.delay_hostkey || loaded_any_ecdsa || ECDSA_DEFAULT_SIZE != 521 )) { +- disablekey(DROPBEAR_SIGNKEY_ECDSA_NISTP521); ++ disablekey(DROPBEAR_SIGNATURE_ECDSA_NISTP521); + } + #endif + #endif /* DROPBEAR_ECDSA */ + + #if DROPBEAR_ED25519 + if (!svr_opts.delay_hostkey && !svr_opts.hostkey->ed25519key) { +- disablekey(DROPBEAR_SIGNKEY_ED25519); ++ disablekey(DROPBEAR_SIGNATURE_ED25519); + } else { + any_keys = 1; + } + #endif + #if DROPBEAR_SK_ECDSA +- disablekey(DROPBEAR_SIGNKEY_SK_ECDSA_NISTP256); ++ disablekey(DROPBEAR_SIGNATURE_SK_ECDSA_NISTP256); + #endif + #if DROPBEAR_SK_ED25519 +- disablekey(DROPBEAR_SIGNKEY_SK_ED25519); ++ disablekey(DROPBEAR_SIGNATURE_SK_ED25519); + #endif + + if (!any_keys) { diff --git a/package/network/services/dropbear/patches/009-use-write-rather-than-fprintf-in-segv-handler.patch b/package/network/services/dropbear/patches/009-use-write-rather-than-fprintf-in-segv-handler.patch new file mode 100644 index 0000000000..e1538a4c1f --- /dev/null +++ b/package/network/services/dropbear/patches/009-use-write-rather-than-fprintf-in-segv-handler.patch @@ -0,0 +1,27 @@ +From 3292b8c6f1e5fcc405fa0f7a20e90a60f74037b2 Mon Sep 17 00:00:00 2001 +From: Matt Johnston +Date: Sun, 12 Feb 2023 23:00:00 +0800 +Subject: Use write() rather than fprintf() in segv handler + +fprintf isn't guaranteed safe (though hasn't had any problems reported). +--- + svr-main.c | 8 ++++++-- + 1 file changed, 6 insertions(+), 2 deletions(-) + +--- a/svr-main.c ++++ b/svr-main.c +@@ -420,8 +420,12 @@ static void sigchld_handler(int UNUSED(u + + /* catch any segvs */ + static void sigsegv_handler(int UNUSED(unused)) { +- fprintf(stderr, "Aiee, segfault! You should probably report " +- "this as a bug to the developer\n"); ++ int i; ++ const char *msg = "Aiee, segfault! You should probably report " ++ "this as a bug to the developer\n"; ++ i = write(STDERR_FILENO, msg, strlen(msg)); ++ /* ignore short writes */ ++ (void)i; + _exit(EXIT_FAILURE); + } + diff --git a/package/network/services/dropbear/patches/010-remove-SO_LINGER.patch b/package/network/services/dropbear/patches/010-remove-SO_LINGER.patch new file mode 100644 index 0000000000..12b1843ee2 --- /dev/null +++ b/package/network/services/dropbear/patches/010-remove-SO_LINGER.patch @@ -0,0 +1,39 @@ +From 5040f21cb4ee6ade966e60c6d5a3c270d03de1f1 Mon Sep 17 00:00:00 2001 +From: Matt Johnston +Date: Mon, 1 May 2023 22:05:43 +0800 +Subject: Remove SO_LINGER + +It could cause channels to take up to 5 seconds to close(), which would block +the entire process. On busy TCP forwarding sessions this would result in +channels seeming stuck and new connections not being accepted. + +We don't need to monitor for flushing failures since we can't report errors, so +SO_LINGER wasn't useful. + +Thanks to GektorUA for reporting and testing + +Fixes #230 +--- + netio.c | 4 ---- + 1 file changed, 4 deletions(-) + +--- a/netio.c ++++ b/netio.c +@@ -472,7 +472,6 @@ int dropbear_listen(const char* address, + struct addrinfo hints, *res = NULL, *res0 = NULL; + int err; + unsigned int nsock; +- struct linger linger; + int val; + int sock; + uint16_t *allocated_lport_p = NULL; +@@ -551,9 +550,6 @@ int dropbear_listen(const char* address, + val = 1; + /* set to reuse, quick timeout */ + setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (void*) &val, sizeof(val)); +- linger.l_onoff = 1; +- linger.l_linger = 5; +- setsockopt(sock, SOL_SOCKET, SO_LINGER, (void*)&linger, sizeof(linger)); + + #if defined(IPPROTO_IPV6) && defined(IPV6_V6ONLY) + if (res->ai_family == AF_INET6) { diff --git a/package/network/services/dropbear/patches/011-add-option-to-bind-to-interface.patch b/package/network/services/dropbear/patches/011-add-option-to-bind-to-interface.patch new file mode 100644 index 0000000000..d1c1fa4cce --- /dev/null +++ b/package/network/services/dropbear/patches/011-add-option-to-bind-to-interface.patch @@ -0,0 +1,147 @@ +From fb64db9eac3fdc6434f2dc7b5ea407fe5df76e6f Mon Sep 17 00:00:00 2001 +From: Diederik De Coninck +Date: Tue, 11 Apr 2023 15:38:04 +0200 +Subject: Add option to bind to interface + +--- + netio.c | 13 +++++++++++-- + netio.h | 2 +- + runopts.h | 1 + + svr-main.c | 2 +- + svr-runopts.c | 9 +++++++++ + svr-tcpfwd.c | 1 + + tcp-accept.c | 2 +- + tcpfwd.h | 1 + + 8 files changed, 26 insertions(+), 5 deletions(-) + +--- a/netio.c ++++ b/netio.c +@@ -467,7 +467,7 @@ int get_sock_port(int sock) { + * failure, if errstring wasn't NULL, it'll be a newly malloced error + * string.*/ + int dropbear_listen(const char* address, const char* port, +- int *socks, unsigned int sockcount, char **errstring, int *maxfd) { ++ int *socks, unsigned int sockcount, char **errstring, int *maxfd, const char* interface) { + + struct addrinfo hints, *res = NULL, *res0 = NULL; + int err; +@@ -497,7 +497,11 @@ int dropbear_listen(const char* address, + TRACE(("dropbear_listen: local loopback")) + } else { + if (address[0] == '\0') { +- TRACE(("dropbear_listen: all interfaces")) ++ if (interface) { ++ TRACE(("dropbear_listen: %s", interface)) ++ } else { ++ TRACE(("dropbear_listen: all interfaces")) ++ } + address = NULL; + } + hints.ai_flags = AI_PASSIVE; +@@ -551,6 +555,11 @@ int dropbear_listen(const char* address, + /* set to reuse, quick timeout */ + setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (void*) &val, sizeof(val)); + ++ if(interface && setsockopt(sock, SOL_SOCKET, SO_BINDTODEVICE, interface, strlen(interface)) < 0) { ++ dropbear_log(LOG_WARNING, "Couldn't set SO_BINDTODEVICE"); ++ TRACE(("Failed setsockopt with errno failure, %d %s", errno, strerror(errno))) ++ } ++ + #if defined(IPPROTO_IPV6) && defined(IPV6_V6ONLY) + if (res->ai_family == AF_INET6) { + int on = 1; +--- a/netio.h ++++ b/netio.h +@@ -19,7 +19,7 @@ void get_socket_address(int fd, char **l + void getaddrstring(struct sockaddr_storage* addr, + char **ret_host, char **ret_port, int host_lookup); + int dropbear_listen(const char* address, const char* port, +- int *socks, unsigned int sockcount, char **errstring, int *maxfd); ++ int *socks, unsigned int sockcount, char **errstring, int *maxfd, const char* interface); + + struct dropbear_progress_connection; + +--- a/runopts.h ++++ b/runopts.h +@@ -128,6 +128,7 @@ typedef struct svr_runopts { + char * pidfile; + + char * forced_command; ++ char* interface; + + #if DROPBEAR_PLUGIN + /* malloced */ +--- a/svr-main.c ++++ b/svr-main.c +@@ -488,7 +488,7 @@ static size_t listensockets(int *socks, + + nsock = dropbear_listen(svr_opts.addresses[i], svr_opts.ports[i], &socks[sockpos], + sockcount - sockpos, +- &errstring, maxfd); ++ &errstring, maxfd, svr_opts.interface); + + if (nsock < 0) { + dropbear_log(LOG_WARNING, "Failed listening on '%s': %s", +--- a/svr-runopts.c ++++ b/svr-runopts.c +@@ -98,6 +98,8 @@ static void printhelp(const char * progn + " (default port is %s if none specified)\n" + "-P PidFile Create pid file PidFile\n" + " (default %s)\n" ++ "-l \n" ++ " interface to bind on\n" + #if INETD_MODE + "-i Start for inetd\n" + #endif +@@ -265,6 +267,9 @@ void svr_getopts(int argc, char ** argv) + case 'P': + next = &svr_opts.pidfile; + break; ++ case 'l': ++ next = &svr_opts.interface; ++ break; + #if DO_MOTD + /* motd is displayed by default, -m turns it off */ + case 'm': +@@ -438,6 +443,10 @@ void svr_getopts(int argc, char ** argv) + dropbear_log(LOG_INFO, "Forced command set to '%s'", svr_opts.forced_command); + } + ++ if (svr_opts.interface) { ++ dropbear_log(LOG_INFO, "Binding to interface '%s'", svr_opts.interface); ++ } ++ + if (reexec_fd_arg) { + if (m_str_to_uint(reexec_fd_arg, &svr_opts.reexec_childpipe) == DROPBEAR_FAILURE + || svr_opts.reexec_childpipe < 0) { +--- a/svr-tcpfwd.c ++++ b/svr-tcpfwd.c +@@ -205,6 +205,7 @@ static int svr_remotetcpreq(int *allocat + tcpinfo->listenport = port; + tcpinfo->chantype = &svr_chan_tcpremote; + tcpinfo->tcp_type = forwarded; ++ tcpinfo->interface = svr_opts.interface; + + tcpinfo->request_listenaddr = request_addr; + if (!opts.listen_fwd_all || (strcmp(request_addr, "localhost") == 0) ) { +--- a/tcp-accept.c ++++ b/tcp-accept.c +@@ -117,7 +117,7 @@ int listen_tcpfwd(struct TCPListener* tc + snprintf(portstring, sizeof(portstring), "%u", tcpinfo->listenport); + + nsocks = dropbear_listen(tcpinfo->listenaddr, portstring, socks, +- DROPBEAR_MAX_SOCKS, &errstring, &ses.maxfd); ++ DROPBEAR_MAX_SOCKS, &errstring, &ses.maxfd, tcpinfo->interface); + if (nsocks < 0) { + dropbear_log(LOG_INFO, "TCP forward failed: %s", errstring); + m_free(errstring); +--- a/tcpfwd.h ++++ b/tcpfwd.h +@@ -42,6 +42,7 @@ struct TCPListener { + unsigned int listenport; + /* The address that the remote host asked to listen on */ + char *request_listenaddr; ++ char* interface; + + const struct ChanType *chantype; + enum {direct, forwarded} tcp_type; diff --git a/package/network/services/dropbear/patches/012-add-ifdef-guards-for-SO_BINDTODEVICE.patch b/package/network/services/dropbear/patches/012-add-ifdef-guards-for-SO_BINDTODEVICE.patch new file mode 100644 index 0000000000..11f902bf90 --- /dev/null +++ b/package/network/services/dropbear/patches/012-add-ifdef-guards-for-SO_BINDTODEVICE.patch @@ -0,0 +1,50 @@ +From 031d09b47912b2401f4934667c0b6f857ede61ee Mon Sep 17 00:00:00 2001 +From: Matt Johnston +Date: Tue, 18 Jul 2023 23:20:16 +0800 +Subject: Add ifdef guards for SO_BINDTODEVICE + +--- + netio.c | 2 ++ + svr-runopts.c | 4 ++++ + 2 files changed, 6 insertions(+) + +--- a/netio.c ++++ b/netio.c +@@ -555,10 +555,12 @@ int dropbear_listen(const char* address, + /* set to reuse, quick timeout */ + setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (void*) &val, sizeof(val)); + ++#ifdef SO_BINDTODEVICE + if(interface && setsockopt(sock, SOL_SOCKET, SO_BINDTODEVICE, interface, strlen(interface)) < 0) { + dropbear_log(LOG_WARNING, "Couldn't set SO_BINDTODEVICE"); + TRACE(("Failed setsockopt with errno failure, %d %s", errno, strerror(errno))) + } ++#endif + + #if defined(IPPROTO_IPV6) && defined(IPV6_V6ONLY) + if (res->ai_family == AF_INET6) { +--- a/svr-runopts.c ++++ b/svr-runopts.c +@@ -98,8 +98,10 @@ static void printhelp(const char * progn + " (default port is %s if none specified)\n" + "-P PidFile Create pid file PidFile\n" + " (default %s)\n" ++#ifdef SO_BINDTODEVICE + "-l \n" + " interface to bind on\n" ++#endif + #if INETD_MODE + "-i Start for inetd\n" + #endif +@@ -267,9 +269,11 @@ void svr_getopts(int argc, char ** argv) + case 'P': + next = &svr_opts.pidfile; + break; ++#ifdef SO_BINDTODEVICE + case 'l': + next = &svr_opts.interface; + break; ++#endif + #if DO_MOTD + /* motd is displayed by default, -m turns it off */ + case 'm': diff --git a/package/network/services/dropbear/patches/013-make-banner-reading-failure-non-fatal.patch b/package/network/services/dropbear/patches/013-make-banner-reading-failure-non-fatal.patch new file mode 100644 index 0000000000..531215c757 --- /dev/null +++ b/package/network/services/dropbear/patches/013-make-banner-reading-failure-non-fatal.patch @@ -0,0 +1,74 @@ +From 62a06cd95f58060a59359f8769c3f35cd680d4fd Mon Sep 17 00:00:00 2001 +From: Matt Johnston +Date: Sun, 23 Jul 2023 21:01:48 +0800 +Subject: Make banner reading failure non-fatal + +--- + svr-runopts.c | 45 ++++++++++++++++++++++++++++----------------- + 1 file changed, 28 insertions(+), 17 deletions(-) + +--- a/svr-runopts.c ++++ b/svr-runopts.c +@@ -38,6 +38,7 @@ static void printhelp(const char * progn + static void addportandaddress(const char* spec); + static void loadhostkey(const char *keyfile, int fatal_duplicate); + static void addhostkey(const char *keyfile); ++static void load_banner(); + + static void printhelp(const char * progname) { + +@@ -382,23 +383,7 @@ void svr_getopts(int argc, char ** argv) + } + + if (svr_opts.bannerfile) { +- struct stat buf; +- if (stat(svr_opts.bannerfile, &buf) != 0) { +- dropbear_exit("Error opening banner file '%s'", +- svr_opts.bannerfile); +- } +- +- if (buf.st_size > MAX_BANNER_SIZE) { +- dropbear_exit("Banner file too large, max is %d bytes", +- MAX_BANNER_SIZE); +- } +- +- svr_opts.banner = buf_new(buf.st_size); +- if (buf_readfile(svr_opts.banner, svr_opts.bannerfile)!=DROPBEAR_SUCCESS) { +- dropbear_exit("Error reading banner file '%s'", +- svr_opts.bannerfile); +- } +- buf_setpos(svr_opts.banner, 0); ++ load_banner(); + } + + #ifdef HAVE_GETGROUPLIST +@@ -715,3 +700,29 @@ void load_all_hostkeys() { + dropbear_exit("No hostkeys available. 'dropbear -R' may be useful or run dropbearkey."); + } + } ++ ++static void load_banner() { ++ struct stat buf; ++ if (stat(svr_opts.bannerfile, &buf) != 0) { ++ dropbear_log(LOG_WARNING, "Error opening banner file '%s'", ++ svr_opts.bannerfile); ++ return; ++ } ++ ++ if (buf.st_size > MAX_BANNER_SIZE) { ++ dropbear_log(LOG_WARNING, "Banner file too large, max is %d bytes", ++ MAX_BANNER_SIZE); ++ return; ++ } ++ ++ svr_opts.banner = buf_new(buf.st_size); ++ if (buf_readfile(svr_opts.banner, svr_opts.bannerfile) != DROPBEAR_SUCCESS) { ++ dropbear_log(LOG_WARNING, "Error reading banner file '%s'", ++ svr_opts.bannerfile); ++ buf_free(svr_opts.banner); ++ svr_opts.banner = NULL; ++ return; ++ } ++ buf_setpos(svr_opts.banner, 0); ++ ++} diff --git a/package/network/services/dropbear/patches/014-dropbearkey-ignore-unsupported-command-line-option.patch b/package/network/services/dropbear/patches/014-dropbearkey-ignore-unsupported-command-line-option.patch new file mode 100644 index 0000000000..ff130f8be0 --- /dev/null +++ b/package/network/services/dropbear/patches/014-dropbearkey-ignore-unsupported-command-line-option.patch @@ -0,0 +1,60 @@ +From ec26975d442163b66d1646a48e022bc8c2f1607a Mon Sep 17 00:00:00 2001 +From: Sergey Ponomarev +Date: Sun, 27 Aug 2023 00:07:05 +0300 +Subject: dropbearkey.c Ignore unsupported command line options + +To generate non interactively a key with OpenSSH the simplest command is: + +ssh-keygen -t ed25519 -q -N '' -f ~/.ssh/id_ed25519 + +The command has two options -q quiet and -N passphrase which aren't supported by the dropbearkey. + +To improve interoperability add explicit ignoring of the -q and -N with empty passphrase. +Also ignore the -v even if the DEBUG_TRACE is not set. + +Signed-off-by: Sergey Ponomarev +--- + dropbearkey.c | 15 +++++++++++++-- + 1 file changed, 13 insertions(+), 2 deletions(-) + +--- a/dropbearkey.c ++++ b/dropbearkey.c +@@ -159,6 +159,7 @@ int main(int argc, char ** argv) { + enum signkey_type keytype = DROPBEAR_SIGNKEY_NONE; + char * typetext = NULL; + char * sizetext = NULL; ++ char * passphrase = NULL; + unsigned int bits = 0, genbits; + int printpub = 0; + +@@ -194,11 +195,16 @@ int main(int argc, char ** argv) { + printhelp(argv[0]); + exit(EXIT_SUCCESS); + break; +-#if DEBUG_TRACE + case 'v': ++#if DEBUG_TRACE + debug_trace = DROPBEAR_VERBOSE_LEVEL; +- break; + #endif ++ break; ++ case 'q': ++ break; /* quiet is default */ ++ case 'N': ++ next = &passphrase; ++ break; + default: + fprintf(stderr, "Unknown argument %s\n", argv[i]); + printhelp(argv[0]); +@@ -266,6 +272,11 @@ int main(int argc, char ** argv) { + check_signkey_bits(keytype, bits);; + } + ++ if (passphrase && *passphrase != '\0') { ++ fprintf(stderr, "Only empty passphrase is supported\n"); ++ exit(EXIT_FAILURE); ++ } ++ + genbits = signkey_generate_get_bits(keytype, bits); + fprintf(stderr, "Generating %u bit %s key, this may take a while...\n", genbits, typetext); + if (signkey_generate(keytype, bits, filename, 0) == DROPBEAR_FAILURE) diff --git a/package/network/services/dropbear/patches/015-libtommath-fix-possible-integer-overflow.patch b/package/network/services/dropbear/patches/015-libtommath-fix-possible-integer-overflow.patch new file mode 100644 index 0000000000..f39417adb7 --- /dev/null +++ b/package/network/services/dropbear/patches/015-libtommath-fix-possible-integer-overflow.patch @@ -0,0 +1,121 @@ +From 3b576d95dcf791d7b945e75f639da8f89c1685a2 Mon Sep 17 00:00:00 2001 +From: czurnieden +Date: Tue, 9 May 2023 17:17:12 +0200 +Subject: Fix possible integer overflow + +--- + libtommath/bn_mp_2expt.c | 4 ++++ + libtommath/bn_mp_grow.c | 4 ++++ + libtommath/bn_mp_init_size.c | 5 +++++ + libtommath/bn_mp_mul_2d.c | 4 ++++ + libtommath/bn_s_mp_mul_digs.c | 4 ++++ + libtommath/bn_s_mp_mul_digs_fast.c | 4 ++++ + libtommath/bn_s_mp_mul_high_digs.c | 4 ++++ + libtommath/bn_s_mp_mul_high_digs_fast.c | 4 ++++ + 8 files changed, 33 insertions(+) + +--- a/libtommath/bn_mp_2expt.c ++++ b/libtommath/bn_mp_2expt.c +@@ -12,6 +12,10 @@ mp_err mp_2expt(mp_int *a, int b) + { + mp_err err; + ++ if (b < 0) { ++ return MP_VAL; ++ } ++ + /* zero a as per default */ + mp_zero(a); + +--- a/libtommath/bn_mp_grow.c ++++ b/libtommath/bn_mp_grow.c +@@ -9,6 +9,10 @@ mp_err mp_grow(mp_int *a, int size) + int i; + mp_digit *tmp; + ++ if (size < 0) { ++ return MP_VAL; ++ } ++ + /* if the alloc size is smaller alloc more ram */ + if (a->alloc < size) { + /* reallocate the array a->dp +--- a/libtommath/bn_mp_init_size.c ++++ b/libtommath/bn_mp_init_size.c +@@ -6,6 +6,11 @@ + /* init an mp_init for a given size */ + mp_err mp_init_size(mp_int *a, int size) + { ++ ++ if (size < 0) { ++ return MP_VAL; ++ } ++ + size = MP_MAX(MP_MIN_PREC, size); + + /* alloc mem */ +--- a/libtommath/bn_mp_mul_2d.c ++++ b/libtommath/bn_mp_mul_2d.c +@@ -9,6 +9,10 @@ mp_err mp_mul_2d(const mp_int *a, int b, + mp_digit d; + mp_err err; + ++ if (b < 0) { ++ return MP_VAL; ++ } ++ + /* copy */ + if (a != c) { + if ((err = mp_copy(a, c)) != MP_OKAY) { +--- a/libtommath/bn_s_mp_mul_digs.c ++++ b/libtommath/bn_s_mp_mul_digs.c +@@ -16,6 +16,10 @@ mp_err s_mp_mul_digs(const mp_int *a, co + mp_word r; + mp_digit tmpx, *tmpt, *tmpy; + ++ if (digs < 0) { ++ return MP_VAL; ++ } ++ + /* can we use the fast multiplier? */ + if ((digs < MP_WARRAY) && + (MP_MIN(a->used, b->used) < MP_MAXFAST)) { +--- a/libtommath/bn_s_mp_mul_digs_fast.c ++++ b/libtommath/bn_s_mp_mul_digs_fast.c +@@ -26,6 +26,10 @@ mp_err s_mp_mul_digs_fast(const mp_int * + mp_digit W[MP_WARRAY]; + mp_word _W; + ++ if (digs < 0) { ++ return MP_VAL; ++ } ++ + /* grow the destination as required */ + if (c->alloc < digs) { + if ((err = mp_grow(c, digs)) != MP_OKAY) { +--- a/libtommath/bn_s_mp_mul_high_digs.c ++++ b/libtommath/bn_s_mp_mul_high_digs.c +@@ -15,6 +15,10 @@ mp_err s_mp_mul_high_digs(const mp_int * + mp_word r; + mp_digit tmpx, *tmpt, *tmpy; + ++ if (digs < 0) { ++ return MP_VAL; ++ } ++ + /* can we use the fast multiplier? */ + if (MP_HAS(S_MP_MUL_HIGH_DIGS_FAST) + && ((a->used + b->used + 1) < MP_WARRAY) +--- a/libtommath/bn_s_mp_mul_high_digs_fast.c ++++ b/libtommath/bn_s_mp_mul_high_digs_fast.c +@@ -19,6 +19,10 @@ mp_err s_mp_mul_high_digs_fast(const mp_ + mp_digit W[MP_WARRAY]; + mp_word _W; + ++ if (digs < 0) { ++ return MP_VAL; ++ } ++ + /* grow the destination as required */ + pa = a->used + b->used; + if (c->alloc < pa) { diff --git a/package/network/services/dropbear/patches/016-src-svr-tcpfwd-Fix-noremotetcp-behavior.patch b/package/network/services/dropbear/patches/016-src-svr-tcpfwd-Fix-noremotetcp-behavior.patch new file mode 100644 index 0000000000..b6933120e6 --- /dev/null +++ b/package/network/services/dropbear/patches/016-src-svr-tcpfwd-Fix-noremotetcp-behavior.patch @@ -0,0 +1,35 @@ +From 3cf8344769eda55e26eee53c1898b2c66544f188 Mon Sep 17 00:00:00 2001 +From: Justin Chen +Date: Fri, 8 Sep 2023 11:35:18 -0700 +Subject: src: svr-tcpfwd: Fix noremotetcp behavior + +If noremotetcp is set, we should still reply with +send_msg_request_failed. This matches the behavior +of !DROPBEAR_SVR_REMOTETCPFWD. + +We were seeing keepalive packets being ignored when +the "-k" option was used. +--- + svr-tcpfwd.c | 6 +++--- + 1 file changed, 3 insertions(+), 3 deletions(-) + +--- a/svr-tcpfwd.c ++++ b/svr-tcpfwd.c +@@ -79,14 +79,14 @@ void recv_msg_global_request_remotetcp() + + TRACE(("enter recv_msg_global_request_remotetcp")) + ++ reqname = buf_getstring(ses.payload, &namelen); ++ wantreply = buf_getbool(ses.payload); ++ + if (svr_opts.noremotetcp || !svr_pubkey_allows_tcpfwd()) { + TRACE(("leave recv_msg_global_request_remotetcp: remote tcp forwarding disabled")) + goto out; + } + +- reqname = buf_getstring(ses.payload, &namelen); +- wantreply = buf_getbool(ses.payload); +- + if (namelen > MAX_NAME_LEN) { + TRACE(("name len is wrong: %d", namelen)) + goto out; diff --git a/package/network/services/dropbear/patches/017-Don-t-try-to-shutdown-a-pty.patch b/package/network/services/dropbear/patches/017-Don-t-try-to-shutdown-a-pty.patch new file mode 100644 index 0000000000..603c61d6fb --- /dev/null +++ b/package/network/services/dropbear/patches/017-Don-t-try-to-shutdown-a-pty.patch @@ -0,0 +1,32 @@ +From e28ba1b9975eab48799aa3ed77d3cd91627d7b27 Mon Sep 17 00:00:00 2001 +From: Matt Johnston +Date: Sat, 9 Dec 2023 23:10:41 +0800 +Subject: Don't try to shutdown() a pty + +shutdown() of a pty doesn't work (ENOTSOCK), so we should close +it instead. + +This will ensure that PTY controlling terminals are closed when a +session exits, including when multiple sessions run over a single SSH +connection. In the normal case of a single session, the PTY controlling +terminal would be closed when the Dropbear server process exits anyway. + +This possibly fixes #264 on github + +It is possible that there could be subtle changes to PTY flushing +behaviour, though nothing caught by tests at present. +--- + svr-chansession.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +--- a/svr-chansession.c ++++ b/svr-chansession.c +@@ -910,7 +910,7 @@ static int ptycommand(struct Channel *ch + channel->readfd = chansess->master; + /* don't need to set stderr here */ + ses.maxfd = MAX(ses.maxfd, chansess->master); +- channel->bidir_fd = 1; ++ channel->bidir_fd = 0; + + setnonblocking(chansess->master); + diff --git a/package/network/services/dropbear/patches/018-dropbearkey-add-alias-to-ssh-keygen.patch b/package/network/services/dropbear/patches/018-dropbearkey-add-alias-to-ssh-keygen.patch new file mode 100644 index 0000000000..9c70c3141c --- /dev/null +++ b/package/network/services/dropbear/patches/018-dropbearkey-add-alias-to-ssh-keygen.patch @@ -0,0 +1,33 @@ +From 806586b585806cbe32013bcd3af3847278972060 Mon Sep 17 00:00:00 2001 +From: Sergey Ponomarev +Date: Sun, 10 Dec 2023 10:31:56 +0200 +Subject: dropbearkey: add alias to ssh-keygen + +The dropbearkey is partially compatible with ssh-keygen and can be used as an alias. + +Closes: #263 +--- + dbmulti.c | 5 +++-- + 1 file changed, 3 insertions(+), 2 deletions(-) + +--- a/dbmulti.c ++++ b/dbmulti.c +@@ -41,7 +41,8 @@ static int runprog(const char *multipath + } + #endif + #ifdef DBMULTI_dropbearkey +- if (strcmp(progname, "dropbearkey") == 0) { ++ if (strcmp(progname, "dropbearkey") == 0 ++ || strcmp(progname, "ssh-keygen") == 0) { + return dropbearkey_main(argc, argv); + } + #endif +@@ -88,7 +89,7 @@ int main(int argc, char ** argv) { + "'dbclient' or 'ssh' - the Dropbear client\n" + #endif + #ifdef DBMULTI_dropbearkey +- "'dropbearkey' - the key generator\n" ++ "'dropbearkey' or 'ssh-keygen' - the key generator\n" + #endif + #ifdef DBMULTI_dropbearconvert + "'dropbearconvert' - the key converter\n" diff --git a/package/network/services/dropbear/patches/019-Allow-inetd-with-non-syslog.patch b/package/network/services/dropbear/patches/019-Allow-inetd-with-non-syslog.patch new file mode 100644 index 0000000000..3544f2123c --- /dev/null +++ b/package/network/services/dropbear/patches/019-Allow-inetd-with-non-syslog.patch @@ -0,0 +1,34 @@ +From 383cc8c97a9420aad9cf93d88e77ec636b183a9d Mon Sep 17 00:00:00 2001 +From: Matt Johnston +Date: Mon, 11 Dec 2023 23:18:09 +0800 +Subject: Allow inetd with non-syslog + +An inetd-alike should be able to distinguish stdout and stderr, so +it's a valid configuration. + +Fixes #218 on github +--- + svr-runopts.c | 12 ------------ + 1 file changed, 12 deletions(-) + +--- a/svr-runopts.c ++++ b/svr-runopts.c +@@ -443,18 +443,6 @@ void svr_getopts(int argc, char ** argv) + } + } + +-#if INETD_MODE +- if (svr_opts.inetdmode && ( +- opts.usingsyslog == 0 +-#if DEBUG_TRACE +- || debug_trace +-#endif +- )) { +- /* log output goes to stderr which would get sent over the inetd network socket */ +- dropbear_exit("Dropbear inetd mode is incompatible with debug -v or non-syslog"); +- } +-#endif +- + if (svr_opts.multiauthmethod && svr_opts.noauthpass) { + dropbear_exit("-t and -s are incompatible"); + } diff --git a/package/network/services/dropbear/patches/020-Fix-test-for-multiuser-kernels.patch b/package/network/services/dropbear/patches/020-Fix-test-for-multiuser-kernels.patch new file mode 100644 index 0000000000..8d016faa9c --- /dev/null +++ b/package/network/services/dropbear/patches/020-Fix-test-for-multiuser-kernels.patch @@ -0,0 +1,33 @@ +From 9ac650401ffc2fb05c9328d26e76a5e7ae39152a Mon Sep 17 00:00:00 2001 +From: Matt Johnston +Date: Mon, 11 Dec 2023 23:31:22 +0800 +Subject: Fix test for multiuser kernels + +getuid() succeeds even on non-multiuser kernels. Instead +getgroups() is a valid test. + +Fixes #214 on github +--- + common-session.c | 11 +++++++---- + 1 file changed, 7 insertions(+), 4 deletions(-) + +--- a/common-session.c ++++ b/common-session.c +@@ -71,10 +71,13 @@ void common_session_init(int sock_in, in + #if !DROPBEAR_SVR_MULTIUSER + /* A sanity check to prevent an accidental configuration option + leaving multiuser systems exposed */ +- errno = 0; +- getuid(); +- if (errno != ENOSYS) { +- dropbear_exit("Non-multiuser Dropbear requires a non-multiuser kernel"); ++ { ++ int ret; ++ errno = 0; ++ ret = getgroups(0, NULL); ++ if (!(ret == -1 && errno == ENOSYS)) { ++ dropbear_exit("Non-multiuser Dropbear requires a non-multiuser kernel"); ++ } + } + #endif + diff --git a/package/network/services/dropbear/patches/021-Implement-Strict-KEX-mode.patch b/package/network/services/dropbear/patches/021-Implement-Strict-KEX-mode.patch new file mode 100644 index 0000000000..d490d9545a --- /dev/null +++ b/package/network/services/dropbear/patches/021-Implement-Strict-KEX-mode.patch @@ -0,0 +1,216 @@ +From 6e43be5c7b99dbee49dc72b6f989f29fdd7e9356 Mon Sep 17 00:00:00 2001 +From: Matt Johnston +Date: Mon, 20 Nov 2023 14:02:47 +0800 +Subject: Implement Strict KEX mode + +As specified by OpenSSH with kex-strict-c-v00@openssh.com and +kex-strict-s-v00@openssh.com. +--- + cli-session.c | 11 +++++++++++ + common-algo.c | 6 ++++++ + common-kex.c | 26 +++++++++++++++++++++++++- + kex.h | 3 +++ + process-packet.c | 34 +++++++++++++++++++--------------- + ssh.h | 4 ++++ + svr-session.c | 3 +++ + 7 files changed, 71 insertions(+), 16 deletions(-) + +--- a/cli-session.c ++++ b/cli-session.c +@@ -46,6 +46,7 @@ static void cli_finished(void) ATTRIB_NO + static void recv_msg_service_accept(void); + static void cli_session_cleanup(void); + static void recv_msg_global_request_cli(void); ++static void cli_algos_initialise(void); + + struct clientsession cli_ses; /* GLOBAL */ + +@@ -117,6 +118,7 @@ void cli_session(int sock_in, int sock_o + } + + chaninitialise(cli_chantypes); ++ cli_algos_initialise(); + + /* Set up cli_ses vars */ + cli_session_init(proxy_cmd_pid); +@@ -487,3 +489,12 @@ void cli_dropbear_log(int priority, cons + fflush(stderr); + } + ++static void cli_algos_initialise(void) { ++ algo_type *algo; ++ for (algo = sshkex; algo->name; algo++) { ++ if (strcmp(algo->name, SSH_STRICT_KEX_S) == 0) { ++ algo->usable = 0; ++ } ++ } ++} ++ +--- a/common-algo.c ++++ b/common-algo.c +@@ -308,6 +308,12 @@ algo_type sshkex[] = { + {SSH_EXT_INFO_C, 0, NULL, 1, NULL}, + #endif + #endif ++#if DROPBEAR_CLIENT ++ {SSH_STRICT_KEX_C, 0, NULL, 1, NULL}, ++#endif ++#if DROPBEAR_SERVER ++ {SSH_STRICT_KEX_S, 0, NULL, 1, NULL}, ++#endif + {NULL, 0, NULL, 0, NULL} + }; + +--- a/common-kex.c ++++ b/common-kex.c +@@ -183,6 +183,10 @@ void send_msg_newkeys() { + gen_new_keys(); + switch_keys(); + ++ if (ses.kexstate.strict_kex) { ++ ses.transseq = 0; ++ } ++ + TRACE(("leave send_msg_newkeys")) + } + +@@ -193,7 +197,11 @@ void recv_msg_newkeys() { + + ses.kexstate.recvnewkeys = 1; + switch_keys(); +- ++ ++ if (ses.kexstate.strict_kex) { ++ ses.recvseq = 0; ++ } ++ + TRACE(("leave recv_msg_newkeys")) + } + +@@ -550,6 +558,10 @@ void recv_msg_kexinit() { + + ses.kexstate.recvkexinit = 1; + ++ if (ses.kexstate.strict_kex && !ses.kexstate.donefirstkex && ses.recvseq != 1) { ++ dropbear_exit("First packet wasn't kexinit"); ++ } ++ + TRACE(("leave recv_msg_kexinit")) + } + +@@ -859,6 +871,18 @@ static void read_kex_algos() { + } + #endif + ++ if (!ses.kexstate.donefirstkex) { ++ const char* strict_name; ++ if (IS_DROPBEAR_CLIENT) { ++ strict_name = SSH_STRICT_KEX_S; ++ } else { ++ strict_name = SSH_STRICT_KEX_C; ++ } ++ if (buf_has_algo(ses.payload, strict_name) == DROPBEAR_SUCCESS) { ++ ses.kexstate.strict_kex = 1; ++ } ++ } ++ + algo = buf_match_algo(ses.payload, sshkex, kexguess2, &goodguess); + allgood &= goodguess; + if (algo == NULL || algo->data == NULL) { +--- a/kex.h ++++ b/kex.h +@@ -83,6 +83,9 @@ struct KEXState { + + unsigned our_first_follows_matches : 1; + ++ /* Boolean indicating that strict kex mode is in use */ ++ unsigned int strict_kex; ++ + time_t lastkextime; /* time of the last kex */ + unsigned int datatrans; /* data transmitted since last kex */ + unsigned int datarecv; /* data received since last kex */ +--- a/process-packet.c ++++ b/process-packet.c +@@ -44,6 +44,7 @@ void process_packet() { + + unsigned char type; + unsigned int i; ++ unsigned int first_strict_kex = ses.kexstate.strict_kex && !ses.kexstate.donefirstkex; + time_t now; + + TRACE2(("enter process_packet")) +@@ -54,22 +55,24 @@ void process_packet() { + now = monotonic_now(); + ses.last_packet_time_keepalive_recv = now; + +- /* These packets we can receive at any time */ +- switch(type) { + +- case SSH_MSG_IGNORE: +- goto out; +- case SSH_MSG_DEBUG: +- goto out; +- +- case SSH_MSG_UNIMPLEMENTED: +- /* debugging XXX */ +- TRACE(("SSH_MSG_UNIMPLEMENTED")) +- goto out; +- +- case SSH_MSG_DISCONNECT: +- /* TODO cleanup? */ +- dropbear_close("Disconnect received"); ++ if (type == SSH_MSG_DISCONNECT) { ++ /* Allowed at any time */ ++ dropbear_close("Disconnect received"); ++ } ++ ++ /* These packets may be received at any time, ++ except during first kex with strict kex */ ++ if (!first_strict_kex) { ++ switch(type) { ++ case SSH_MSG_IGNORE: ++ goto out; ++ case SSH_MSG_DEBUG: ++ goto out; ++ case SSH_MSG_UNIMPLEMENTED: ++ TRACE(("SSH_MSG_UNIMPLEMENTED")) ++ goto out; ++ } + } + + /* Ignore these packet types so that keepalives don't interfere with +@@ -98,7 +101,8 @@ void process_packet() { + if (type >= 1 && type <= 49 + && type != SSH_MSG_SERVICE_REQUEST + && type != SSH_MSG_SERVICE_ACCEPT +- && type != SSH_MSG_KEXINIT) ++ && type != SSH_MSG_KEXINIT ++ && !first_strict_kex) + { + TRACE(("unknown allowed packet during kexinit")) + recv_unimplemented(); +--- a/ssh.h ++++ b/ssh.h +@@ -100,6 +100,10 @@ + #define SSH_EXT_INFO_C "ext-info-c" + #define SSH_SERVER_SIG_ALGS "server-sig-algs" + ++/* OpenSSH strict KEX feature */ ++#define SSH_STRICT_KEX_S "kex-strict-s-v00@openssh.com" ++#define SSH_STRICT_KEX_C "kex-strict-c-v00@openssh.com" ++ + /* service types */ + #define SSH_SERVICE_USERAUTH "ssh-userauth" + #define SSH_SERVICE_USERAUTH_LEN 12 +--- a/svr-session.c ++++ b/svr-session.c +@@ -370,6 +370,9 @@ static void svr_algos_initialise(void) { + algo->usable = 0; + } + #endif ++ if (strcmp(algo->name, SSH_STRICT_KEX_C) == 0) { ++ algo->usable = 0; ++ } + } + } + diff --git a/package/network/services/dropbear/patches/910-signkey-fix-use-of-rsa-sha2-256-pubkeys.patch b/package/network/services/dropbear/patches/910-signkey-fix-use-of-rsa-sha2-256-pubkeys.patch index f078814403..442fdcfc75 100644 --- a/package/network/services/dropbear/patches/910-signkey-fix-use-of-rsa-sha2-256-pubkeys.patch +++ b/package/network/services/dropbear/patches/910-signkey-fix-use-of-rsa-sha2-256-pubkeys.patch @@ -21,7 +21,7 @@ Signed-off-by: Petr Å tetiar --- a/signkey.c +++ b/signkey.c -@@ -646,8 +646,12 @@ int buf_verify(buffer * buf, sign_key *k +@@ -652,8 +652,12 @@ int buf_verify(buffer * buf, sign_key *k sigtype = signature_type_from_name(type_name, type_name_len); m_free(type_name); -- 2.30.2