Skip to content
This repository has been archived by the owner on Sep 16, 2022. It is now read-only.

CVE list: Show only the currently running kernel meta-package #791

Merged
Merged
Show file tree
Hide file tree
Changes from 4 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
12 changes: 7 additions & 5 deletions backend/device_registry/api_views.py
Original file line number Diff line number Diff line change
Expand Up @@ -102,12 +102,13 @@ def post(self, request, *args, **kwargs):
device.set_deb_packages(deb_packages['packages'], os_release)
kernel_deb_package = data.get('kernel_package')
if kernel_deb_package:
device.kernel_deb_package = DebPackage.objects.get(name=kernel_deb_package['name'],
version=kernel_deb_package['version'],
arch=kernel_deb_package['arch'],
os_release_codename=os_release['codename'])
device.kernel_deb_package = device.deb_packages.get(name=kernel_deb_package['name'],
version=kernel_deb_package['version'],
arch=kernel_deb_package['arch'],
os_release_codename=os_release['codename'])
else:
device.kernel_deb_package = None
device.reboot_required = data.get('reboot_required')
device.cpu = data.get('cpu', {})
device.os_release = os_release
device.mysql_root_access = data.get('mysql_root_access')
Expand Down Expand Up @@ -154,7 +155,8 @@ def post(self, request, *args, **kwargs):
device.update_trust_score = True
device.save(update_fields=['last_ping', 'agent_version', 'audit_files', 'deb_packages_hash',
'update_trust_score', 'os_release', 'auto_upgrades',
'mysql_root_access', 'cpu', 'kernel_deb_package', 'default_password_users'])
'mysql_root_access', 'cpu', 'kernel_deb_package', 'reboot_required',
'default_password_users'])
# Un-snooze recommended actions which were "Fixed" (i.e. snoozed until next ping)
device.recommendedactionstatus_set.filter(status=RecommendedAction.Status.SNOOZED_UNTIL_PING) \
.update(status=RecommendedAction.Status.AFFECTED)
Expand Down
11 changes: 7 additions & 4 deletions backend/device_registry/celery_tasks/common.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
import redis

from device_registry.models import Device, Vulnerability, DebPackage, DEBIAN_SUITES, UBUNTU_SUITES
from device_registry.models import UBUNTU_KERNEL_PACKAGES_RE_PATTERN
from profile_page.models import Profile

logger = logging.getLogger('django')
Expand Down Expand Up @@ -72,6 +73,7 @@ def update_packages_vulnerabilities(batch):
if vuln.is_vulnerable(package.source_version) and vuln.fix_available:
relations.append(Relation(debpackage_id=package.id, vulnerability_id=vuln.id))
counter += 1
# TODO: Execute ORM requests below in one transaction.
Relation.objects.filter(debpackage_id__in=package_ids).delete()
Relation.objects.bulk_create(relations, batch_size=10000, ignore_conflicts=True)
logger.info('finished')
Expand All @@ -87,10 +89,11 @@ def send_packages_to_vulns_update(task):
# In case of success set the lock's timeout to 2.5m.
with redis_conn.lock('vulns_lock', timeout=60 * 2.5, blocking_timeout=3):
logger.info('lock acquired.')
distro_suites = DEBIAN_SUITES + UBUNTU_SUITES + ('amzn2',)
package_ids = list(DebPackage.objects.filter(
processed=False, os_release_codename__in=distro_suites).order_by(
'os_release_codename', 'source_name').values_list('id', flat=True))
package_ids = list((DebPackage.objects.filter(
processed=False, os_release_codename__in=DEBIAN_SUITES + ('amzn2',)) |
DebPackage.objects.filter(processed=False, os_release_codename__in=UBUNTU_SUITES
).exclude(name__regex=UBUNTU_KERNEL_PACKAGES_RE_PATTERN)
).order_by('os_release_codename', 'source_name').values_list('id', flat=True))
logger.info('%d packages to process found.' % len(package_ids))
batch_size = 500
position = 0
Expand Down
40 changes: 40 additions & 0 deletions backend/device_registry/migrations/0088_auto_20200306_1702.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
# Generated by Django 2.2.10 on 2020-03-06 17:02

from django.db import migrations, models

from device_registry.models import UBUNTU_SUITES, UBUNTU_KERNEL_PACKAGES_RE_PATTERN


def reset_kernel_packages_vulns(apps, schema_editor):
# Delete vulns of kernel-related packages.
DebPackageVulnerability = apps.get_model('device_registry', 'DebPackage').vulnerabilities.through
# Ubuntu.
DebPackageVulnerability.objects.filter(
debpackage__os_release_codename__in=UBUNTU_SUITES, debpackage__name__regex=UBUNTU_KERNEL_PACKAGES_RE_PATTERN
).delete()


class Migration(migrations.Migration):

dependencies = [
('device_registry', '0087_auto_20200318_0652'),
]

operations = [
migrations.AddField(
model_name='device',
name='reboot_required',
field=models.BooleanField(blank=True, db_index=True, null=True),
),
migrations.AlterField(
model_name='vulnerability',
name='name',
field=models.CharField(db_index=True, max_length=64),
),
migrations.AlterField(
model_name='vulnerability',
name='fix_available',
field=models.BooleanField(db_index=True),
),
migrations.RunPython(reset_kernel_packages_vulns)
]
17 changes: 8 additions & 9 deletions backend/device_registry/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,8 @@
apt_pkg.init()

DEBIAN_SUITES = ('jessie', 'stretch', 'buster') # Supported Debian suite names.
UBUNTU_SUITES = ('xenial', 'bionic') # Supported Ubuntu suite names.
UBUNTU_SUITES = ('xenial', 'bionic') # Supported Ubuntu suite (16.04, 18.04) names.
UBUNTU_KERNEL_PACKAGES_RE_PATTERN = r'linux-(?:headers|aws-headers|image|modules)-.+'
Copy link
Contributor

@a-martynovich a-martynovich Mar 19, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would also add (gcp|kvm|oem|oem-osp1|azure|azure-edge|oracle|gke|raspi2)-headers here (see linux-headers)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done

IPV4_ANY = '0.0.0.0'
IPV6_ANY = '::'
FTP_PORT = 21
Expand Down Expand Up @@ -73,6 +74,9 @@ class Arch(Enum):
class Meta:
unique_together = ['name', 'version', 'arch', 'os_release_codename']

def __str__(self):
return f'{self.name}:{self.version}:{self.arch}:{self.os_release_codename}'


class Device(models.Model):
class SshdIssueItem(NamedTuple):
Expand Down Expand Up @@ -111,6 +115,7 @@ class SshdIssueItem(NamedTuple):
deb_packages_hash = models.CharField(max_length=32, blank=True)
cpu = JSONField(blank=True, default=dict)
kernel_deb_package = models.ForeignKey(DebPackage, null=True, on_delete=models.SET_NULL, related_name='+')
reboot_required = models.BooleanField(null=True, blank=True, db_index=True)
audit_files = JSONField(blank=True, default=list)
os_release = JSONField(blank=True, default=dict)
auto_upgrades = models.BooleanField(null=True, blank=True)
Expand Down Expand Up @@ -475,12 +480,6 @@ def set_meta_tags(self):
if all_devices_tag not in self.tags:
self.tags.add(all_devices_tag)

@property
def vulnerable_packages(self):
if self.deb_packages_hash and self.deb_packages.exists() and self.os_release and \
self.os_release.get('codename') in DEBIAN_SUITES + UBUNTU_SUITES + ('amzn2',):
return self.deb_packages.filter(vulnerabilities__isnull=False).distinct().order_by('name')

@property
def cve_count(self):
"""
Expand Down Expand Up @@ -985,14 +984,14 @@ class Urgency(IntEnum):
HIGH = 3

os_release_codename = models.CharField(max_length=64, db_index=True)
name = models.CharField(max_length=64)
name = models.CharField(max_length=64, db_index=True)
package = models.CharField(max_length=64, db_index=True)
is_binary = models.BooleanField()
unstable_version = models.CharField(max_length=64, blank=True)
other_versions = ArrayField(models.CharField(max_length=64), blank=True)
urgency = models.PositiveSmallIntegerField(choices=[(tag, tag.value) for tag in Urgency])
remote = models.BooleanField(null=True)
fix_available = models.BooleanField()
fix_available = models.BooleanField(db_index=True)
pub_date = models.DateField(null=True)

def is_vulnerable(self, src_ver):
Expand Down
13 changes: 13 additions & 0 deletions backend/device_registry/recommended_actions.py
Original file line number Diff line number Diff line change
Expand Up @@ -497,6 +497,19 @@ def severity(cls, param=None):
return Severity.MED


# OS reboot required action.
class RebootRequiredAction(SimpleAction, metaclass=ActionMeta):
_severity = Severity.MED

@classmethod
def _affected_devices(cls, qs):
return qs.filter(reboot_required=True)

@classmethod
def _is_affected(cls, device) -> bool:
return device.reboot_required is True
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please implement _affected_devices()

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The one from the parent class is ok

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I know, but if it can be done with a simple query, then why not



# Automatic security update disabled action.
class AutoUpdatesAction(SimpleAction, metaclass=ActionMeta):
@classmethod
Expand Down
16 changes: 12 additions & 4 deletions backend/device_registry/tests/test_recommended_actions.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,10 @@
from device_registry.models import Device, DeviceInfo, FirewallState, PortScan, DebPackage, Vulnerability, \
GlobalPolicy, RecommendedAction, RecommendedActionStatus
from device_registry.recommended_actions import DefaultCredentialsAction, FirewallDisabledAction, AutoUpdatesAction, \
VulnerablePackagesAction, MySQLDefaultRootPasswordAction, \
FtpServerAction, CpuVulnerableAction, BaseAction, ActionMeta, Action, \
PUBLIC_SERVICE_PORTS, GithubAction, EnrollAction, INSECURE_SERVICES, InsecureServicesAction, \
SSHD_CONFIG_PARAMS_INFO, OpensshIssueAction, PubliclyAccessibleServiceAction, Severity, SimpleAction, ParamStatus
VulnerablePackagesAction, MySQLDefaultRootPasswordAction, FtpServerAction, CpuVulnerableAction, ActionMeta, \
Action, PUBLIC_SERVICE_PORTS, GithubAction, EnrollAction, INSECURE_SERVICES, InsecureServicesAction, \
SSHD_CONFIG_PARAMS_INFO, OpensshIssueAction, PubliclyAccessibleServiceAction, Severity, SimpleAction, ParamStatus, \
RebootRequiredAction

from freezegun import freeze_time

Expand Down Expand Up @@ -586,3 +586,11 @@ def enable_action(self):
pkg.save()
self.device.cpu = {'vendor': 'GenuineIntel'}
self.device.save()


class RebootRequiredActionTest(TestsMixin, TestCase):
action_class = RebootRequiredAction

def enable_action(self):
self.device.reboot_required = True
self.device.save(update_fields=['reboot_required'])
2 changes: 1 addition & 1 deletion backend/device_registry/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -697,7 +697,7 @@ def get_context_data(self, **kwargs):
vuln_names = Vulnerability.objects.filter(vuln_query)\
.values('name').distinct()
vuln_pub_dates_qs = Vulnerability.objects.filter(name__in=vuln_names) \
.values('name').annotate(pubdate=Max('pub_date')).distinct()
.values('name').distinct().annotate(pubdate=Max('pub_date'))
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

what does this change?

# Build a lookup dictionary for CVE publication dates.
vuln_pub_dates = {v['name']: v['pubdate'] for v in vuln_pub_dates_qs}

Expand Down
11 changes: 11 additions & 0 deletions backend/recommended_actions.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -503,3 +503,14 @@
terminal_code: |
$ export CLAIM_TOKEN="{key}"
$ curl -sL https://install.wott.io | sudo -E bash

- title: Reboot required
class: RebootRequiredAction
short: |
Reboot required for kernel upgrade to complete.
long: |
You have recently installed a new Linux kernel, but the system is currently running an older version. In order to apply the kernel upgrade, you need to reboot your system.
terminal_title: |
To reboot the node, run the following command:
terminal_code: |
$ sudo shutdown -r now