apparmor/utils/aa-unconfined
Steve Beattie 8cc7b73552 In testing, I did notice one thing not getting turned up, from
netstat -nlp46 output:

  raw6       0      0 :::58                   :::*                    7        1326/NetworkManager

which when asking netstat to display name resolution ends up being:

  raw6       0      0 [::]:ipv6-icmp          [::]:*                  7        1326/NetworkManager

Of course, aa-unconfined doesn't show this, the following patch adds
that, by adding the raw keyword as an alternative to tcp|udp and
accepting a number as an alternative to LISTEN.

Signed-off-by: Steve Beattie <steve@nxnw.org>
Acked-by: John Johansen <john.johansen@canonical.com>
2016-12-01 17:32:52 -08:00

99 lines
4 KiB
Python
Executable file

#! /usr/bin/python3
# ----------------------------------------------------------------------
# Copyright (C) 2013 Kshitij Gupta <kgupta8592@gmail.com>
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of version 2 of the GNU General Public
# License as published by the Free Software Foundation.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# ----------------------------------------------------------------------
import argparse
import os
import re
import sys
import apparmor.aa as aa
import apparmor.ui as ui
import apparmor.common
# setup exception handling
from apparmor.fail import enable_aa_exception_handler
enable_aa_exception_handler()
# setup module translations
from apparmor.translations import init_translation
_ = init_translation()
parser = argparse.ArgumentParser(description=_("Lists unconfined processes having tcp or udp ports"))
parser.add_argument("--paranoid", action="store_true", help=_("scan all processes from /proc"))
args = parser.parse_args()
paranoid = args.paranoid
aa_mountpoint = aa.check_for_apparmor()
if not aa_mountpoint:
raise aa.AppArmorException(_("It seems AppArmor was not started. Please enable AppArmor and try again."))
pids = []
if paranoid:
pids = list(filter(lambda x: re.search(r"^\d+$", x), aa.get_subdirectories("/proc")))
else:
regex_tcp_udp = re.compile(r"^(tcp|udp|raw)6?\s+\d+\s+\d+\s+\S+\:(\d+)\s+\S+\:(\*|\d+)\s+(LISTEN|\d+|\s+)\s+(\d+)\/(\S+)")
import subprocess
if sys.version_info < (3, 0):
output = subprocess.check_output("LANG=C netstat -nlp46", shell=True).split("\n")
else:
#Python3 needs to translate a stream of bytes to string with specified encoding
output = str(subprocess.check_output("LANG=C netstat -nlp46", shell=True), encoding='utf8').split("\n")
for line in output:
match = regex_tcp_udp.search(line)
if match:
pids.append(match.groups()[4])
# We can safely remove duplicate pid's?
pids = list(map(int, set(pids)))
for pid in sorted(pids):
try:
prog = os.readlink("/proc/%s/exe"%pid)
except OSError:
continue
attr = None
if os.path.exists("/proc/%s/attr/current"%pid):
with aa.open_file_read("/proc/%s/attr/current"%pid) as current:
for line in current:
line = line.strip()
if line.endswith(' (complain)', 1) or line.endswith(' (enforce)', 1): # enforce at least one char as profile name
attr = line
cmdline = apparmor.common.cmd(["cat", "/proc/%s/cmdline"%pid])[1]
pname = cmdline.split("\0")[0]
if '/' in pname and pname != prog:
pname = "(%s)"% pname
else:
pname = ""
regex_interpreter = re.compile(r"^(/usr)?/bin/(python|perl|bash|dash|sh)$")
if not attr:
if regex_interpreter.search(prog):
cmdline = re.sub(r"\x00", " ", cmdline)
cmdline = re.sub(r"\s+$", "", cmdline).strip()
ui.UI_Info(_("%(pid)s %(program)s (%(commandline)s) not confined") % { 'pid': pid, 'program': prog, 'commandline': cmdline })
else:
if pname and pname[-1] == ')':
pname = ' ' + pname
ui.UI_Info(_("%(pid)s %(program)s%(pname)s not confined") % { 'pid': pid, 'program': prog, 'pname': pname })
else:
if regex_interpreter.search(prog):
cmdline = re.sub(r"\0", " ", cmdline)
cmdline = re.sub(r"\s+$", "", cmdline).strip()
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] == ')':
pname = ' ' + pname
ui.UI_Info(_("%(pid)s %(program)s%(pname)s confined by '%(attribute)s'") % { 'pid': pid, 'program': prog, 'pname': pname, 'attribute': attr })