diff --git a/openssh-8.1p1-audit.patch b/openssh-8.1p1-audit.patch index e56c5dd..9210fea 100644 --- a/openssh-8.1p1-audit.patch +++ b/openssh-8.1p1-audit.patch @@ -1550,7 +1550,7 @@ Index: openssh-8.9p1/monitor_wrap.c sshbuf_free(m); } #endif /* SSH_AUDIT_EVENTS */ -@@ -1074,3 +1114,83 @@ mm_ssh_gssapi_update_creds(ssh_gssapi_cc +@@ -1074,3 +1114,130 @@ mm_ssh_gssapi_update_creds(ssh_gssapi_cc } #endif /* GSSAPI */ @@ -1633,6 +1633,53 @@ Index: openssh-8.9p1/monitor_wrap.c + mm_request_send(pmonitor->m_recvfd, MONITOR_REQ_AUDIT_SERVER_KEY_FREE, m); + sshbuf_free(m); +} ++ ++int mm_forward_audit_messages(int fdin) ++{ ++ u_char buf[4]; ++ u_int blen, msg_len; ++ struct sshbuf *m; ++ int ret = 0; ++ ++ debug3("%s: entering", __func__); ++ m = sshbuf_new(); ++ do { ++ int r; ++ ++ blen = atomicio(read, fdin, buf, sizeof(buf)); ++ if (blen == 0) /* closed pipe */ ++ break; ++ if (blen != sizeof(buf)) { ++ error("%s: Failed to read the buffer from child", __func__); ++ ret = -1; ++ break; ++ } ++ ++ msg_len = get_u32(buf); ++ if (msg_len > 256 * 1024) ++ fatal("%s: read: bad msg_len %d", __func__, msg_len); ++ sshbuf_reset(m); ++ if ((r = sshbuf_reserve(m, msg_len, NULL)) != 0) ++ fatal("%s: buffer error: %s", __func__, ssh_err(r)); ++ if (atomicio(read, fdin, sshbuf_mutable_ptr(m), msg_len) != msg_len) { ++ error("%s: Failed to read the the buffer conent from the child", __func__); ++ ret = -1; ++ break; ++ } ++ if (atomicio(vwrite, pmonitor->m_recvfd, buf, blen) != blen || ++ atomicio(vwrite, pmonitor->m_recvfd, sshbuf_mutable_ptr(m), msg_len) != msg_len) { ++ error("%s: Failed to write the messag to the monitor", __func__); ++ ret = -1; ++ break; ++ } ++ } while (1); ++ sshbuf_free(m); ++ return ret; ++} ++void mm_set_monitor_pipe(int fd) ++{ ++ pmonitor->m_recvfd = fd; ++} +#endif /* SSH_AUDIT_EVENTS */ Index: openssh-8.9p1/monitor_wrap.h =================================================================== @@ -1649,7 +1696,7 @@ Index: openssh-8.9p1/monitor_wrap.h const u_char *, size_t, const char *, u_int, struct sshkey_sig_details **); #ifdef GSSAPI -@@ -83,7 +85,12 @@ void mm_sshpam_free_ctx(void *); +@@ -83,7 +85,14 @@ void mm_sshpam_free_ctx(void *); #ifdef SSH_AUDIT_EVENTS #include "audit.h" void mm_audit_event(struct ssh *, ssh_audit_event_t); @@ -1660,6 +1707,8 @@ Index: openssh-8.9p1/monitor_wrap.h +void mm_audit_kex_body(struct ssh *, int, char *, char *, char *, char *, pid_t, uid_t); +void mm_audit_session_key_free_body(struct ssh *, int, pid_t, uid_t); +void mm_audit_destroy_sensitive_data(struct ssh *, const char *, pid_t, uid_t); ++int mm_forward_audit_messages(int); ++void mm_set_monitor_pipe(int); #endif struct Session; @@ -1689,7 +1738,12 @@ Index: openssh-8.9p1/packet.c /* * Returns the IP-address of the remote host as a string. The returned * string must not be freed. -@@ -583,22 +591,19 @@ ssh_packet_close_internal(struct ssh *ss +@@ -579,26 +587,23 @@ ssh_packet_rdomain_in(struct ssh *ssh) + /* Closes the connection and clears and frees internal data structures. */ + + static void +-ssh_packet_close_internal(struct ssh *ssh, int do_close) ++ssh_packet_close_internal(struct ssh *ssh, int do_close, int do_audit) { struct session_state *state = ssh->state; u_int mode; @@ -1721,7 +1775,7 @@ Index: openssh-8.9p1/packet.c #endif /* WITH_ZLIB */ cipher_free(state->send_context); cipher_free(state->receive_context); -+ if (had_keys && state->server_side) { ++ if (do_audit && had_keys && state->server_side) { + /* Assuming this is called only from privsep child */ + audit_session_key_free(ssh, MODE_MAX); + } @@ -1736,7 +1790,29 @@ Index: openssh-8.9p1/packet.c free(ssh->local_ipaddr); ssh->local_ipaddr = NULL; free(ssh->remote_ipaddr); -@@ -892,6 +907,7 @@ ssh_set_newkeys(struct ssh *ssh, int mod +@@ -650,13 +665,19 @@ ssh_packet_close_internal(struct ssh *ss + void + ssh_packet_close(struct ssh *ssh) + { +- ssh_packet_close_internal(ssh, 1); ++ ssh_packet_close_internal(ssh, 1, 1); + } + + void + ssh_packet_clear_keys(struct ssh *ssh) + { +- ssh_packet_close_internal(ssh, 0); ++ ssh_packet_close_internal(ssh, 0, 1); ++} ++ ++void ++ssh_packet_clear_keys_noaudit(struct ssh *ssh) ++{ ++ ssh_packet_close_internal(ssh, 0, 0); + } + + /* Sets remote side protocol flags. */ +@@ -892,6 +913,7 @@ ssh_set_newkeys(struct ssh *ssh, int mod (unsigned long long)state->p_send.bytes, (unsigned long long)state->p_send.blocks); kex_free_newkeys(state->newkeys[mode]); @@ -1744,7 +1820,7 @@ Index: openssh-8.9p1/packet.c state->newkeys[mode] = NULL; } /* note that both bytes and the seqnr are not reset */ -@@ -2183,6 +2199,73 @@ ssh_packet_get_output(struct ssh *ssh) +@@ -2183,6 +2205,73 @@ ssh_packet_get_output(struct ssh *ssh) return (void *)ssh->state->output; } @@ -1822,7 +1898,15 @@ Index: openssh-8.9p1/packet.h =================================================================== --- openssh-8.9p1.orig/packet.h +++ openssh-8.9p1/packet.h -@@ -220,4 +220,5 @@ const u_char *sshpkt_ptr(struct ssh *, s +@@ -102,6 +102,7 @@ int ssh_packet_get_connection_out(s + void ssh_packet_close(struct ssh *); + void ssh_packet_set_input_hook(struct ssh *, ssh_packet_hook_fn *, void *); + void ssh_packet_clear_keys(struct ssh *); ++void ssh_packet_clear_keys_noaudit(struct ssh *); + void ssh_clear_newkeys(struct ssh *, int); + + int ssh_packet_is_rekeying(struct ssh *); +@@ -220,4 +221,5 @@ const u_char *sshpkt_ptr(struct ssh *, s # undef EC_POINT #endif @@ -1841,7 +1925,18 @@ Index: openssh-8.9p1/session.c extern struct sshbuf *loginmsg; extern struct sshauthopt *auth_opts; extern char *tun_fwd_ifnames; /* serverloop.c */ -@@ -642,6 +642,14 @@ do_exec_pty(struct ssh *ssh, Session *s, +@@ -157,6 +157,10 @@ static Session *sessions = NULL; + login_cap_t *lc; + #endif + ++#ifdef SSH_AUDIT_EVENTS ++int paudit[2]; ++#endif ++ + static int is_child = 0; + static int in_chroot = 0; + +@@ -642,6 +646,14 @@ do_exec_pty(struct ssh *ssh, Session *s, /* Parent. Close the slave side of the pseudo tty. */ close(ttyfd); @@ -1856,7 +1951,7 @@ Index: openssh-8.9p1/session.c /* Enter interactive session. */ s->ptymaster = ptymaster; ssh_packet_set_interactive(ssh, 1, -@@ -706,15 +714,19 @@ do_exec(struct ssh *ssh, Session *s, con +@@ -706,15 +718,21 @@ do_exec(struct ssh *ssh, Session *s, con s->self); #ifdef SSH_AUDIT_EVENTS @@ -1875,23 +1970,66 @@ Index: openssh-8.9p1/session.c } + if (s->command != NULL && s->ptyfd == -1) + s->command_handle = PRIVSEP(audit_run_command(ssh, s->command)); ++ if (pipe(paudit) < 0) ++ fatal("pipe: %s", strerror(errno)); #endif if (s->ttyfd != -1) ret = do_exec_pty(ssh, s, command); -@@ -1533,8 +1545,11 @@ do_child(struct ssh *ssh, Session *s, co +@@ -730,6 +748,20 @@ do_exec(struct ssh *ssh, Session *s, con + */ + sshbuf_reset(loginmsg); + ++#ifdef SSH_AUDIT_EVENTS ++ close(paudit[1]); ++ if (use_privsep && ret == 0) { ++ /* ++ * Read the audit messages from forked child and send them ++ * back to monitor. We don't want to communicate directly, ++ * because the messages might get mixed up. ++ * Continue after the pipe gets closed (all messages sent). ++ */ ++ ret = mm_forward_audit_messages(paudit[0]); ++ } ++ close(paudit[0]); ++#endif /* SSH_AUDIT_EVENTS */ ++ + return ret; + } + +@@ -1530,11 +1562,30 @@ do_child(struct ssh *ssh, Session *s, co + int env_size; + int r = 0; + ++#ifdef SSH_AUDIT_EVENTS ++ int pparent = paudit[1]; ++ close(paudit[0]); ++ /* Hack the monitor pipe to avoid race condition with parent */ ++ if (use_privsep) ++ mm_set_monitor_pipe(pparent); ++#endif ++ sshpkt_fmt_connection_id(ssh, remote_id, sizeof(remote_id)); /* remove hostkey from the child's memory */ - destroy_sensitive_data(); -+ destroy_sensitive_data(ssh, 1); - ssh_packet_clear_keys(ssh); -+ /* Don't audit this - both us and the parent would be talking to the -+ monitor over a single socket, with no synchronization. */ +- ssh_packet_clear_keys(ssh); ++ destroy_sensitive_data(ssh, use_privsep); ++ ssh_packet_clear_keys_noaudit(ssh); ++ /* ++ * We can audit this, because we hacked the pipe to direct the ++ * messages over postauth child. But this message requires an answer ++ * which we can't do using a one-way pipe. ++ */ + packet_destroy_all(ssh, 0, 1); ++ ++#ifdef SSH_AUDIT_EVENTS ++ /* Notify parent that we are done */ ++ close(pparent); ++#endif /* Force a password change */ if (s->authctxt->force_pwchange) { -@@ -1743,6 +1758,9 @@ session_unused(int id) +@@ -1743,6 +1794,9 @@ session_unused(int id) sessions[id].ttyfd = -1; sessions[id].ptymaster = -1; sessions[id].x11_chanids = NULL; @@ -1901,7 +2039,7 @@ Index: openssh-8.9p1/session.c sessions[id].next_unused = sessions_first_unused; sessions_first_unused = id; } -@@ -1822,6 +1840,19 @@ session_open(Authctxt *authctxt, int cha +@@ -1822,6 +1876,19 @@ session_open(Authctxt *authctxt, int cha } Session * @@ -1921,7 +2059,7 @@ Index: openssh-8.9p1/session.c session_by_tty(char *tty) { int i; -@@ -2429,6 +2460,32 @@ session_exit_message(struct ssh *ssh, Se +@@ -2429,6 +2496,32 @@ session_exit_message(struct ssh *ssh, Se chan_write_failed(ssh, c); } @@ -1954,7 +2092,7 @@ Index: openssh-8.9p1/session.c void session_close(struct ssh *ssh, Session *s) { -@@ -2470,6 +2527,10 @@ session_close(struct ssh *ssh, Session * +@@ -2470,6 +2563,10 @@ session_close(struct ssh *ssh, Session * if (s->ttyfd != -1) session_pty_cleanup(s); @@ -1965,7 +2103,7 @@ Index: openssh-8.9p1/session.c free(s->term); free(s->display); free(s->x11_chanids); -@@ -2544,14 +2605,14 @@ session_close_by_channel(struct ssh *ssh +@@ -2544,14 +2641,14 @@ session_close_by_channel(struct ssh *ssh } void @@ -1982,7 +2120,7 @@ Index: openssh-8.9p1/session.c else session_close(ssh, s); } -@@ -2677,6 +2738,15 @@ do_authenticated2(struct ssh *ssh, Authc +@@ -2677,6 +2774,15 @@ do_authenticated2(struct ssh *ssh, Authc server_loop2(ssh, authctxt); } @@ -1998,7 +2136,7 @@ Index: openssh-8.9p1/session.c void do_cleanup(struct ssh *ssh, Authctxt *authctxt) { -@@ -2740,7 +2810,7 @@ do_cleanup(struct ssh *ssh, Authctxt *au +@@ -2740,7 +2846,7 @@ do_cleanup(struct ssh *ssh, Authctxt *au * or if running in monitor. */ if (!use_privsep || mm_is_monitor()) diff --git a/openssh-do-not-send-empty-message.patch b/openssh-do-not-send-empty-message.patch new file mode 100644 index 0000000..3e956fe --- /dev/null +++ b/openssh-do-not-send-empty-message.patch @@ -0,0 +1,19 @@ +--- openssh-8.4p1.orig/auth-pam.c 2020-09-27 09:25:01.000000000 +0200 ++++ openssh-8.4p1/auth-pam.c 2022-03-04 13:02:23.447712697 +0100 +@@ -638,10 +638,12 @@ + switch (PAM_MSG_MEMBER(msg, i, msg_style)) { + case PAM_ERROR_MSG: + case PAM_TEXT_INFO: +- if ((r = sshbuf_putf(loginmsg, "%s\n", +- PAM_MSG_MEMBER(msg, i, msg))) != 0) +- fatal("%s: buffer error: %s", +- __func__, ssh_err(r)); ++ if (strlen(PAM_MSG_MEMBER(msg, i, msg)) != 0) { ++ if ((r = sshbuf_putf(loginmsg, "%s\n", ++ PAM_MSG_MEMBER(msg, i, msg))) != 0) ++ fatal("%s: buffer error: %s", ++ __func__, ssh_err(r)); ++ } + reply[i].resp_retcode = PAM_SUCCESS; + break; + default: diff --git a/openssh.changes b/openssh.changes index dc23d08..d99ed25 100644 --- a/openssh.changes +++ b/openssh.changes @@ -1,3 +1,11 @@ +------------------------------------------------------------------- +Thu Nov 10 02:18:08 UTC 2022 - Hans Petter Jansson + +- Update openssh-8.1p1-audit.patch: Merge fix for race condition + (bsc#1115550, bsc#1174162). +- Add openssh-do-not-send-empty-message.patch, which prevents + superfluous newlines with empty MOTD files (bsc#1192439). + ------------------------------------------------------------------- Mon Aug 8 07:36:55 UTC 2022 - Thorsten Kukuk diff --git a/openssh.spec b/openssh.spec index 783c280..cc8fa47 100644 --- a/openssh.spec +++ b/openssh.spec @@ -109,6 +109,7 @@ Patch45: openssh-8.4p1-ssh_config_d.patch Patch46: openssh-whitelist-syscalls.patch Patch47: openssh-8.4p1-vendordir.patch Patch48: openssh-8.4p1-pam_motd.patch +Patch49: openssh-do-not-send-empty-message.patch BuildRequires: audit-devel BuildRequires: automake BuildRequires: groff