Feat/build#1
Conversation
Previously non-strict packets would be allowed once Dropbear's own SSH_MSG_NEWKEYS had been sent, but for correctness it should only be allowed once receiving the SSH_MSG_NEWKEYS from the peer. Reported by Fabian Bäumer
This avoids problems with shell escaping if arguments contain special characters.
The path for distribution customizations is src/distrooptions.h, not src/distoptions.h. This minor typo was added in 454591d (Use src/distrooptions.h as another source, 2024-01-22).
fixes e5a0ef2 "Execute multihop commands directly, no shell" Signed-off-by: Konstantin Demin <rockdrilla@gmail.com>
Previously the channel window and increments were limited to 500MB. That is incorrect and causes stuck connections if peers advertise a large window, then don't send an increment within the first 500MB. That's seen with SSH.NET sshnet/SSH.NET#1671
fixes 440b7b5 "Add sntrup761x25519-sha512 post-quantum key exchange" Signed-off-by: Konstantin Demin <rockdrilla@gmail.com>
Should help for non-gmake platforms
Auth delay was meant to be 250-350ms, it was actually 150-350ms or possibly negative. Fixes mkj#387
Previous allow_reuse_addr was incorrect, it should be allow_reuse_address. Confirmed looking at setsockopt in strace when running tcpflushout test. This is a partial fix for github mkj#386
When RSA or DSS are not built, the private key buffer size is too small, resulting in a "bad_getbuf" or similar exit. This was a regression in 2025.87. Fixes: 440b7b5 ("Add sntrup761x25519-sha512 post-quantum key exchange") ECDSA private key requires around 241 bytes 4 + len("ecdsa-sha2-nistp521") + 4 + (521/8+1 + 4)*3 + 4 Fixes mkj#368 on github.
Instead of switching user privileges after forking to a shell, switch to the user immediately upon successful authentication. This will require further commits to fix utmp and hostkey handling. The DROPBEAR_SVR_DROP_PRIVS configuration option controls this behaviour. This should generally be enabled, but can be set to 0 for incompatible platforms. In future it may become non-optional, those platforms should be investigated. Most uses of DROPBEAR_SVR_MULTIUSER have been replaced by !DROPBEAR_SVR_DROP_PRIVS.
Previously this was always 0, so not useful.
utmp is required to record logout. The saved group is reset by the OS for the executed user shell. This requires setresgid() function which is not available on all platforms. Notable platforms are netbsd and macos. Those platforms will have to set DROPBEAR_SVR_DROP_PRIVS 0 unless an alternative approach is found.
During rekey dropbear process may be running with user privileges, that can't write a new hostkey when auto-generating keys. Only offer the original hostkey when rekeying, also for non-autogenerate case.
Ignore "disable" arguments when the feature is compiled out. -j Disable local port forwarding -k Disable remote port forwarding -m Don't display the motd on login
Authorized_keys reading is pre-authentication so should not be modified in the post-auth drop-privilege change. Fixes: e0251be ("Drop privileges after user authentication")
Otherwise the stream will be created by the root user and other programs may trust the root user via SO_PEERCRED/SO_PASSCRED
Being able to create a unix stream to a system may bypass forced command restrictions, so disallow that.
Cherry-pick from OpenSSH portable
391ffc4b9d31 ("upstream: check in scp client that filenames sent during")
upstream: check in scp client that filenames sent during
remote->local directory copies satisfy the wildcard specified by the user.
This checking provides some protection against a malicious server
sending unexpected filenames, but it comes at a risk of rejecting wanted
files due to differences between client and server wildcard expansion rules.
For this reason, this also adds a new -T flag to disable the check.
reported by Harry Sintonen
fix approach suggested by markus@;
has been in snaps for ~1wk courtesy deraadt@
Script doesn't use config.h so define it manually
macos doesn't currently support DROPBEAR_SVR_DROP_PRIVS so can't use unix socket forwarding either. Also disable it for nondefault builds.
Recent glibc doesn't include crypt(), it's now provided by libxcrypt.
Dropbear 2026.90 added a limit to the number of queries that could be made to a server when determining usable keys. This was intended to be set to 15 (MAX_PUBKEY_QUERIES) but the logic was incorrect (and also debug code was accidentally committed). This meant only 10 (default MAX_AUTH_TRIES/-T) tried keys would be allowed - not a huge difference. Reported by Rui Salvaterra Fixes: db0d3fd ("Limit server number of public key queries")
There was a problem hiding this comment.
Code Review
This pull request updates Dropbear to version 2026.91, introducing security fixes, RSA exponent blinding, a new Zig build system, and improved port and stream forwarding. The code review identified several critical issues: a missing NULL terminator in the multihop_args array that could cause crashes during execution or cleanup, an uninitialized entry->host pointer in permitlisten options that leads to crashes when freed, and a potential NULL pointer dereference in svr_remotestreamlocalreq during early exit. Additionally, compilation errors were found in the new build.zig file regarding incorrect std.ArrayList usage and invalid io arguments in directory operations. Finally, minor improvements were suggested to remove an unused variable in rsa.c and add a defensive NULL check in m_mp_burn.
Important
The consumer version of Gemini Code Assist on GitHub is being sunset. Starting June 18, 2026, new organization installations will be blocked, and all code review activity will officially cease on July 17, 2026.
For more details on the timeline and next steps, please review the Help Documentation.
| /* hostnames of prior hops */ | ||
| args[pos] = m_strdup(prior_hops); | ||
| pos++; | ||
|
|
||
| return args; | ||
| } |
There was a problem hiding this comment.
The allocated args array in multihop_args is not NULL-terminated before being returned. Since execve expects a NULL-terminated array of arguments, and the cleanup loop in cli_proxy_cmd relies on a NULL sentinel to stop freeing elements, this will lead to out-of-bounds reads and crashes. Please ensure the array is explicitly NULL-terminated.
\t/* hostnames of prior hops */\n\targs[pos] = m_strdup(prior_hops);\n\tpos++;\n\n\targs[pos] = NULL;\n\treturn args;| struct PermitTCPFwdEntry *entry = | ||
| (struct PermitTCPFwdEntry*)m_malloc(sizeof(struct PermitTCPFwdEntry)); | ||
|
|
||
| list_append(pubkey_options->permit_listens, entry); |
There was a problem hiding this comment.
The entry->host pointer is never initialized to NULL when parsing permitlisten options. Since m_malloc does not zero-initialize memory, entry->host will contain garbage. When svr_pubkey_options_cleanup is called, it attempts to free entry->host, which will result in a crash due to freeing an uninitialized pointer. Please initialize entry->host to NULL.
\t\t\t\t\tstruct PermitTCPFwdEntry *entry =\n\t\t\t\t\t\t\t(struct PermitTCPFwdEntry*)m_malloc(sizeof(struct PermitTCPFwdEntry));\n\t\t\t\t\tentry->host = NULL;\n\n\t\t\t\t\tlist_append(pubkey_options->permit_listens, entry);| out: | ||
| if (ret == DROPBEAR_FAILURE) { | ||
| /* we only free it if a listener wasn't created, since the listener | ||
| * has to remember it if it's to be cancelled */ | ||
| m_free(request_path); | ||
| m_free(tcpinfo->socket_path); | ||
| m_free(tcpinfo); | ||
| } |
There was a problem hiding this comment.
If svr_remotestreamlocalreq exits early (for example, if a forced command is active), tcpinfo remains NULL. The out block unconditionally attempts to dereference tcpinfo->socket_path to free it, which will cause a NULL pointer dereference and crash the server. Please add a NULL check for tcpinfo before freeing its members.
out:\n if (ret == DROPBEAR_FAILURE) {\n /* we only free it if a listener wasn't created, since the listener\n * has to remember it if it's to be cancelled */\n m_free(request_path);\n if (tcpinfo) {\n m_free(tcpinfo->socket_path);\n m_free(tcpinfo);\n }\n }| }; | ||
|
|
||
| // Common preprocessor / compiler flags. | ||
| var common_flags: std.ArrayList([]const u8) = .empty; |
There was a problem hiding this comment.
The std.ArrayList type is used with .empty and has b.allocator passed to its appendSlice calls. In Zig, std.ArrayList is a managed list whose methods do not accept an allocator. You should use std.ArrayListUnmanaged instead, which is designed to be initialized with .empty and accepts an allocator for its operations. This applies to lines 36, 66, 88, 240, and 286.
var common_flags: std.ArrayListUnmanaged([]const u8) = .empty;
| fn collectCSources(b: *std.Build, comptime sub: []const u8, recursive: bool) [][]const u8 { | ||
| const io = b.graph.io; | ||
| var list: std.ArrayList([]const u8) = .empty; | ||
| var dir = b.build_root.handle.openDir(io, sub, .{ .iterate = true }) catch |err| { |
There was a problem hiding this comment.
The standard library std.fs.Dir.openDir does not accept an io parameter. Similarly, walker.next() and it.next() do not accept io as an argument. Passing io to these functions will cause a compilation error. Please remove the io argument from these calls (lines 241, 249, and 260).
var dir = b.build_root.handle.openDir(sub, .{ .iterate = true }) catch |err| {
| DEF_MP_INT(rsa_b_phi); | ||
| DEF_MP_INT(rsa_b_d); | ||
|
|
||
| TRACE(("enter buf_put_rsa_sign")) | ||
| dropbear_assert(key != NULL); | ||
|
|
||
| m_mp_init_multi(&rsa_s, &rsa_tmp1, &rsa_tmp2, &rsa_tmp3, NULL); | ||
| m_mp_init_multi(&rsa_s, &rsa_tmp1, &rsa_tmp2, &rsa_tmp3, | ||
| &rsa_phi_n, &rsa_b_tmp, &rsa_b_rand, &rsa_b_phi, &rsa_b_d, | ||
| NULL); |
There was a problem hiding this comment.
The variable rsa_b_phi is initialized in m_mp_init_multi but is never used in any calculations. It should be removed to clean up the code. Remember to also remove it from m_mp_burn and mp_clear_multi calls later in the function.
\tDEF_MP_INT(rsa_b_d);\n\t\n\tTRACE((\"enter buf_put_rsa_sign\"))\n\tdropbear_assert(key != NULL);\n\n\tm_mp_init_multi(&rsa_s, &rsa_tmp1, &rsa_tmp2, &rsa_tmp3,\n\t\t&rsa_phi_n, &rsa_b_tmp, &rsa_b_rand, &rsa_b_d,\n\t\tNULL);| void m_mp_burn(mp_int *mp) { | ||
| m_burn(mp->dp, mp->alloc * sizeof(*mp->dp)); | ||
| mp->used = 0; | ||
| } |
There was a problem hiding this comment.
To prevent potential undefined behavior or crashes when m_mp_burn is called on an uninitialized or already cleared mp_int (where mp->dp is NULL), it is safer to add a defensive NULL check before calling m_burn.
void m_mp_burn(mp_int *mp) {\n\tif (mp->dp) {\n\t\tm_burn(mp->dp, mp->alloc * sizeof(*mp->dp));\n\t}\n\tmp->used = 0;\n}…ld.zig 显式加 SDK include 路径修复 util.h
…le64),_GNU_SOURCE 改 Linux-only,修复跨 SDK 构建
…代码消除,sftp-server 433KB→~119KB
… 死代码消除(prod+UPX 359KB→195KB)
On Linux, resolve the sftp-server path from the running executable's own directory (via /proc/self/exe) so a relocatable install where sftp-server sits beside dropbearmulti works out of the box. Falls back to the compiled-in SFTPSERVER_PATH when no sibling binary is found. Verified end-to-end on x86_64 Ubuntu 24.04: with sftp-server in the same dir the sftp subsystem succeeds; without it, it falls back to SFTPSERVER_PATH as before.
…SHELL Restore upstream get_user_shell() logic and gate the fixed-shell behaviour behind a documented DROPBEAR_FORCE_SHELL option in default_options.h. The appliance account shell is /bin/login (which prompts for a second password) and /etc/passwd cannot be modified on the device, so SSH sessions must be forced to /bin/sh to drop straight into a shell. The previous hardcoded 'return "/bin/sh"' achieved this but silently overrode standard behaviour; the option makes the intent explicit and reversible.
# Conflicts: # .github/workflows/autoconf.yml # .github/workflows/outoftree.yml # .github/workflows/tarball.yml # src/svr-runopts.c
Add compile-time option DROPBEAR_SVR_OTP_PASSWORD (default off). When enabled and the DROPBEAR_OTP environment variable is set at server startup, a client may authenticate any existing account with that password as an additional channel alongside the normal crypt() check, and even for locked accounts. Constant-time compared; never logged. Intended for appliances whose system files are read-only: start a temporary dropbear with a high-entropy DROPBEAR_OTP and stop it when done.
No description provided.