Skip to content
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
39 changes: 39 additions & 0 deletions tools/bashreadline.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
from bcc import BPF
from time import strftime
import argparse
import subprocess

parser = argparse.ArgumentParser(
description="Print entered bash commands from all running shells",
Expand All @@ -44,8 +45,46 @@ def get_sym(filename):
return "readline"


def is_sym_defined(filename, symname):
"""Check if symbol is defined (not just imported) in an ELF binary."""
try:
with open(filename, 'rb') as f:
elf = ELFFile(f)
dynsym = elf.get_section_by_name(".dynsym")
if dynsym:
for s in dynsym.iter_symbols():
if s.name == symname:
return s.entry['st_shndx'] != 'SHN_UNDEF'
except Exception:
pass
return False


def find_readline_so():
"""Find libreadline.so that bash dynamically links against."""
try:
out = subprocess.check_output(["ldd", "/bin/bash"],
stderr=subprocess.DEVNULL, text=True)
for line in out.splitlines():
if "libreadline" in line and "=>" in line:
path = line.split("=>")[1].strip().split()[0]
if path.startswith("/"):
return path
except Exception:
pass
return None


sym = get_sym(name)

# When readline is undefined in /bin/bash (dynamically linked),
# auto-detect and use libreadline.so instead.
if not args.shared and not is_sym_defined(name, sym):
lib = find_readline_so()
if lib:
name = lib
sym = get_sym(name)

# load BPF program
bpf_text = """
#include <uapi/linux/ptrace.h>
Expand Down
Loading