How to running dd effectively type into the shell

bash

Try running:

dd if=/dev/urandom count=1000

Then once it's done, hit enter. I'm running Debian Sid, and I get:

user@host$ dd if=/dev/urandom count=1000
<lots of random characters, then I hit enter again>
bash: 62: command not found
bash: 9: command not found
bash: c62: command not found
bash: 9: command not found
bash: c62: command not found
bash: 9: command not found
bash: c: command not found
user@host$

This seems obscenely inappropriate! How can dd writing to its stdout possibly cause that text to end up in an input buffer to Bash? I'm deeply confused about how this can happen, and how it can be considered acceptable behavior from a security perspective.

Best Answer

  • It is not advisable to send random data to your terminal.

    Random data can contain escape sequences, which cause the terminal to take some action other than printing visible characters.

    Simple examples from the ECMA-48 (a.k.a. "ANSI" a.k.a. "vt100") terminal definition include ESC [ 1 m to enter bold mode, ESC [ 2 J to clear the screen, and ESC c to reset the terminal.

    Some escape sequences don't just change the state of the terminal - they request information. These vary between different terminals and emulators. An example of a terminal with lots of supported escape sequences and good documentation of them is xterm. Its ctlseqs.ms document is a good general reference, because lots of later terminal emulators are intended to be compatible with it. Here's a webified version of it: http://invisible-island.net/xterm/ctlseqs/ctlseqs.html

    Direct your attention to this command:

    CSI Ps c  Send Device Attributes (Primary DA)
    

    Quick guide to understanding the entry: CSI means either ESC [ or a 0x9b byte (ESC with the high bit set). Ps is a numeric parameter, which is optional in this command (and most others). To trigger this action by outputting random bytes, you only need to have a 0x9b byte followed by a 0x63 ('c') somewhere in the stream, which is not terribly unlikely in 1000 blocks of 512 bytes.

    What this command does is ask the terminal a question: "what are you?" and the terminal replies by sending an escape sequence back. There are several possible responses which you can read in the ctlseqs document but I find it interesting that both 6c and 62 appear in the list.

    These request/reply escape sequences are meant to be used by a program which writes the request and then immediately reads the reply. If instead the request is sent by a program that was just spewing garbage and not reading anything from the terminal, the reply can stay in the input buffer.

    Remember a terminal is connected to a computer by a serial line (real or emulated). It carries a single stream of bytes in each direction. There is no detectable difference between a ESC [ 6 c that arrived as a reply to a Device Attributes query and a ESC [ 6 c that arrived because you pressed the keys Esc [ 6 c, except for timing.

    So what happens in general if you run a command that doesn't use terminal input, and type some stuff while it's running? The stuff you typed stays in the tty buffer until that program is done, and then your shell reads it.

    (Typing a command to be read at a prompt that hasn't been printed yet is called typeahead and is a time-saving feature. You don't have to politely sit on your hands and wait for the computer to finish what it's doing, if you know what you want it to do next, you can just start typing!)

  • Related Question