apparmor/utils/aa-unconfined
Steve Beattie b0df52a7e5 utils/aa-unconfined: fix netstat invocation regression
Merge from 2.10 branch commit rev 3380

It was reported that converting the netstat command to examine
processes bound to ipv6 addresses broke on OpenSUSE due to the version
of nettools not supporting the short -4 -6 arguments.

This patch fixes the invocation of netstat to use the "--protocol
inet,inet6" arguments instead, which should return the same results
as the short options.

Signed-off-by: Steve Beattie <steve@nxnw.org>
Acked-by: Christian Boltz <apparmor@cboltz.de>
2017-01-09 09:25:35 -08:00

95 lines
4 KiB
Python
Executable file

#! /usr/bin/env python
# ----------------------------------------------------------------------
# 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 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 -nlp --protocol inet,inet6", 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 -nlp --protocol inet,inet6", 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 })