From d51b102c3a2fc7e83f777e20bc654181ad4640da Mon Sep 17 00:00:00 2001 From: John Johansen Date: Tue, 30 Jan 2024 09:43:23 +0000 Subject: [PATCH] Merge Prevent ANSI terminal injection in aa-unconfined /proc/$pid/cmdline can be changed by an application, therefore escape it before printing. The program name in /proc/$pid/exe can also contain any characters (except \0 and shashes) and needs escaping. Note: repr() wraps the string into single quotes, which we have to remove to avoid changing the output format. The test program from issue 364 now gets displayed as 28443 /path/to/issue364 (/\x1b]0;X\x07) not confined Fixes: https://gitlab.com/apparmor/apparmor/-/issues/364 I propose this patch for 2.13..master Closes #364 MR: https://gitlab.com/apparmor/apparmor/-/merge_requests/1142 Approved-by: John Johansen Merged-by: John Johansen (cherry picked from commit e63c1e3a76dd03dfae954d6ac2bf900133914553) Signed-off-by: John Johansen --- utils/aa-unconfined | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/utils/aa-unconfined b/utils/aa-unconfined index 04073955e..811cd8ec0 100755 --- a/utils/aa-unconfined +++ b/utils/aa-unconfined @@ -99,6 +99,15 @@ def get_pids_netstat(netstat='netstat'): return pids +def escape_special_chars(data): + """escape special characters in program names so that they can't mess up the terminal""" + data = repr(data) + if len(data) > 1 and data.startswith("'") and data.endswith("'"): + return data[1:-1] + else: + return data + + pids = set() if paranoid: pids = get_all_pids() @@ -110,6 +119,7 @@ else: for pid in sorted(map(int, pids)): try: prog = os.readlink("/proc/%s/exe" % pid) + prog = escape_special_chars(prog) except OSError: continue attr = None @@ -127,6 +137,7 @@ for pid in sorted(map(int, pids)): pname = cmdline.split("\0")[0] if '/' in pname and pname != prog: pname = "(%s)" % pname + pname = escape_special_chars(pname) else: pname = "" regex_interpreter = re.compile(r"^(/usr)?/bin/(python|perl|bash|dash|sh)$") @@ -134,6 +145,7 @@ for pid in sorted(map(int, pids)): if regex_interpreter.search(prog): cmdline = re.sub(r"\x00", " ", cmdline) cmdline = re.sub(r"\s+$", "", cmdline).strip() + cmdline = escape_special_chars(cmdline) ui.UI_Info(_("%(pid)s %(program)s (%(commandline)s) not confined") % {'pid': pid, 'program': prog, 'commandline': cmdline}) else: @@ -144,6 +156,7 @@ for pid in sorted(map(int, pids)): if regex_interpreter.search(prog): cmdline = re.sub(r"\0", " ", cmdline) cmdline = re.sub(r"\s+$", "", cmdline).strip() + cmdline = escape_special_chars(cmdline) ui.UI_Info(_("%(pid)s %(program)s (%(commandline)s) confined by '%(attribute)s'") % {'pid': pid, 'program': prog, 'commandline': cmdline, 'attribute': attr}) else: if pname and pname[-1] == ')':