# arguments
examples = """examples:
- ./ttysnoop /dev/pts/2 # snoop output from /dev/pts/2
- ./ttysnoop 2 # snoop output from /dev/pts/2 (shortcut)
- ./ttysnoop /dev/console # snoop output from the system console
- ./ttysnoop /dev/tty0 # snoop output from /dev/tty0
+ ./ttysnoop /dev/pts/2 # snoop output from /dev/pts/2
+ ./ttysnoop 2 # snoop output from /dev/pts/2 (shortcut)
+ ./ttysnoop /dev/console # snoop output from the system console
+ ./ttysnoop /dev/tty0 # snoop output from /dev/tty0
+ ./ttysnoop /dev/pts/2 -s 1024 # snoop output from /dev/pts/2 with data size 1024
+ ./ttysnoop /dev/pts/2 -c 2 # snoop output from /dev/pts/2 with 2 checks for 256 bytes of data in buffer
+ (potentially retrieving 512 bytes)
"""
parser = argparse.ArgumentParser(
description="Snoop output from a pts or tty device, eg, a shell",
help="don't clear the screen")
parser.add_argument("device", default="-1",
help="path to a tty device (eg, /dev/tty0) or pts number")
+parser.add_argument("-s", "--datasize", default="256",
+ help="size of the transmitting buffer (default 256)")
+parser.add_argument("-c", "--datacount", default="16",
+ help="number of times we check for 'data-size' data (default 16)")
parser.add_argument("--ebpf", action="store_true",
help=argparse.SUPPRESS)
args = parser.parse_args()
#include <linux/fs.h>
#include <linux/uio.h>
-#define BUFSIZE 256
+#define BUFSIZE USER_DATASIZE
struct data_t {
int count;
char buf[BUFSIZE];
static int do_tty_write(void *ctx, const char __user *buf, size_t count)
{
- int zero = 0;
+ int zero = 0, i;
struct data_t *data;
/* We can't read data to map data before v4.11 */
return 0;
#endif
- // bpf_probe_read_user() can only use a fixed size, so truncate to count
- // in user space:
- bpf_probe_read_user(&data->buf, BUFSIZE, (void *)buf);
- if (count > BUFSIZE)
- data->count = BUFSIZE;
- else
- data->count = count;
- events.perf_submit(ctx, data, sizeof(*data));
+ #pragma unroll
+ for (i = 0; i < USER_DATACOUNT; i++) {
+ // bpf_probe_read_user() can only use a fixed size, so truncate to count
+ // in user space:
+ if (bpf_probe_read_user(&data->buf, BUFSIZE, (void *)buf))
+ return 0;
+ if (count > BUFSIZE)
+ data->count = BUFSIZE;
+ else
+ data->count = count;
+ events.perf_submit(ctx, data, sizeof(*data));
+ if (count < BUFSIZE)
+ return 0;
+ count -= BUFSIZE;
+ buf += BUFSIZE;
+ }
return 0;
};
if args.ebpf:
exit()
+bpf_text = bpf_text.replace('USER_DATASIZE', '%s' % args.datasize)
+bpf_text = bpf_text.replace('USER_DATACOUNT', '%s' % args.datacount)
+
# initialize BPF
b = BPF(text=bpf_text)
device path to a tty device (eg, /dev/tty0) or pts number
optional arguments:
- -h, --help show this help message and exit
- -C, --noclear don't clear the screen
+ -h, --help show this help message and exit
+ -C, --noclear don't clear the screen
+ -s, --datasize size of the transmitting buffer (default 256)
+ -c, --datacount number of times ttysnop checks for data (default 16)
examples:
- ./ttysnoop /dev/pts/2 # snoop output from /dev/pts/2
- ./ttysnoop 2 # snoop output from /dev/pts/2 (shortcut)
- ./ttysnoop /dev/console # snoop output from the system console
- ./ttysnoop /dev/tty0 # snoop output from /dev/tty0
+ ./ttysnoop /dev/pts/2 # snoop output from /dev/pts/2
+ ./ttysnoop 2 # snoop output from /dev/pts/2 (shortcut)
+ ./ttysnoop /dev/console # snoop output from the system console
+ ./ttysnoop /dev/tty0 # snoop output from /dev/tty0
+ ./ttysnoop /dev/pts/2 -s 1024 # snoop output from /dev/pts/2 with data size 1024
+ ./ttysnoop /dev/pts/2 -c 2 # snoop output from /dev/pts/2 with 2 checks for 256 bytes of data in buffer
+ (potentionaly retrieving 512 bytes)