Only enter the sig_no switch if we actually return from read(2) with
authormartijn <martijn@openbsd.org>
Wed, 11 Aug 2021 15:13:46 +0000 (15:13 +0000)
committermartijn <martijn@openbsd.org>
Wed, 11 Aug 2021 15:13:46 +0000 (15:13 +0000)
errno == EINTR. There was a race here where read(2) can return with a
different errno, but the signal handler enters between the read return and
the switch, which could result in handling a signal, while we should be
handling the error.

This fix assumes that signal handlers don't clobber our errno, but doing
that would open a whole other can of worms.

OK schwarze@, millert@

lib/libedit/read.c

index 754d898..7900193 100644 (file)
@@ -1,4 +1,4 @@
-/*     $OpenBSD: read.c,v 1.46 2021/08/10 14:28:10 schwarze Exp $      */
+/*     $OpenBSD: read.c,v 1.47 2021/08/11 15:13:46 martijn Exp $       */
 /*     $NetBSD: read.c,v 1.100 2016/05/24 19:31:27 christos Exp $      */
 
 /*-
@@ -240,15 +240,17 @@ read_char(EditLine *el, wchar_t *cp)
        el->el_signal->sig_no = 0;
        while ((num_read = read(el->el_infd, cbuf + cbp, 1)) == -1) {
                int e = errno;
-               switch (el->el_signal->sig_no) {
-               case SIGCONT:
-                       el_set(el, EL_REFRESH);
-                       /*FALLTHROUGH*/
-               case SIGWINCH:
-                       sig_set(el);
-                       goto again;
-               default:
-                       break;
+               if (errno == EINTR) {
+                       switch (el->el_signal->sig_no) {
+                       case SIGCONT:
+                               el_set(el, EL_REFRESH);
+                               /*FALLTHROUGH*/
+                       case SIGWINCH:
+                               sig_set(el);
+                               goto again;
+                       default:
+                               break;
+                       }
                }
                if (!tried && read__fixio(el->el_infd, e) == 0) {
                        errno = save_errno;