From 393932175060d4be03782fedc9541ea19666a0d2 Mon Sep 17 00:00:00 2001 From: Matt Johnston Date: Tue, 1 Feb 2022 22:18:23 +0800 Subject: [PATCH] Make re-exec work with "dropbearmulti dropbear" The re-exec needs to know to use the dropbearmulti binary instead. Add a test for this case. --- .github/multiwrapper | 9 +++++ .github/workflows/build.yml | 68 ++++++++++++++++++++++--------------- dbmulti.c | 15 +++----- dbutil.h | 8 +++++ svr-main.c | 37 ++++++++++++++------ test/test_dropbear.py | 8 +++-- 6 files changed, 94 insertions(+), 51 deletions(-) create mode 100755 .github/multiwrapper diff --git a/.github/multiwrapper b/.github/multiwrapper new file mode 100755 index 0000000..12474a3 --- /dev/null +++ b/.github/multiwrapper @@ -0,0 +1,9 @@ +#!/bin/sh + +# symlink this to dropbear/dbclient/dropbearkey next to dropbearmulti +# good enough for testing purposes. + +DIR=$(dirname $0) +PROG=$(basename $0) +exec $DIR/dropbearmulti $PROG "$@" + diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 63ed3e7..48690f2 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -22,37 +22,42 @@ jobs: - name: multi binary multi: 1 + multilink: 1 - - name: bundled libtom, bionic , no writev() - # test can use an older distro with bundled libtommath - os: ubuntu-18.04 - configure_flags: --enable-bundled-libtom --enable-werror - # NOWRITEV is unrelated, test here to save a job - nowritev: 1 - # our tests expect >= python3.7 - runcheck: 'no' + # - name: multi binary, dropbearmulti argv0 + # multi: 1 + # multiwrapper: 1 - - name: linux clang - cc: clang + # - name: bundled libtom, bionic , no writev() + # # test can use an older distro with bundled libtommath + # os: ubuntu-18.04 + # configure_flags: --enable-bundled-libtom --enable-werror + # # NOWRITEV is unrelated, test here to save a job + # nowritev: 1 + # # our tests expect >= python3.7 + # runcheck: 'no' - - name: macos 10.15 - os: macos-10.15 - cc: clang - # OS X says daemon() and utmp are deprecated - extracflags: -Wno-deprecated-declarations - runcheck: 'no' - apt: 'no' - # fails with: - # .../ranlib: file: libtomcrypt.a(cbc_setiv.o) has no symbols - ranlib: ranlib -no_warning_for_no_symbols + # - name: linux clang + # cc: clang - - name: macos 11 - os: macos-11 - cc: clang - extracflags: -Wno-deprecated-declarations - runcheck: 'no' - apt: 'no' - ranlib: ranlib -no_warning_for_no_symbols + # - name: macos 10.15 + # os: macos-10.15 + # cc: clang + # # OS X says daemon() and utmp are deprecated + # extracflags: -Wno-deprecated-declarations + # runcheck: 'no' + # apt: 'no' + # # fails with: + # # .../ranlib: file: libtomcrypt.a(cbc_setiv.o) has no symbols + # ranlib: ranlib -no_warning_for_no_symbols + + # - name: macos 11 + # os: macos-11 + # cc: clang + # extracflags: -Wno-deprecated-declarations + # runcheck: 'no' + # apt: 'no' + # ranlib: ranlib -no_warning_for_no_symbols # # Fuzzers run standalone. A bit superfluous with cifuzz, but # # good to run the whole corpus to keep it working. @@ -102,9 +107,16 @@ jobs: run: make -j3 - name: multilink - if: ${{ matrix.multi }} + if: ${{ matrix.multilink }} run: make multilink + - name: multi wrapper script + if: ${{ matrix.multiwrapper }} + run: | + cp .github/multiwrapper dropbear + cp .github/multiwrapper dbclient + cp .github/multiwrapper dropbearkey + - name: makefuzz run: make fuzzstandalone if: ${{ matrix.fuzz }} diff --git a/dbmulti.c b/dbmulti.c index 204e9a3..514d7be 100644 --- a/dbmulti.c +++ b/dbmulti.c @@ -23,20 +23,15 @@ * SOFTWARE. */ #include "includes.h" +#include "dbutil.h" -/* definitions are cleanest if we just put them here */ -int dropbear_main(int argc, char ** argv); -int cli_main(int argc, char ** argv); -int dropbearkey_main(int argc, char ** argv); -int dropbearconvert_main(int argc, char ** argv); -int scp_main(int argc, char ** argv); - -static int runprog(const char *progname, int argc, char ** argv, int *match) { +static int runprog(const char *multipath, + const char *progname, int argc, char ** argv, int *match) { *match = DROPBEAR_SUCCESS; #ifdef DBMULTI_dropbear if (strcmp(progname, "dropbear") == 0) { - return dropbear_main(argc, argv); + return dropbear_main(argc, argv, multipath); } #endif #ifdef DBMULTI_dbclient @@ -72,7 +67,7 @@ int main(int argc, char ** argv) { int match, res; /* figure which form we're being called as */ const char* progname = basename(argv[i]); - res = runprog(progname, argc-i, &argv[i], &match); + res = runprog(argv[0], progname, argc-i, &argv[i], &match); if (match == DROPBEAR_SUCCESS) { return res; } diff --git a/dbutil.h b/dbutil.h index 39e1c35..87cd69d 100644 --- a/dbutil.h +++ b/dbutil.h @@ -99,4 +99,12 @@ int fd_read_pending(int fd); #define DROPBEAR_FD_ZERO(fds) FD_ZERO(fds) #endif +/* dropbearmulti entry points */ +int dropbear_main(int argc, char ** argv, const char * multipath); +int cli_main(int argc, char ** argv); +int dropbearkey_main(int argc, char ** argv); +int dropbearconvert_main(int argc, char ** argv); +int scp_main(int argc, char ** argv); + + #endif /* DROPBEAR_DBUTIL_H_ */ diff --git a/svr-main.c b/svr-main.c index 3595d4c..871b037 100644 --- a/svr-main.c +++ b/svr-main.c @@ -36,16 +36,20 @@ static void sigchld_handler(int dummy); static void sigsegv_handler(int); static void sigintterm_handler(int fish); static void main_inetd(void); -static void main_noinetd(int argc, char ** argv); +static void main_noinetd(int argc, char ** argv, const char* multipath); static void commonsetup(void); #if defined(DBMULTI_dropbear) || !DROPBEAR_MULTI #if defined(DBMULTI_dropbear) && DROPBEAR_MULTI -int dropbear_main(int argc, char ** argv) +int dropbear_main(int argc, char ** argv, const char* multipath) #else int main(int argc, char ** argv) #endif { +#if !DROPBEAR_MULTI + const char* multipath = NULL; +#endif + _dropbear_exit = svr_dropbear_exit; _dropbear_log = svr_dropbear_log; @@ -80,7 +84,7 @@ int main(int argc, char ** argv) #endif #if NON_INETD_MODE - main_noinetd(argc, argv); + main_noinetd(argc, argv, multipath); /* notreached */ #endif @@ -121,7 +125,7 @@ static void main_inetd() { #endif /* INETD_MODE */ #if NON_INETD_MODE -static void main_noinetd(int argc, char ** argv) { +static void main_noinetd(int argc, char ** argv, const char* multipath) { fd_set fds; unsigned int i, j; int val; @@ -163,7 +167,11 @@ static void main_noinetd(int argc, char ** argv) { } #if DROPBEAR_DO_REEXEC - execfd = open(argv[0], O_CLOEXEC|O_RDONLY); + if (multipath) { + execfd = open(multipath, O_CLOEXEC|O_RDONLY); + } else { + execfd = open(argv[0], O_CLOEXEC|O_RDONLY); + } if (execfd < 0) { /* Just fallback to straight fork */ TRACE(("Couldn't open own binary %s, disabling re-exec: %s", argv[0], strerror(errno))) @@ -338,11 +346,20 @@ static void main_noinetd(int argc, char ** argv) { if (execfd >= 0) { #if DROPBEAR_DO_REEXEC - /* Add "-2" to the args and re-execute ourself */ - char **new_argv = m_malloc(sizeof(char*) * (argc+2)); - memcpy(new_argv, argv, sizeof(char*) * argc); - new_argv[argc] = "-2"; - new_argv[argc+1] = NULL; + /* Add "-2" to the args and re-execute ourself. */ + char **new_argv = m_malloc(sizeof(char*) * (argc+3)); + int pos0 = 0, new_argc = argc+1; + + /* We need to specially handle "dropbearmulti dropbear". */ + if (multipath) { + new_argv[0] = (char*)multipath; + pos0 = 1; + new_argc++; + } + + memcpy(&new_argv[pos0], argv, sizeof(char*) * argc); + new_argv[new_argc-1] = "-2"; + new_argv[new_argc] = NULL; if ((dup2(childsock, STDIN_FILENO) < 0)) { dropbear_exit("dup2 failed: %s", strerror(errno)); diff --git a/test/test_dropbear.py b/test/test_dropbear.py index 0b6e1a0..5e7fcc6 100644 --- a/test/test_dropbear.py +++ b/test/test_dropbear.py @@ -19,7 +19,8 @@ def dropbear(request): yield None return - args = [opt.dropbear, + # split so that "dropbearmulti dropbear" works + args = opt.dropbear.split() + [ "-p", LOCALADDR, # bind locally only "-r", opt.hostkey, "-p", opt.port, @@ -43,9 +44,10 @@ def dropbear(request): def dbclient(request, *args, **kwargs): opt = request.config.option host = opt.remote or LOCALADDR - base_args = [opt.dbclient, "-y", host, "-p", opt.port] + # split so that "dropbearmulti dbclient" works + base_args = opt.dbclient.split() + ["-y", host, "-p", opt.port] if opt.user: - full_args.extend(['-l', opt.user]) + base_args.extend(['-l', opt.user]) full_args = base_args + list(args) bg = kwargs.get("background") if "background" in kwargs: