mirror of
https://github.com/hackerschoice/segfault.git
synced 2024-06-30 18:51:22 +00:00
200 lines
5.8 KiB
Diff
200 lines
5.8 KiB
Diff
diff -x !*.[ch] -u openssh-9.1p1-orig/channels.c openssh-9.1p1-sf/channels.c
|
|
--- openssh-9.1p1-orig/channels.c 2022-10-03 15:51:42
|
|
+++ openssh-9.1p1-sf/channels.c 2023-01-29 21:13:05
|
|
@@ -3510,7 +3510,7 @@
|
|
ssh->chanctxt->IPv4or6 = af;
|
|
}
|
|
|
|
-
|
|
+extern int sf_by_signal;
|
|
/*
|
|
* Determine whether or not a port forward listens to loopback, the
|
|
* specified address or wildcard. On the client, a specified bind
|
|
@@ -3548,6 +3548,7 @@
|
|
* address and it was overridden.
|
|
*/
|
|
if (*listen_addr != '\0' &&
|
|
+ sf_by_signal == 0 &&
|
|
strcmp(listen_addr, "0.0.0.0") != 0 &&
|
|
strcmp(listen_addr, "*") != 0) {
|
|
ssh_packet_send_debug(ssh,
|
|
diff -x !*.[ch] -u openssh-9.1p1-orig/serverloop.c openssh-9.1p1-sf/serverloop.c
|
|
--- openssh-9.1p1-orig/serverloop.c 2022-10-03 15:51:42
|
|
+++ openssh-9.1p1-sf/serverloop.c 2023-01-29 21:39:06
|
|
@@ -102,6 +102,12 @@
|
|
/* requested tunnel forwarding interface(s), shared with session.c */
|
|
char *tun_fwd_ifnames = NULL;
|
|
|
|
+extern int sf_done;
|
|
+extern size_t sf_ports_n;
|
|
+extern int sf_ports[64];
|
|
+extern int sf_sigusr1_received;
|
|
+void sf_sshd2ns(void);
|
|
+
|
|
/* returns 1 if bind to specified port by specified user is permitted */
|
|
static int
|
|
bind_permitted(int port, uid_t uid)
|
|
@@ -380,6 +386,8 @@
|
|
if (sigprocmask(SIG_BLOCK, &bsigset, &osigset) == -1)
|
|
error_f("bsigset sigprocmask: %s", strerror(errno));
|
|
collect_children(ssh);
|
|
+ if (sf_sigusr1_received != 0)
|
|
+ sf_sshd2ns();
|
|
wait_until_can_do_something(ssh, connection_in, connection_out,
|
|
&pfd, &npfd_alloc, &npfd_active, rekey_timeout_ms, &osigset,
|
|
&conn_in_ready, &conn_out_ready);
|
|
@@ -637,12 +645,14 @@
|
|
|
|
if (strcmp(ctype, "session") == 0) {
|
|
c = server_request_session(ssh);
|
|
- } else if (strcmp(ctype, "direct-tcpip") == 0) {
|
|
- c = server_request_direct_tcpip(ssh, &reason, &errmsg);
|
|
- } else if (strcmp(ctype, "direct-streamlocal@openssh.com") == 0) {
|
|
- c = server_request_direct_streamlocal(ssh);
|
|
- } else if (strcmp(ctype, "tun@openssh.com") == 0) {
|
|
- c = server_request_tun(ssh);
|
|
+ } else if (sf_done != 0) {
|
|
+ if (strcmp(ctype, "direct-tcpip") == 0) {
|
|
+ c = server_request_direct_tcpip(ssh, &reason, &errmsg);
|
|
+ } else if (strcmp(ctype, "direct-streamlocal@openssh.com") == 0) {
|
|
+ c = server_request_direct_streamlocal(ssh);
|
|
+ } else if (strcmp(ctype, "tun@openssh.com") == 0) {
|
|
+ c = server_request_tun(ssh);
|
|
+ }
|
|
}
|
|
if (c != NULL) {
|
|
debug_f("confirm %s", ctype);
|
|
@@ -802,8 +812,20 @@
|
|
ssh_packet_send_debug(ssh, "Server has disabled port forwarding.");
|
|
} else {
|
|
/* Start listening on the port */
|
|
- success = channel_setup_remote_fwd_listener(ssh, &fwd,
|
|
- &allocated_listen_port, &options.fwd_opts);
|
|
+ if (sf_done == 0)
|
|
+ {
|
|
+ // HERE: sshd has not yet been moved to guest's network namespace.
|
|
+ // Fake the -R request and complete in cb_sigusr1().
|
|
+ allocated_listen_port = fwd.listen_port;
|
|
+ if (sf_ports_n < sizeof sf_ports / sizeof *sf_ports)
|
|
+ {
|
|
+ success = 1;
|
|
+ sf_ports[sf_ports_n++] = fwd.listen_port;
|
|
+ }
|
|
+ } else {
|
|
+ success = channel_setup_remote_fwd_listener(ssh, &fwd,
|
|
+ &allocated_listen_port, &options.fwd_opts);
|
|
+ }
|
|
}
|
|
if ((resp = sshbuf_new()) == NULL)
|
|
fatal_f("sshbuf_new");
|
|
diff -x !*.[ch] -u openssh-9.1p1-orig/sshd.c openssh-9.1p1-sf/sshd.c
|
|
--- openssh-9.1p1-orig/sshd.c 2022-10-03 15:51:42
|
|
+++ openssh-9.1p1-sf/sshd.c 2023-01-29 21:13:05
|
|
@@ -536,8 +536,71 @@
|
|
return 0;
|
|
}
|
|
}
|
|
+#include <linux/types.h>
|
|
+#include <sys/capability.h>
|
|
+#include <sys/prctl.h>
|
|
+#ifndef SECBIT_KEEP_CAPS
|
|
+#define SECBIT_KEEP_CAPS (1<<4)
|
|
+#endif
|
|
|
|
+int sf_done;
|
|
+int sf_by_signal;
|
|
+int sf_sigusr1_received;
|
|
+int sf_ports[64];
|
|
+size_t sf_ports_n;
|
|
+static char sf_nsnet_name[128];
|
|
+static struct ssh *sf_ssh;
|
|
static void
|
|
+cb_sigusr1(int sig)
|
|
+{
|
|
+ debug("SIGUSR1 RECEIVED");
|
|
+ sf_sigusr1_received = 1;
|
|
+ signal(SIGUSR1, SIG_IGN);
|
|
+}
|
|
+
|
|
+void
|
|
+sf_sshd2ns(void)
|
|
+{
|
|
+ int fd;
|
|
+ if ((fd = open(sf_nsnet_name, O_RDONLY | O_CLOEXEC)) < 0)
|
|
+ {
|
|
+ debug("open(%s)=%d: %s", sf_nsnet_name, fd, strerror(errno));
|
|
+ exit(252);
|
|
+ }
|
|
+
|
|
+ sf_sigusr1_received = 0;
|
|
+
|
|
+ // No longer needed
|
|
+ unlink(sf_nsnet_name);
|
|
+
|
|
+ debug("THC moving sshd. setns(%s)", sf_nsnet_name);
|
|
+ if (setns(fd, CLONE_NEWNET) != 0)
|
|
+ {
|
|
+ debug("THC setns(%s) (fd=%d): %s", sf_nsnet_name, fd, strerror(errno));
|
|
+ exit(255);
|
|
+ }
|
|
+
|
|
+ // Continue -R forwards
|
|
+ if (sf_ssh == NULL)
|
|
+ return;
|
|
+ sf_by_signal = 1;
|
|
+ struct Forward fwd;
|
|
+ memset(&fwd, 0, sizeof fwd);
|
|
+ fwd.listen_host = "localhost";
|
|
+ size_t i;
|
|
+ for (i = 0; i < sf_ports_n; i++)
|
|
+ {
|
|
+ fwd.listen_port = sf_ports[i];
|
|
+ debug("THC remote forward #%zu for %d", i, fwd.listen_port);
|
|
+ channel_setup_remote_fwd_listener(sf_ssh, &fwd, NULL /* allocated_listen_port */, &options.fwd_opts);
|
|
+ }
|
|
+ sf_ports_n = 0;
|
|
+ sf_by_signal = 0;
|
|
+
|
|
+ sf_done = 1;
|
|
+}
|
|
+
|
|
+static void
|
|
privsep_postauth(struct ssh *ssh, Authctxt *authctxt)
|
|
{
|
|
#ifdef DISABLE_FD_PASSING
|
|
@@ -576,8 +639,34 @@
|
|
|
|
reseed_prngs();
|
|
|
|
+ // Keep CAPS after setuid() so that non priv can call setns() with CAP_SYS_ADMIN
|
|
+ prctl(PR_SET_SECUREBITS, SECBIT_KEEP_CAPS);
|
|
+
|
|
/* Drop privileges */
|
|
do_setusercontext(authctxt->pw);
|
|
+
|
|
+ // Set the effective CAPS to remove SECUREBITS
|
|
+ cap_t caps = cap_get_proc();
|
|
+ const cap_value_t cl[] = {CAP_SETPCAP};
|
|
+ cap_set_flag(caps, CAP_EFFECTIVE, 1, cl, CAP_SET);
|
|
+ cap_set_proc(caps);
|
|
+
|
|
+ // Delete SECBIT_KEEP_CAPS
|
|
+ if (prctl(PR_SET_SECUREBITS, 0) != 0)
|
|
+ exit(254);
|
|
+
|
|
+ // Only keep CAP_SYS_ADMIN for setns()
|
|
+ const cap_value_t cap_list[1] = {CAP_SYS_ADMIN};
|
|
+ cap_clear(caps);
|
|
+ cap_set_flag(caps, CAP_EFFECTIVE, 1, cap_list, CAP_SET);
|
|
+ cap_set_flag(caps, CAP_PERMITTED, 1, cap_list, CAP_SET);
|
|
+ cap_set_proc(caps);
|
|
+ cap_free(caps);
|
|
+
|
|
+ // segfaultsh will signal with USR1 when guest's PID is known (for setns()).
|
|
+ snprintf(sf_nsnet_name, sizeof sf_nsnet_name, "/dev/shm/ns-net-%d", getpid());
|
|
+ sf_ssh = ssh;
|
|
+ signal(SIGUSR1, cb_sigusr1);
|
|
|
|
skip:
|
|
/* It is safe now to apply the key state */
|