From 13b28af08ab54a49b1e1360c69595b29f0d6c923 Mon Sep 17 00:00:00 2001 From: CentOS Sources Date: Tue, 9 Nov 2021 04:52:38 -0500 Subject: [PATCH] import openssh-8.0p1-10.el8 --- SOURCES/openssh-6.7p1-coverity.patch | 42 +-- SOURCES/openssh-7.7p1-fips.patch | 10 +- SOURCES/openssh-7.8p1-role-mls.patch | 2 +- SOURCES/openssh-7.9p1-ssh-copy-id.patch | 11 + SOURCES/openssh-8.0p1-cve-2020-14145.patch | 127 +++++++ .../openssh-8.0p1-keygen-strip-doseol.patch | 12 + SOURCES/openssh-8.0p1-pkcs11-uri.patch | 14 +- .../openssh-8.0p1-preserve-pam-errors.patch | 44 +++ SOURCES/openssh-8.0p1-restore-nonblock.patch | 311 ++++++++++++++++++ SOURCES/openssh-8.0p1-sftp-timespeccmp.patch | 16 + SOURCES/openssh-8.0p1-sshd_config.patch | 97 ++++++ SPECS/openssh.spec | 50 ++- 12 files changed, 697 insertions(+), 39 deletions(-) create mode 100644 SOURCES/openssh-8.0p1-cve-2020-14145.patch create mode 100644 SOURCES/openssh-8.0p1-keygen-strip-doseol.patch create mode 100644 SOURCES/openssh-8.0p1-preserve-pam-errors.patch create mode 100644 SOURCES/openssh-8.0p1-restore-nonblock.patch create mode 100644 SOURCES/openssh-8.0p1-sftp-timespeccmp.patch create mode 100644 SOURCES/openssh-8.0p1-sshd_config.patch diff --git a/SOURCES/openssh-6.7p1-coverity.patch b/SOURCES/openssh-6.7p1-coverity.patch index 15d489d..0159482 100644 --- a/SOURCES/openssh-6.7p1-coverity.patch +++ b/SOURCES/openssh-6.7p1-coverity.patch @@ -1,25 +1,29 @@ -diff -up openssh-7.4p1/channels.c.coverity openssh-7.4p1/channels.c ---- openssh-7.4p1/channels.c.coverity 2016-12-23 16:40:26.881788686 +0100 -+++ openssh-7.4p1/channels.c 2016-12-23 16:42:36.244818763 +0100 -@@ -288,11 +288,11 @@ channel_register_fds(Channel *c, int rfd - - /* enable nonblocking mode */ - if (nonblock) { -- if (rfd != -1) -+ if (rfd >= 0) +diff -up openssh-8.0p1/channels.c.coverity openssh-8.0p1/channels.c +--- openssh-8.0p1/channels.c.coverity 2021-06-21 10:59:17.297473319 +0200 ++++ openssh-8.0p1/channels.c 2021-06-21 11:11:32.467290400 +0200 +@@ -341,15 +341,15 @@ channel_register_fds(struct ssh *ssh, Ch + * restore their blocking state on exit to avoid interfering + * with other programs that follow. + */ +- if (rfd != -1 && !isatty(rfd) && fcntl(rfd, F_GETFL) == 0) { ++ if (rfd >= 0 && !isatty(rfd) && fcntl(rfd, F_GETFL) == 0) { + c->restore_block |= CHANNEL_RESTORE_RFD; set_nonblock(rfd); -- if (wfd != -1) -+ if (wfd >= 0) + } +- if (wfd != -1 && !isatty(wfd) && fcntl(wfd, F_GETFL) == 0) { ++ if (wfd >= 0 && !isatty(wfd) && fcntl(wfd, F_GETFL) == 0) { + c->restore_block |= CHANNEL_RESTORE_WFD; set_nonblock(wfd); -- if (efd != -1) -+ if (efd >= 0) + } +- if (efd != -1 && !isatty(efd) && fcntl(efd, F_GETFL) == 0) { ++ if (efd >= 0 && !isatty(efd) && fcntl(efd, F_GETFL) == 0) { + c->restore_block |= CHANNEL_RESTORE_EFD; set_nonblock(efd); - } - } -diff -up openssh-7.4p1/monitor.c.coverity openssh-7.4p1/monitor.c ---- openssh-7.4p1/monitor.c.coverity 2016-12-23 16:40:26.888788688 +0100 -+++ openssh-7.4p1/monitor.c 2016-12-23 16:40:26.900788691 +0100 -@@ -411,7 +411,7 @@ monitor_child_preauth(Authctxt *_authctx + } +diff -up openssh-8.0p1/monitor.c.coverity openssh-8.0p1/monitor.c +--- openssh-8.0p1/monitor.c.coverity 2021-06-21 10:59:17.282473202 +0200 ++++ openssh-8.0p1/monitor.c 2021-06-21 10:59:17.297473319 +0200 +@@ -401,7 +401,7 @@ monitor_child_preauth(struct ssh *ssh, s mm_get_keystate(ssh, pmonitor); /* Drain any buffered messages from the child */ diff --git a/SOURCES/openssh-7.7p1-fips.patch b/SOURCES/openssh-7.7p1-fips.patch index 32091e3..2fb8200 100644 --- a/SOURCES/openssh-7.7p1-fips.patch +++ b/SOURCES/openssh-7.7p1-fips.patch @@ -296,17 +296,17 @@ diff -up openssh-7.9p1/sshconnect2.c.fips openssh-7.9p1/sshconnect2.c #include "openbsd-compat/sys-queue.h" #include "xmalloc.h" -@@ -117,7 +117,8 @@ order_hostkeyalgs(char *host, struct soc - for (i = 0; i < options.num_system_hostfiles; i++) - load_hostkeys(hostkeys, hostname, options.system_hostfiles[i]); - +@@ -148,7 +150,8 @@ order_hostkeyalgs(char *host, struct soc + * Otherwise, prefer the host key algorithms that match known keys + * while keeping the ordering of HostkeyAlgorithms as much as possible. + */ - oavail = avail = xstrdup(KEX_DEFAULT_PK_ALG); + oavail = avail = xstrdup((FIPS_mode() + ? KEX_FIPS_PK_ALG : KEX_DEFAULT_PK_ALG)); maxlen = strlen(avail) + 1; first = xmalloc(maxlen); last = xmalloc(maxlen); -@@ -185,14 +185,16 @@ ssh_kex2(char *host, struct sockaddr *ho +@@ -229,14 +232,16 @@ ssh_kex2(struct ssh *ssh, char *host, st if (options.hostkeyalgorithms != NULL) { all_key = sshkey_alg_list(0, 0, 1, ','); if (kex_assemble_names(&options.hostkeyalgorithms, diff --git a/SOURCES/openssh-7.8p1-role-mls.patch b/SOURCES/openssh-7.8p1-role-mls.patch index 84ba9b3..c3bec2a 100644 --- a/SOURCES/openssh-7.8p1-role-mls.patch +++ b/SOURCES/openssh-7.8p1-role-mls.patch @@ -284,7 +284,7 @@ diff -up openssh/monitor.c.role-mls openssh/monitor.c fail++; if ((r = sshbuf_get_cstring(b, &cp, NULL)) != 0) fatal("%s: buffer error: %s", __func__, ssh_err(r)); -+ if ((s = strchr(p, '/')) != NULL) ++ if ((s = strchr(cp, '/')) != NULL) + *s = '\0'; xasprintf(&userstyle, "%s%s%s", authctxt->user, authctxt->style ? ":" : "", diff --git a/SOURCES/openssh-7.9p1-ssh-copy-id.patch b/SOURCES/openssh-7.9p1-ssh-copy-id.patch index d47880a..6ff2b25 100644 --- a/SOURCES/openssh-7.9p1-ssh-copy-id.patch +++ b/SOURCES/openssh-7.9p1-ssh-copy-id.patch @@ -11,6 +11,17 @@ diff -up openssh-7.9p1/contrib/ssh-copy-id.ssh-copy-id openssh-7.9p1/contrib/ssh # implement something like getopt to avoid Solaris pain case "$1" in -i?*|-o?*|-p?*) +@@ -185,8 +185,8 @@ + usage + fi + +-# drop trailing colon +-USER_HOST=$(printf "%s\n" "$1" | sed 's/:$//') ++# don't drop trailing colon because it can be a valid ipv6 address ++USER_HOST=$(printf "%s\n" "$1") + # tack the hostname onto SSH_OPTS + SSH_OPTS="${SSH_OPTS:+$SSH_OPTS }'$(quote "$USER_HOST")'" + # and populate "$@" for later use (only way to get proper quoting of options) @@ -261,7 +262,7 @@ populate_new_ids() { fi if [ -z "$NEW_IDS" ] ; then diff --git a/SOURCES/openssh-8.0p1-cve-2020-14145.patch b/SOURCES/openssh-8.0p1-cve-2020-14145.patch new file mode 100644 index 0000000..c296bc4 --- /dev/null +++ b/SOURCES/openssh-8.0p1-cve-2020-14145.patch @@ -0,0 +1,127 @@ +diff -up openssh-8.0p1/hostfile.c.cve-2020-14145 openssh-8.0p1/hostfile.c +--- openssh-8.0p1/hostfile.c.cve-2020-14145 2019-04-18 00:52:57.000000000 +0200 ++++ openssh-8.0p1/hostfile.c 2021-05-17 16:53:38.694577251 +0200 +@@ -409,6 +409,18 @@ lookup_key_in_hostkeys_by_type(struct ho + found) == HOST_FOUND); + } + ++int ++lookup_marker_in_hostkeys(struct hostkeys *hostkeys, int want_marker) ++{ ++ u_int i; ++ ++ for (i = 0; i < hostkeys->num_entries; i++) { ++ if (hostkeys->entries[i].marker == (HostkeyMarker)want_marker) ++ return 1; ++ } ++ return 0; ++} ++ + static int + write_host_entry(FILE *f, const char *host, const char *ip, + const struct sshkey *key, int store_hash) +diff -up openssh-8.0p1/hostfile.h.cve-2020-14145 openssh-8.0p1/hostfile.h +--- openssh-8.0p1/hostfile.h.cve-2020-14145 2019-04-18 00:52:57.000000000 +0200 ++++ openssh-8.0p1/hostfile.h 2021-05-17 16:53:38.694577251 +0200 +@@ -39,6 +39,7 @@ HostStatus check_key_in_hostkeys(struct + const struct hostkey_entry **); + int lookup_key_in_hostkeys_by_type(struct hostkeys *, int, + const struct hostkey_entry **); ++int lookup_marker_in_hostkeys(struct hostkeys *, int); + + int hostfile_read_key(char **, u_int *, struct sshkey *); + int add_host_to_hostfile(const char *, const char *, +diff -up openssh-8.0p1/sshconnect2.c.cve-2020-14145 openssh-8.0p1/sshconnect2.c +--- openssh-8.0p1/sshconnect2.c.cve-2020-14145 2021-05-17 16:53:38.610576561 +0200 ++++ openssh-8.0p1/sshconnect2.c 2021-05-17 16:54:58.169230103 +0200 +@@ -98,12 +98,25 @@ verify_host_key_callback(struct sshkey * + return 0; + } + ++/* Returns the first item from a comma-separated algorithm list */ ++static char * ++first_alg(const char *algs) ++{ ++ char *ret, *cp; ++ ++ ret = xstrdup(algs); ++ if ((cp = strchr(ret, ',')) != NULL) ++ *cp = '\0'; ++ return ret; ++} ++ + static char * + order_hostkeyalgs(char *host, struct sockaddr *hostaddr, u_short port) + { +- char *oavail, *avail, *first, *last, *alg, *hostname, *ret; ++ char *oavail = NULL, *avail = NULL, *first = NULL, *last = NULL; ++ char *alg = NULL, *hostname = NULL, *ret = NULL, *best = NULL; + size_t maxlen; +- struct hostkeys *hostkeys; ++ struct hostkeys *hostkeys = NULL; + int ktype; + u_int i; + +@@ -115,6 +128,26 @@ order_hostkeyalgs(char *host, struct soc + for (i = 0; i < options.num_system_hostfiles; i++) + load_hostkeys(hostkeys, hostname, options.system_hostfiles[i]); + ++ /* ++ * If a plain public key exists that matches the type of the best ++ * preference HostkeyAlgorithms, then use the whole list as is. ++ * Note that we ignore whether the best preference algorithm is a ++ * certificate type, as sshconnect.c will downgrade certs to ++ * plain keys if necessary. ++ */ ++ best = first_alg(options.hostkeyalgorithms); ++ if (lookup_key_in_hostkeys_by_type(hostkeys, ++ sshkey_type_plain(sshkey_type_from_name(best)), NULL)) { ++ debug3("%s: have matching best-preference key type %s, " ++ "using HostkeyAlgorithms verbatim", __func__, best); ++ ret = xstrdup(options.hostkeyalgorithms); ++ goto out; ++ } ++ ++ /* ++ * Otherwise, prefer the host key algorithms that match known keys ++ * while keeping the ordering of HostkeyAlgorithms as much as possible. ++ */ + oavail = avail = xstrdup(KEX_DEFAULT_PK_ALG); + maxlen = strlen(avail) + 1; + first = xmalloc(maxlen); +@@ -131,11 +164,23 @@ order_hostkeyalgs(char *host, struct soc + while ((alg = strsep(&avail, ",")) && *alg != '\0') { + if ((ktype = sshkey_type_from_name(alg)) == KEY_UNSPEC) + fatal("%s: unknown alg %s", __func__, alg); ++ /* ++ * If we have a @cert-authority marker in known_hosts then ++ * prefer all certificate algorithms. ++ */ ++ if (sshkey_type_is_cert(ktype) && ++ lookup_marker_in_hostkeys(hostkeys, MRK_CA)) { ++ ALG_APPEND(first, alg); ++ continue; ++ } ++ /* If the key appears in known_hosts then prefer it */ + if (lookup_key_in_hostkeys_by_type(hostkeys, +- sshkey_type_plain(ktype), NULL)) ++ sshkey_type_plain(ktype), NULL)) { + ALG_APPEND(first, alg); +- else +- ALG_APPEND(last, alg); ++ continue; ++ } ++ /* Otherwise, put it last */ ++ ALG_APPEND(last, alg); + } + #undef ALG_APPEND + xasprintf(&ret, "%s%s%s", first, +@@ -143,6 +188,8 @@ order_hostkeyalgs(char *host, struct soc + if (*first != '\0') + debug3("%s: prefer hostkeyalgs: %s", __func__, first); + ++ out: ++ free(best); + free(first); + free(last); + free(hostname); diff --git a/SOURCES/openssh-8.0p1-keygen-strip-doseol.patch b/SOURCES/openssh-8.0p1-keygen-strip-doseol.patch new file mode 100644 index 0000000..3117a7a --- /dev/null +++ b/SOURCES/openssh-8.0p1-keygen-strip-doseol.patch @@ -0,0 +1,12 @@ +diff -up openssh-8.0p1/ssh-keygen.c.strip-doseol openssh-8.0p1/ssh-keygen.c +--- openssh-8.0p1/ssh-keygen.c.strip-doseol 2021-03-18 17:41:34.472404994 +0100 ++++ openssh-8.0p1/ssh-keygen.c 2021-03-18 17:41:55.255538761 +0100 +@@ -901,7 +901,7 @@ do_fingerprint(struct passwd *pw) + while (getline(&line, &linesize, f) != -1) { + lnum++; + cp = line; +- cp[strcspn(cp, "\n")] = '\0'; ++ cp[strcspn(cp, "\r\n")] = '\0'; + /* Trim leading space and comments */ + cp = line + strspn(line, " \t"); + if (*cp == '#' || *cp == '\0') diff --git a/SOURCES/openssh-8.0p1-pkcs11-uri.patch b/SOURCES/openssh-8.0p1-pkcs11-uri.patch index a24dea6..80af3e0 100644 --- a/SOURCES/openssh-8.0p1-pkcs11-uri.patch +++ b/SOURCES/openssh-8.0p1-pkcs11-uri.patch @@ -1167,7 +1167,7 @@ new file mode 100644 index 00000000..e1a7b4e0 --- /dev/null +++ b/ssh-pkcs11-uri.c -@@ -0,0 +1,421 @@ +@@ -0,0 +1,425 @@ +/* + * Copyright (c) 2017 Red Hat + * @@ -1419,6 +1419,10 @@ index 00000000..e1a7b4e0 +void +pkcs11_uri_cleanup(struct pkcs11_uri *pkcs11) +{ ++ if (pkcs11 == NULL) { ++ return; ++ } ++ + free(pkcs11->id); + free(pkcs11->module_path); + free(pkcs11->token); @@ -2677,6 +2681,9 @@ index 70f06bff..59332945 100644 + } + + provider_uri = pkcs11_uri_get(uri); ++ if (pin == NULL && uri->pin != NULL) { ++ pin = uri->pin; ++ } + nkeys = 0; + for (i = 0; i < p->module->nslots; i++) { + token = &p->module->slotinfo[i].token; @@ -2712,9 +2719,6 @@ index 70f06bff..59332945 100644 + provider_uri, (unsigned long)i, token->label, token->manufacturerID, token->model, token->serialNumber, token->flags); -+ if (pin == NULL && uri->pin != NULL) { -+ pin = uri->pin; -+ } /* - * open session, login with pin and retrieve public - * keys (if keyp is provided) @@ -2741,8 +2745,8 @@ index 70f06bff..59332945 100644 + uri->object = label; + } } -+ pin = NULL; /* Will be cleaned up with URI */ } ++ pin = NULL; /* Will be cleaned up with URI */ /* now owned by caller */ *providerp = p; diff --git a/SOURCES/openssh-8.0p1-preserve-pam-errors.patch b/SOURCES/openssh-8.0p1-preserve-pam-errors.patch new file mode 100644 index 0000000..dbdbe93 --- /dev/null +++ b/SOURCES/openssh-8.0p1-preserve-pam-errors.patch @@ -0,0 +1,44 @@ +diff -up openssh-8.0p1/auth-pam.c.preserve-pam-errors openssh-8.0p1/auth-pam.c +--- openssh-8.0p1/auth-pam.c.preserve-pam-errors 2021-03-31 17:03:15.618592347 +0200 ++++ openssh-8.0p1/auth-pam.c 2021-03-31 17:06:58.115220014 +0200 +@@ -511,7 +511,11 @@ sshpam_thread(void *ctxtp) + goto auth_fail; + + if (!do_pam_account()) { +- sshpam_err = PAM_ACCT_EXPIRED; ++ /* Preserve PAM_PERM_DENIED and PAM_USER_UNKNOWN. ++ * Backward compatibility for other errors. */ ++ if (sshpam_err != PAM_PERM_DENIED ++ && sshpam_err != PAM_USER_UNKNOWN) ++ sshpam_err = PAM_ACCT_EXPIRED; + goto auth_fail; + } + if (sshpam_authctxt->force_pwchange) { +@@ -568,8 +572,10 @@ sshpam_thread(void *ctxtp) + pam_strerror(sshpam_handle, sshpam_err))) != 0) + fatal("%s: buffer error: %s", __func__, ssh_err(r)); + /* XXX - can't do much about an error here */ +- if (sshpam_err == PAM_ACCT_EXPIRED) +- ssh_msg_send(ctxt->pam_csock, PAM_ACCT_EXPIRED, buffer); ++ if (sshpam_err == PAM_PERM_DENIED ++ || sshpam_err == PAM_USER_UNKNOWN ++ || sshpam_err == PAM_ACCT_EXPIRED) ++ ssh_msg_send(ctxt->pam_csock, sshpam_err, buffer); + else if (sshpam_maxtries_reached) + ssh_msg_send(ctxt->pam_csock, PAM_MAXTRIES, buffer); + else +@@ -856,10 +862,12 @@ sshpam_query(void *ctx, char **name, cha + plen++; + free(msg); + break; ++ case PAM_USER_UNKNOWN: ++ case PAM_PERM_DENIED: + case PAM_ACCT_EXPIRED: ++ sshpam_account_status = 0; ++ /* FALLTHROUGH */ + case PAM_MAXTRIES: +- if (type == PAM_ACCT_EXPIRED) +- sshpam_account_status = 0; + if (type == PAM_MAXTRIES) + sshpam_set_maxtries_reached(1); + /* FALLTHROUGH */ diff --git a/SOURCES/openssh-8.0p1-restore-nonblock.patch b/SOURCES/openssh-8.0p1-restore-nonblock.patch new file mode 100644 index 0000000..b16e17e --- /dev/null +++ b/SOURCES/openssh-8.0p1-restore-nonblock.patch @@ -0,0 +1,311 @@ +diff -up openssh-8.0p1/channels.c.restore-nonblock openssh-8.0p1/channels.c +--- openssh-8.0p1/channels.c.restore-nonblock 2021-06-21 10:44:26.380559612 +0200 ++++ openssh-8.0p1/channels.c 2021-06-21 10:48:47.754579151 +0200 +@@ -333,7 +333,27 @@ channel_register_fds(struct ssh *ssh, Ch + #endif + + /* enable nonblocking mode */ +- if (nonblock) { ++ c->restore_block = 0; ++ if (nonblock == CHANNEL_NONBLOCK_STDIO) { ++ /* ++ * Special handling for stdio file descriptors: do not set ++ * non-blocking mode if they are TTYs. Otherwise prepare to ++ * restore their blocking state on exit to avoid interfering ++ * with other programs that follow. ++ */ ++ if (rfd != -1 && !isatty(rfd) && fcntl(rfd, F_GETFL) == 0) { ++ c->restore_block |= CHANNEL_RESTORE_RFD; ++ set_nonblock(rfd); ++ } ++ if (wfd != -1 && !isatty(wfd) && fcntl(wfd, F_GETFL) == 0) { ++ c->restore_block |= CHANNEL_RESTORE_WFD; ++ set_nonblock(wfd); ++ } ++ if (efd != -1 && !isatty(efd) && fcntl(efd, F_GETFL) == 0) { ++ c->restore_block |= CHANNEL_RESTORE_EFD; ++ set_nonblock(efd); ++ } ++ } else if (nonblock) { + if (rfd != -1) + set_nonblock(rfd); + if (wfd != -1) +@@ -422,17 +442,23 @@ channel_find_maxfd(struct ssh_channels * + } + + int +-channel_close_fd(struct ssh *ssh, int *fdp) ++channel_close_fd(struct ssh *ssh, Channel *c, int *fdp) + { + struct ssh_channels *sc = ssh->chanctxt; +- int ret = 0, fd = *fdp; ++ int ret, fd = *fdp; + +- if (fd != -1) { +- ret = close(fd); +- *fdp = -1; +- if (fd == sc->channel_max_fd) +- channel_find_maxfd(sc); +- } ++ if (fd == -1) ++ return 0; ++ ++ if ((*fdp == c->rfd && (c->restore_block & CHANNEL_RESTORE_RFD) != 0) || ++ (*fdp == c->wfd && (c->restore_block & CHANNEL_RESTORE_WFD) != 0) || ++ (*fdp == c->efd && (c->restore_block & CHANNEL_RESTORE_EFD) != 0)) ++ (void)fcntl(*fdp, F_SETFL, 0); /* restore blocking */ ++ ++ ret = close(fd); ++ *fdp = -1; ++ if (fd == sc->channel_max_fd) ++ channel_find_maxfd(sc); + return ret; + } + +@@ -442,13 +468,13 @@ channel_close_fds(struct ssh *ssh, Chann + { + int sock = c->sock, rfd = c->rfd, wfd = c->wfd, efd = c->efd; + +- channel_close_fd(ssh, &c->sock); ++ channel_close_fd(ssh, c, &c->sock); + if (rfd != sock) +- channel_close_fd(ssh, &c->rfd); ++ channel_close_fd(ssh, c, &c->rfd); + if (wfd != sock && wfd != rfd) +- channel_close_fd(ssh, &c->wfd); ++ channel_close_fd(ssh, c, &c->wfd); + if (efd != sock && efd != rfd && efd != wfd) +- channel_close_fd(ssh, &c->efd); ++ channel_close_fd(ssh, c, &c->efd); + } + + static void +@@ -681,7 +707,7 @@ channel_stop_listening(struct ssh *ssh) + case SSH_CHANNEL_X11_LISTENER: + case SSH_CHANNEL_UNIX_LISTENER: + case SSH_CHANNEL_RUNIX_LISTENER: +- channel_close_fd(ssh, &c->sock); ++ channel_close_fd(ssh, c, &c->sock); + channel_free(ssh, c); + break; + } +@@ -1487,7 +1513,8 @@ channel_decode_socks5(Channel *c, struct + + Channel * + channel_connect_stdio_fwd(struct ssh *ssh, +- const char *host_to_connect, u_short port_to_connect, int in, int out) ++ const char *host_to_connect, u_short port_to_connect, ++ int in, int out, int nonblock) + { + Channel *c; + +@@ -1495,7 +1522,7 @@ channel_connect_stdio_fwd(struct ssh *ss + + c = channel_new(ssh, "stdio-forward", SSH_CHANNEL_OPENING, in, out, + -1, CHAN_TCP_WINDOW_DEFAULT, CHAN_TCP_PACKET_DEFAULT, +- 0, "stdio-forward", /*nonblock*/0); ++ 0, "stdio-forward", nonblock); + + c->path = xstrdup(host_to_connect); + c->host_port = port_to_connect; +@@ -1650,7 +1677,7 @@ channel_post_x11_listener(struct ssh *ss + if (c->single_connection) { + oerrno = errno; + debug2("single_connection: closing X11 listener."); +- channel_close_fd(ssh, &c->sock); ++ channel_close_fd(ssh, c, &c->sock); + chan_mark_dead(ssh, c); + errno = oerrno; + } +@@ -2087,7 +2114,7 @@ channel_handle_efd_write(struct ssh *ssh + return 1; + if (len <= 0) { + debug2("channel %d: closing write-efd %d", c->self, c->efd); +- channel_close_fd(ssh, &c->efd); ++ channel_close_fd(ssh, c, &c->efd); + } else { + if ((r = sshbuf_consume(c->extended, len)) != 0) { + fatal("%s: channel %d: consume: %s", +@@ -2119,7 +2146,7 @@ channel_handle_efd_read(struct ssh *ssh, + if (len <= 0) { + debug2("channel %d: closing read-efd %d", + c->self, c->efd); +- channel_close_fd(ssh, &c->efd); ++ channel_close_fd(ssh, c, &c->efd); + } else { + if (c->extended_usage == CHAN_EXTENDED_IGNORE) { + debug3("channel %d: discard efd", +diff -up openssh-8.0p1/channels.h.restore-nonblock openssh-8.0p1/channels.h +--- openssh-8.0p1/channels.h.restore-nonblock 2021-06-21 10:44:26.380559612 +0200 ++++ openssh-8.0p1/channels.h 2021-06-21 10:44:26.387559665 +0200 +@@ -63,6 +63,16 @@ + + #define CHANNEL_CANCEL_PORT_STATIC -1 + ++/* nonblocking flags for channel_new */ ++#define CHANNEL_NONBLOCK_LEAVE 0 /* don't modify non-blocking state */ ++#define CHANNEL_NONBLOCK_SET 1 /* set non-blocking state */ ++#define CHANNEL_NONBLOCK_STDIO 2 /* set non-blocking and restore on close */ ++ ++/* c->restore_block mask flags */ ++#define CHANNEL_RESTORE_RFD 0x01 ++#define CHANNEL_RESTORE_WFD 0x02 ++#define CHANNEL_RESTORE_EFD 0x04 ++ + /* TCP forwarding */ + #define FORWARD_DENY 0 + #define FORWARD_REMOTE (1) +@@ -131,6 +141,7 @@ struct Channel { + * to a matching pre-select handler. + * this way post-select handlers are not + * accidentally called if a FD gets reused */ ++ int restore_block; /* fd mask to restore blocking status */ + struct sshbuf *input; /* data read from socket, to be sent over + * encrypted connection */ + struct sshbuf *output; /* data received over encrypted connection for +@@ -258,7 +269,7 @@ void channel_register_filter(struct ssh + void channel_register_status_confirm(struct ssh *, int, + channel_confirm_cb *, channel_confirm_abandon_cb *, void *); + void channel_cancel_cleanup(struct ssh *, int); +-int channel_close_fd(struct ssh *, int *); ++int channel_close_fd(struct ssh *, Channel *, int *); + void channel_send_window_changes(struct ssh *); + + /* mux proxy support */ +@@ -305,7 +316,7 @@ Channel *channel_connect_to_port(struct + char *, char *, int *, const char **); + Channel *channel_connect_to_path(struct ssh *, const char *, char *, char *); + Channel *channel_connect_stdio_fwd(struct ssh *, const char*, +- u_short, int, int); ++ u_short, int, int, int); + Channel *channel_connect_by_listen_address(struct ssh *, const char *, + u_short, char *, char *); + Channel *channel_connect_by_listen_path(struct ssh *, const char *, +diff -up openssh-8.0p1/clientloop.c.restore-nonblock openssh-8.0p1/clientloop.c +--- openssh-8.0p1/clientloop.c.restore-nonblock 2021-06-21 10:44:26.290558923 +0200 ++++ openssh-8.0p1/clientloop.c 2021-06-21 10:44:26.387559665 +0200 +@@ -1436,14 +1436,6 @@ client_loop(struct ssh *ssh, int have_pt + if (have_pty) + leave_raw_mode(options.request_tty == REQUEST_TTY_FORCE); + +- /* restore blocking io */ +- if (!isatty(fileno(stdin))) +- unset_nonblock(fileno(stdin)); +- if (!isatty(fileno(stdout))) +- unset_nonblock(fileno(stdout)); +- if (!isatty(fileno(stderr))) +- unset_nonblock(fileno(stderr)); +- + /* + * If there was no shell or command requested, there will be no remote + * exit status to be returned. In that case, clear error code if the +diff -up openssh-8.0p1/mux.c.restore-nonblock openssh-8.0p1/mux.c +--- openssh-8.0p1/mux.c.restore-nonblock 2019-04-18 00:52:57.000000000 +0200 ++++ openssh-8.0p1/mux.c 2021-06-21 10:50:51.007537336 +0200 +@@ -454,14 +454,6 @@ mux_master_process_new_session(struct ss + if (cctx->want_tty && tcgetattr(new_fd[0], &cctx->tio) == -1) + error("%s: tcgetattr: %s", __func__, strerror(errno)); + +- /* enable nonblocking unless tty */ +- if (!isatty(new_fd[0])) +- set_nonblock(new_fd[0]); +- if (!isatty(new_fd[1])) +- set_nonblock(new_fd[1]); +- if (!isatty(new_fd[2])) +- set_nonblock(new_fd[2]); +- + window = CHAN_SES_WINDOW_DEFAULT; + packetmax = CHAN_SES_PACKET_DEFAULT; + if (cctx->want_tty) { +@@ -471,7 +463,7 @@ mux_master_process_new_session(struct ss + + nc = channel_new(ssh, "session", SSH_CHANNEL_OPENING, + new_fd[0], new_fd[1], new_fd[2], window, packetmax, +- CHAN_EXTENDED_WRITE, "client-session", /*nonblock*/0); ++ CHAN_EXTENDED_WRITE, "client-session", CHANNEL_NONBLOCK_STDIO); + + nc->ctl_chan = c->self; /* link session -> control channel */ + c->remote_id = nc->self; /* link control -> session channel */ +@@ -1033,13 +1025,8 @@ mux_master_process_stdio_fwd(struct ssh + } + } + +- /* enable nonblocking unless tty */ +- if (!isatty(new_fd[0])) +- set_nonblock(new_fd[0]); +- if (!isatty(new_fd[1])) +- set_nonblock(new_fd[1]); +- +- nc = channel_connect_stdio_fwd(ssh, chost, cport, new_fd[0], new_fd[1]); ++ nc = channel_connect_stdio_fwd(ssh, chost, cport, new_fd[0], new_fd[1], ++ CHANNEL_NONBLOCK_STDIO); + free(chost); + + nc->ctl_chan = c->self; /* link session -> control channel */ +diff -up openssh-8.0p1/nchan.c.restore-nonblock openssh-8.0p1/nchan.c +--- openssh-8.0p1/nchan.c.restore-nonblock 2021-06-21 10:44:26.388559673 +0200 ++++ openssh-8.0p1/nchan.c 2021-06-21 10:52:42.685405537 +0200 +@@ -387,7 +387,7 @@ chan_shutdown_write(struct ssh *ssh, Cha + strerror(errno)); + } + } else { +- if (channel_close_fd(ssh, &c->wfd) < 0) { ++ if (channel_close_fd(ssh, c, &c->wfd) < 0) { + logit("channel %d: %s: close() failed for " + "fd %d [i%d o%d]: %.100s", + c->self, __func__, c->wfd, c->istate, c->ostate, +@@ -417,7 +417,7 @@ chan_shutdown_read(struct ssh *ssh, Chan + strerror(errno)); + } + } else { +- if (channel_close_fd(ssh, &c->rfd) < 0) { ++ if (channel_close_fd(ssh, c, &c->rfd) < 0) { + logit("channel %d: %s: close() failed for " + "fd %d [i%d o%d]: %.100s", + c->self, __func__, c->rfd, c->istate, c->ostate, +@@ -437,7 +437,7 @@ chan_shutdown_extended_read(struct ssh * + debug2("channel %d: %s (i%d o%d sock %d wfd %d efd %d [%s])", + c->self, __func__, c->istate, c->ostate, c->sock, c->rfd, c->efd, + channel_format_extended_usage(c)); +- if (channel_close_fd(ssh, &c->efd) < 0) { ++ if (channel_close_fd(ssh, c, &c->efd) < 0) { + logit("channel %d: %s: close() failed for " + "extended fd %d [i%d o%d]: %.100s", + c->self, __func__, c->efd, c->istate, c->ostate, +diff -up openssh-8.0p1/ssh.c.restore-nonblock openssh-8.0p1/ssh.c +--- openssh-8.0p1/ssh.c.restore-nonblock 2021-06-21 10:44:26.389559681 +0200 ++++ openssh-8.0p1/ssh.c 2021-06-21 10:54:47.651377045 +0200 +@@ -1709,7 +1709,8 @@ ssh_init_stdio_forwarding(struct ssh *ss + (out = dup(STDOUT_FILENO)) < 0) + fatal("channel_connect_stdio_fwd: dup() in/out failed"); + if ((c = channel_connect_stdio_fwd(ssh, options.stdio_forward_host, +- options.stdio_forward_port, in, out)) == NULL) ++ options.stdio_forward_port, in, out, ++ CHANNEL_NONBLOCK_STDIO)) == NULL) + fatal("%s: channel_connect_stdio_fwd failed", __func__); + channel_register_cleanup(ssh, c->self, client_cleanup_stdio_fwd, 0); + channel_register_open_confirm(ssh, c->self, ssh_stdio_confirm, NULL); +@@ -1862,14 +1863,6 @@ ssh_session2_open(struct ssh *ssh) + if (in < 0 || out < 0 || err < 0) + fatal("dup() in/out/err failed"); + +- /* enable nonblocking unless tty */ +- if (!isatty(in)) +- set_nonblock(in); +- if (!isatty(out)) +- set_nonblock(out); +- if (!isatty(err)) +- set_nonblock(err); +- + window = CHAN_SES_WINDOW_DEFAULT; + packetmax = CHAN_SES_PACKET_DEFAULT; + if (tty_flag) { +@@ -1879,7 +1872,7 @@ ssh_session2_open(struct ssh *ssh) + c = channel_new(ssh, + "session", SSH_CHANNEL_OPENING, in, out, err, + window, packetmax, CHAN_EXTENDED_WRITE, +- "client-session", /*nonblock*/0); ++ "client-session", CHANNEL_NONBLOCK_STDIO); + + debug3("%s: channel_new: %d", __func__, c->self); + diff --git a/SOURCES/openssh-8.0p1-sftp-timespeccmp.patch b/SOURCES/openssh-8.0p1-sftp-timespeccmp.patch new file mode 100644 index 0000000..7254b4a --- /dev/null +++ b/SOURCES/openssh-8.0p1-sftp-timespeccmp.patch @@ -0,0 +1,16 @@ +diff -up openssh-8.0p1/sftp.c.original openssh-8.0p1/sftp.c +--- openssh-8.0p1/sftp.c.original 2020-12-22 17:05:02.105698989 +0900 ++++ openssh-8.0p1/sftp.c 2020-12-22 17:05:42.922035780 +0900 +@@ -937,7 +937,11 @@ sglob_comp(const void *aa, const void *b + return (rmul * strcmp(ap, bp)); + else if (sort_flag & LS_TIME_SORT) { + #if defined(HAVE_STRUCT_STAT_ST_MTIM) +- return (rmul * timespeccmp(&as->st_mtim, &bs->st_mtim, <)); ++ if (timespeccmp(&as->st_mtim, &bs->st_mtim, <)){ ++ return rmul; ++ } else { ++ return -rmul; ++ } + #elif defined(HAVE_STRUCT_STAT_ST_MTIME) + return (rmul * NCMP(as->st_mtime, bs->st_mtime)); + #else diff --git a/SOURCES/openssh-8.0p1-sshd_config.patch b/SOURCES/openssh-8.0p1-sshd_config.patch new file mode 100644 index 0000000..e4b7912 --- /dev/null +++ b/SOURCES/openssh-8.0p1-sshd_config.patch @@ -0,0 +1,97 @@ +diff --git a/servconf.c b/servconf.c +index ffac5d2c..340045b2 100644 +--- a/servconf.c ++++ b/servconf.c +@@ -1042,7 +1042,7 @@ match_cfg_line(char **condition, int line, struct connection_info *ci) + return -1; + } + if (strcasecmp(attrib, "user") == 0) { +- if (ci == NULL) { ++ if (ci == NULL || (ci->test && ci->user == NULL)) { + result = 0; + continue; + } +@@ -1054,7 +1054,7 @@ match_cfg_line(char **condition, int line, struct connection_info *ci) + debug("user %.100s matched 'User %.100s' at " + "line %d", ci->user, arg, line); + } else if (strcasecmp(attrib, "group") == 0) { +- if (ci == NULL) { ++ if (ci == NULL || (ci->test && ci->user == NULL)) { + result = 0; + continue; + } +@@ -1067,7 +1067,7 @@ match_cfg_line(char **condition, int line, struct connection_info *ci) + result = 0; + } + } else if (strcasecmp(attrib, "host") == 0) { +- if (ci == NULL) { ++ if (ci == NULL || (ci->test && ci->host == NULL)) { + result = 0; + continue; + } +@@ -1079,7 +1079,7 @@ match_cfg_line(char **condition, int line, struct connection_info *ci) + debug("connection from %.100s matched 'Host " + "%.100s' at line %d", ci->host, arg, line); + } else if (strcasecmp(attrib, "address") == 0) { +- if (ci == NULL) { ++ if (ci == NULL || (ci->test && ci->address == NULL)) { + result = 0; + continue; + } +@@ -1098,7 +1098,7 @@ match_cfg_line(char **condition, int line, struct connection_info *ci) + return -1; + } + } else if (strcasecmp(attrib, "localaddress") == 0){ +- if (ci == NULL) { ++ if (ci == NULL || (ci->test && ci->laddress == NULL)) { + result = 0; + continue; + } +@@ -1124,7 +1124,7 @@ match_cfg_line(char **condition, int line, struct connection_info *ci) + arg); + return -1; + } +- if (ci == NULL) { ++ if (ci == NULL || (ci->test && ci->lport == -1)) { + result = 0; + continue; + } +@@ -1138,10 +1138,12 @@ match_cfg_line(char **condition, int line, struct connection_info *ci) + else + result = 0; + } else if (strcasecmp(attrib, "rdomain") == 0) { +- if (ci == NULL || ci->rdomain == NULL) { ++ if (ci == NULL || (ci->test && ci->rdomain == NULL)) { + result = 0; + continue; + } ++ if (ci->rdomain == NULL) ++ match_test_missing_fatal("RDomain", "rdomain"); + if (match_pattern_list(ci->rdomain, arg, 0) != 1) + result = 0; + else +diff --git a/servconf.h b/servconf.h +index 54e0a8d8..5483da05 100644 +--- a/servconf.h ++++ b/servconf.h +@@ -221,6 +221,8 @@ struct connection_info { + const char *laddress; /* local address */ + int lport; /* local port */ + const char *rdomain; /* routing domain if available */ ++ int test; /* test mode, allow some attributes to be ++ * unspecified */ + }; + + +diff --git a/sshd.c b/sshd.c +index cbd3bce9..1fcde502 100644 +--- a/sshd.c ++++ b/sshd.c +@@ -1843,6 +1843,7 @@ main(int ac, char **av) + */ + if (connection_info == NULL) + connection_info = get_connection_info(ssh, 0, 0); ++ connection_info->test = 1; + parse_server_match_config(&options, connection_info); + dump_config(&options); + } diff --git a/SPECS/openssh.spec b/SPECS/openssh.spec index 6c281fc..ab3b01e 100644 --- a/SPECS/openssh.spec +++ b/SPECS/openssh.spec @@ -66,14 +66,14 @@ # Do not forget to bump pam_ssh_agent_auth release if you rewind the main package release to 1 %global openssh_ver 8.0p1 -%global openssh_rel 6 +%global openssh_rel 10 %global pam_ssh_agent_ver 0.10.3 %global pam_ssh_agent_rel 7 Summary: An open source implementation of SSH protocol version 2 Name: openssh Version: %{openssh_ver} -Release: %{openssh_rel}%{?dist}%{?rescue_rel}.2 +Release: %{openssh_rel}%{?dist}%{?rescue_rel} URL: http://www.openssh.com/portable.html #URL1: http://pamsshagentauth.sourceforge.net Source0: ftp://ftp.openbsd.org/pub/OpenBSD/OpenSSH/portable/openssh-%{version}.tar.gz @@ -232,6 +232,19 @@ Patch970: openssh-8.0p1-rdomain.patch Patch971: openssh-8.0p1-x11-without-ipv6.patch # Client window fix (#1913041) Patch972: openssh-8.0p1-channel-limits.patch +# SFTP sort upon the modification time (#1909988) +# https://bugzilla.mindrot.org/show_bug.cgi?id=3248 +Patch973: openssh-8.0p1-sftp-timespeccmp.patch +# ssh-keygen printing fingerprint issue with Windows keys (#1901518) +Patch974: openssh-8.0p1-keygen-strip-doseol.patch +# sshd provides PAM an incorrect error code (#1879503) +Patch975: openssh-8.0p1-preserve-pam-errors.patch +# ssh incorrectly restores the blocking mode on standard output (#1942901) +Patch976: openssh-8.0p1-restore-nonblock.patch +# CVE 2020-14145 +Patch977: openssh-8.0p1-cve-2020-14145.patch +# sshd -T requires -C when "Match" is used in sshd_config (#1836277) +Patch978: openssh-8.0p1-sshd_config.patch License: BSD Group: Applications/Internet @@ -324,7 +337,7 @@ Requires: openssh = %{version}-%{release} Summary: PAM module for authentication with ssh-agent Group: System Environment/Base Version: %{pam_ssh_agent_ver} -Release: %{pam_ssh_agent_rel}.%{openssh_rel}%{?dist}%{?rescue_rel}.1 +Release: %{pam_ssh_agent_rel}.%{openssh_rel}%{?dist}%{?rescue_rel} License: BSD %description @@ -451,6 +464,12 @@ popd %patch970 -p1 -b .rdomain %patch971 -p1 -b .x11-ipv6 %patch972 -p1 -b .channel-limits +%patch973 -p1 -b .sftp-timespeccmp +%patch974 -p1 -b .keygen-strip-doseol +%patch975 -p1 -b .preserve-pam-errors +%patch976 -p1 -b .restore-nonblock +%patch977 -p1 -b .cve-2020-14145 +%patch978 -p1 -b .sshd_config %patch200 -p1 -b .audit %patch201 -p1 -b .audit-race @@ -742,14 +761,27 @@ getent passwd sshd >/dev/null || \ %endif %changelog -* Wed Apr 14 2021 Dmitry Belyavskiy - 8.0p1-6.2 + 0.10.3-7.1 -- rebuilt +* Mon Jun 21 2021 Dmitry Belyavskiy - 8.0p1-10 +- sshd -T requires -C when "Match" is used in sshd_config (#1836277) -* Wed Apr 14 2021 Dmitry Belyavskiy - 8.0p1-6.1 + 0.10.3-7 -- rebuilt +* Wed Jun 02 2021 Dmitry Belyavskiy - 8.0p1-9 +- CVE-2020-14145 openssh: Observable Discrepancy leading to an information + leak in the algorithm negotiation (#1882252) +- Hostbased ssh authentication fails if session ID contains a '/' (#1944125) -* Tue Mar 16 2021 Dmitry Belyavskiy - 8.0p1-6 + 0.10.3-7 -- Openssh client window fix (#1942364) +* Mon Apr 26 2021 Dmitry Belyavskiy - 8.0p1-8 +- ssh doesn't restore the blocking mode on standard output (#1942901) + +* Fri Apr 09 2021 Dmitry Belyavskiy - 8.0p1-7 + 0.10.3-7 +- SFTP sort upon the modification time (#1909988) +- ssh-keygen printing fingerprint issue with Windows keys (#1901518) +- PIN is lost when iterating over tokens when adding pkcs11 keys to ssh-agent (#1843372) +- ssh-agent segfaults during ssh-add -s pkcs11 (#1868996) +- ssh-copy-id could not resolve ipv6 address ends with colon (#1933517) +- sshd provides PAM an incorrect error code (#1879503) + +* Tue Mar 16 2021 Dmitry Belyavskiy - 8.0p1-6 + 0.10.3-7 +- Openssh client window fix (#1913041) * Tue Mar 24 2020 Jakub Jelen - 8.0p1-5 + 0.10.3-7 - Do not print "no slots" warning by default (#1744220)