Accepting request 1165549 from home:alarrosa:branches:network2
- Add patch from SLE which was missing in Factory: * Mon Jun 7 20:54:09 UTC 2021 - Hans Petter Jansson <hpj@suse.com> - Add openssh-mitigate-lingering-secrets.patch (bsc#1186673), which attempts to mitigate instances of secrets lingering in memory after a session exits. (bsc#1213004 bsc#1213008) - Rebase patch: * openssh-6.6p1-privsep-selinux.patch OBS-URL: https://build.opensuse.org/request/show/1165549 OBS-URL: https://build.opensuse.org/package/show/network/openssh?expand=0&rev=259
This commit is contained in:
parent
2399b4e4c2
commit
b0b10ece31
@ -114,7 +114,7 @@ Index: openssh-9.3p2/sshd.c
|
||||
if (privsep_chroot) {
|
||||
/* Change our root directory */
|
||||
@@ -602,6 +606,9 @@ privsep_postauth(struct ssh *ssh, Authct
|
||||
{
|
||||
|
||||
#ifdef DISABLE_FD_PASSING
|
||||
if (1) {
|
||||
+#elif defined(WITH_SELINUX)
|
||||
|
344
openssh-mitigate-lingering-secrets.patch
Normal file
344
openssh-mitigate-lingering-secrets.patch
Normal file
@ -0,0 +1,344 @@
|
||||
Index: openssh-9.3p2/kex.c
|
||||
===================================================================
|
||||
--- openssh-9.3p2.orig/kex.c
|
||||
+++ openssh-9.3p2/kex.c
|
||||
@@ -1564,16 +1564,16 @@ enc_destroy(struct sshenc *enc)
|
||||
return;
|
||||
|
||||
if (enc->key) {
|
||||
- memset(enc->key, 0, enc->key_len);
|
||||
+ explicit_bzero(enc->key, enc->key_len);
|
||||
free(enc->key);
|
||||
}
|
||||
|
||||
if (enc->iv) {
|
||||
- memset(enc->iv, 0, enc->iv_len);
|
||||
+ explicit_bzero(enc->iv, enc->iv_len);
|
||||
free(enc->iv);
|
||||
}
|
||||
|
||||
- memset(enc, 0, sizeof(*enc));
|
||||
+ explicit_bzero(enc, sizeof(*enc));
|
||||
}
|
||||
|
||||
void
|
||||
@@ -1584,7 +1584,7 @@ newkeys_destroy(struct newkeys *newkeys)
|
||||
|
||||
enc_destroy(&newkeys->enc);
|
||||
mac_destroy(&newkeys->mac);
|
||||
- memset(&newkeys->comp, 0, sizeof(newkeys->comp));
|
||||
+ explicit_bzero(&newkeys->comp, sizeof(newkeys->comp));
|
||||
}
|
||||
|
||||
/*
|
||||
Index: openssh-9.3p2/mac.c
|
||||
===================================================================
|
||||
--- openssh-9.3p2.orig/mac.c
|
||||
+++ openssh-9.3p2/mac.c
|
||||
@@ -284,11 +284,11 @@ mac_destroy(struct sshmac *mac)
|
||||
return;
|
||||
|
||||
if (mac->key) {
|
||||
- memset(mac->key, 0, mac->key_len);
|
||||
+ explicit_bzero(mac->key, mac->key_len);
|
||||
free(mac->key);
|
||||
}
|
||||
|
||||
- memset(mac, 0, sizeof(*mac));
|
||||
+ explicit_bzero(mac, sizeof(*mac));
|
||||
}
|
||||
|
||||
/* XXX copied from ciphers_valid */
|
||||
Index: openssh-9.3p2/monitor.c
|
||||
===================================================================
|
||||
--- openssh-9.3p2.orig/monitor.c
|
||||
+++ openssh-9.3p2/monitor.c
|
||||
@@ -1789,8 +1789,12 @@ mm_answer_audit_end_command(struct ssh *
|
||||
void
|
||||
monitor_clear_keystate(struct ssh *ssh, struct monitor *pmonitor)
|
||||
{
|
||||
- ssh_clear_newkeys(ssh, MODE_IN);
|
||||
- ssh_clear_newkeys(ssh, MODE_OUT);
|
||||
+ u_int mode;
|
||||
+
|
||||
+ for (mode = 0; mode < MODE_MAX; mode++) {
|
||||
+ ssh_clear_curkeys(ssh, mode); /* current keys */
|
||||
+ ssh_clear_newkeys(ssh, mode); /* next keys */
|
||||
+ }
|
||||
sshbuf_free(child_state);
|
||||
child_state = NULL;
|
||||
}
|
||||
Index: openssh-9.3p2/packet.c
|
||||
===================================================================
|
||||
--- openssh-9.3p2.orig/packet.c
|
||||
+++ openssh-9.3p2/packet.c
|
||||
@@ -655,6 +655,7 @@ ssh_packet_close_internal(struct ssh *ss
|
||||
ssh->local_ipaddr = NULL;
|
||||
free(ssh->remote_ipaddr);
|
||||
ssh->remote_ipaddr = NULL;
|
||||
+ explicit_bzero(ssh->state, sizeof(*ssh->state));
|
||||
free(ssh->state);
|
||||
ssh->state = NULL;
|
||||
kex_free(ssh->kex);
|
||||
@@ -783,8 +784,10 @@ compress_buffer(struct ssh *ssh, struct
|
||||
case Z_OK:
|
||||
/* Append compressed data to output_buffer. */
|
||||
if ((r = sshbuf_put(out, buf, sizeof(buf) -
|
||||
- ssh->state->compression_out_stream.avail_out)) != 0)
|
||||
+ ssh->state->compression_out_stream.avail_out)) != 0) {
|
||||
+ explicit_bzero(buf, sizeof(buf));
|
||||
return r;
|
||||
+ }
|
||||
break;
|
||||
case Z_STREAM_ERROR:
|
||||
default:
|
||||
@@ -819,8 +822,10 @@ uncompress_buffer(struct ssh *ssh, struc
|
||||
switch (status) {
|
||||
case Z_OK:
|
||||
if ((r = sshbuf_put(out, buf, sizeof(buf) -
|
||||
- ssh->state->compression_in_stream.avail_out)) != 0)
|
||||
+ ssh->state->compression_in_stream.avail_out)) != 0) {
|
||||
+ explicit_bzero(buf, sizeof(buf));
|
||||
return r;
|
||||
+ }
|
||||
break;
|
||||
case Z_BUF_ERROR:
|
||||
/*
|
||||
@@ -870,6 +875,17 @@ uncompress_buffer(struct ssh *ssh, struc
|
||||
#endif /* WITH_ZLIB */
|
||||
|
||||
void
|
||||
+ssh_clear_curkeys(struct ssh *ssh, int mode)
|
||||
+{
|
||||
+ struct session_state *state = ssh->state;
|
||||
+
|
||||
+ if (state && state->newkeys[mode]) {
|
||||
+ kex_free_newkeys(state->newkeys[mode]);
|
||||
+ state->newkeys[mode] = NULL;
|
||||
+ }
|
||||
+}
|
||||
+
|
||||
+void
|
||||
ssh_clear_newkeys(struct ssh *ssh, int mode)
|
||||
{
|
||||
if (ssh->kex && ssh->kex->newkeys[mode]) {
|
||||
@@ -1418,7 +1434,9 @@ ssh_packet_read_seqnr(struct ssh *ssh, u
|
||||
}
|
||||
|
||||
/* Append it to the buffer. */
|
||||
- if ((r = ssh_packet_process_incoming(ssh, buf, len)) != 0)
|
||||
+ r = ssh_packet_process_incoming(ssh, buf, len);
|
||||
+ explicit_bzero(buf, len);
|
||||
+ if (r != 0)
|
||||
goto out;
|
||||
}
|
||||
out:
|
||||
@@ -2375,9 +2393,12 @@ ssh_packet_get_state(struct ssh *ssh, st
|
||||
(r = sshbuf_put_u32(m, state->p_read.packets)) != 0 ||
|
||||
(r = sshbuf_put_u64(m, state->p_read.bytes)) != 0 ||
|
||||
(r = sshbuf_put_stringb(m, state->input)) != 0 ||
|
||||
- (r = sshbuf_put_stringb(m, state->output)) != 0)
|
||||
+ (r = sshbuf_put_stringb(m, state->output)) != 0) {
|
||||
+ sshbuf_obfuscate(m);
|
||||
return r;
|
||||
+ }
|
||||
|
||||
+ sshbuf_obfuscate(m);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -2496,6 +2517,8 @@ ssh_packet_set_state(struct ssh *ssh, st
|
||||
size_t ilen, olen;
|
||||
int r;
|
||||
|
||||
+ sshbuf_unobfuscate(m);
|
||||
+
|
||||
if ((r = kex_from_blob(m, &ssh->kex)) != 0 ||
|
||||
(r = newkeys_from_blob(m, ssh, MODE_OUT)) != 0 ||
|
||||
(r = newkeys_from_blob(m, ssh, MODE_IN)) != 0 ||
|
||||
@@ -2509,7 +2532,7 @@ ssh_packet_set_state(struct ssh *ssh, st
|
||||
(r = sshbuf_get_u64(m, &state->p_read.blocks)) != 0 ||
|
||||
(r = sshbuf_get_u32(m, &state->p_read.packets)) != 0 ||
|
||||
(r = sshbuf_get_u64(m, &state->p_read.bytes)) != 0)
|
||||
- return r;
|
||||
+ goto out;
|
||||
/*
|
||||
* We set the time here so that in post-auth privsep child we
|
||||
* count from the completion of the authentication.
|
||||
@@ -2518,10 +2541,10 @@ ssh_packet_set_state(struct ssh *ssh, st
|
||||
/* XXX ssh_set_newkeys overrides p_read.packets? XXX */
|
||||
if ((r = ssh_set_newkeys(ssh, MODE_IN)) != 0 ||
|
||||
(r = ssh_set_newkeys(ssh, MODE_OUT)) != 0)
|
||||
- return r;
|
||||
+ goto out;
|
||||
|
||||
if ((r = ssh_packet_set_postauth(ssh)) != 0)
|
||||
- return r;
|
||||
+ goto out;
|
||||
|
||||
sshbuf_reset(state->input);
|
||||
sshbuf_reset(state->output);
|
||||
@@ -2529,12 +2552,19 @@ ssh_packet_set_state(struct ssh *ssh, st
|
||||
(r = sshbuf_get_string_direct(m, &output, &olen)) != 0 ||
|
||||
(r = sshbuf_put(state->input, input, ilen)) != 0 ||
|
||||
(r = sshbuf_put(state->output, output, olen)) != 0)
|
||||
- return r;
|
||||
+ goto out;
|
||||
|
||||
- if (sshbuf_len(m))
|
||||
- return SSH_ERR_INVALID_FORMAT;
|
||||
+ if (sshbuf_len(m)) {
|
||||
+ r = SSH_ERR_INVALID_FORMAT;
|
||||
+ goto out;
|
||||
+ }
|
||||
+
|
||||
+ r = 0;
|
||||
+out:
|
||||
+ if (r != 0)
|
||||
+ sshbuf_obfuscate(m);
|
||||
debug3_f("done");
|
||||
- return 0;
|
||||
+ return r;
|
||||
}
|
||||
|
||||
/* NEW API */
|
||||
Index: openssh-9.3p2/packet.h
|
||||
===================================================================
|
||||
--- openssh-9.3p2.orig/packet.h
|
||||
+++ openssh-9.3p2/packet.h
|
||||
@@ -103,6 +103,7 @@ 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_curkeys(struct ssh *, int);
|
||||
void ssh_clear_newkeys(struct ssh *, int);
|
||||
|
||||
int ssh_packet_is_rekeying(struct ssh *);
|
||||
Index: openssh-9.3p2/sshbuf.c
|
||||
===================================================================
|
||||
--- openssh-9.3p2.orig/sshbuf.c
|
||||
+++ openssh-9.3p2/sshbuf.c
|
||||
@@ -309,6 +309,31 @@ sshbuf_mutable_ptr(const struct sshbuf *
|
||||
return buf->d + buf->off;
|
||||
}
|
||||
|
||||
+/* Trivially obfuscate the buffer. This is used to make sensitive data
|
||||
+ * (e.g. keystate) slightly less obvious if found lingering in kernel
|
||||
+ * memory after being sent from the privsep child to its parent.
|
||||
+ *
|
||||
+ * Longer term we should consider using a one-time pad or a stream cipher
|
||||
+ * here. */
|
||||
+void
|
||||
+sshbuf_obfuscate(struct sshbuf *buf)
|
||||
+{
|
||||
+ size_t i;
|
||||
+
|
||||
+ if (sshbuf_check_sanity(buf) != 0 || buf->readonly || buf->refcount > 1)
|
||||
+ return;
|
||||
+
|
||||
+ for (i = buf->off; i < buf->size; i++) {
|
||||
+ buf->d [i] ^= 0xaa;
|
||||
+ }
|
||||
+}
|
||||
+
|
||||
+void
|
||||
+sshbuf_unobfuscate(struct sshbuf *buf)
|
||||
+{
|
||||
+ sshbuf_obfuscate(buf);
|
||||
+}
|
||||
+
|
||||
int
|
||||
sshbuf_check_reserve(const struct sshbuf *buf, size_t len)
|
||||
{
|
||||
Index: openssh-9.3p2/sshbuf.h
|
||||
===================================================================
|
||||
--- openssh-9.3p2.orig/sshbuf.h
|
||||
+++ openssh-9.3p2/sshbuf.h
|
||||
@@ -298,6 +298,9 @@ int sshbuf_write_file(const char *path,
|
||||
int sshbuf_read(int, struct sshbuf *, size_t, size_t *)
|
||||
__attribute__((__nonnull__ (2)));
|
||||
|
||||
+void sshbuf_obfuscate(struct sshbuf *buf);
|
||||
+void sshbuf_unobfuscate(struct sshbuf *buf);
|
||||
+
|
||||
/* Macros for decoding/encoding integers */
|
||||
#define PEEK_U64(p) \
|
||||
(((u_int64_t)(((const u_char *)(p))[0]) << 56) | \
|
||||
Index: openssh-9.3p2/sshd.c
|
||||
===================================================================
|
||||
--- openssh-9.3p2.orig/sshd.c
|
||||
+++ openssh-9.3p2/sshd.c
|
||||
@@ -272,6 +272,19 @@ static void do_ssh2_kex(struct ssh *);
|
||||
static char *listener_proctitle;
|
||||
|
||||
/*
|
||||
+ * Clear some stack space. This is a bit naive, but hopefully helps mitigate
|
||||
+ * information leaks due to registers and other data having been stored on
|
||||
+ * the stack. Called after fork() and before exit().
|
||||
+ */
|
||||
+static void
|
||||
+clobber_stack(void)
|
||||
+{
|
||||
+ char data [32768];
|
||||
+
|
||||
+ explicit_bzero(data, 32768);
|
||||
+}
|
||||
+
|
||||
+/*
|
||||
* Close all listening sockets
|
||||
*/
|
||||
static void
|
||||
@@ -430,6 +443,8 @@ destroy_sensitive_data(struct ssh *ssh,
|
||||
sensitive_data.host_certificates[i] = NULL;
|
||||
}
|
||||
}
|
||||
+
|
||||
+ clobber_stack();
|
||||
}
|
||||
|
||||
/* Demote private to public keys for network child */
|
||||
@@ -600,6 +615,8 @@ privsep_preauth(struct ssh *ssh)
|
||||
static void
|
||||
privsep_postauth(struct ssh *ssh, Authctxt *authctxt)
|
||||
{
|
||||
+ clobber_stack();
|
||||
+
|
||||
#ifdef DISABLE_FD_PASSING
|
||||
if (1) {
|
||||
#else
|
||||
@@ -2360,6 +2377,7 @@ main(int ac, char **av)
|
||||
if (use_privsep) {
|
||||
mm_send_keystate(ssh, pmonitor);
|
||||
ssh_packet_clear_keys(ssh);
|
||||
+ clobber_stack();
|
||||
exit(0);
|
||||
}
|
||||
|
||||
@@ -2436,6 +2454,7 @@ main(int ac, char **av)
|
||||
if (use_privsep)
|
||||
mm_terminate();
|
||||
|
||||
+ clobber_stack();
|
||||
exit(0);
|
||||
}
|
||||
|
||||
@@ -2596,8 +2615,10 @@ cleanup_exit(int i)
|
||||
/* cleanup_exit can be called at the very least from the privsep
|
||||
wrappers used for auditing. Make sure we don't recurse
|
||||
indefinitely. */
|
||||
- if (in_cleanup)
|
||||
+ if (in_cleanup) {
|
||||
+ clobber_stack();
|
||||
_exit(i);
|
||||
+ }
|
||||
in_cleanup = 1;
|
||||
if (the_active_state != NULL && the_authctxt != NULL) {
|
||||
do_cleanup(the_active_state, the_authctxt);
|
||||
@@ -2623,5 +2644,7 @@ cleanup_exit(int i)
|
||||
(!use_privsep || mm_is_monitor()))
|
||||
audit_event(the_active_state, SSH_CONNECTION_ABANDON);
|
||||
#endif
|
||||
+
|
||||
+ clobber_stack();
|
||||
_exit(i);
|
||||
}
|
@ -1,3 +1,14 @@
|
||||
-------------------------------------------------------------------
|
||||
Thu Apr 4 12:23:13 UTC 2024 - Antonio Larrosa <alarrosa@suse.com>
|
||||
|
||||
- Add patch from SLE which was missing in Factory:
|
||||
* Mon Jun 7 20:54:09 UTC 2021 - Hans Petter Jansson <hpj@suse.com>
|
||||
- Add openssh-mitigate-lingering-secrets.patch (bsc#1186673), which
|
||||
attempts to mitigate instances of secrets lingering in memory
|
||||
after a session exits. (bsc#1213004 bsc#1213008)
|
||||
- Rebase patch:
|
||||
* openssh-6.6p1-privsep-selinux.patch
|
||||
|
||||
-------------------------------------------------------------------
|
||||
Tue Apr 2 13:07:43 UTC 2024 - Martin Sirringhaus <martin.sirringhaus@suse.com>
|
||||
|
||||
|
@ -116,6 +116,7 @@ Patch49: openssh-do-not-send-empty-message.patch
|
||||
Patch50: openssh-openssl-3.patch
|
||||
Patch51: wtmpdb.patch
|
||||
Patch52: logind_set_tty.patch
|
||||
Patch54: openssh-mitigate-lingering-secrets.patch
|
||||
Patch100: fix-missing-lz.patch
|
||||
Patch102: openssh-7.8p1-role-mls.patch
|
||||
Patch103: openssh-6.6p1-privsep-selinux.patch
|
||||
|
Loading…
Reference in New Issue
Block a user