changeset 1870:0dcc5b0d93fa

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.
author Matt Johnston <matt@ucc.asn.au>
date Tue, 01 Feb 2022 22:18:23 +0800
parents d7247462fa0d
children b89cf71ec40c
files .github/multiwrapper .github/workflows/build.yml dbmulti.c dbutil.h svr-main.c test/test_dropbear.py
diffstat 6 files changed, 94 insertions(+), 51 deletions(-) [+]
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/.github/multiwrapper	Tue Feb 01 22:18:23 2022 +0800
@@ -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 "$@"
+
--- a/.github/workflows/build.yml	Tue Feb 01 22:12:25 2022 +0800
+++ b/.github/workflows/build.yml	Tue Feb 01 22:18:23 2022 +0800
@@ -22,37 +22,42 @@
 
           - 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: linux clang
+          #   cc: clang
 
-          - 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 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
+          # - 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 @@
         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 }}
--- a/dbmulti.c	Tue Feb 01 22:12:25 2022 +0800
+++ b/dbmulti.c	Tue Feb 01 22:18:23 2022 +0800
@@ -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 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;
 			}
--- a/dbutil.h	Tue Feb 01 22:12:25 2022 +0800
+++ b/dbutil.h	Tue Feb 01 22:18:23 2022 +0800
@@ -99,4 +99,12 @@
 #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_ */
--- a/svr-main.c	Tue Feb 01 22:12:25 2022 +0800
+++ b/svr-main.c	Tue Feb 01 22:18:23 2022 +0800
@@ -36,16 +36,20 @@
 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 @@
 #endif
 
 #if NON_INETD_MODE
-	main_noinetd(argc, argv);
+	main_noinetd(argc, argv, multipath);
 	/* notreached */
 #endif
 
@@ -121,7 +125,7 @@
 #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 @@
 	}
 
 #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 @@
 
 				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));
--- a/test/test_dropbear.py	Tue Feb 01 22:12:25 2022 +0800
+++ b/test/test_dropbear.py	Tue Feb 01 22:18:23 2022 +0800
@@ -19,7 +19,8 @@
 		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 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: