[Gllug] Disconnected ssh sessions and pseudo-terminals

Robert McKay robert at mckay.com
Tue Oct 28 22:33:59 UTC 2008


On Tue, Oct 28, 2008 at 10:59 AM, Ziya Suzen <ziya at suzen.net> wrote:
> I have tried a few tricks without any luck:
>
> Exit the Editor:
>  # echo -n ^[ >> /dev/pts/1
>  # echo -n :x >> /dev/pts/1

This isn't going to be a practical answer. :-)

You've got the right idea. Unfortunately you can't write into
/dev/pts/1 - that would send your characters back towards the pty
(your defunct sshd will see them not your vi). You need to write into
the pty associated with the /dev/pts/1 device in order for vi to see
them.

This would have been easier to do back in the old days when everyone
used the old style /dev/ttypX and each had it's own corresponding
/dev/ptypX device.

Unfortunately most Linux distros now use a new tty scheme based around
a multiplexer device and the 'other end' of /dev/pts/1 is now
/dev/ptmx which is the same endpoint for all the other ttys as well.

The main advantage of this new scheme is that it makes writing tty
allocation code far easier. Before you'd have to loop over all the
ttypXX devices in /dev/ until you found a free one. Now you just do
some magic ioctls on /dev/ptmx and the kernel hands you an available
one. The downside is it makes nasty hacks like this slightly nastier.

I think I'm right in saying there is no way to re-open /dev/ptmx and
get connected to the same front side tty (at least not without
recycling that tty which would mean killing any programs attached to
that session -- this is actually an option as well though - you could
fork() the vi process and connect the fork to a new session on a new
tty and kill -9 the old one leaving you with almost the same effect
but I digress).

You can still do exactly what you propose by jacking the open
filehandle of the (hopefully) still running sshd process (if the sshd
isn't still running I think I'm right in saying your vi will be dead
anyway as it should have received a sigterm when the sshd lost it's
filehandle to the pty).

You can get access to this filehandle using gdb (or write your own
thing to call ptrace).

Basically you need to figure out which file descriptor sshd has open
to /dev/ptmx - you can get this by looking in /dev/<pidofsshd>/fd. It
should look something like this:

total 0
lrwx------ 1 root root 64 2008-10-28 21:48 0 -> /dev/null
lrwx------ 1 root root 64 2008-10-28 21:48 1 -> /dev/null
lrwx------ 1 root root 64 2008-10-28 21:48 10 -> /dev/ptmx
lrwx------ 1 root root 64 2008-10-28 21:48 2 -> /dev/null
lrwx------ 1 root root 64 2008-10-28 21:48 3 -> socket:[3530852]
lrwx------ 1 root root 64 2008-10-28 21:48 4 -> socket:[3530966]
lrwx------ 1 root root 64 2008-10-28 21:48 5 -> socket:[3530970]
lr-x------ 1 root root 64 2008-10-28 21:48 6 -> pipe:[3530971]
l-wx------ 1 root root 64 2008-10-28 21:48 7 -> pipe:[3530971]
lrwx------ 1 root root 64 2008-10-28 21:48 8 -> /dev/ptmx
lrwx------ 1 root root 64 2008-10-28 21:48 9 -> /dev/ptmx

As you can see there are three fd's connected to /dev/ptmx.

Then you attach to the sshd process with gdb and poke stuff into the
file descriptor by doing something like:

call malloc(1024)
call strcpy($1, ":q!\n")
call write(<fd>, $1, 4)

(just tried exactly this and it actually worked -- you need to attach
to the sshd proces that is owned by your user - not the root owned
one).

root      2877  0.0  0.2   7880  2404 ?        Ss   21:47   0:00 sshd:
rm [priv]
rm        2998  0.0  0.1   7880  1508 ?        S    21:47   0:00 sshd: rm at pts/9

(so attach to 2998)

(gdb) call malloc(1024)
$1 = -2147044680
(gdb) call strcpy($1, ":q!\n")
$2 = -2147044680
(gdb) call write(10, $1, 4)
$3 = 4

in this example there are three filehandles to ptmx presumably one for
each of the stdin/stdout/stderr ssh channels. It doesn't seem to
matter which one you use. I used 10.. I guess which ever one you use
needs to have been opened for writing though so maybe 8 (stdin)
wouldn't have worked.

Another option you could try is to exec() some other program like cat
and then dup2() the ptmx file descriptor to stdout or maybe get real
fancy and exec() something that would let you read and write at the
same time. You could use nc for that actually.. just exec it so that
it connects to somewhere, and then dup2() the tty fd over the network
socket.

I've previously toyed around with a few similar ideas and eventually
came up with this script:

http://wari.mckay.com/~rm/hijack.sh.txt

which allows you to migrate an already running program from one tty to
a new one. It uses the fork() method I mentioned earlier.

Cheers,

Rob.
-- 
Gllug mailing list  -  Gllug at gllug.org.uk
http://lists.gllug.org.uk/mailman/listinfo/gllug




More information about the GLLUG mailing list