mirror of
https://github.com/freedombox/FreedomBox.git
synced 2026-05-27 10:44:33 +00:00
security: List whether each app is sandboxed
Signed-off-by: James Valleroy <jvalleroy@mailbox.org> [sunil: i18n for yes, no, N/A strings, avoid changing an i18ned string] Signed-off-by: Sunil Mohan Adapa <sunil@medhas.org> Reviewed-by: Sunil Mohan Adapa <sunil@medhas.org>
This commit is contained in:
parent
1be1af9b18
commit
89aefc00cf
@ -113,8 +113,8 @@ def set_restricted_access(enabled):
|
|||||||
actions.superuser_run('security', [action])
|
actions.superuser_run('security', [action])
|
||||||
|
|
||||||
|
|
||||||
def get_vulnerability_counts():
|
def get_apps_report():
|
||||||
"""Return number of security vulnerabilities for each app"""
|
"""Return a security report for each app"""
|
||||||
lines = subprocess.check_output(['debsecan']).decode().split('\n')
|
lines = subprocess.check_output(['debsecan']).decode().split('\n')
|
||||||
cves = defaultdict(set)
|
cves = defaultdict(set)
|
||||||
for line in lines:
|
for line in lines:
|
||||||
@ -132,12 +132,12 @@ def get_vulnerability_counts():
|
|||||||
'freedombox': {
|
'freedombox': {
|
||||||
'name': 'freedombox',
|
'name': 'freedombox',
|
||||||
'packages': {'freedombox'},
|
'packages': {'freedombox'},
|
||||||
'count': 0,
|
'vulns': 0,
|
||||||
'past_count': 0 if past_cves else None,
|
'past_vulns': 0 if past_cves else None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if past_cves and 'freedombox' in past_cves:
|
if past_cves and 'freedombox' in past_cves:
|
||||||
apps['freedombox']['past_count'] = len(past_cves['freedombox'])
|
apps['freedombox']['past_vulns'] = len(past_cves['freedombox'])
|
||||||
|
|
||||||
for module_name, module in module_loader.loaded_modules.items():
|
for module_name, module in module_loader.loaded_modules.items():
|
||||||
try:
|
try:
|
||||||
@ -145,6 +145,11 @@ def get_vulnerability_counts():
|
|||||||
except AttributeError:
|
except AttributeError:
|
||||||
continue # app has no managed packages
|
continue # app has no managed packages
|
||||||
|
|
||||||
|
try:
|
||||||
|
services = module.managed_services
|
||||||
|
except AttributeError:
|
||||||
|
services = None
|
||||||
|
|
||||||
# filter out apps not setup yet
|
# filter out apps not setup yet
|
||||||
if module.setup_helper.get_state() == 'needs-setup':
|
if module.setup_helper.get_state() == 'needs-setup':
|
||||||
continue
|
continue
|
||||||
@ -152,17 +157,56 @@ def get_vulnerability_counts():
|
|||||||
apps[module_name] = {
|
apps[module_name] = {
|
||||||
'name': module_name,
|
'name': module_name,
|
||||||
'packages': set(packages),
|
'packages': set(packages),
|
||||||
'count': 0,
|
'vulns': 0,
|
||||||
'past_count': 0 if past_cves else None,
|
'past_vulns': 0 if past_cves else None,
|
||||||
|
'sandboxed': None,
|
||||||
}
|
}
|
||||||
|
|
||||||
for package in packages:
|
for package in packages:
|
||||||
if past_cves and package in past_cves:
|
if past_cves and package in past_cves:
|
||||||
apps[module_name]['past_count'] += len(past_cves[package])
|
apps[module_name]['past_vulns'] += len(past_cves[package])
|
||||||
|
|
||||||
|
if services:
|
||||||
|
apps[module_name]['sandboxed'] = False
|
||||||
|
for service in services:
|
||||||
|
if _get_service_is_sandboxed(service):
|
||||||
|
apps[module_name]['sandboxed'] = True
|
||||||
|
|
||||||
for cve_packages in cves.values():
|
for cve_packages in cves.values():
|
||||||
for app_ in apps.values():
|
for app_ in apps.values():
|
||||||
if cve_packages & app_['packages']:
|
if cve_packages & app_['packages']:
|
||||||
app_['count'] += 1
|
app_['vulns'] += 1
|
||||||
|
|
||||||
return apps
|
return apps
|
||||||
|
|
||||||
|
|
||||||
|
def _get_service_is_sandboxed(service):
|
||||||
|
"""Return whether service is sandboxed."""
|
||||||
|
lines = subprocess.check_output([
|
||||||
|
'systemctl',
|
||||||
|
'show',
|
||||||
|
service,
|
||||||
|
'--property=ProtectSystem',
|
||||||
|
'--property=ProtectHome',
|
||||||
|
'--property=PrivateTmp',
|
||||||
|
'--property=PrivateDevices',
|
||||||
|
'--property=PrivateNetwork',
|
||||||
|
'--property=PrivateUsers',
|
||||||
|
'--property=PrivateMounts',
|
||||||
|
]).decode().strip().split('\n')
|
||||||
|
pairs = [line.partition('=')[::2] for line in lines]
|
||||||
|
properties = {name: value for name, value in pairs}
|
||||||
|
if properties['ProtectSystem'] in ['yes', 'full', 'strict']:
|
||||||
|
return True
|
||||||
|
|
||||||
|
if properties['ProtectHome'] in ['yes', 'read-only', 'tmpfs']:
|
||||||
|
return True
|
||||||
|
|
||||||
|
for name in [
|
||||||
|
'PrivateTmp', 'PrivateDevices', 'PrivateNetwork', 'PrivateUsers',
|
||||||
|
'PrivateMounts'
|
||||||
|
]:
|
||||||
|
if properties[name] == 'yes':
|
||||||
|
return True
|
||||||
|
|
||||||
|
return False
|
||||||
|
|||||||
@ -24,7 +24,7 @@
|
|||||||
{% block content %}
|
{% block content %}
|
||||||
<h3>{% trans "Security Report" %}</h3>
|
<h3>{% trans "Security Report" %}</h3>
|
||||||
<p>
|
<p>
|
||||||
{% blocktrans trimmed with count=freedombox_vulns.count %}
|
{% blocktrans trimmed with count=freedombox_report.vulns %}
|
||||||
The installed version of FreedomBox has {{ count }} reported security
|
The installed version of FreedomBox has {{ count }} reported security
|
||||||
vulnerabilities.
|
vulnerabilities.
|
||||||
{% endblocktrans %}
|
{% endblocktrans %}
|
||||||
@ -32,7 +32,8 @@
|
|||||||
<p>
|
<p>
|
||||||
{% blocktrans trimmed %}
|
{% blocktrans trimmed %}
|
||||||
The following table lists the current reported number, and historical
|
The following table lists the current reported number, and historical
|
||||||
count, of security vulnerabilities for each installed app.
|
count, of security vulnerabilities for each installed app. It also lists
|
||||||
|
whether each service is using sandboxing features.
|
||||||
{% endblocktrans %}
|
{% endblocktrans %}
|
||||||
</p>
|
</p>
|
||||||
<table class="table table-bordered table-condensed table-striped">
|
<table class="table table-bordered table-condensed table-striped">
|
||||||
@ -41,14 +42,24 @@
|
|||||||
<th>{% trans "App Name" %}</th>
|
<th>{% trans "App Name" %}</th>
|
||||||
<th>{% trans "Current Vulnerabilities" %}</th>
|
<th>{% trans "Current Vulnerabilities" %}</th>
|
||||||
<th>{% trans "Past Vulnerabilities" %}</th>
|
<th>{% trans "Past Vulnerabilities" %}</th>
|
||||||
|
<th>{% trans "Sandboxed" %}</th>
|
||||||
</tr>
|
</tr>
|
||||||
</thead>
|
</thead>
|
||||||
<tbody>
|
<tbody>
|
||||||
{% for app in apps_vulns %}
|
{% for app in apps_report %}
|
||||||
<tr>
|
<tr>
|
||||||
<td>{{ app.name }}</td>
|
<td>{{ app.name }}</td>
|
||||||
<td>{{ app.count }}</td>
|
<td>{{ app.vulns }}</td>
|
||||||
<td>{{ app.past_count|default_if_none:"❗"}}</td>
|
<td>{{ app.past_vulns|default_if_none:"❗"}}</td>
|
||||||
|
<td>
|
||||||
|
{% if app.sandboxed is None %}
|
||||||
|
{% trans "N/A" %}
|
||||||
|
{% elif app.sandboxed %}
|
||||||
|
{% trans "Yes" %}
|
||||||
|
{% else %}
|
||||||
|
{% trans "No" %}
|
||||||
|
{% endif %}
|
||||||
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
</tbody>
|
</tbody>
|
||||||
|
|||||||
@ -80,14 +80,13 @@ def _apply_changes(request, old_status, new_status):
|
|||||||
|
|
||||||
def report(request):
|
def report(request):
|
||||||
"""Serve the security report page"""
|
"""Serve the security report page"""
|
||||||
vulnerability_counts = security.get_vulnerability_counts()
|
apps_report = security.get_apps_report()
|
||||||
return TemplateResponse(
|
return TemplateResponse(
|
||||||
request, 'security_report.html', {
|
request, 'security_report.html', {
|
||||||
'title':
|
'title':
|
||||||
_('Security Report'),
|
_('Security Report'),
|
||||||
'freedombox_vulns':
|
'freedombox_report':
|
||||||
vulnerability_counts.pop('freedombox'),
|
apps_report.pop('freedombox'),
|
||||||
'apps_vulns':
|
'apps_report':
|
||||||
sorted(vulnerability_counts.values(),
|
sorted(apps_report.values(), key=lambda app: app['name']),
|
||||||
key=lambda app: app['name']),
|
|
||||||
})
|
})
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user