Hi,

Here is an attempt to pledge ssh(1) - the client.

There are two parts:
  - pledging a mux client, which is used when ControlMaster is in
    used, and your client reuse an existing connection.

    it ends with "stdio proc tty" (proc is to permit sending SIGWINCH to
    mux master on window resize).

  - pledging the client loop of a "classical" ssh.

For client loop, the pledging arrive after lot of initialisation
(ProxyCommand was already executed, TunOpen has opened
/dev/{tun,tap}*...) so only few things should remains. It is mostly
cleanup path and events that are managed in client_loop().

The followed principe is instaurated severals levels of pledging, each
level includes permissions of previous one.

>From bottom to top:
  - network: "stdio unix inet dns tty"
    minimal promises to operate.

  - filesystem create: same as previous + "cpath"
    used for ControlMaster: the cpath is needed in cleanup path, in
    order to unlink the ControlPath socket.

  - proc: same as previous + "proc"
    used for ProxyCommand: if the command was already executed, the
    cleanup path still needs to kill(2) it on exit.

  - filesystem full: same as previous + "rpath wpath"
    used for UpdateHostkeys: it needs to rewrite known_hosts file.

  - exec: same as previous + "exec"
    used for PermitLocalCommand (executing commands locally with EscapeKey)
    and for ForwardX11 (launching xauth(1) binary to manage
    MIT-MAGIC-COOKIE-1).

Your ssh process (only the client) should be pledged in all cases (you
can report if it is not).

If you encounter pledge related problem please reports:
  - your dmesg

  - the output of the running command with -v (verbose mode: the used
    pledge policy with be printed), including the command-line used.

  - the features/options used (on command-line, ~/.ssh/config,
    /etc/ssh/ssh_config [if modified])

  - a backtrace (with debugging symbols) of the generated core file:

$ cd /usr/src/usr.bin/ssh && make obj && make depend && make DEBUG=-g
$ cd /usr/src/usr.bin/ssh/ssh/obj && ./ssh -v ...
$ cd /usr/src/usr.bin/ssh/ssh/obj && gdb ./ssh ssh.core
(gdb) bt
...

  - any other useful informations :)

Thanks for testing.

Comments ?
-- 
Sebastien Marie


Index: clientloop.c
===================================================================
RCS file: /cvs/src/usr.bin/ssh/clientloop.c,v
retrieving revision 1.276
diff -u -p -r1.276 clientloop.c
--- clientloop.c        20 Oct 2015 03:36:35 -0000      1.276
+++ clientloop.c        1 Dec 2015 05:28:50 -0000
@@ -1473,6 +1473,36 @@ client_loop(int have_pty, int escape_cha
 
        debug("Entering interactive session.");
 
+       if (options.forward_x11 || options.permit_local_command) {
+               debug("pledge: exec");
+               if (pledge("stdio rpath wpath cpath unix inet dns proc exec 
tty",
+                   NULL) == -1)
+                       fatal("%s pledge(): %s", __func__, strerror(errno));
+
+       } else if (options.update_hostkeys) {
+               debug("pledge: filesystem full");
+               if (pledge("stdio rpath wpath cpath unix inet dns proc tty",
+                   NULL) == -1)
+                       fatal("%s pledge(): %s", __func__, strerror(errno));
+
+       } else if (! option_clear_or_none(options.proxy_command)) {
+               debug("pledge: proc");
+               if (pledge("stdio cpath unix inet dns proc tty", NULL) == -1)
+                       fatal("%s pledge(): %s", __func__, strerror(errno));
+
+       } else if (options.control_master &&
+           ! option_clear_or_none(options.control_path)) {
+               debug("pledge: filesystem create");
+               if (pledge("stdio cpath unix inet dns tty",
+                   NULL) == -1)
+                       fatal("%s pledge(): %s", __func__, strerror(errno));
+
+       } else {
+               debug("pledge: network");
+               if (pledge("stdio unix inet dns tty", NULL) == -1)
+                       fatal("%s pledge(): %s", __func__, strerror(errno));
+       }
+
        start_time = get_current_time();
 
        /* Initialize variables. */
Index: mux.c
===================================================================
RCS file: /cvs/src/usr.bin/ssh/mux.c,v
retrieving revision 1.55
diff -u -p -r1.55 mux.c
--- mux.c       15 Oct 2015 23:51:40 -0000      1.55
+++ mux.c       1 Dec 2015 05:28:50 -0000
@@ -1832,6 +1832,9 @@ mux_client_request_session(int fd)
            mm_send_fd(fd, STDERR_FILENO) == -1)
                fatal("%s: send fds failed", __func__);
 
+       if (pledge("stdio proc tty", NULL) == -1)
+               fatal("%s pledge(): %s", __func__, strerror(errno));
+
        debug3("%s: session request sent", __func__);
 
        /* Read their reply */
@@ -1977,6 +1980,9 @@ mux_client_request_stdio_fwd(int fd)
            mm_send_fd(fd, STDOUT_FILENO) == -1)
                fatal("%s: send fds failed", __func__);
 
+       if (pledge("stdio proc tty", NULL) == -1)
+               fatal("%s pledge(): %s", __func__, strerror(errno));
+
        debug3("%s: stdio forward request sent", __func__);
 
        /* Read their reply */
@@ -2138,6 +2144,9 @@ muxclient(const char *path)
                return;
        }
        set_nonblock(sock);
+
+       if (pledge("stdio sendfd proc tty", NULL) == -1)
+               fatal("%s pledge(): %s", __func__, strerror(errno));
 
        if (mux_client_hello_exchange(sock) != 0) {
                error("%s: master hello exchange failed", __func__);

Reply via email to