diff --git a/CHANGES b/CHANGES index f4dc5fd..2b35f10 100644 --- a/CHANGES +++ b/CHANGES @@ -16,6 +16,11 @@ corrections: compiling with MUSL libc failed. Problem reported by Kennedy33. + The async signal safe diagnostic system used FDs 3 and 4 internally, so + use of appropriate fdin or fdout led to failures. + Test: DIAG_FDIN + Problem reported by Onur Sentürk. + testing: test.sh: Show a warning when phase-1 (insecure phase) of a security test fails diff --git a/error.c b/error.c index bc60b1e..7de3d39 100644 --- a/error.c +++ b/error.c @@ -210,6 +210,19 @@ const char *diag_get_string(char what) { return NULL; } +/* make sure that the diag_sock fds do not have this num */ +int diag_reserve_fd(int fd) { + DIAG_INIT; + if (diag_sock_send == fd) { + diag_sock_send = Dup(fd); + Close(fd); + } + if (diag_sock_recv == fd) { + diag_sock_recv = Dup(fd); + Close(fd); + } + return 0; +} /* Linux and AIX syslog format: Oct 4 17:10:37 hostname socat[52798]: D signal(13, 1) diff --git a/error.h b/error.h index 09c0727..d37982f 100644 --- a/error.h +++ b/error.h @@ -236,6 +236,7 @@ extern void diag_set(char what, const char *arg); extern void diag_set_int(char what, int arg); extern int diag_get_int(char what); extern const char *diag_get_string(char what); +extern int diag_reserve_fd(int fd); extern int diag_dup(void); extern int diag_dup2(int newfd); extern void msg(int level, const char *format, ...); diff --git a/test.sh b/test.sh index 2a2659c..9f9787f 100755 --- a/test.sh +++ b/test.sh @@ -12799,6 +12799,48 @@ esac PORT=$((PORT+1)) N=$((N+1)) + +# The fix to "Make code async-signal-safe" used internally FD 3 and FD 4. +# Using option fdin=3 did not pass data to executed program. +NAME=DIAG_FDIN +case "$TESTS" in +*%$N%*|*%functions%*|*%bugs%*|*%exec%*|*%$NAME%*) +TEST="$NAME: test use of fdin=3" +# Use FD 3 explicitely with fdin and test if Socat passes data to executed +# program +if ! eval $NUMCOND; then :; else +tf="$td/test$N.stdout" +te="$td/test$N.stderr" +tdiff="$td/test$N.diff" +da="test$N $(date) $RANDOM" +CMD0="$TRACE $SOCAT $opts - SYSTEM:\"cat >&3 <&4\",fdin=4,fdout=3" +printf "test $F_n $TEST... " $N +echo "$da" |$TRACE $SOCAT $opts - SYSTEM:"cat <&3 >&4",fdin=3,fdout=4 >${tf}0 2>"${te}0" +rc0=$? +if [ $rc0 -ne 0 ]; then + $PRINTF "$FAILED\n" + echo "$CMD0" + cat "${te}0" + numFAIL=$((numFAIL+1)) + listFAIL="$listFAIL $N" +elif echo "$da" |diff - ${tf}0 >$tdiff; then + $PRINTF "$OK\n" + numOK=$((numOK+1)) +else + $PRINTF "$FAILED\n" + echo "$CMD0" + cat "${te}0" + cat "$tdiff" + numFAIL=$((numFAIL+1)) + listFAIL="$listFAIL $N" +fi +fi # NUMCOND + ;; +esac +PORT=$((PORT+1)) +N=$((N+1)) + + ################################################################################## #================================================================================= # here come tests that might affect your systems integrity. Put normal tests diff --git a/xio-progcall.c b/xio-progcall.c index 1196cf4..bcb7d34 100644 --- a/xio-progcall.c +++ b/xio-progcall.c @@ -168,7 +168,7 @@ int _xioopen_foxec(int xioflags, /* XIO_RDONLY etc. */ } #endif - /* remember: fdin is the fs where the sub program reads from, thus it is + /* remember: fdin is the fd where the sub program reads from, thus it is sock0[]'s read fd */ /*! problem: when fdi==WRFD(sock[0]) or fdo==RDFD(sock[0]) */ if (rw != XIO_WRONLY) { @@ -177,6 +177,9 @@ int _xioopen_foxec(int xioflags, /* XIO_RDONLY etc. */ Warn2("fcntl(%d, F_SETFD, 0): %s", fdo, strerror(errno)); } } else { + /* make sure that the internal diagnostic socket pair fds do not conflict + with our choices */ + diag_reserve_fd(fdo); if (Dup2(XIO_GETWRFD(sock[0]), fdo) < 0) { Error3("dup2(%d, %d): %s", XIO_GETWRFD(sock[0]), fdo, strerror(errno)); @@ -190,6 +193,9 @@ int _xioopen_foxec(int xioflags, /* XIO_RDONLY etc. */ Warn2("fcntl(%d, F_SETFD, 0): %s", fdi, strerror(errno)); } } else { + /* make sure that the internal diagnostic socket pair fds do not conflict + with our choices */ + diag_reserve_fd(fdi); if (Dup2(XIO_GETRDFD(sock[0]), fdi) < 0) { Error3("dup2(%d, %d): %s)", XIO_GETRDFD(sock[0]), fdi, strerror(errno)); @@ -425,12 +431,18 @@ int _xioopen_foxec(int xioflags, /* XIO_RDONLY etc. */ if (usepty) { Close(ptyfd); if (rw != XIO_RDONLY && fdi != ttyfd) { + /* make sure that the internal diagnostic socket pair fds do not conflict + with our choices */ + diag_reserve_fd(fdi); if (Dup2(ttyfd, fdi) < 0) { Error3("dup2(%d, %d): %s", ttyfd, fdi, strerror(errno)); return -1; } /*0 Info2("dup2(%d, %d)", ttyfd, fdi);*/ } if (rw != XIO_WRONLY && fdo != ttyfd) { + /* make sure that the internal diagnostic socket pair fds do not conflict + with our choices */ + diag_reserve_fd(fdo); if (Dup2(ttyfd, fdo) < 0) { Error3("dup2(%d, %d): %s", ttyfd, fdo, strerror(errno)); return -1; } @@ -472,6 +484,9 @@ int _xioopen_foxec(int xioflags, /* XIO_RDONLY etc. */ } if (rw != XIO_WRONLY && rdpip[1] != fdo) { + /* make sure that the internal diagnostic socket pair fds do not conflict + with our choices */ + diag_reserve_fd(fdo); if (Dup2(rdpip[1], fdo) < 0) { Error3("dup2(%d, %d): %s", rdpip[1], fdo, strerror(errno)); return -1; @@ -481,6 +496,9 @@ int _xioopen_foxec(int xioflags, /* XIO_RDONLY etc. */ /*0 applyopts_cloexec(fdo, *copts);*/ } if (rw != XIO_RDONLY && wrpip[0] != fdi) { + /* make sure that the internal diagnostic socket pair fds do not conflict + with our choices */ + diag_reserve_fd(fdi); if (Dup2(wrpip[0], fdi) < 0) { Error3("dup2(%d, %d): %s", wrpip[0], fdi, strerror(errno)); return -1; @@ -499,12 +517,18 @@ int _xioopen_foxec(int xioflags, /* XIO_RDONLY etc. */ } else { /* socketpair */ Close(sv[0]); if (rw != XIO_RDONLY && fdi != sv[1]) { + /* make sure that the internal diagnostic socket pair fds do not conflict + with our choices */ + diag_reserve_fd(fdi); if (Dup2(sv[1], fdi) < 0) { Error3("dup2(%d, %d): %s", sv[1], fdi, strerror(errno)); return -1; } /*0 Info2("dup2(%d, %d)", sv[1], fdi);*/ } if (rw != XIO_WRONLY && fdo != sv[1]) { + /* make sure that the internal diagnostic socket pair fds do not conflict + with our choices */ + diag_reserve_fd(fdo); if (Dup2(sv[1], fdo) < 0) { Error3("dup2(%d, %d): %s", sv[1], fdo, strerror(errno)); return -1; }