Vincent C. Emeakaroha

35 papers B 3C 8Misc 2Journal 9Unranked 12
YearRankTypeTitle / Venue / Authors
2024 J jnl
SN Comput. Sci.
Jose Luis Lo Huang, Vincent C. Emeakaroha
2023 C conf
ISTAS
John Gilvarry, Vincent C. Emeakaroha
2023 C conf
CLOSER
Jose Luis Lo Huang, Vincent C. Emeakaroha
2019 J jnl
J. Cloud Comput.
Lisa van der Werff, Grace Fox, Ieva Masevic, Vincent C. Emeakaroha, John P. Morrison, Theo Lynn
2017 C conf
CloudCom
Theo Lynn, Pierangelo Rosati, Arnaud Lejeune, Vincent C. Emeakaroha
2017 J jnl
IEEE Trans. Serv. Comput.
Vincent C. Emeakaroha, Kaniz Fatema, Lisa van der Werff, Philip D. Healy, Theo Lynn, John P. Morrison
2017 C conf
CLOSER
Vincent C. Emeakaroha, Eoin O'Meara, Brian Lee, Theo Lynn, John P. Morrison
2017 ch.
Cloud Computing, 2nd Ed.
Vincent C. Emeakaroha, Philip D. Healy, John P. Morrison
2016 conf
CLOSER (1)
David O'Shea, Vincent C. Emeakaroha, John Pendlebury, Neil Cafferkey, John P. Morrison, Theo Lynn
2016 conf
AMCIS
Wipawee Victoria Paulsson, Vincent C. Emeakaroha, John P. Morrison, Theo Lynn
2016 conf
CLOSER (Selected Papers)
David O'Shea, Vincent C. Emeakaroha, Neil Cafferkey, John P. Morrison, Theo Lynn
2016 conf
CloudNet
Vincent C. Emeakaroha, Martin Bullman, John P. Morrison
2015 conf
FiCloud
Vincent C. Emeakaroha, Neil Cafferkey, Philip D. Healy, John P. Morrison
2014 conf
CLOSER (Selected Papers)
Kaniz Fatema, Philip D. Healy, Vincent C. Emeakaroha, John P. Morrison, Theo Lynn
2014 C conf
CLOSER
Kaniz Fatema, Philip D. Healy, Vincent C. Emeakaroha, John P. Morrison, Theo Lynn
2014 J jnl
J. Parallel Distributed Comput.
Kaniz Fatema, Vincent C. Emeakaroha, Philip D. Healy, John P. Morrison, Theo Lynn
2013 Misc conf
UCC
Vincent C. Emeakaroha, Philip D. Healy, Kaniz Fatema, John P. Morrison
2013 conf
Euro-Par Workshops
Vincent C. Emeakaroha, Philip D. Healy, Kaniz Fatema, John P. Morrison
2013 J jnl
Concurr. Comput. Pract. Exp.
Vincent C. Emeakaroha, Ivona Brandic, Michael Maurer, Schahram Dustdar
2013 J jnl
J. Grid Comput.
Vincent C. Emeakaroha, Michael Maurer, Patrick Stern, Pawel P. Labaj, Ivona Brandic, David P. Kreil
2012 B conf
COMPSAC
Vincent C. Emeakaroha, Tiago C. Ferreto, Marco Aurélio Stelmar Netto, Ivona Brandic, César A. F. De Rose
2012 J jnl
Future Gener. Comput. Syst.
Michael Maurer, Vincent C. Emeakaroha, Ivona Brandic, Jörn Altmann
2012 C conf
CLOSER
Toni Mastelic, Vincent C. Emeakaroha, Michael Maurer, Ivona Brandic
2012 J jnl
Future Gener. Comput. Syst.
Vincent C. Emeakaroha, Marco Aurélio Stelmar Netto, Rodrigo N. Calheiros, Ivona Brandic, Rajkumar Buyya, César A. F. De Rose
2011 conf
ITSC
Christoph Stögerer, Ivona Brandic, Vincent C. Emeakaroha, Wolfgang Kastner, Thomas Novak
2011 Misc conf
UCC
Ivan Breskovic, Michael Maurer, Vincent C. Emeakaroha, Ivona Brandic, Schahram Dustdar
2011 conf
WORKS@SC
Vincent C. Emeakaroha, Pawel P. Labaj, Michael Maurer, Ivona Brandic, David P. Kreil
2011 C conf
ISCC
Michael Maurer, Ivan Breskovic, Vincent C. Emeakaroha, Ivona Brandic
2011 conf
COMPSAC Workshops
Vincent C. Emeakaroha, Ivona Brandic, Michael Maurer, Ivan Breskovic
2011 C conf
CLOSER
Ivan Breskovic, Michael Maurer, Vincent C. Emeakaroha, Ivona Brandic, Jörn Altmann
2010 J jnl
ERCIM News
Vincent C. Emeakaroha, Michael Maurer, Ivona Brandic, Schahram Dustdar
2010 conf
COMPSAC Workshops
Ivona Brandic, Vincent C. Emeakaroha, Michael Maurer, Schahram Dustdar, Sandor Acs, Attila Kertész, Gabor Kecskemeti
2010 conf
HPCS
Vincent C. Emeakaroha, Ivona Brandic, Michael Maurer, Schahram Dustdar
2010 B conf
SERVICES
Michael Maurer, Ivona Brandic, Vincent C. Emeakaroha, Schahram Dustdar
2009 B conf
LCN
Brikena Statovci-Halimi, Vincent C. Emeakaroha
redb/extractors/malcontent.py
← Index redb/extractors/malcontent.py python
import inspect
import json
import subprocess
from typing import Any
from datetime import datetime, timezone

from redb.extractors.enum import Tag
from redb.models.dataclasses import Malcontent
from redb.extractors.extractor import Extractor
from dotenv import load_dotenv
import os

load_dotenv(override=True)


class MalcontentExtractor(Extractor):
    """
    Extractor for malcontent tool from chainguard-dev/malcontent.

    Malcontent discovers supply-chain compromises through context, differential
    analysis, and 14,000+ YARA rules. It analyzes binaries and code to detect
    malicious content and suspicious behavioral patterns.

    Binary can be extracted from Docker image:
        docker cp $(docker create cgr.dev/chainguard/malcontent:latest):/usr/bin/mal /usr/local/bin/mal

    Stores full JSON output for materialized view extraction.
    """

    # Cache version at class level to avoid repeated subprocess calls
    _cached_version = None

    def __init__(
        self,
        filepath,
        log,
        exporters=None,
        index_prefix=None,
        elastic_index=None,
        known_benign=False,
        known_malicious=False,
    ):
        super().__init__(
            filepath,
            log,
            exporters,
            index_prefix,
            elastic_index,
            known_benign,
            known_malicious
        )
        self.malcontent = None

    @classmethod
    def _get_malcontent_version(cls, log) -> str:
        """Get malcontent version, cached at class level."""
        if cls._cached_version is not None:
            return cls._cached_version

        malcontent_path = os.getenv("MALCONTENT_PATH", "/usr/local/bin/mal")
        try:
            result = subprocess.run(
                [malcontent_path, "--version"],
                capture_output=True,
                text=True,
                timeout=10
            )
            version_output = result.stdout.strip()
            if result.returncode == 0 and version_output:
                # Parse "malcontent version v1.21.5" -> "1.21.5"
                if version_output.startswith("malcontent version v"):
                    version_output = version_output[len("malcontent version v"):]
                elif version_output.startswith("malcontent version "):
                    version_output = version_output[len("malcontent version "):]
                cls._cached_version = version_output
            else:
                cls._cached_version = "unknown"
        except Exception as e:
            log.warning(f"Could not get malcontent version: {e}")
            cls._cached_version = "unknown"

        return cls._cached_version

    def _extract_malcontent(self):
        self.log.debug(inspect.currentframe().f_code.co_name)
        TIMEOUT = int(os.getenv("MALCONTENT_TIMEOUT", "300"))
        malcontent_path = os.getenv("MALCONTENT_PATH", "/usr/local/bin/mal")

        malcontent_command = [malcontent_path, "analyze", "--format=json", self.filepath]

        import signal

        try:
            process = subprocess.Popen(
                malcontent_command,
                stdout=subprocess.PIPE,
                stderr=subprocess.PIPE,
                text=True,
                preexec_fn=os.setsid
            )

            try:
                stdout, stderr = process.communicate(timeout=TIMEOUT)
                if process.returncode != 0:
                    self.log.error(f"Error running malcontent, return code: {process.returncode}, stderr: {stderr}")
                    return {}
            except subprocess.TimeoutExpired:
                self.log.warning(f"The malcontent command timed out after {TIMEOUT} seconds, terminating process group")
                try:
                    os.killpg(process.pid, signal.SIGTERM)
                    try:
                        process.wait(timeout=3)
                    except subprocess.TimeoutExpired:
                        self.log.warning("Process didn't terminate with SIGTERM, sending SIGKILL")
                        os.killpg(process.pid, signal.SIGKILL)
                    process.wait()
                except (ProcessLookupError, OSError) as e:
                    self.log.warning(f"Error while killing process: {e}")
                return {}

            try:
                malcontent_output = json.loads(stdout)
            except json.JSONDecodeError as e:
                self.log.error(f"Error parsing malcontent output: {e}")
                return {}

            # Unwrap the Files/<path> structure to get the inner content
            # Structure is: {"Files": {"/path/to/file": {<actual content>}}}
            files_dict = malcontent_output.get("Files", {})
            if not files_dict:
                self.log.warning("Malcontent output has no 'Files' key")
                return {}

            # Get the first (and only) file's content
            file_content = next(iter(files_dict.values()), {})
            if not file_content:
                self.log.warning("Malcontent output has empty file content")
                return {}

            # Extract risk score and level from the unwrapped content
            risk_score = file_content.get("RiskScore", 0)
            risk_level = file_content.get("RiskLevel", "")

            version = self._get_malcontent_version(self.log)

            self.malcontent = Malcontent(
                malcontent_dump=json.dumps(file_content),
                version=version,
                risk_score=risk_score,
                risk_level=risk_level
            )
            self.log.debug(f"Malcontent analysis complete, version={version}, risk={risk_level}({risk_score})")

        except Exception as e:
            self.log.error(f"Unexpected error in malcontent extraction: {str(e)}")
            if 'process' in locals() and process.poll() is None:
                try:
                    os.killpg(process.pid, signal.SIGKILL)
                    process.wait()
                except:
                    pass
            return {}

    def prepare_export_data(self, exporter_type: str) -> Any:
        if exporter_type == "ClickHouseExporter":
            current_time = datetime.now(timezone.utc)

            data = [[
                self.sha256,
                current_time,
                self.malcontent.version,
                self.malcontent.risk_score,
                self.malcontent.risk_level,
                self.malcontent.malcontent_dump
            ]]

            column_names = [
                'sha256', 'analysis_date',
                'malcontent_version', 'malcontent_risk_score', 'malcontent_risk_level',
                'malcontent_json'
            ]

            column_type_names = [
                'FixedString(64)',
                'DateTime64(3, \'UTC\')',
                'LowCardinality(String)', 'UInt8', 'LowCardinality(String)',
                'JSON'
            ]

            return (data, column_names, column_type_names)

    def get_clickhouse_table(self) -> str:
        return "redb_malcontent"

    def extract(self):
        self.log.debug(inspect.currentframe().f_code.co_name)
        try:
            self._extract_malcontent()
            return self.malcontent
        except Exception as e:
            self.log.error(f"Error extracting malcontent: {e}")
            return None

    def tag(self):
        return Tag.MALCONTENT.value