All of lore.kernel.org
 help / color / mirror / Atom feed
* [yocto] [meta-security][PATCH 1/2] image-with-hardened-binaries: add class
       [not found] <378fa893-050e-ccf8-82f8-2c6f8a88f51e@gmail.com>
@ 2021-08-19  6:05 ` Maximilian Blenk
  0 siblings, 0 replies; 5+ messages in thread
From: Maximilian Blenk @ 2021-08-19  6:05 UTC (permalink / raw)
  To: yocto, akuster808, blenkmax; +Cc: Maximilian Blenk

Hi Armin,

sorry for the confusion, this is a resend (had some issues submitting 
the patch via mail and in the end it seems it ended up on the mailing 
list twice)
(and happened again, so i guess you will also get this mail twice :-D 
Hope this is fixed now...)

BR Max

On 18.08.21 23:44, akuster808 wrote:
> Hello Max,
>
>
> On 8/18/21 8:42 AM, Maximilian Blenk via lists.yoctoproject.org wrote:
>> Add class to analyze binaries with checksec.py. checksec.py is a tool
>> that checks if security features of a compiler have been used. To do
>> so, it analyses the resulting binaries:
>> * NX Proctection is enabled
>> * Full RELRO is enabled
>> * RPATH and RUNPATH are not set
>> * Executables are compiled to be position independent
>> * FORTIFY_SOURCE is set (false-positives possible)
>> * Stack Canaries are enabled (false-positives possible)
>>
>> Signed-off-by: Maximilian Blenk <Maximilian.Blenk@bmw.de>
>> ---
>> Hi guys,
>>
>> we are currently working on adding automatically checking the binaries
>> we put into an image for the presence of certain recommended compiler
>> features. To achieve this, we created a bbclass that wraps around the
>> existing project checksec.py (https://github.com/Wenzel/checksec.py). In
>> particular, checksec.py is used to check if
>> * relro is enabled
>> * executables are compiled to be position indipendet code
>> * rpath and runpath are not set
>> * stack canaries are enabled
>> * fortify source is enabled
>> I must however admit that the last two checks can suffer from
>> false-positives which need manual analysis and whitelisting (check can
>> also be completely disabled).
>>
>> Motivation:
>> We've decided that such checks would be a nice thing to have because
>> people might overwrite important compiler flags in their local recipe.
>> Additionally there is always the possibility that components are shipped
>> as binaries instead of code (so they are actually build outside the
>> current build environment). Overall we've detected several cases where
>> required compiler flags have not been applied to shipped components.
>> After internal discussion we came to the conclusion that you guys would
>> maybe also be interested in this kind of checks, so I'm offering this
>> patch to you as well.
> Is this a v2 or a resend?
>
> Thanks for the patch set. I will need some time to take a look at it.
>
> - armin
>> I would really appreciate your feedback :-)
>>
>> BR Max
>>
>> classes/image-with-hardened-binaries.bbclass | 338 ++++++++++++++++++
>> ...1-main-Add-option-to-ignore-symlinks.patch | 81 +++++
>> .../0002-Elf-Fix-relro-detection.patch | 51 +++
>> ...heck-Treat-binaries-with-0-fortifiab.patch | 33 ++
>> ...o-use-pre-compiled-version-of-spdlog.patch | 154 ++++++++
>> .../python/python3-asttokens_2.0.5.bb | 15 +
>> .../python3-checksec.py-native_0.6.1.bb | 31 ++
>> .../python/python3-colorama_%.bbappend | 1 +
>> .../python/python3-commonmark_0.9.1.bb | 14 +
>> .../python/python3-docopt_0.6.2.bb | 18 +
>> .../python/python3-icontract_2.5.3.bb | 14 +
>> .../python/python3-lief_0.11.5.bb | 36 ++
>> .../python/python3-pylddwrap_1.0.1.bb | 21 ++
>> recipes-devtools/python/python3-rich_7.1.0.bb | 16 +
>> .../python/python3-setuptools-scm_6.0.1.bb | 17 +
>> .../python/python3-toml_%.bbappend | 1 +
>> 16 files changed, 841 insertions(+)
>> create mode 100644 classes/image-with-hardened-binaries.bbclass
>> create mode 100644 
>> recipes-devtools/python/files/python3-checksec.py/0001-main-Add-option-to-ignore-symlinks.patch
>> create mode 100644 
>> recipes-devtools/python/files/python3-checksec.py/0002-Elf-Fix-relro-detection.patch
>> create mode 100644 
>> recipes-devtools/python/files/python3-checksec.py/0003-fortify-source-check-Treat-binaries-with-0-fortifiab.patch
>> create mode 100644 
>> recipes-devtools/python/files/python3-lief/0001-Enable-to-use-pre-compiled-version-of-spdlog.patch
>> create mode 100644 recipes-devtools/python/python3-asttokens_2.0.5.bb
>> create mode 100644 
>> recipes-devtools/python/python3-checksec.py-native_0.6.1.bb
>> create mode 100644 recipes-devtools/python/python3-colorama_%.bbappend
>> create mode 100644 recipes-devtools/python/python3-commonmark_0.9.1.bb
>> create mode 100644 recipes-devtools/python/python3-docopt_0.6.2.bb
>> create mode 100644 recipes-devtools/python/python3-icontract_2.5.3.bb
>> create mode 100644 recipes-devtools/python/python3-lief_0.11.5.bb
>> create mode 100644 recipes-devtools/python/python3-pylddwrap_1.0.1.bb
>> create mode 100644 recipes-devtools/python/python3-rich_7.1.0.bb
>> create mode 100644 
>> recipes-devtools/python/python3-setuptools-scm_6.0.1.bb
>> create mode 100644 recipes-devtools/python/python3-toml_%.bbappend
>>
>> diff --git a/classes/image-with-hardened-binaries.bbclass 
>> b/classes/image-with-hardened-binaries.bbclass
>> new file mode 100644
>> index 0000000..d7d3908
>> --- /dev/null
>> +++ b/classes/image-with-hardened-binaries.bbclass
>> @@ -0,0 +1,338 @@
>> +# Provide qa checks to ensure all applications and libraries shipped 
>> with the image
>> +# have common compiler security features enabled. In particular 
>> there are checks that:
>> +# * nx protection is enabled
>> +# * relro is enabled
>> +# * executables (except for static linked ones) are position independent
>> +# * rpath and runpath are not set
>> +
>> +IMAGE_QA_COMMANDS += "image_check_binary_hardening"
>> +
>> +DEPENDS += "python3-checksec.py-native"
>> +
>> +inherit python3native
>> +
>> +# Add mappings to the path mappers (which determines if a binary is 
>> a application or
>> +# shared library). To add a mapping append " 
>> /path/from/the/root/to/bin:{application,library,ignore}"
>> +# to the list
>> +HARDENED_BINARIES_EXTRA_MAPPING ?= ""
>> +
>> +# Config file in TOML format:
>> +# [check]
>> +# enabled = true
>> +# whitelist = [
>> +# "path to some binary",
>> +# "path to some other binary"
>> +# ]
>> +# supported checks are: nx, relro, pie, rpath, runpath
>> +HARDENED_BINARIES_CONFIG_FILE ?= ""
>> +
>> +# Custom message to show in case of a detected violation
>> +# For instace if you want to add whom to contact for support
>> +HARDENED_BINARIES_CUSTOM_ERROR_MESSAGE ?= ""
>> +
>> +# Path to libc used for foritfy source analysis. If fortify_source 
>> check is
>> +# not enabled, this variable can be ignored.
>> +HARDENED_BINARIES_LIBC_PATH ?= "${IMAGE_ROOTFS}${baselib}/libc.so.6"
>> +
>> +python image_check_binary_hardening () {
>> + import fnmatch
>> + import json
>> + import os
>> + import subprocess
>> + import toml
>> + from collections import defaultdict, OrderedDict
>> + from enum import Enum, auto
>> +
>> + from oe.utils import ImageQAFailed
>> +
>> + rootfs = d.getVar("IMAGE_ROOTFS")
>> +
>> + #################################
>> + ## Data about supported checks ##
>> + #################################
>> +
>> + class BinType(Enum):
>> + IGNORE = "ignore"
>> + APPLICATION = "application"
>> + LIBRARY = "library"
>> +
>> + # Dict of checks to perform on the analysis result of checksec.py
>> + # Each entry needs to contain the following attributes:
>> + # - allowed_value: Value in the analysis result that should be accepted
>> + # - bintypes: List of types on which the check shall be enforced 
>> (e.g. PIE check on libraries
>> + # doesn't make much sense because PIE is only for executables)
>> + # - errormsg: Message that should be prompted in case violators 
>> have been found
>> + # - ignore_static: Indicates if statically linked applications 
>> should be ignored for that check
>> + # Notes specific checks:
>> + # - NX: Needs to be enforced on applications and libraries. This is 
>> because if only a single shared
>> + # library doesn't use that, the whole process needs to have a 
>> executable stack.
>> + # - RELRO: Statically linked applications do not make use of 
>> relocation, so this check would always
>> + # fail for statically linked applications.
>> + # - PIE: This check is only valid for applications (as in "position 
>> independent executable" for
>> + # applications vs. "position independent code" (PIC) for shared 
>> libraries)
>> + CHECK_DATA = {
>> + "nx" : {
>> + "allowed_value": True,
>> + "bintypes": [BinType.APPLICATION, BinType.LIBRARY],
>> + "errormsg":
>> + "The following {} binaries do not use nx (not executable) 
>> protection. This mechanism is used " \
>> + "to separate data from executable code. Disabling this mechanism is 
>> a security issue because " \
>> + "this enables attackers to put code onto the stack. Please also 
>> note, if the nx protection is " \
>> + "disabled in a shared library, all binary objects that link against 
>> this library will not be " \
>> + "protected. This message usually appears if your binary is linked 
>> using the \"-z execstack\" " \
>> + "flag.",
>> + "ignore_static": False,
>> + },
>> + "relro": {
>> + "allowed_value": "Full",
>> + "bintypes": [BinType.APPLICATION, BinType.LIBRARY],
>> + "errormsg":
>> + "The following {} binaries do not make use of the relro (relocation 
>> read-only). This feature " \
>> + "prevents attackers from modifying addresses of functions that are 
>> located in shared libraries " \
>> + "(which is a common technique to exploit vulnerabilities). Due to 
>> this, not making use of this " \
>> + "feature is a security issue. Please make sure your application is 
>> linked using " \
>> + "\"-Wl,-z,relro,-z,now\". ",
>> + "ignore_static": True,
>> + },
>> + "rpath": {
>> + "allowed_value": False,
>> + "bintypes": [BinType.APPLICATION, BinType.LIBRARY],
>> + "errormsg":
>> + "The following {} binaries are making use of the rpath feature. 
>> This can easily enable an attacker " \
>> + "to get malicious code executed if there is some issue with the 
>> file permissions at the specified " \
>> + "location. Due to this, the usage of this feature is generally 
>> discouraged and needs approval " \
>> + "by the security team.",
>> + "ignore_static": False,
>> + },
>> + "runpath": {
>> + "allowed_value": False,
>> + "bintypes": [BinType.APPLICATION, BinType.LIBRARY],
>> + "errormsg":
>> + "The following {} binaries are making use of the runpath feature. 
>> This can easily enable an attacker" \
>> + " to get malicious code executed if there is some issue with the 
>> file permissions at the specified " \
>> + "location. Due to this, the usage of this feature is generally 
>> discouraged and needs approval " \
>> + "by the security team.",
>> + "ignore_static": False,
>> + },
>> + "pie": {
>> + "allowed_value": "PIE",
>> + "bintypes": [BinType.APPLICATION],
>> + "errormsg":
>> + "The following {} applications are not compiled to be position 
>> independent executables (pie). This " \
>> + "compiler feature compiles the code in a way that it can be mapped 
>> to any location in the virtual " \
>> + "memory. Compiling the application this way is required to make use 
>> of the Address Space Layout " \
>> + "Randomization (ASLR). This feature maps executable code to a 
>> random location, which means an " \
>> + "attacker can not rely on the fact that a specific portion of code 
>> is mapped to a specific address. " \
>> + "Please ensure that you application is compiled using \"-fPIE\".",
>> + "ignore_static": True,
>> + },
>> + "canary": {
>> + "allowed_value": True,
>> + "bintypes": [BinType.APPLICATION, BinType.LIBRARY],
>> + "errormsg":
>> + "The following {} binaries seem to be not using stack canaries. 
>> These canaries are used to mitigate " \
>> + "stack buffer overflows attacks. To do so the compiler adds checks 
>> to the end of a function to " \
>> + "ensure that this function did not overwrite the stack frames of 
>> another function. Not using " \
>> + "canaries may allow an attacker to exploit stack based buffer 
>> overflows by modifying the stack frame " \
>> + "of other function calls (which simplifies exploiting such 
>> vulnerabilities a lot). Please make sure " \
>> + "your components are compiled with the \"-fstack-protector-strong\" 
>> compile flag. Please note that " \
>> + "there is a slight possibility for false-positives in this check: 
>> The compiler checks if a function " \
>> + "needs canary protection or not. If there is no function that needs 
>> proctedtion in your binary, this " \
>> + "check will fail anyway and the binary needs to be whitelisted.",
>> + "ignore_static": False,
>> + },
>> + "fortify_source": {
>> + "allowed_value": True,
>> + "bintypes": [BinType.APPLICATION, BinType.LIBRARY],
>> + "errormsg":
>> + "The following {} binaries seem to be not using the fortify source 
>> feature. This feature protects " \
>> + "(some, not all) calls to memory manipulations function like 
>> memcpy, strcpy or strcat by adding " \
>> + "checks that prevent buffer overflows. These checks can prevent 
>> attackers from exploiting such a " \
>> + "buffer overflow. Please make sure your component is compiled with 
>> \"-D_FORTIFY_SOURCE=2\". In " \
>> + "addition the compiler optimizations need to be enabled with 
>> \"-O1\" or higher. Please note that " \
>> + "there is a slight possibility for false positives here: Not all 
>> occurences of these mentioned " \
>> + "memory calls that can not be protected they will appear as 
>> if_FORTIFY_SOURCE has not been set. " \
>> + "In such a case the binary needs to be whitelisted.",
>> + "ignore_static": False,
>> + }
>> + }
>> +
>> + #################################
>> + ## Parse data from config file ##
>> + #################################
>> +
>> + config_file = d.getVar("HARDENED_BINARIES_CONFIG_FILE", True)
>> + if not config_file:
>> + msg = "Hardend Binary Check: No config file specifed. Please create 
>> a config file and set " \
>> + "the variable \"HARDENED_BINARIES_CONFIG_FILE\" accordingly"
>> + raise ImageQAFailed(msg, image_check_binary_hardening)
>> +
>> + CHECK_CONFIG_DATA = defaultdict(lambda: {"enabled": False})
>> + CHECK_CONFIG_DATA.update(toml.load(config_file))
>> +
>> + # Expand whitelisted paths with rootfs
>> + for check, values in CHECK_CONFIG_DATA.items():
>> + values["whitelist"] = [rootfs + x for x in values["whitelist"]]
>> +
>> + ###############################################
>> + ## Classes and functions to perform analysis ##
>> + ###############################################
>> +
>> + class PathMapping:
>> + """ Class to map paths to BinTypes """
>> + def __init__(self, rootfs):
>> + self.rootfs = rootfs
>> + self.mapping = OrderedDict()
>> +
>> + self.add("/bin/*", BinType.APPLICATION)
>> + self.add("/lib/firmware/*", BinType.IGNORE)
>> + self.add("/lib/modules/*", BinType.IGNORE)
>> + self.add("/lib/systemd/*.so", BinType.LIBRARY)
>> + self.add("/lib/systemd/*", BinType.APPLICATION)
>> + self.add("/lib/*", BinType.LIBRARY)
>> + self.add("/sbin/*", BinType.APPLICATION)
>> + self.add("/usr/bin/*", BinType.APPLICATION)
>> + self.add("/usr/libexec/*", BinType.APPLICATION)
>> + self.add("/usr/lib/firmware/*", BinType.IGNORE)
>> + self.add("/usr/lib/modules/*", BinType.IGNORE)
>> + self.add("/usr/lib/systemd/*.so", BinType.LIBRARY)
>> + self.add("/usr/lib/systemd/*", BinType.APPLICATION)
>> + self.add("/usr/lib/*", BinType.LIBRARY)
>> + self.add("/usr/sbin/*", BinType.APPLICATION)
>> +
>> +
>> + def add(self, path, bin_type):
>> + """ Add mapping of a path to a FileyType """
>> + self.mapping[self.rootfs + path] = bin_type
>> +
>> + def map(self, path):
>> + """ Map a path to a FilesType. Returns None if path can not be 
>> mapped. """
>> + for match_path, bin_type in self.mapping.items():
>> + if fnmatch.fnmatch(path, match_path):
>> + return bin_type
>> + else:
>> + return None
>> +
>> + def call_checksec(rootfs):
>> + """ Wrapper to call the checksec.py script
>> +
>> + This function returns a list of result dicts, e.g.:
>> + [
>> + ...,
>> + "/bin/systemd-hwdb": {
>> + "relro": "No",
>> + "canary": true,
>> + "nx": true,
>> + "pie": "PIE",
>> + "rpath": false,
>> + "runpath": false,
>> + "symbols": false,
>> + "fortify_source": true,
>> + "fortified": 5,
>> + "fortify-able": 16,
>> + "fortify_score": 31
>> + }
>> + ]
>> +
>> + """
>> + parallel_make = d.getVar("PARALLEL_MAKE")
>> +
>> + cmd = ["python3", "-m", "checksec", "--json", "--recursive", 
>> "--ignore-symlinks"]
>> + if parallel_make:
>> + cmd.append(parallel_make.replace("-j", "--workers="))
>> + if CHECK_CONFIG_DATA["foritfy_source"]["enabled"]:
>> + libc_path = d.getVar("HARDENED_BINARIES_LIBC_PATH", True)
>> + cmd.append("--set-libc={}".format(libc_path))
>> + cmd.append(rootfs)
>> +
>> + return json.loads(subprocess.check_output(cmd).decode('utf-8'))
>> +
>> +
>> + class ResultAnalyzer:
>> + """ Class to evaluate the results produced by checksec.py """
>> + def __init__(self, rootfs):
>> + self.rootfs = rootfs
>> + self.violators = defaultdict(list)
>> +
>> + @staticmethod
>> + def __is_static(path):
>> + """ Checks if binary at given path is statically linked """
>> + return "statically linked" in subprocess.check_output(["file", 
>> path], stderr=subprocess.STDOUT).decode('utf-8')
>> +
>> + def check_result(self, path, result, bintype):
>> + """ Perfom checks specified in CHECK_DATA on the given analysis 
>> result (of a specific binary) """
>> +
>> + for check, values in CHECK_DATA.items():
>> + if CHECK_CONFIG_DATA[check]["enabled"] and bintype in 
>> values["bintypes"]:
>> + for whitelisted in CHECK_CONFIG_DATA[check]["whitelist"]:
>> + if fnmatch.fnmatch(path, whitelisted):
>> + break
>> + else:
>> + if result[check] != values["allowed_value"] and \
>> + (not values["ignore_static"] or not self.__is_static(path)):
>> + self.violators[check].append(path)
>> +
>> +
>> + def perform_analysis(rootfs):
>> + """ Analyze all binaries in a given rootfs. In case a container 
>> shall be analyzed the absolute path to the container_path
>> + rootfs needs to be passed.
>> + """
>> +
>> + # Add custom path mapping (for bins in non-standard locations)
>> + path_mapping = PathMapping(rootfs)
>> + extra_mapping = d.getVar("HARDENED_BINARIES_EXTRA_MAPPING")
>> + if extra_mapping:
>> + for mapping in extra_mapping.split():
>> + try:
>> + path, type = mapping.split(':')
>> + except:
>> + bb.error("Hardened Binary Checks: Got misformated extra mapping {}. 
>> Mapping needs to be " \
>> + "in form: \"<path 
>> regex>:{application,library,ignore}\"".format(mapping))
>> + raise
>> + path_mapping.add(path, BinType(type))
>> +
>> + # Perform analysis of complete rootfs
>> + analysis_result = call_checksec(rootfs)
>> +
>> + # Check analysis results and ensure that all we can actually map 
>> all binaries to a BinType
>> + result_analyzer = ResultAnalyzer(rootfs)
>> + unmapped_binaries = []
>> + for path, result in analysis_result.items():
>> + bintype = path_mapping.map(path)
>> + if bintype in [BinType.APPLICATION, BinType.LIBRARY]:
>> + result_analyzer.check_result(path, result, bintype)
>> + elif bintype != BinType.IGNORE:
>> + unmapped_binaries.append(path)
>> +
>> + # To ensure that we analyze all the binaries lets break the build 
>> if we can not map binaries
>> + if unmapped_binaries:
>> + msg = "Hardend Binary Check: Couldn't figure out if the following 
>> files are applications " \
>> + "or libraries. This is probably due to a non standard location for 
>> applications or " \
>> + "libraries. If you think this is required add the mapping to " \
>> + "HARDENED_BINARIES_EXTRA_MAPPING and/or contact 
>> mgu-security-frontdesk@list.bmw.com" \
>> + "\nUnmapped:\n{}".format("\n".join(unmapped_binaries),
>> + image_check_binary_hardening)
>> + raise ImageQAFailed(msg, image_check_binary_hardening)
>> +
>> + custom_error_message = 
>> d.getVar('HARDENED_BINARIES_CUSTOM_ERROR_MESSAGE')
>> +
>> + # Break the build and show error message if we detected violators 
>> that are not whitelisted
>> + errors = []
>> + for check, violators in result_analyzer.violators.items():
>> + if violators:
>> + errormsg = CHECK_DATA[check]["errormsg"].format(len(violators))
>> + errormsg += "\n{}".format("\n".join(violators))
>> + if custom_error_message:
>> + errormsg += "\n" + custom_error_message
>> + errors.append(errormsg)
>> +
>> + if errors:
>> + raise ImageQAFailed("\n".join(errors), image_check_binary_hardening)
>> +
>> + ##############################
>> + ## Start analysis on rootfs ##
>> + ##############################
>> +
>> + perform_analysis(rootfs)
>> +
>> +}
>> diff --git 
>> a/recipes-devtools/python/files/python3-checksec.py/0001-main-Add-option-to-ignore-symlinks.patch 
>> b/recipes-devtools/python/files/python3-checksec.py/0001-main-Add-option-to-ignore-symlinks.patch
>> new file mode 100644
>> index 0000000..ae434bc
>> --- /dev/null
>> +++ 
>> b/recipes-devtools/python/files/python3-checksec.py/0001-main-Add-option-to-ignore-symlinks.patch
>> @@ -0,0 +1,81 @@
>> +From 182268203951750dcfb2c134354e801dea472e4c Mon Sep 17 00:00:00 2001
>> +From: Maximilian Blenk <Maximilian.Blenk@bmw.de>
>> +Date: Fri, 2 Jul 2021 14:42:25 +0200
>> +Subject: [PATCH 1/2] main: Add option to ignore symlinks
>> +
>> +When analyzing a complete rootfs (which might not be the rootfs of the
>> +analyzing system) symlinks within that rootfs might be broken. In
>> +particular absolute symlinks. However, if by chance such a symlink
>> +currently points to a valid binary in your system, this binary pointed
>> +to is analyzed. This commit adds the possibility to ignore symlinks to
>> +files (symlinks to dirs are already ignored by default). This allows to
>> +solve the issue described above, and if the whole rootfs is analyzed
>> +there shouldn't be a loss of information (because all the binaries will
>> +be analyzed anyway). Additionally, this also saves some time when
>> +performing the analysis.
>> +
>> +Upstream-Status: Submitted 
>> https://github.com/Wenzel/checksec.py/pull/106
>> +---
>> + checksec/__main__.py | 12 +++++++-----
>> + 1 file changed, 7 insertions(+), 5 deletions(-)
>> +
>> +diff --git a/checksec/__main__.py b/checksec/__main__.py
>> +index 856d0b3..f1a3445 100644
>> +--- a/checksec/__main__.py
>> ++++ b/checksec/__main__.py
>> +@@ -8,6 +8,7 @@ Options:
>> + -w WORKERS --workers=WORKERS Specify the number of process pool 
>> workers [default: 4]
>> + -j --json Display results as JSON
>> + -s LIBC --set-libc=LIBC Specify LIBC library to use to check for 
>> fortify scores (ELF)
>> ++ -i --ignore-symlinks Ignore symlinks to files
>> + -d --debug Enable debug output
>> + -h --help Display this message
>> + """
>> +@@ -27,15 +28,15 @@ from .pe import PEChecksecData, PESecurity, is_pe
>> + from .utils import lief_set_logging
>> +
>> +
>> +-def walk_filepath_list(filepath_list: List[Path], recursive: bool = 
>> False) -> Iterator[Path]:
>> ++def walk_filepath_list(filepath_list: List[Path], recursive: bool = 
>> False, ignore_symlinks: bool = False) -> Iterator[Path]:
>> + for path in filepath_list:
>> + if path.is_dir() and not path.is_symlink():
>> + if recursive:
>> + for f in os.scandir(path):
>> +- yield from walk_filepath_list([Path(f)], recursive)
>> ++ yield from walk_filepath_list([Path(f)], recursive, ignore_symlinks)
>> + else:
>> + yield from (Path(f) for f in os.scandir(path))
>> +- elif path.is_file():
>> ++ elif path.is_file() and (not ignore_symlinks or not 
>> path.is_symlink()):
>> + yield path
>> +
>> +
>> +@@ -72,6 +73,7 @@ def main(args):
>> + json = args["--json"]
>> + recursive = args["--recursive"]
>> + libc_path = args["--set-libc"]
>> ++ ignore_symlinks = args["--ignore-symlinks"]
>> +
>> + # logging
>> + formatter = "%(asctime)s %(levelname)s:%(name)s:%(message)s"
>> +@@ -107,7 +109,7 @@ def main(args):
>> + # we need to consume the iterator once to get the total
>> + # for the progress bar
>> + check_output.enumerating_tasks_start()
>> +- count = sum(1 for i in walk_filepath_list(filepath_list, recursive))
>> ++ count = sum(1 for i in walk_filepath_list(filepath_list, 
>> recursive, ignore_symlinks))
>> + check_output.enumerating_tasks_stop(count)
>> + with ProcessPoolExecutor(
>> + max_workers=workers, initializer=worker_initializer, 
>> initargs=(libc_path,)
>> +@@ -116,7 +118,7 @@ def main(args):
>> + check_output.processing_tasks_start()
>> + future_to_checksec = {
>> + pool.submit(checksec_file, filepath): filepath
>> +- for filepath in walk_filepath_list(filepath_list, recursive)
>> ++ for filepath in walk_filepath_list(filepath_list, recursive, 
>> ignore_symlinks)
>> + }
>> + for future in as_completed(future_to_checksec):
>> + filepath = future_to_checksec[future]
>> +--
>> +2.31.1
>> +
>> diff --git 
>> a/recipes-devtools/python/files/python3-checksec.py/0002-Elf-Fix-relro-detection.patch 
>> b/recipes-devtools/python/files/python3-checksec.py/0002-Elf-Fix-relro-detection.patch
>> new file mode 100644
>> index 0000000..a891c2b
>> --- /dev/null
>> +++ 
>> b/recipes-devtools/python/files/python3-checksec.py/0002-Elf-Fix-relro-detection.patch
>> @@ -0,0 +1,51 @@
>> +From f550777f35e178bc16a2ec612b2b39aa2c3946f2 Mon Sep 17 00:00:00 2001
>> +From: Maximilian Blenk <Maximilian.Blenk@bmw.de>
>> +Date: Fri, 2 Jul 2021 16:16:47 +0200
>> +Subject: [PATCH 2/2] Elf: Fix relro detection
>> +
>> +Currently, relro is only detected when the BIND_NOW is set. If however
>> +the NOW flag in the FLAGS_1 section is set, relro is not detected (it
>> +does not even tell that relro is enabled partially). With this commit
>> +relro is detected correctly.
>> +
>> +Upstream-Status: Submitted 
>> https://github.com/Wenzel/checksec.py/pull/107
>> +---
>> + checksec/elf.py | 19 +++++++++++++++----
>> + 1 file changed, 15 insertions(+), 4 deletions(-)
>> +
>> +diff --git a/checksec/elf.py b/checksec/elf.py
>> +index 78ecacc..ef1850c 100644
>> +--- a/checksec/elf.py
>> ++++ b/checksec/elf.py
>> +@@ -118,13 +118,24 @@ class ELFSecurity(BinarySecurity):
>> + def relro(self) -> RelroType:
>> + try:
>> + self.bin.get(lief.ELF.SEGMENT_TYPES.GNU_RELRO)
>> +- if lief.ELF.DYNAMIC_FLAGS.BIND_NOW in 
>> self.bin.get(lief.ELF.DYNAMIC_TAGS.FLAGS):
>> +- return RelroType.Full
>> +- else:
>> +- return RelroType.Partial
>> + except lief.not_found:
>> + return RelroType.No
>> +
>> ++ try:
>> ++ bind_now = lief.ELF.DYNAMIC_FLAGS.BIND_NOW in 
>> self.bin.get(lief.ELF.DYNAMIC_TAGS.FLAGS)
>> ++ except lief.not_found:
>> ++ bind_now = False
>> ++
>> ++ try:
>> ++ now = lief.ELF.DYNAMIC_FLAGS_1.NOW in 
>> self.bin.get(lief.ELF.DYNAMIC_TAGS.FLAGS_1)
>> ++ except lief.not_found:
>> ++ now = False
>> ++
>> ++ if bind_now or now:
>> ++ return RelroType.Full
>> ++ else:
>> ++ return RelroType.Partial
>> ++
>> + @property
>> + def has_canary(self) -> bool:
>> + canary_sections = ["__stack_chk_fail", "__intel_security_cookie"]
>> +--
>> +2.31.1
>> +
>> diff --git 
>> a/recipes-devtools/python/files/python3-checksec.py/0003-fortify-source-check-Treat-binaries-with-0-fortifiab.patch 
>> b/recipes-devtools/python/files/python3-checksec.py/0003-fortify-source-check-Treat-binaries-with-0-fortifiab.patch
>> new file mode 100644
>> index 0000000..0351f84
>> --- /dev/null
>> +++ 
>> b/recipes-devtools/python/files/python3-checksec.py/0003-fortify-source-check-Treat-binaries-with-0-fortifiab.patch
>> @@ -0,0 +1,33 @@
>> +From 8de048c0065f8c5890d9e04ef2b32306e2ac4f8c Mon Sep 17 00:00:00 2001
>> +From: Maximilian Blenk <Maximilian.Blenk@bmw.de>
>> +Date: Thu, 5 Aug 2021 15:21:58 +0200
>> +Subject: [PATCH] fortify source check: Treat binaries with 0 
>> fortifiable as
>> + fortified
>> +
>> +Currently, if checksec.py detects 0 fortifiable instances it still
>> +treats the binary as not fortified. Semtically it would make sense to
>> +treat these binaries as fortified (because there is no evidence that it
>> +is not)
>> +
>> +Upstream-Status: Submitted 
>> https://github.com/Wenzel/checksec.py/pull/109
>> +---
>> + checksec/elf.py | 3 +--
>> + 1 file changed, 1 insertion(+), 2 deletions(-)
>> +
>> +diff --git a/checksec/elf.py b/checksec/elf.py
>> +index ef1850c..5914135 100644
>> +--- a/checksec/elf.py
>> ++++ b/checksec/elf.py
>> +@@ -229,8 +229,7 @@ class ELFSecurity(BinarySecurity):
>> + else:
>> + score = (fortified_count * 100) / fortifiable_count
>> + score = round(score)
>> +-
>> +- fortify_source = True if fortified_count != 0 else False
>> ++ fortify_source = True if fortified_count != 0 or fortifiable_count 
>> == 0 else False
>> + return ELFChecksecData(
>> + relro=self.relro,
>> + canary=self.has_canary,
>> +--
>> +2.31.1
>> +
>> diff --git 
>> a/recipes-devtools/python/files/python3-lief/0001-Enable-to-use-pre-compiled-version-of-spdlog.patch 
>> b/recipes-devtools/python/files/python3-lief/0001-Enable-to-use-pre-compiled-version-of-spdlog.patch
>> new file mode 100644
>> index 0000000..af94cfa
>> --- /dev/null
>> +++ 
>> b/recipes-devtools/python/files/python3-lief/0001-Enable-to-use-pre-compiled-version-of-spdlog.patch
>> @@ -0,0 +1,154 @@
>> +From d2ad8f6108c750c3dbd33ee6d4e4c94ada748b8a Mon Sep 17 00:00:00 2001
>> +From: Romain Thomas <me@romainthomas.fr>
>> +Date: Mon, 3 May 2021 11:25:49 +0200
>> +Subject: [PATCH] Enable to use pre-compiled version of spdlog
>> +
>> +---
>> + CMakeLists.txt | 8 ++++----
>> + cmake/LIEFDependencies.cmake | 36 +++++++++++++++++++++++-------------
>> + cmake/LIEFOptions.cmake | 4 ++++
>> + setup.py | 17 +++++++++++++++++
>> + 4 files changed, 48 insertions(+), 17 deletions(-)
>> +
>> +diff --git a/CMakeLists.txt b/CMakeLists.txt
>> +index d1665cd..b92519a 100644
>> +--- a/CMakeLists.txt
>> ++++ b/CMakeLists.txt
>> +@@ -307,8 +307,7 @@ source_group("mbedtls\\tls" FILES 
>> ${mbedtls_src_tls})
>> + # Library definition
>> + # ==================
>> + target_include_directories(
>> +- LIB_LIEF SYSTEM PRIVATE "${SPDLOG_SOURCE_DIR}/include"
>> +- "${MBEDTLS_INCLUDE_DIRS}")
>> ++ LIB_LIEF SYSTEM PRIVATE "${MBEDTLS_INCLUDE_DIRS}")
>> +
>> + target_include_directories(
>> + LIB_LIEF
>> +@@ -355,7 +354,8 @@ target_sources(LIB_LIEF PRIVATE
>> + ${CMAKE_CURRENT_BINARY_DIR}/include/LIEF/third-party/utfcpp/utf8.h)
>> +
>> +
>> +-add_dependencies(LIB_LIEF lief_spdlog lief_mbed_tls)
>> ++add_dependencies(LIB_LIEF lief_mbed_tls)
>> ++target_link_libraries(LIB_LIEF PRIVATE lief_spdlog)
>> +
>> + # Flags definition
>> + # ----------------
>> +@@ -626,7 +626,7 @@ install(
>> + DESTINATION lib/pkgconfig
>> + COMPONENT libraries)
>> +
>> +-export(TARGETS LIB_LIEF FILE LIEFExport.cmake)
>> ++export(TARGETS LIB_LIEF lief_spdlog FILE LIEFExport.cmake)
>> +
>> + # Package
>> + # ======================
>> +diff --git a/cmake/LIEFDependencies.cmake b/cmake/LIEFDependencies.cmake
>> +index e75326f..37e6987 100644
>> +--- a/cmake/LIEFDependencies.cmake
>> ++++ b/cmake/LIEFDependencies.cmake
>> +@@ -144,21 +144,31 @@ set(mbedtls_src_tls
>> + "${MBEDTLS_SOURCE_DIR}/library/ssl_tls13_keys.c"
>> + )
>> +
>> +-#set_source_files_properties("${MBEDTLS_SOURCE_DIR}/library/bignum.c" 
>> PROPERTIES COMPILE_FLAGS -Wno-overlength-strings)
>> ++add_library(lief_spdlog INTERFACE)
>> +
>> +-set(SPDLOG_VERSION 1.8.2)
>> +-set(SPDLOG_SHA256 
>> SHA256=f0410b12b526065802b40db01304783550d3d20b4b6fe2f8da55f9d08ed2035d)
>> +-set(SPDLOG_URL 
>> "${THIRD_PARTY_DIRECTORY}/spdlog-${SPDLOG_VERSION}.zip" CACHE STRING 
>> "URL to the spdlog lib repo")
>> +-ExternalProject_Add(lief_spdlog
>> +- URL ${SPDLOG_URL}
>> +- URL_HASH ${SPDLOG_SHA256}
>> +- CONFIGURE_COMMAND ""
>> +- BUILD_COMMAND ""
>> +- UPDATE_COMMAND ""
>> +- INSTALL_COMMAND "")
>> ++if(LIEF_EXTERNAL_SPDLOG)
>> ++ find_package(spdlog REQUIRED)
>> ++ list(APPEND CMAKE_MODULE_PATH "${SPDLOG_DIR}/cmake")
>> ++ target_link_libraries(lief_spdlog INTERFACE spdlog::spdlog)
>> ++ get_target_property(SPDLOG_INC_DIR spdlog::spdlog 
>> INTERFACE_INCLUDE_DIRECTORIES)
>> ++ target_include_directories(lief_spdlog SYSTEM INTERFACE 
>> ${SPDLOG_INC_DIR})
>> ++else()
>> ++ set(SPDLOG_VERSION 1.8.2)
>> ++ set(SPDLOG_SHA256 
>> SHA256=f0410b12b526065802b40db01304783550d3d20b4b6fe2f8da55f9d08ed2035d)
>> ++ set(SPDLOG_URL 
>> "${THIRD_PARTY_DIRECTORY}/spdlog-${SPDLOG_VERSION}.zip" CACHE STRING 
>> "URL to the spdlog source")
>> ++ ExternalProject_Add(lief_spdlog_project
>> ++ URL ${SPDLOG_URL}
>> ++ URL_HASH ${SPDLOG_SHA256}
>> ++ CONFIGURE_COMMAND ""
>> ++ BUILD_COMMAND ""
>> ++ UPDATE_COMMAND ""
>> ++ INSTALL_COMMAND "")
>> +
>> +-ExternalProject_get_property(lief_spdlog SOURCE_DIR)
>> +-set(SPDLOG_SOURCE_DIR "${SOURCE_DIR}")
>> ++ ExternalProject_get_property(lief_spdlog_project SOURCE_DIR)
>> ++ set(SPDLOG_SOURCE_DIR "${SOURCE_DIR}")
>> ++ add_dependencies(lief_spdlog lief_spdlog_project)
>> ++ target_include_directories(lief_spdlog SYSTEM INTERFACE 
>> ${SPDLOG_SOURCE_DIR}/include)
>> ++endif()
>> +
>> + # Fuzzing
>> + # ~~~~~~~
>> +diff --git a/cmake/LIEFOptions.cmake b/cmake/LIEFOptions.cmake
>> +index fd6df6c..3bb92c3 100644
>> +--- a/cmake/LIEFOptions.cmake
>> ++++ b/cmake/LIEFOptions.cmake
>> +@@ -45,6 +45,10 @@ option(LIEF_PROFILING "Enable performance 
>> profiling" OFF)
>> + cmake_dependent_option(LIEF_INSTALL_COMPILED_EXAMPLES "Install LIEF 
>> Compiled examples" OFF
>> + "LIEF_EXAMPLES" OFF)
>> +
>> ++# Use a user-provided version of spdlog
>> ++# It can be useful to reduce compile time
>> ++option(LIEF_EXTERNAL_SPDLOG OFF)
>> ++
>> + set(LIEF_ELF_SUPPORT 0)
>> + set(LIEF_PE_SUPPORT 0)
>> + set(LIEF_MACHO_SUPPORT 0)
>> +diff --git a/setup.py b/setup.py
>> +index b915180..ad70bd8 100644
>> +--- a/setup.py
>> ++++ b/setup.py
>> +@@ -45,6 +45,10 @@ class LiefDistribution(setuptools.Distribution):
>> + ('lief-no-vdex', None, 'Disable VDEX module'),
>> + ('lief-no-oat', None, 'Disable OAT module'),
>> + ('lief-no-dex', None, 'Disable DEX module'),
>> ++
>> ++ ('lief-no-cache', None, 'Do not use compiler cache (ccache)'),
>> ++
>> ++ ('spdlog-dir=', None, 'Path to the directory that contains 
>> spdlogConfig.cmake'),
>> + ]
>> +
>> + def __init__(self, attrs=None):
>> +@@ -66,6 +70,10 @@ class LiefDistribution(setuptools.Distribution):
>> +
>> + self.lief_no_android = False
>> + self.doc = False
>> ++
>> ++ self.lief_no_cache = False
>> ++
>> ++ self.spdlog_dir = None
>> + super().__init__(attrs)
>> +
>> +
>> +@@ -154,6 +162,15 @@ class BuildLibrary(build_ext):
>> + else:
>> + cmake_args += ["-DLIEF_LOGGING_DEBUG=off"]
>> +
>> ++ if self.distribution.lief_no_cache:
>> ++ cmake_args += ["-DLIEF_USE_CCACHE=off"]
>> ++
>> ++ # Setup spdlog configuration flags if
>> ++ # the user provides --spdlog-dir
>> ++ if self.distribution.spdlog_dir is not None:
>> ++ cmake_args.append("-DLIEF_EXTERNAL_SPDLOG=ON")
>> ++ 
>> cmake_args.append("-Dspdlog_DIR={}".format(self.distribution.spdlog_dir))
>> ++
>> + # Main formats
>> + # ============
>> + if self.distribution.lief_no_elf:
>> +--
>> +2.31.1
>> +
>> diff --git a/recipes-devtools/python/python3-asttokens_2.0.5.bb 
>> b/recipes-devtools/python/python3-asttokens_2.0.5.bb
>> new file mode 100644
>> index 0000000..7ac2052
>> --- /dev/null
>> +++ b/recipes-devtools/python/python3-asttokens_2.0.5.bb
>> @@ -0,0 +1,15 @@
>> +SUMMARY = "Annotate AST trees with source code positions"
>> +HOMEPAGE = "https://github.com/gristlabs/asttokens"
>> +AUTHOR = "Dmitry Sagalovskiy, Grist Labs <dmitry@getgrist.com>"
>> +LICENSE = "Apache-2.0"
>> +LIC_FILES_CHKSUM = "file://LICENSE;md5=e3fc50a88d0a364313df4b21ef20c29e"
>> +
>> +SRC_URI[md5sum] = "0a2a057b9c9a220bffdb3e7512062f17"
>> +SRC_URI[sha256sum] = 
>> "9a54c114f02c7a9480d56550932546a3f1fe71d8a02f1bc7ccd0ee3ee35cf4d5"
>> +
>> +RDEPENDS_${PN} = "python3-six"
>> +DEPENDS += "python3-setuptools-scm python3-toml"
>> +
>> +inherit pypi setuptools3
>> +
>> +BBCLASSEXTEND += "native"
>> diff --git 
>> a/recipes-devtools/python/python3-checksec.py-native_0.6.1.bb 
>> b/recipes-devtools/python/python3-checksec.py-native_0.6.1.bb
>> new file mode 100644
>> index 0000000..edce0a6
>> --- /dev/null
>> +++ b/recipes-devtools/python/python3-checksec.py-native_0.6.1.bb
>> @@ -0,0 +1,31 @@
>> +SUMMARY = "Tool to verify the security properties of binaries"
>> +DESCRIPTION = "checksec.py is a tool verify if certain compiler flags \
>> + have been enabled on compield applications and libraries."
>> +HOMEPAGE = "https://github.com/Wenzel/checksec.py"
>> +BUGTRACKER = "https://github.com/Wenzel/checksec.py/issues"
>> +SECTION = "devel/python"
>> +
>> +LICENSE = "GPL-3.0"
>> +LIC_FILES_CHKSUM = "file://LICENSE;md5=1ebbd3e34237af26da5dc08a4e440464"
>> +
>> +RDEPENDS_${PN} += " \
>> + python3-docopt-native \
>> + python3-lief-native \
>> + python3-pylddwrap-native \
>> + python3-rich-native \
>> + "
>> +
>> +# Needs to be pulled from github becuase pypi package is currently 
>> broken
>> +SRC_URI = " \
>> + git://github.com/Wenzel/checksec.py.git;protocol=https;branch=master \
>> + 
>> file://python3-checksec.py/0001-main-Add-option-to-ignore-symlinks.patch 
>> \
>> + file://python3-checksec.py/0002-Elf-Fix-relro-detection.patch \
>> + 
>> file://python3-checksec.py/0003-fortify-source-check-Treat-binaries-with-0-fortifiab.patch 
>> \
>> + "
>> +
>> +SRCREV = "4335ecd08f6ee13ff4ca9b01e83857ae6a8074e9"
>> +
>> +S="${WORKDIR}/git"
>> +
>> +inherit setuptools3 native
>> +
>> diff --git a/recipes-devtools/python/python3-colorama_%.bbappend 
>> b/recipes-devtools/python/python3-colorama_%.bbappend
>> new file mode 100644
>> index 0000000..d6f5869
>> --- /dev/null
>> +++ b/recipes-devtools/python/python3-colorama_%.bbappend
>> @@ -0,0 +1 @@
>> +BBCLASSEXTEND += "native"
>> diff --git a/recipes-devtools/python/python3-commonmark_0.9.1.bb 
>> b/recipes-devtools/python/python3-commonmark_0.9.1.bb
>> new file mode 100644
>> index 0000000..a35abc3
>> --- /dev/null
>> +++ b/recipes-devtools/python/python3-commonmark_0.9.1.bb
>> @@ -0,0 +1,14 @@
>> +SUMMARY = "Python parser for the CommonMark Markdown spec"
>> +HOMEPAGE = "https://github.com/rtfd/commonmark.py"
>> +AUTHOR = "Bibek Kafle <bkafle662@gmail.com>, Roland Shoemaker 
>> <rolandshoemaker@gmail.com>"
>> +LICENSE = "BSD-3-Clause"
>> +LIC_FILES_CHKSUM = "file://LICENSE;md5=37e127eb75a030780aefcfc584e78523"
>> +
>> +SRC_URI[md5sum] = "cd1dc70c4714d9ed4117a40490c25e00"
>> +SRC_URI[sha256sum] = 
>> "452f9dc859be7f06631ddcb328b6919c67984aca654e5fefb3914d54691aed60"
>> +
>> +S = "${WORKDIR}/commonmark-0.9.1"
>> +
>> +inherit pypi setuptools3
>> +
>> +BBCLASSEXTEND += "native"
>> diff --git a/recipes-devtools/python/python3-docopt_0.6.2.bb 
>> b/recipes-devtools/python/python3-docopt_0.6.2.bb
>> new file mode 100644
>> index 0000000..c1b111a
>> --- /dev/null
>> +++ b/recipes-devtools/python/python3-docopt_0.6.2.bb
>> @@ -0,0 +1,18 @@
>> +
>> +SUMMARY = "Pythonic argument parser, that will make you smile"
>> +HOMEPAGE = "http://docopt.org"
>> +AUTHOR = "Vladimir Keleshev <vladimir@keleshev.com>"
>> +LICENSE = "MIT"
>> +LIC_FILES_CHKSUM = 
>> "file://LICENSE-MIT;md5=09b77fb74986791a3d4a0e746a37d88f"
>> +
>> +SRC_URI = 
>> "https://github.com/docopt/docopt/archive/refs/tags/${PV}.tar.gz"
>> +SRC_URI[md5sum] = "a6c44155426fd0f7def8b2551d02fef6"
>> +SRC_URI[sha256sum] = 
>> "2113eed1e7fbbcd43fb7ee6a977fb02d0b482753586c9dc1a8e3b7d541426e99"
>> +
>> +S = "${WORKDIR}/docopt-0.6.2"
>> +
>> +RDEPENDS_${PN} = ""
>> +
>> +inherit setuptools3
>> +
>> +BBCLASSEXTEND += "native"
>> diff --git a/recipes-devtools/python/python3-icontract_2.5.3.bb 
>> b/recipes-devtools/python/python3-icontract_2.5.3.bb
>> new file mode 100644
>> index 0000000..88ac2ef
>> --- /dev/null
>> +++ b/recipes-devtools/python/python3-icontract_2.5.3.bb
>> @@ -0,0 +1,14 @@
>> +SUMMARY = "Provide design-by-contract with informative violation 
>> messages."
>> +HOMEPAGE = "https://github.com/Parquery/icontract"
>> +AUTHOR = "Marko Ristin <marko.ristin@gmail.com>"
>> +LICENSE = "MIT"
>> +LIC_FILES_CHKSUM = 
>> "file://LICENSE.txt;md5=1d4a9b1f6b84bedf7a38843931e0dd57"
>> +
>> +SRC_URI[md5sum] = "6f41b9b84e4405374c160836587b3235"
>> +SRC_URI[sha256sum] = 
>> "b790101c8cc0d9df0105d852a645373c4d90d5049391b6e54db32a0acb4bccd7"
>> +
>> +inherit pypi setuptools3
>> +
>> +RDEPENDS_${PN} += "python3-asttokens"
>> +
>> +BBCLASSEXTEND += "native"
>> diff --git a/recipes-devtools/python/python3-lief_0.11.5.bb 
>> b/recipes-devtools/python/python3-lief_0.11.5.bb
>> new file mode 100644
>> index 0000000..5e4b422
>> --- /dev/null
>> +++ b/recipes-devtools/python/python3-lief_0.11.5.bb
>> @@ -0,0 +1,36 @@
>> +SUMMARY = "Library to instrument executable formats"
>> +DESCRIPTION = " \
>> + This project provides a cross platform library which can parse, 
>> modify \
>> + and abstract ELF, PE and MachO formats. \
>> + "
>> +SECTION = "devel/python"
>> +HOMEPAGE = "https://github.com/lief-project/LIEF"
>> +LICENSE = "APACHE-2.0"
>> +LIC_FILES_CHKSUM = "file://LICENSE;md5=1809bd489c3dae63aa0cb70070dc308e"
>> +
>> +SRC_URI = " \
>> + 
>> https://github.com/lief-project/LIEF/releases/download/${PV}/lief-${PV}.zip 
>> \
>> + 
>> file://python3-lief/0001-Enable-to-use-pre-compiled-version-of-spdlog.patch 
>> \
>> + "
>> +SRC_URI[sha256sum] = 
>> "947825134d5dab91df218bb201fa4551814f1da0a47e4a890283716b800c8e8f"
>> +
>> +S = "${WORKDIR}/lief-${PV}"
>> +
>> +inherit setuptools3
>> +
>> +DEPENDS += "cmake-native"
>> +
>> +BBCLASSEXTEND += "native"
>> +
>> +DISTUTILS_BUILD_ARGS += " ${PARALLEL_MAKE} "
>> +
>> +do_compile() {
>> + # From distutils3.bbclass (needs to be modified here to avoid usage 
>> of ccache)
>> + cd ${DISTUTILS_SETUP_PATH}
>> + NO_FETCH_BUILD=1 \
>> + STAGING_INCDIR=${STAGING_INCDIR} \
>> + STAGING_LIBDIR=${STAGING_LIBDIR} \
>> + ${STAGING_BINDIR_NATIVE}/${PYTHON_PN}-native/${PYTHON_PN} setup.py \
>> + --lief-no-cache build --build-base=${B} ${DISTUTILS_BUILD_ARGS} || \
>> + bbfatal_log "'${PYTHON_PN} setup.py --lief-no-cache build 
>> ${DISTUTILS_BUILD_ARGS}' execution failed."
>> +}
>> diff --git a/recipes-devtools/python/python3-pylddwrap_1.0.1.bb 
>> b/recipes-devtools/python/python3-pylddwrap_1.0.1.bb
>> new file mode 100644
>> index 0000000..985c424
>> --- /dev/null
>> +++ b/recipes-devtools/python/python3-pylddwrap_1.0.1.bb
>> @@ -0,0 +1,21 @@
>> +SUMMARY = "Python wrapper for ldd"
>> +DESCRIPTION = " \
>> + Pylddwrap wraps ldd *nix utility to determine shared libraries 
>> required by a program. \
>> + "
>> +SECTION = "devel/python"
>> +HOMEPAGE = "https://github.com/Parquery/pylddwrap"
>> +LICENSE = "MIT"
>> +LIC_FILES_CHKSUM = "file://LICENSE;md5=48fd6c978d39a38b3a04f45a1456d0fa"
>> +
>> +SRC_URI[sha256sum] = 
>> "171a39fc7feb33e607706c57c08373ceb2f6fd4362af9241ccc65e80c948ccdf"
>> +
>> +inherit pypi setuptools3
>> +
>> +RDEPENDS_${PN} += "python3-icontract"
>> +
>> +do_install_append() {
>> + rm -f "${D}/${datadir}/requirements.txt"
>> + rm -f "${D}/${datadir}/README.rst"
>> +}
>> +
>> +BBCLASSEXTEND += "native"
>> diff --git a/recipes-devtools/python/python3-rich_7.1.0.bb 
>> b/recipes-devtools/python/python3-rich_7.1.0.bb
>> new file mode 100644
>> index 0000000..59c26a4
>> --- /dev/null
>> +++ b/recipes-devtools/python/python3-rich_7.1.0.bb
>> @@ -0,0 +1,16 @@
>> +SUMMARY = "Render rich text, tables, progress bars, syntax 
>> highlighting, markdown and more to the terminal"
>> +HOMEPAGE = "https://github.com/willmcgugan/rich"
>> +AUTHOR = "Will McGugan <willmcgugan@gmail.com>"
>> +LICENSE = "MIT"
>> +LIC_FILES_CHKSUM = "file://LICENSE;md5=d0d35d5357392e5bfeb0d0a7e6ba4d83"
>> +
>> +SRC_URI[md5sum] = "25daeefa226770a84b98c591069b419c"
>> +SRC_URI[sha256sum] = 
>> "ff701be541be32bcf46e821487c00bf4fa560aa814fc3cc9b3d514fd9b19a6f6"
>> +
>> +S = "${WORKDIR}/rich-7.1.0"
>> +
>> +RDEPENDS_${PN} = "python3-typing-extensions python3-pygments 
>> python3-commonmark python3-colorama"
>> +
>> +inherit pypi setuptools3
>> +
>> +BBCLASSEXTEND += "native"
>> diff --git a/recipes-devtools/python/python3-setuptools-scm_6.0.1.bb 
>> b/recipes-devtools/python/python3-setuptools-scm_6.0.1.bb
>> new file mode 100644
>> index 0000000..234694e
>> --- /dev/null
>> +++ b/recipes-devtools/python/python3-setuptools-scm_6.0.1.bb
>> @@ -0,0 +1,17 @@
>> +SUMMARY = "the blessed package to manage your versions by scm tags"
>> +HOMEPAGE = "https://github.com/pypa/setuptools_scm/"
>> +AUTHOR = "Ronny Pfannschmidt <opensource@ronnypfannschmidt.de>"
>> +LICENSE = "MIT"
>> +LIC_FILES_CHKSUM = "file://LICENSE;md5=838c366f69b72c5df05c96dff79b35f2"
>> +
>> +SRC_URI = 
>> "git://github.com/pypa/setuptools_scm.git;protocol=https;branch=main;tag=v${PV}"
>> +
>> +SRC_URI[sha256sum] = 
>> "8f85bfc7272fb5c04df28f00bde9db8f862c586d25fa155eea90fe62ea6a3302"
>> +
>> +RDEPENDS_${PN} = "python3-setuptools"
>> +
>> +inherit setuptools3
>> +
>> +S = "${WORKDIR}/git"
>> +
>> +BBCLASSEXTEND += "native"
>> diff --git a/recipes-devtools/python/python3-toml_%.bbappend 
>> b/recipes-devtools/python/python3-toml_%.bbappend
>> new file mode 100644
>> index 0000000..d6f5869
>> --- /dev/null
>> +++ b/recipes-devtools/python/python3-toml_%.bbappend
>> @@ -0,0 +1 @@
>> +BBCLASSEXTEND += "native"
>>
>> 
>>

^ permalink raw reply	[flat|nested] 5+ messages in thread

* Re: [yocto] [meta-security][PATCH 1/2] image-with-hardened-binaries: add class
       [not found]     ` <195fee4b-a186-0519-2e77-da854b4f6603@gmail.com>
@ 2021-09-08 14:26       ` Maximilian Blenk
  0 siblings, 0 replies; 5+ messages in thread
From: Maximilian Blenk @ 2021-09-08 14:26 UTC (permalink / raw)
  To: Robert Berger, akuster808, yocto

[-- Attachment #1: Type: text/plain, Size: 1963 bytes --]

Hi,

I'm really not used to this e-mail process :-D
forwording my original answer to the mailing list...

BR Max

On 06.09.21 10:18, Maximilian Blenk wrote:
>
> Hi Robert, Hi Armin,
>
> sorry for the late reply.
>
> Regarding  Armins question:
> If the config file you've used (e.g. th eon ein the selftest) enables 
> all the tests, then it should be fine indeed. I'm not completely sure 
> what the core-mage-minimal includes though. It if it contains systemd 
> the build should be failing if the rpath check is enabled (you would 
> have to whitelist the binaries in the config file)
> Currently there is no test for failing. Should i add one?
>
> Sure i can remove the ".py", i just want to avoid confusion of 
> "checksec.sh" and "checksec.py" (which are completely different tools)
>
> Regarding Roberts question:
> In case the tooling finds a violation it fails the build and outputs 
> an error message containing the buildsystem paths to the binaries and 
> the actual check it is failing. The message also contains some 
> reasoning on why the used feature shouldn't be used. The bitbake class 
> basically take the output you pasted (there is a json mode) and checks 
> it against the whitelist (and some other unreasonable things, such as 
> usage of relro in statically linked applications)
>
>
> Br Max
>
> On 21.08.21 18:59, Robert Berger wrote:
>> Hi,
>>
>> On 21/08/2021 18:35, Armin Kuster wrote:
>>>
>>> Regarding the selftest, is there test for failure?
>>>
>>> I ran this against core-image-minimal and nothing was printed out. Does
>>> that mean its fine?
>>>
>>> You may want to remove the ".py" from
>>> python3-checksec.py-native_0.6.1.bb, its not needed.
>>
>> If you run checksec manually against some binary e.g. ls.coreutils it 
>> outputs something like this:
>>
>> https://pastebin.com/JkeN1h3k
>>
>> Not sure what this should output.
>>
>>>
>>> -armin
>>>>
>>
>> 
>>

[-- Attachment #2: Type: text/html, Size: 3435 bytes --]

^ permalink raw reply	[flat|nested] 5+ messages in thread

* Re: [yocto] [meta-security][PATCH 1/2] image-with-hardened-binaries: add class
  2021-08-21 15:35 ` [yocto] " Armin Kuster
@ 2021-08-21 16:59   ` Robert Berger
       [not found]     ` <195fee4b-a186-0519-2e77-da854b4f6603@gmail.com>
  0 siblings, 1 reply; 5+ messages in thread
From: Robert Berger @ 2021-08-21 16:59 UTC (permalink / raw)
  To: Armin Kuster, Maximilian Blenk, yocto

Hi,

On 21/08/2021 18:35, Armin Kuster wrote:
> 
> Regarding the selftest, is there test for failure?
> 
> I ran this against core-image-minimal and nothing was printed out. Does
> that mean its fine?
> 
> You may want to remove the ".py" from
> python3-checksec.py-native_0.6.1.bb, its not needed.

If you run checksec manually against some binary e.g. ls.coreutils it 
outputs something like this:

https://pastebin.com/JkeN1h3k

Not sure what this should output.

> 
> -armin
>>

^ permalink raw reply	[flat|nested] 5+ messages in thread

* Re: [yocto] [meta-security][PATCH 1/2] image-with-hardened-binaries: add class
  2021-08-13 13:18 Maximilian Blenk
@ 2021-08-21 15:35 ` Armin Kuster
  2021-08-21 16:59   ` Robert Berger
  0 siblings, 1 reply; 5+ messages in thread
From: Armin Kuster @ 2021-08-21 15:35 UTC (permalink / raw)
  To: Maximilian Blenk, yocto

Hello Max,

See feedback below

On 8/13/21 6:18 AM, Maximilian Blenk wrote:
> Add class to analyze binaries with checksec.py. checksec.py is a tool
> that checks if security features of a compiler have been used. To do
> so, it analyses the resulting binaries:
>  * NX Proctection is enabled
>  * Full RELRO is enabled
>  * RPATH and RUNPATH are not set
>  * Executables are compiled to be position independent
>  * FORTIFY_SOURCE is set (false-positives possible)
>  * Stack Canaries are enabled (false-positives possible)
>
> Signed-off-by: Maximilian Blenk <Maximilian.Blenk@bmw.de>
> ---
> Hi guys,
>
> we are currently working on adding automatically checking the binaries
> we put into an image for the presence of certain recommended compiler
> features. To achieve this, we created a bbclass that wraps around the
> existing project checksec.py (https://github.com/Wenzel/checksec.py). In
> particular, checksec.py is used to check if
> * relro is enabled
> * executables are compiled to be position indipendet code
> * rpath and runpath are not set
> * stack canaries are enabled
> * fortify source is enabled
> I must however admit that the last two checks can suffer from
> false-positives which need manual analysis and whitelisting (check can
> also be completely disabled).
>
> Motivation:
> We've decided that such checks would be a nice thing to have because
> people might overwrite important compiler flags in their local recipe.
> Additionally there is always the possibility that components are shipped
> as binaries instead of code (so they are actually build outside the
> current build environment). Overall we've detected several cases where
> required compiler flags have not been applied to shipped components.
> After internal discussion we came to the conclusion that you guys would
> maybe also be interested in this kind of checks, so I'm offering this
> patch to you as well.
>
> I would really appreciate your feedback :-)

I used these against current master and found some duplicate recipes in
either Core or meta-python so I removed these.

 python3-asttokens_2.0.5.bb     
 python3-colorama_%.bbappend   
 python3-docopt_0.6.2.bb      
 python3-setuptools-scm_6.0.1.bb
 python3-toml_%.bbappend        

see:
https://gitlab.com/akuster/meta-security/-/commit/1332825d23eb8ff08e124422b3f25a030c032c0b

I needed to covert to the new overrides scheme before I could build.

see:
https://gitlab.com/akuster/meta-security/-/commit/847bd7551acd3a9ca539b9beccd83a149bdd417d

feel free to reuse those changes.

Regarding the selftest, is there test for failure?

I ran this against core-image-minimal and nothing was printed out. Does
that mean its fine?

You may want to remove the ".py" from
python3-checksec.py-native_0.6.1.bb, its not needed.

-armin
>
> BR Max
>
>  classes/image-with-hardened-binaries.bbclass  | 338 ++++++++++++++++++
>  ...1-main-Add-option-to-ignore-symlinks.patch |  81 +++++
>  .../0002-Elf-Fix-relro-detection.patch        |  51 +++
>  ...heck-Treat-binaries-with-0-fortifiab.patch |  33 ++
>  ...o-use-pre-compiled-version-of-spdlog.patch | 154 ++++++++
>  .../python/python3-asttokens_2.0.5.bb         |  15 +
>  .../python3-checksec.py-native_0.6.1.bb       |  31 ++
>  .../python/python3-colorama_%.bbappend        |   1 +
>  .../python/python3-commonmark_0.9.1.bb        |  14 +
>  .../python/python3-docopt_0.6.2.bb            |  18 +
>  .../python/python3-icontract_2.5.3.bb         |  14 +
>  .../python/python3-lief_0.11.5.bb             |  36 ++
>  .../python/python3-pylddwrap_1.0.1.bb         |  21 ++
>  recipes-devtools/python/python3-rich_7.1.0.bb |  16 +
>  .../python/python3-setuptools-scm_6.0.1.bb    |  17 +
>  .../python/python3-toml_%.bbappend            |   1 +
>  16 files changed, 841 insertions(+)
>  create mode 100644 classes/image-with-hardened-binaries.bbclass
>  create mode 100644 recipes-devtools/python/files/python3-checksec.py/0001-main-Add-option-to-ignore-symlinks.patch
>  create mode 100644 recipes-devtools/python/files/python3-checksec.py/0002-Elf-Fix-relro-detection.patch
>  create mode 100644 recipes-devtools/python/files/python3-checksec.py/0003-fortify-source-check-Treat-binaries-with-0-fortifiab.patch
>  create mode 100644 recipes-devtools/python/files/python3-lief/0001-Enable-to-use-pre-compiled-version-of-spdlog.patch
>  create mode 100644 recipes-devtools/python/python3-asttokens_2.0.5.bb
>  create mode 100644 recipes-devtools/python/python3-checksec.py-native_0.6.1.bb
>  create mode 100644 recipes-devtools/python/python3-colorama_%.bbappend
>  create mode 100644 recipes-devtools/python/python3-commonmark_0.9.1.bb
>  create mode 100644 recipes-devtools/python/python3-docopt_0.6.2.bb
>  create mode 100644 recipes-devtools/python/python3-icontract_2.5.3.bb
>  create mode 100644 recipes-devtools/python/python3-lief_0.11.5.bb
>  create mode 100644 recipes-devtools/python/python3-pylddwrap_1.0.1.bb
>  create mode 100644 recipes-devtools/python/python3-rich_7.1.0.bb
>  create mode 100644 recipes-devtools/python/python3-setuptools-scm_6.0.1.bb
>  create mode 100644 recipes-devtools/python/python3-toml_%.bbappend
>
> diff --git a/classes/image-with-hardened-binaries.bbclass b/classes/image-with-hardened-binaries.bbclass
> new file mode 100644
> index 0000000..d7d3908
> --- /dev/null
> +++ b/classes/image-with-hardened-binaries.bbclass
> @@ -0,0 +1,338 @@
> +# Provide qa checks to ensure all applications and libraries shipped with the image
> +# have common compiler security features enabled. In particular there are checks that:
> +# * nx protection is enabled
> +# * relro is enabled
> +# * executables (except for static linked ones) are position independent
> +# * rpath and runpath are not set
> +
> +IMAGE_QA_COMMANDS += "image_check_binary_hardening"
> +
> +DEPENDS += "python3-checksec.py-native"
> +
> +inherit python3native
> +
> +# Add mappings to the path mappers (which determines if a binary is a application or
> +# shared library). To add a mapping append " /path/from/the/root/to/bin:{application,library,ignore}"
> +# to the list
> +HARDENED_BINARIES_EXTRA_MAPPING ?= ""
> +
> +# Config file in TOML format:
> +# [check]
> +# enabled = true
> +# whitelist = [
> +#   "path to some binary",
> +#   "path to some other binary"
> +# ]
> +# supported checks are: nx, relro, pie, rpath, runpath
> +HARDENED_BINARIES_CONFIG_FILE ?= ""
> +
> +# Custom message to show in case of a detected violation
> +# For instace if you want to add whom to contact for support
> +HARDENED_BINARIES_CUSTOM_ERROR_MESSAGE ?= ""
> +
> +# Path to libc used for foritfy source analysis. If fortify_source check is
> +# not enabled, this variable can be ignored.
> +HARDENED_BINARIES_LIBC_PATH ?= "${IMAGE_ROOTFS}${baselib}/libc.so.6"
> +
> +python image_check_binary_hardening () {
> +    import fnmatch
> +    import json
> +    import os
> +    import subprocess
> +    import toml
> +    from collections import defaultdict, OrderedDict
> +    from enum import Enum, auto
> +
> +    from oe.utils import ImageQAFailed
> +
> +    rootfs = d.getVar("IMAGE_ROOTFS")
> +
> +    #################################
> +    ## Data about supported checks ##
> +    #################################
> +
> +    class BinType(Enum):
> +        IGNORE = "ignore"
> +        APPLICATION = "application"
> +        LIBRARY = "library"
> +
> +    # Dict of checks to perform on the analysis result of checksec.py
> +    # Each entry needs to contain the following attributes:
> +    #  - allowed_value: Value in the analysis result that should be accepted
> +    #  - bintypes: List of types on which the check shall be enforced (e.g. PIE check on libraries
> +    #              doesn't make much sense because PIE is only for executables)
> +    #  - errormsg: Message that should be prompted in case violators have been found
> +    #  - ignore_static: Indicates if statically linked applications should be ignored for that check
> +    #  Notes specific checks:
> +    #  - NX: Needs to be enforced on applications and libraries. This is because if only a single shared
> +    #        library doesn't use that, the whole process needs to have a executable stack.
> +    #  - RELRO: Statically linked applications do not make use of relocation, so this check would always
> +    #           fail for statically linked applications.
> +    #  - PIE: This check is only valid for applications (as in "position independent executable" for
> +    #         applications vs. "position independent code" (PIC) for shared libraries)
> +    CHECK_DATA = {
> +        "nx" : {
> +            "allowed_value": True,
> +            "bintypes": [BinType.APPLICATION, BinType.LIBRARY],
> +            "errormsg":
> +                "The following {} binaries do not use nx (not executable) protection. This mechanism is used " \
> +                "to separate data from executable code. Disabling this mechanism is a security issue because " \
> +                "this enables attackers to put code onto the stack. Please also note, if the nx protection is " \
> +                "disabled in a shared library, all binary objects that link against this library will not be " \
> +                "protected. This message usually appears if your binary is linked using the \"-z execstack\" " \
> +                "flag.",
> +            "ignore_static": False,
> +        },
> +        "relro": {
> +            "allowed_value": "Full",
> +            "bintypes": [BinType.APPLICATION, BinType.LIBRARY],
> +            "errormsg":
> +                "The following {} binaries do not make use of the relro (relocation read-only). This feature " \
> +                "prevents attackers from modifying addresses of functions that are located in shared libraries " \
> +                "(which is a common technique to exploit vulnerabilities). Due to this, not making use of this " \
> +                "feature is a security issue. Please make sure your application is linked using " \
> +                "\"-Wl,-z,relro,-z,now\". ",
> +            "ignore_static": True,
> +        },
> +        "rpath": {
> +            "allowed_value": False,
> +            "bintypes": [BinType.APPLICATION, BinType.LIBRARY],
> +            "errormsg":
> +                "The following {} binaries are making use of the rpath feature. This can easily enable an attacker " \
> +                "to get malicious code executed if there is some issue with the file permissions at the specified " \
> +                "location. Due to this, the usage of this feature is generally discouraged and needs approval " \
> +                "by the security team.",
> +            "ignore_static": False,
> +        },
> +        "runpath": {
> +            "allowed_value": False,
> +            "bintypes": [BinType.APPLICATION, BinType.LIBRARY],
> +            "errormsg":
> +                "The following {} binaries are making use of the runpath feature. This can easily enable an attacker" \
> +                " to get malicious code executed if there is some issue with the file permissions at the specified " \
> +                "location. Due to this, the usage of this feature is generally discouraged and needs approval " \
> +                "by the security team.",
> +            "ignore_static": False,
> +        },
> +        "pie": {
> +            "allowed_value": "PIE",
> +            "bintypes": [BinType.APPLICATION],
> +            "errormsg":
> +                "The following {} applications are not compiled to be position independent executables (pie). This " \
> +                "compiler feature compiles the code in a way that it can be mapped to any location in the virtual " \
> +                "memory. Compiling the application this way is required to make use of the Address Space Layout " \
> +                "Randomization (ASLR). This feature maps executable code to a random location, which means an " \
> +                "attacker can not rely on the fact that a specific portion of code is mapped to a specific address. " \
> +                "Please ensure that you application is compiled using \"-fPIE\".",
> +            "ignore_static": True,
> +        },
> +        "canary": {
> +            "allowed_value": True,
> +            "bintypes": [BinType.APPLICATION, BinType.LIBRARY],
> +            "errormsg":
> +                "The following {} binaries seem to be not using stack canaries. These canaries are used to mitigate " \
> +                "stack buffer overflows attacks. To do so the compiler adds checks to the end of a function to " \
> +                "ensure that this function did not overwrite the stack frames of another function. Not using " \
> +                "canaries may allow an attacker to exploit stack based buffer overflows by modifying the stack frame " \
> +                "of other function calls (which simplifies exploiting such vulnerabilities a lot). Please make sure " \
> +                "your components are compiled with the \"-fstack-protector-strong\" compile flag. Please note that " \
> +                "there is a slight possibility for false-positives in this check: The compiler checks if a function " \
> +                "needs canary protection or not. If there is no function that needs proctedtion in your binary, this " \
> +                "check will fail anyway and the binary needs to be whitelisted.",
> +            "ignore_static": False,
> +        },
> +        "fortify_source": {
> +            "allowed_value": True,
> +            "bintypes": [BinType.APPLICATION, BinType.LIBRARY],
> +            "errormsg":
> +                "The following {} binaries seem to be not using the fortify source feature. This feature protects " \
> +                "(some, not all) calls to memory manipulations function like memcpy, strcpy or strcat by adding " \
> +                "checks that prevent buffer overflows. These checks can prevent attackers from exploiting such a " \
> +                "buffer overflow. Please make sure your component is compiled with \"-D_FORTIFY_SOURCE=2\". In " \
> +                "addition the compiler optimizations need to be enabled with \"-O1\" or higher. Please note that " \
> +                "there is a slight possibility for false positives here: Not all occurences of these mentioned " \
> +                "memory calls that can not be protected they will appear as if_FORTIFY_SOURCE has not been set. " \
> +                "In such a case the binary needs to be whitelisted.",
> +            "ignore_static": False,
> +        }
> +    }
> +
> +    #################################
> +    ## Parse data from config file ##
> +    #################################
> +
> +    config_file = d.getVar("HARDENED_BINARIES_CONFIG_FILE", True)
> +    if not config_file:
> +        msg = "Hardend Binary Check: No config file specifed. Please create a config file and set " \
> +              "the variable \"HARDENED_BINARIES_CONFIG_FILE\" accordingly"
> +        raise ImageQAFailed(msg, image_check_binary_hardening)
> +
> +    CHECK_CONFIG_DATA = defaultdict(lambda: {"enabled": False})
> +    CHECK_CONFIG_DATA.update(toml.load(config_file))
> +
> +    # Expand whitelisted paths with rootfs
> +    for check, values in CHECK_CONFIG_DATA.items():
> +        values["whitelist"] = [rootfs + x for x in values["whitelist"]]
> +
> +    ###############################################
> +    ## Classes and functions to perform analysis ##
> +    ###############################################
> +
> +    class PathMapping:
> +        """ Class to map paths to BinTypes """
> +        def __init__(self, rootfs):
> +            self.rootfs = rootfs
> +            self.mapping = OrderedDict()
> +
> +            self.add("/bin/*", BinType.APPLICATION)
> +            self.add("/lib/firmware/*", BinType.IGNORE)
> +            self.add("/lib/modules/*", BinType.IGNORE)
> +            self.add("/lib/systemd/*.so", BinType.LIBRARY)
> +            self.add("/lib/systemd/*", BinType.APPLICATION)
> +            self.add("/lib/*", BinType.LIBRARY)
> +            self.add("/sbin/*", BinType.APPLICATION)
> +            self.add("/usr/bin/*", BinType.APPLICATION)
> +            self.add("/usr/libexec/*", BinType.APPLICATION)
> +            self.add("/usr/lib/firmware/*", BinType.IGNORE)
> +            self.add("/usr/lib/modules/*", BinType.IGNORE)
> +            self.add("/usr/lib/systemd/*.so", BinType.LIBRARY)
> +            self.add("/usr/lib/systemd/*", BinType.APPLICATION)
> +            self.add("/usr/lib/*", BinType.LIBRARY)
> +            self.add("/usr/sbin/*", BinType.APPLICATION)
> +
> +
> +        def add(self, path, bin_type):
> +            """ Add mapping of a path to a FileyType """
> +            self.mapping[self.rootfs + path] = bin_type
> +
> +        def map(self, path):
> +            """ Map a path to a FilesType. Returns None if path can not be mapped. """
> +            for match_path, bin_type in self.mapping.items():
> +                if fnmatch.fnmatch(path, match_path):
> +                    return bin_type
> +            else:
> +                return None
> +
> +    def call_checksec(rootfs):
> +        """ Wrapper to call the checksec.py script
> +
> +            This function returns a list of result dicts, e.g.:
> +            [
> +                ...,
> +                "/bin/systemd-hwdb": {
> +                    "relro": "No",
> +                    "canary": true,
> +                    "nx": true,
> +                    "pie": "PIE",
> +                    "rpath": false,
> +                    "runpath": false,
> +                    "symbols": false,
> +                    "fortify_source": true,
> +                    "fortified": 5,
> +                    "fortify-able": 16,
> +                    "fortify_score": 31
> +                }
> +            ]
> +
> +        """
> +        parallel_make = d.getVar("PARALLEL_MAKE")
> +
> +        cmd = ["python3", "-m", "checksec", "--json", "--recursive", "--ignore-symlinks"]
> +        if parallel_make:
> +            cmd.append(parallel_make.replace("-j", "--workers="))
> +        if CHECK_CONFIG_DATA["foritfy_source"]["enabled"]:
> +            libc_path = d.getVar("HARDENED_BINARIES_LIBC_PATH", True)
> +            cmd.append("--set-libc={}".format(libc_path))
> +        cmd.append(rootfs)
> +
> +        return json.loads(subprocess.check_output(cmd).decode('utf-8'))
> +
> +
> +    class ResultAnalyzer:
> +        """ Class to evaluate the results produced by checksec.py """
> +        def __init__(self, rootfs):
> +            self.rootfs = rootfs
> +            self.violators = defaultdict(list)
> +
> +        @staticmethod
> +        def __is_static(path):
> +            """ Checks if binary at given path is statically linked """
> +            return "statically linked" in subprocess.check_output(["file", path], stderr=subprocess.STDOUT).decode('utf-8')
> +
> +        def check_result(self, path, result, bintype):
> +            """ Perfom checks specified in CHECK_DATA on the given analysis result (of a specific binary) """
> +
> +            for check, values in CHECK_DATA.items():
> +                if CHECK_CONFIG_DATA[check]["enabled"] and bintype in values["bintypes"]:
> +                    for whitelisted in CHECK_CONFIG_DATA[check]["whitelist"]:
> +                        if fnmatch.fnmatch(path, whitelisted):
> +                            break
> +                    else:
> +                        if result[check] != values["allowed_value"] and \
> +                                (not values["ignore_static"] or not self.__is_static(path)):
> +                            self.violators[check].append(path)
> +
> +
> +    def perform_analysis(rootfs):
> +        """ Analyze all binaries in a given rootfs. In case a container shall be analyzed the absolute path to the container_path
> +            rootfs needs to be passed.
> +        """
> +
> +        # Add custom path mapping (for bins in non-standard locations)
> +        path_mapping = PathMapping(rootfs)
> +        extra_mapping = d.getVar("HARDENED_BINARIES_EXTRA_MAPPING")
> +        if extra_mapping:
> +            for mapping in extra_mapping.split():
> +                try:
> +                    path, type = mapping.split(':')
> +                except:
> +                    bb.error("Hardened Binary Checks: Got misformated extra mapping {}. Mapping needs to be " \
> +                             "in form: \"<path regex>:{application,library,ignore}\"".format(mapping))
> +                    raise
> +                path_mapping.add(path, BinType(type))
> +
> +        # Perform analysis of complete rootfs
> +        analysis_result = call_checksec(rootfs)
> +
> +        # Check analysis results and ensure that all we can actually map all binaries to a BinType
> +        result_analyzer = ResultAnalyzer(rootfs)
> +        unmapped_binaries = []
> +        for path, result in analysis_result.items():
> +            bintype = path_mapping.map(path)
> +            if bintype in [BinType.APPLICATION, BinType.LIBRARY]:
> +                result_analyzer.check_result(path, result, bintype)
> +            elif bintype != BinType.IGNORE:
> +                unmapped_binaries.append(path)
> +
> +        # To ensure that we analyze all the binaries lets break the build if we can not map binaries
> +        if unmapped_binaries:
> +            msg = "Hardend Binary Check: Couldn't figure out if the following files are applications " \
> +                  "or libraries. This is probably due to a non standard location for applications or " \
> +                  "libraries. If you think this is required add the mapping to " \
> +                  "HARDENED_BINARIES_EXTRA_MAPPING and/or contact mgu-security-frontdesk@list.bmw.com" \
> +                  "\nUnmapped:\n{}".format("\n".join(unmapped_binaries),
> +                  image_check_binary_hardening)
> +            raise ImageQAFailed(msg, image_check_binary_hardening)
> +
> +        custom_error_message = d.getVar('HARDENED_BINARIES_CUSTOM_ERROR_MESSAGE')
> +
> +        # Break the build and show error message if we detected violators that are not whitelisted
> +        errors = []
> +        for check, violators in result_analyzer.violators.items():
> +            if violators:
> +                errormsg = CHECK_DATA[check]["errormsg"].format(len(violators))
> +                errormsg += "\n{}".format("\n".join(violators))
> +                if custom_error_message:
> +                    errormsg += "\n" + custom_error_message
> +                errors.append(errormsg)
> +
> +        if errors:
> +            raise ImageQAFailed("\n".join(errors), image_check_binary_hardening)
> +
> +    ##############################
> +    ## Start analysis on rootfs ##
> +    ##############################
> +
> +    perform_analysis(rootfs)
> +
> +}
> diff --git a/recipes-devtools/python/files/python3-checksec.py/0001-main-Add-option-to-ignore-symlinks.patch b/recipes-devtools/python/files/python3-checksec.py/0001-main-Add-option-to-ignore-symlinks.patch
> new file mode 100644
> index 0000000..ae434bc
> --- /dev/null
> +++ b/recipes-devtools/python/files/python3-checksec.py/0001-main-Add-option-to-ignore-symlinks.patch
> @@ -0,0 +1,81 @@
> +From 182268203951750dcfb2c134354e801dea472e4c Mon Sep 17 00:00:00 2001
> +From: Maximilian Blenk <Maximilian.Blenk@bmw.de>
> +Date: Fri, 2 Jul 2021 14:42:25 +0200
> +Subject: [PATCH 1/2] main: Add option to ignore symlinks
> +
> +When analyzing a complete rootfs (which might not be the rootfs of the
> +analyzing system) symlinks within that rootfs might be broken. In
> +particular absolute symlinks. However, if by chance such a symlink
> +currently points to a valid binary in your system, this binary pointed
> +to is analyzed. This commit adds the possibility to ignore symlinks to
> +files (symlinks to dirs are already ignored by default). This allows to
> +solve the issue described above, and if the whole rootfs is analyzed
> +there shouldn't be a loss of information (because all the binaries will
> +be analyzed anyway). Additionally, this also saves some time when
> +performing the analysis.
> +
> +Upstream-Status: Submitted https://github.com/Wenzel/checksec.py/pull/106
> +---
> + checksec/__main__.py | 12 +++++++-----
> + 1 file changed, 7 insertions(+), 5 deletions(-)
> +
> +diff --git a/checksec/__main__.py b/checksec/__main__.py
> +index 856d0b3..f1a3445 100644
> +--- a/checksec/__main__.py
> ++++ b/checksec/__main__.py
> +@@ -8,6 +8,7 @@ Options:
> +     -w WORKERS --workers=WORKERS    Specify the number of process pool workers [default: 4]
> +     -j --json                       Display results as JSON
> +     -s LIBC --set-libc=LIBC         Specify LIBC library to use to check for fortify scores (ELF)
> ++    -i --ignore-symlinks            Ignore symlinks to files
> +     -d --debug                      Enable debug output
> +     -h --help                       Display this message
> + """
> +@@ -27,15 +28,15 @@ from .pe import PEChecksecData, PESecurity, is_pe
> + from .utils import lief_set_logging
> + 
> + 
> +-def walk_filepath_list(filepath_list: List[Path], recursive: bool = False) -> Iterator[Path]:
> ++def walk_filepath_list(filepath_list: List[Path], recursive: bool = False, ignore_symlinks: bool = False) -> Iterator[Path]:
> +     for path in filepath_list:
> +         if path.is_dir() and not path.is_symlink():
> +             if recursive:
> +                 for f in os.scandir(path):
> +-                    yield from walk_filepath_list([Path(f)], recursive)
> ++                    yield from walk_filepath_list([Path(f)], recursive, ignore_symlinks)
> +             else:
> +                 yield from (Path(f) for f in os.scandir(path))
> +-        elif path.is_file():
> ++        elif path.is_file() and (not ignore_symlinks or not path.is_symlink()):
> +             yield path
> + 
> + 
> +@@ -72,6 +73,7 @@ def main(args):
> +     json = args["--json"]
> +     recursive = args["--recursive"]
> +     libc_path = args["--set-libc"]
> ++    ignore_symlinks = args["--ignore-symlinks"]
> + 
> +     # logging
> +     formatter = "%(asctime)s %(levelname)s:%(name)s:%(message)s"
> +@@ -107,7 +109,7 @@ def main(args):
> +             # we need to consume the iterator once to get the total
> +             # for the progress bar
> +             check_output.enumerating_tasks_start()
> +-            count = sum(1 for i in walk_filepath_list(filepath_list, recursive))
> ++            count = sum(1 for i in walk_filepath_list(filepath_list, recursive, ignore_symlinks))
> +             check_output.enumerating_tasks_stop(count)
> +             with ProcessPoolExecutor(
> +                 max_workers=workers, initializer=worker_initializer, initargs=(libc_path,)
> +@@ -116,7 +118,7 @@ def main(args):
> +                     check_output.processing_tasks_start()
> +                     future_to_checksec = {
> +                         pool.submit(checksec_file, filepath): filepath
> +-                        for filepath in walk_filepath_list(filepath_list, recursive)
> ++                        for filepath in walk_filepath_list(filepath_list, recursive, ignore_symlinks)
> +                     }
> +                     for future in as_completed(future_to_checksec):
> +                         filepath = future_to_checksec[future]
> +-- 
> +2.31.1
> +
> diff --git a/recipes-devtools/python/files/python3-checksec.py/0002-Elf-Fix-relro-detection.patch b/recipes-devtools/python/files/python3-checksec.py/0002-Elf-Fix-relro-detection.patch
> new file mode 100644
> index 0000000..a891c2b
> --- /dev/null
> +++ b/recipes-devtools/python/files/python3-checksec.py/0002-Elf-Fix-relro-detection.patch
> @@ -0,0 +1,51 @@
> +From f550777f35e178bc16a2ec612b2b39aa2c3946f2 Mon Sep 17 00:00:00 2001
> +From: Maximilian Blenk <Maximilian.Blenk@bmw.de>
> +Date: Fri, 2 Jul 2021 16:16:47 +0200
> +Subject: [PATCH 2/2] Elf: Fix relro detection
> +
> +Currently, relro is only detected when the BIND_NOW is set. If however
> +the NOW flag in the FLAGS_1 section is set, relro is not detected (it
> +does not even tell that relro is enabled partially). With this commit
> +relro is detected correctly.
> +
> +Upstream-Status: Submitted https://github.com/Wenzel/checksec.py/pull/107
> +---
> + checksec/elf.py | 19 +++++++++++++++----
> + 1 file changed, 15 insertions(+), 4 deletions(-)
> +
> +diff --git a/checksec/elf.py b/checksec/elf.py
> +index 78ecacc..ef1850c 100644
> +--- a/checksec/elf.py
> ++++ b/checksec/elf.py
> +@@ -118,13 +118,24 @@ class ELFSecurity(BinarySecurity):
> +     def relro(self) -> RelroType:
> +         try:
> +             self.bin.get(lief.ELF.SEGMENT_TYPES.GNU_RELRO)
> +-            if lief.ELF.DYNAMIC_FLAGS.BIND_NOW in self.bin.get(lief.ELF.DYNAMIC_TAGS.FLAGS):
> +-                return RelroType.Full
> +-            else:
> +-                return RelroType.Partial
> +         except lief.not_found:
> +             return RelroType.No
> + 
> ++        try:
> ++            bind_now = lief.ELF.DYNAMIC_FLAGS.BIND_NOW in self.bin.get(lief.ELF.DYNAMIC_TAGS.FLAGS)
> ++        except lief.not_found:
> ++            bind_now = False
> ++
> ++        try:
> ++            now = lief.ELF.DYNAMIC_FLAGS_1.NOW in self.bin.get(lief.ELF.DYNAMIC_TAGS.FLAGS_1)
> ++        except lief.not_found:
> ++            now = False
> ++
> ++        if bind_now or now:
> ++            return RelroType.Full
> ++        else:
> ++            return RelroType.Partial
> ++
> +     @property
> +     def has_canary(self) -> bool:
> +         canary_sections = ["__stack_chk_fail", "__intel_security_cookie"]
> +-- 
> +2.31.1
> +
> diff --git a/recipes-devtools/python/files/python3-checksec.py/0003-fortify-source-check-Treat-binaries-with-0-fortifiab.patch b/recipes-devtools/python/files/python3-checksec.py/0003-fortify-source-check-Treat-binaries-with-0-fortifiab.patch
> new file mode 100644
> index 0000000..0351f84
> --- /dev/null
> +++ b/recipes-devtools/python/files/python3-checksec.py/0003-fortify-source-check-Treat-binaries-with-0-fortifiab.patch
> @@ -0,0 +1,33 @@
> +From 8de048c0065f8c5890d9e04ef2b32306e2ac4f8c Mon Sep 17 00:00:00 2001
> +From: Maximilian Blenk <Maximilian.Blenk@bmw.de>
> +Date: Thu, 5 Aug 2021 15:21:58 +0200
> +Subject: [PATCH] fortify source check: Treat binaries with 0 fortifiable as
> + fortified
> +
> +Currently, if checksec.py detects 0 fortifiable instances it still
> +treats the binary as not fortified. Semtically it would make sense to
> +treat these binaries as fortified (because there is no evidence that it
> +is not)
> +
> +Upstream-Status: Submitted https://github.com/Wenzel/checksec.py/pull/109
> +---
> + checksec/elf.py | 3 +--
> + 1 file changed, 1 insertion(+), 2 deletions(-)
> +
> +diff --git a/checksec/elf.py b/checksec/elf.py
> +index ef1850c..5914135 100644
> +--- a/checksec/elf.py
> ++++ b/checksec/elf.py
> +@@ -229,8 +229,7 @@ class ELFSecurity(BinarySecurity):
> +                 else:
> +                     score = (fortified_count * 100) / fortifiable_count
> +                     score = round(score)
> +-
> +-            fortify_source = True if fortified_count != 0 else False
> ++            fortify_source = True if fortified_count != 0 or fortifiable_count == 0 else False
> +         return ELFChecksecData(
> +             relro=self.relro,
> +             canary=self.has_canary,
> +-- 
> +2.31.1
> +
> diff --git a/recipes-devtools/python/files/python3-lief/0001-Enable-to-use-pre-compiled-version-of-spdlog.patch b/recipes-devtools/python/files/python3-lief/0001-Enable-to-use-pre-compiled-version-of-spdlog.patch
> new file mode 100644
> index 0000000..af94cfa
> --- /dev/null
> +++ b/recipes-devtools/python/files/python3-lief/0001-Enable-to-use-pre-compiled-version-of-spdlog.patch
> @@ -0,0 +1,154 @@
> +From d2ad8f6108c750c3dbd33ee6d4e4c94ada748b8a Mon Sep 17 00:00:00 2001
> +From: Romain Thomas <me@romainthomas.fr>
> +Date: Mon, 3 May 2021 11:25:49 +0200
> +Subject: [PATCH] Enable to use pre-compiled version of spdlog
> +
> +---
> + CMakeLists.txt               |  8 ++++----
> + cmake/LIEFDependencies.cmake | 36 +++++++++++++++++++++++-------------
> + cmake/LIEFOptions.cmake      |  4 ++++
> + setup.py                     | 17 +++++++++++++++++
> + 4 files changed, 48 insertions(+), 17 deletions(-)
> +
> +diff --git a/CMakeLists.txt b/CMakeLists.txt
> +index d1665cd..b92519a 100644
> +--- a/CMakeLists.txt
> ++++ b/CMakeLists.txt
> +@@ -307,8 +307,7 @@ source_group("mbedtls\\tls" FILES ${mbedtls_src_tls})
> + # Library definition
> + # ==================
> + target_include_directories(
> +-  LIB_LIEF SYSTEM PRIVATE "${SPDLOG_SOURCE_DIR}/include"
> +-                          "${MBEDTLS_INCLUDE_DIRS}")
> ++  LIB_LIEF SYSTEM PRIVATE "${MBEDTLS_INCLUDE_DIRS}")
> + 
> + target_include_directories(
> +   LIB_LIEF
> +@@ -355,7 +354,8 @@ target_sources(LIB_LIEF PRIVATE
> +   ${CMAKE_CURRENT_BINARY_DIR}/include/LIEF/third-party/utfcpp/utf8.h)
> + 
> + 
> +-add_dependencies(LIB_LIEF lief_spdlog lief_mbed_tls)
> ++add_dependencies(LIB_LIEF lief_mbed_tls)
> ++target_link_libraries(LIB_LIEF PRIVATE lief_spdlog)
> + 
> + # Flags definition
> + # ----------------
> +@@ -626,7 +626,7 @@ install(
> +   DESTINATION lib/pkgconfig
> +   COMPONENT libraries)
> + 
> +-export(TARGETS LIB_LIEF FILE LIEFExport.cmake)
> ++export(TARGETS LIB_LIEF lief_spdlog FILE LIEFExport.cmake)
> + 
> + # Package
> + # ======================
> +diff --git a/cmake/LIEFDependencies.cmake b/cmake/LIEFDependencies.cmake
> +index e75326f..37e6987 100644
> +--- a/cmake/LIEFDependencies.cmake
> ++++ b/cmake/LIEFDependencies.cmake
> +@@ -144,21 +144,31 @@ set(mbedtls_src_tls
> +   "${MBEDTLS_SOURCE_DIR}/library/ssl_tls13_keys.c"
> + )
> + 
> +-#set_source_files_properties("${MBEDTLS_SOURCE_DIR}/library/bignum.c" PROPERTIES COMPILE_FLAGS -Wno-overlength-strings)
> ++add_library(lief_spdlog INTERFACE)
> + 
> +-set(SPDLOG_VERSION 1.8.2)
> +-set(SPDLOG_SHA256 SHA256=f0410b12b526065802b40db01304783550d3d20b4b6fe2f8da55f9d08ed2035d)
> +-set(SPDLOG_URL "${THIRD_PARTY_DIRECTORY}/spdlog-${SPDLOG_VERSION}.zip" CACHE STRING "URL to the spdlog lib repo")
> +-ExternalProject_Add(lief_spdlog
> +-  URL               ${SPDLOG_URL}
> +-  URL_HASH          ${SPDLOG_SHA256}
> +-  CONFIGURE_COMMAND ""
> +-  BUILD_COMMAND     ""
> +-  UPDATE_COMMAND    ""
> +-  INSTALL_COMMAND   "")
> ++if(LIEF_EXTERNAL_SPDLOG)
> ++  find_package(spdlog REQUIRED)
> ++  list(APPEND CMAKE_MODULE_PATH "${SPDLOG_DIR}/cmake")
> ++  target_link_libraries(lief_spdlog INTERFACE spdlog::spdlog)
> ++  get_target_property(SPDLOG_INC_DIR spdlog::spdlog INTERFACE_INCLUDE_DIRECTORIES)
> ++  target_include_directories(lief_spdlog SYSTEM INTERFACE ${SPDLOG_INC_DIR})
> ++else()
> ++  set(SPDLOG_VERSION 1.8.2)
> ++  set(SPDLOG_SHA256 SHA256=f0410b12b526065802b40db01304783550d3d20b4b6fe2f8da55f9d08ed2035d)
> ++  set(SPDLOG_URL "${THIRD_PARTY_DIRECTORY}/spdlog-${SPDLOG_VERSION}.zip" CACHE STRING "URL to the spdlog source")
> ++  ExternalProject_Add(lief_spdlog_project
> ++    URL               ${SPDLOG_URL}
> ++    URL_HASH          ${SPDLOG_SHA256}
> ++    CONFIGURE_COMMAND ""
> ++    BUILD_COMMAND     ""
> ++    UPDATE_COMMAND    ""
> ++    INSTALL_COMMAND   "")
> + 
> +-ExternalProject_get_property(lief_spdlog SOURCE_DIR)
> +-set(SPDLOG_SOURCE_DIR "${SOURCE_DIR}")
> ++  ExternalProject_get_property(lief_spdlog_project SOURCE_DIR)
> ++  set(SPDLOG_SOURCE_DIR "${SOURCE_DIR}")
> ++  add_dependencies(lief_spdlog lief_spdlog_project)
> ++  target_include_directories(lief_spdlog SYSTEM INTERFACE ${SPDLOG_SOURCE_DIR}/include)
> ++endif()
> + 
> + # Fuzzing
> + # ~~~~~~~
> +diff --git a/cmake/LIEFOptions.cmake b/cmake/LIEFOptions.cmake
> +index fd6df6c..3bb92c3 100644
> +--- a/cmake/LIEFOptions.cmake
> ++++ b/cmake/LIEFOptions.cmake
> +@@ -45,6 +45,10 @@ option(LIEF_PROFILING "Enable performance profiling" OFF)
> + cmake_dependent_option(LIEF_INSTALL_COMPILED_EXAMPLES "Install LIEF Compiled examples" OFF
> +                        "LIEF_EXAMPLES" OFF)
> + 
> ++# Use a user-provided version of spdlog
> ++# It can be useful to reduce compile time
> ++option(LIEF_EXTERNAL_SPDLOG OFF)
> ++
> + set(LIEF_ELF_SUPPORT 0)
> + set(LIEF_PE_SUPPORT 0)
> + set(LIEF_MACHO_SUPPORT 0)
> +diff --git a/setup.py b/setup.py
> +index b915180..ad70bd8 100644
> +--- a/setup.py
> ++++ b/setup.py
> +@@ -45,6 +45,10 @@ class LiefDistribution(setuptools.Distribution):
> +         ('lief-no-vdex', None, 'Disable VDEX module'),
> +         ('lief-no-oat', None, 'Disable OAT module'),
> +         ('lief-no-dex', None, 'Disable DEX module'),
> ++
> ++        ('lief-no-cache', None, 'Do not use compiler cache (ccache)'),
> ++
> ++        ('spdlog-dir=', None, 'Path to the directory that contains spdlogConfig.cmake'),
> +     ]
> + 
> +     def __init__(self, attrs=None):
> +@@ -66,6 +70,10 @@ class LiefDistribution(setuptools.Distribution):
> + 
> +         self.lief_no_android  = False
> +         self.doc = False
> ++
> ++        self.lief_no_cache  = False
> ++
> ++        self.spdlog_dir = None
> +         super().__init__(attrs)
> + 
> + 
> +@@ -154,6 +162,15 @@ class BuildLibrary(build_ext):
> +         else:
> +             cmake_args += ["-DLIEF_LOGGING_DEBUG=off"]
> + 
> ++        if self.distribution.lief_no_cache:
> ++            cmake_args += ["-DLIEF_USE_CCACHE=off"]
> ++
> ++        # Setup spdlog configuration flags if
> ++        # the user provides --spdlog-dir
> ++        if self.distribution.spdlog_dir is not None:
> ++            cmake_args.append("-DLIEF_EXTERNAL_SPDLOG=ON")
> ++            cmake_args.append("-Dspdlog_DIR={}".format(self.distribution.spdlog_dir))
> ++
> +         # Main formats
> +         # ============
> +         if self.distribution.lief_no_elf:
> +-- 
> +2.31.1
> +
> diff --git a/recipes-devtools/python/python3-asttokens_2.0.5.bb b/recipes-devtools/python/python3-asttokens_2.0.5.bb
> new file mode 100644
> index 0000000..7ac2052
> --- /dev/null
> +++ b/recipes-devtools/python/python3-asttokens_2.0.5.bb
> @@ -0,0 +1,15 @@
> +SUMMARY = "Annotate AST trees with source code positions"
> +HOMEPAGE = "https://github.com/gristlabs/asttokens"
> +AUTHOR = "Dmitry Sagalovskiy, Grist Labs <dmitry@getgrist.com>"
> +LICENSE = "Apache-2.0"
> +LIC_FILES_CHKSUM = "file://LICENSE;md5=e3fc50a88d0a364313df4b21ef20c29e"
> +
> +SRC_URI[md5sum] = "0a2a057b9c9a220bffdb3e7512062f17"
> +SRC_URI[sha256sum] = "9a54c114f02c7a9480d56550932546a3f1fe71d8a02f1bc7ccd0ee3ee35cf4d5"
> +
> +RDEPENDS_${PN} = "python3-six"
> +DEPENDS += "python3-setuptools-scm python3-toml"
> +
> +inherit pypi setuptools3
> +
> +BBCLASSEXTEND += "native"
> diff --git a/recipes-devtools/python/python3-checksec.py-native_0.6.1.bb b/recipes-devtools/python/python3-checksec.py-native_0.6.1.bb
> new file mode 100644
> index 0000000..edce0a6
> --- /dev/null
> +++ b/recipes-devtools/python/python3-checksec.py-native_0.6.1.bb
> @@ -0,0 +1,31 @@
> +SUMMARY = "Tool to verify the security properties of binaries"
> +DESCRIPTION = "checksec.py is a tool verify if certain compiler flags \
> +               have been enabled on compield applications and libraries."
> +HOMEPAGE = "https://github.com/Wenzel/checksec.py"
> +BUGTRACKER = "https://github.com/Wenzel/checksec.py/issues"
> +SECTION = "devel/python"
> +
> +LICENSE = "GPL-3.0"
> +LIC_FILES_CHKSUM = "file://LICENSE;md5=1ebbd3e34237af26da5dc08a4e440464"
> +
> +RDEPENDS_${PN} += " \
> +    python3-docopt-native \
> +    python3-lief-native \
> +    python3-pylddwrap-native \
> +    python3-rich-native \
> +    "
> +
> +# Needs to be pulled from github becuase pypi package is currently broken
> +SRC_URI = " \
> +    git://github.com/Wenzel/checksec.py.git;protocol=https;branch=master \
> +    file://python3-checksec.py/0001-main-Add-option-to-ignore-symlinks.patch \
> +    file://python3-checksec.py/0002-Elf-Fix-relro-detection.patch \
> +    file://python3-checksec.py/0003-fortify-source-check-Treat-binaries-with-0-fortifiab.patch \
> +    "
> +
> +SRCREV = "4335ecd08f6ee13ff4ca9b01e83857ae6a8074e9"
> +
> +S="${WORKDIR}/git"
> +
> +inherit setuptools3 native
> +
> diff --git a/recipes-devtools/python/python3-colorama_%.bbappend b/recipes-devtools/python/python3-colorama_%.bbappend
> new file mode 100644
> index 0000000..d6f5869
> --- /dev/null
> +++ b/recipes-devtools/python/python3-colorama_%.bbappend
> @@ -0,0 +1 @@
> +BBCLASSEXTEND += "native"
> diff --git a/recipes-devtools/python/python3-commonmark_0.9.1.bb b/recipes-devtools/python/python3-commonmark_0.9.1.bb
> new file mode 100644
> index 0000000..a35abc3
> --- /dev/null
> +++ b/recipes-devtools/python/python3-commonmark_0.9.1.bb
> @@ -0,0 +1,14 @@
> +SUMMARY = "Python parser for the CommonMark Markdown spec"
> +HOMEPAGE = "https://github.com/rtfd/commonmark.py"
> +AUTHOR = "Bibek Kafle <bkafle662@gmail.com>, Roland Shoemaker <rolandshoemaker@gmail.com>"
> +LICENSE = "BSD-3-Clause"
> +LIC_FILES_CHKSUM = "file://LICENSE;md5=37e127eb75a030780aefcfc584e78523"
> +
> +SRC_URI[md5sum] = "cd1dc70c4714d9ed4117a40490c25e00"
> +SRC_URI[sha256sum] = "452f9dc859be7f06631ddcb328b6919c67984aca654e5fefb3914d54691aed60"
> +
> +S = "${WORKDIR}/commonmark-0.9.1"
> +
> +inherit pypi setuptools3
> +
> +BBCLASSEXTEND += "native"
> diff --git a/recipes-devtools/python/python3-docopt_0.6.2.bb b/recipes-devtools/python/python3-docopt_0.6.2.bb
> new file mode 100644
> index 0000000..c1b111a
> --- /dev/null
> +++ b/recipes-devtools/python/python3-docopt_0.6.2.bb
> @@ -0,0 +1,18 @@
> +
> +SUMMARY = "Pythonic argument parser, that will make you smile"
> +HOMEPAGE = "http://docopt.org"
> +AUTHOR = "Vladimir Keleshev <vladimir@keleshev.com>"
> +LICENSE = "MIT"
> +LIC_FILES_CHKSUM = "file://LICENSE-MIT;md5=09b77fb74986791a3d4a0e746a37d88f"
> +
> +SRC_URI = "https://github.com/docopt/docopt/archive/refs/tags/${PV}.tar.gz"
> +SRC_URI[md5sum] = "a6c44155426fd0f7def8b2551d02fef6"
> +SRC_URI[sha256sum] = "2113eed1e7fbbcd43fb7ee6a977fb02d0b482753586c9dc1a8e3b7d541426e99"
> +
> +S = "${WORKDIR}/docopt-0.6.2"
> +
> +RDEPENDS_${PN} = ""
> +
> +inherit setuptools3
> +
> +BBCLASSEXTEND += "native"
> diff --git a/recipes-devtools/python/python3-icontract_2.5.3.bb b/recipes-devtools/python/python3-icontract_2.5.3.bb
> new file mode 100644
> index 0000000..88ac2ef
> --- /dev/null
> +++ b/recipes-devtools/python/python3-icontract_2.5.3.bb
> @@ -0,0 +1,14 @@
> +SUMMARY = "Provide design-by-contract with informative violation messages."
> +HOMEPAGE = "https://github.com/Parquery/icontract"
> +AUTHOR = "Marko Ristin <marko.ristin@gmail.com>"
> +LICENSE = "MIT"
> +LIC_FILES_CHKSUM = "file://LICENSE.txt;md5=1d4a9b1f6b84bedf7a38843931e0dd57"
> +
> +SRC_URI[md5sum] = "6f41b9b84e4405374c160836587b3235"
> +SRC_URI[sha256sum] = "b790101c8cc0d9df0105d852a645373c4d90d5049391b6e54db32a0acb4bccd7"
> +
> +inherit pypi setuptools3
> +
> +RDEPENDS_${PN} += "python3-asttokens"
> +
> +BBCLASSEXTEND += "native"
> diff --git a/recipes-devtools/python/python3-lief_0.11.5.bb b/recipes-devtools/python/python3-lief_0.11.5.bb
> new file mode 100644
> index 0000000..5e4b422
> --- /dev/null
> +++ b/recipes-devtools/python/python3-lief_0.11.5.bb
> @@ -0,0 +1,36 @@
> +SUMMARY = "Library to instrument executable formats"
> +DESCRIPTION = " \
> +    This project provides a cross platform library which can parse, modify \
> +    and abstract ELF, PE and MachO formats. \
> +  "
> +SECTION = "devel/python"
> +HOMEPAGE = "https://github.com/lief-project/LIEF"
> +LICENSE = "APACHE-2.0"
> +LIC_FILES_CHKSUM = "file://LICENSE;md5=1809bd489c3dae63aa0cb70070dc308e"
> +
> +SRC_URI = " \
> +    https://github.com/lief-project/LIEF/releases/download/${PV}/lief-${PV}.zip \
> +    file://python3-lief/0001-Enable-to-use-pre-compiled-version-of-spdlog.patch \
> +    "
> +SRC_URI[sha256sum] = "947825134d5dab91df218bb201fa4551814f1da0a47e4a890283716b800c8e8f"
> +
> +S = "${WORKDIR}/lief-${PV}"
> +
> +inherit setuptools3
> +
> +DEPENDS += "cmake-native"
> +
> +BBCLASSEXTEND += "native"
> +
> +DISTUTILS_BUILD_ARGS += " ${PARALLEL_MAKE} "
> +
> +do_compile() {
> +    # From distutils3.bbclass (needs to be modified here to avoid usage of ccache)
> +    cd ${DISTUTILS_SETUP_PATH}
> +    NO_FETCH_BUILD=1 \
> +    STAGING_INCDIR=${STAGING_INCDIR} \
> +    STAGING_LIBDIR=${STAGING_LIBDIR} \
> +    ${STAGING_BINDIR_NATIVE}/${PYTHON_PN}-native/${PYTHON_PN} setup.py \
> +    --lief-no-cache build --build-base=${B} ${DISTUTILS_BUILD_ARGS} || \
> +    bbfatal_log "'${PYTHON_PN} setup.py --lief-no-cache build ${DISTUTILS_BUILD_ARGS}' execution failed."
> +}
> diff --git a/recipes-devtools/python/python3-pylddwrap_1.0.1.bb b/recipes-devtools/python/python3-pylddwrap_1.0.1.bb
> new file mode 100644
> index 0000000..985c424
> --- /dev/null
> +++ b/recipes-devtools/python/python3-pylddwrap_1.0.1.bb
> @@ -0,0 +1,21 @@
> +SUMMARY = "Python wrapper for ldd"
> +DESCRIPTION = " \
> +    Pylddwrap wraps ldd *nix utility to determine shared libraries required by a program. \
> +  "
> +SECTION = "devel/python"
> +HOMEPAGE = "https://github.com/Parquery/pylddwrap"
> +LICENSE = "MIT"
> +LIC_FILES_CHKSUM = "file://LICENSE;md5=48fd6c978d39a38b3a04f45a1456d0fa"
> +
> +SRC_URI[sha256sum] = "171a39fc7feb33e607706c57c08373ceb2f6fd4362af9241ccc65e80c948ccdf"
> +
> +inherit pypi setuptools3
> +
> +RDEPENDS_${PN} += "python3-icontract"
> +
> +do_install_append() {
> +    rm -f "${D}/${datadir}/requirements.txt"
> +    rm -f "${D}/${datadir}/README.rst"
> +}
> +
> +BBCLASSEXTEND += "native"
> diff --git a/recipes-devtools/python/python3-rich_7.1.0.bb b/recipes-devtools/python/python3-rich_7.1.0.bb
> new file mode 100644
> index 0000000..59c26a4
> --- /dev/null
> +++ b/recipes-devtools/python/python3-rich_7.1.0.bb
> @@ -0,0 +1,16 @@
> +SUMMARY = "Render rich text, tables, progress bars, syntax highlighting, markdown and more to the terminal"
> +HOMEPAGE = "https://github.com/willmcgugan/rich"
> +AUTHOR = "Will McGugan <willmcgugan@gmail.com>"
> +LICENSE = "MIT"
> +LIC_FILES_CHKSUM = "file://LICENSE;md5=d0d35d5357392e5bfeb0d0a7e6ba4d83"
> +
> +SRC_URI[md5sum] = "25daeefa226770a84b98c591069b419c"
> +SRC_URI[sha256sum] = "ff701be541be32bcf46e821487c00bf4fa560aa814fc3cc9b3d514fd9b19a6f6"
> +
> +S = "${WORKDIR}/rich-7.1.0"
> +
> +RDEPENDS_${PN} = "python3-typing-extensions python3-pygments python3-commonmark python3-colorama"
> +
> +inherit pypi setuptools3
> +
> +BBCLASSEXTEND += "native"
> diff --git a/recipes-devtools/python/python3-setuptools-scm_6.0.1.bb b/recipes-devtools/python/python3-setuptools-scm_6.0.1.bb
> new file mode 100644
> index 0000000..234694e
> --- /dev/null
> +++ b/recipes-devtools/python/python3-setuptools-scm_6.0.1.bb
> @@ -0,0 +1,17 @@
> +SUMMARY = "the blessed package to manage your versions by scm tags"
> +HOMEPAGE = "https://github.com/pypa/setuptools_scm/"
> +AUTHOR = "Ronny Pfannschmidt <opensource@ronnypfannschmidt.de>"
> +LICENSE = "MIT"
> +LIC_FILES_CHKSUM = "file://LICENSE;md5=838c366f69b72c5df05c96dff79b35f2"
> +
> +SRC_URI = "git://github.com/pypa/setuptools_scm.git;protocol=https;branch=main;tag=v${PV}"
> +
> +SRC_URI[sha256sum] = "8f85bfc7272fb5c04df28f00bde9db8f862c586d25fa155eea90fe62ea6a3302"
> +
> +RDEPENDS_${PN} = "python3-setuptools"
> +
> +inherit setuptools3
> +
> +S = "${WORKDIR}/git"
> +
> +BBCLASSEXTEND += "native"
> diff --git a/recipes-devtools/python/python3-toml_%.bbappend b/recipes-devtools/python/python3-toml_%.bbappend
> new file mode 100644
> index 0000000..d6f5869
> --- /dev/null
> +++ b/recipes-devtools/python/python3-toml_%.bbappend
> @@ -0,0 +1 @@
> +BBCLASSEXTEND += "native"
>
> 
>


^ permalink raw reply	[flat|nested] 5+ messages in thread

* Re: [yocto] [meta-security][PATCH 1/2] image-with-hardened-binaries: add class
  2021-08-18 15:42 blenkmax
@ 2021-08-18 21:44 ` Armin Kuster
  0 siblings, 0 replies; 5+ messages in thread
From: Armin Kuster @ 2021-08-18 21:44 UTC (permalink / raw)
  To: blenkmax, yocto; +Cc: Maximilian Blenk

Hello Max,


On 8/18/21 8:42 AM, Maximilian Blenk via lists.yoctoproject.org wrote:
> Add class to analyze binaries with checksec.py. checksec.py is a tool
> that checks if security features of a compiler have been used. To do
> so, it analyses the resulting binaries:
>  * NX Proctection is enabled
>  * Full RELRO is enabled
>  * RPATH and RUNPATH are not set
>  * Executables are compiled to be position independent
>  * FORTIFY_SOURCE is set (false-positives possible)
>  * Stack Canaries are enabled (false-positives possible)
>
> Signed-off-by: Maximilian Blenk <Maximilian.Blenk@bmw.de>
> ---
> Hi guys,
>
> we are currently working on adding automatically checking the binaries
> we put into an image for the presence of certain recommended compiler
> features. To achieve this, we created a bbclass that wraps around the
> existing project checksec.py (https://github.com/Wenzel/checksec.py). In
> particular, checksec.py is used to check if
> * relro is enabled
> * executables are compiled to be position indipendet code
> * rpath and runpath are not set
> * stack canaries are enabled
> * fortify source is enabled
> I must however admit that the last two checks can suffer from
> false-positives which need manual analysis and whitelisting (check can
> also be completely disabled).
>
> Motivation:
> We've decided that such checks would be a nice thing to have because
> people might overwrite important compiler flags in their local recipe.
> Additionally there is always the possibility that components are shipped
> as binaries instead of code (so they are actually build outside the
> current build environment). Overall we've detected several cases where
> required compiler flags have not been applied to shipped components.
> After internal discussion we came to the conclusion that you guys would
> maybe also be interested in this kind of checks, so I'm offering this
> patch to you as well.

Is this a v2 or a resend?

Thanks for the patch set. I will need some time to take a look at it.

- armin
> I would really appreciate your feedback :-)
>
> BR Max
>
>  classes/image-with-hardened-binaries.bbclass  | 338 ++++++++++++++++++
>  ...1-main-Add-option-to-ignore-symlinks.patch |  81 +++++
>  .../0002-Elf-Fix-relro-detection.patch        |  51 +++
>  ...heck-Treat-binaries-with-0-fortifiab.patch |  33 ++
>  ...o-use-pre-compiled-version-of-spdlog.patch | 154 ++++++++
>  .../python/python3-asttokens_2.0.5.bb         |  15 +
>  .../python3-checksec.py-native_0.6.1.bb       |  31 ++
>  .../python/python3-colorama_%.bbappend        |   1 +
>  .../python/python3-commonmark_0.9.1.bb        |  14 +
>  .../python/python3-docopt_0.6.2.bb            |  18 +
>  .../python/python3-icontract_2.5.3.bb         |  14 +
>  .../python/python3-lief_0.11.5.bb             |  36 ++
>  .../python/python3-pylddwrap_1.0.1.bb         |  21 ++
>  recipes-devtools/python/python3-rich_7.1.0.bb |  16 +
>  .../python/python3-setuptools-scm_6.0.1.bb    |  17 +
>  .../python/python3-toml_%.bbappend            |   1 +
>  16 files changed, 841 insertions(+)
>  create mode 100644 classes/image-with-hardened-binaries.bbclass
>  create mode 100644 recipes-devtools/python/files/python3-checksec.py/0001-main-Add-option-to-ignore-symlinks.patch
>  create mode 100644 recipes-devtools/python/files/python3-checksec.py/0002-Elf-Fix-relro-detection.patch
>  create mode 100644 recipes-devtools/python/files/python3-checksec.py/0003-fortify-source-check-Treat-binaries-with-0-fortifiab.patch
>  create mode 100644 recipes-devtools/python/files/python3-lief/0001-Enable-to-use-pre-compiled-version-of-spdlog.patch
>  create mode 100644 recipes-devtools/python/python3-asttokens_2.0.5.bb
>  create mode 100644 recipes-devtools/python/python3-checksec.py-native_0.6.1.bb
>  create mode 100644 recipes-devtools/python/python3-colorama_%.bbappend
>  create mode 100644 recipes-devtools/python/python3-commonmark_0.9.1.bb
>  create mode 100644 recipes-devtools/python/python3-docopt_0.6.2.bb
>  create mode 100644 recipes-devtools/python/python3-icontract_2.5.3.bb
>  create mode 100644 recipes-devtools/python/python3-lief_0.11.5.bb
>  create mode 100644 recipes-devtools/python/python3-pylddwrap_1.0.1.bb
>  create mode 100644 recipes-devtools/python/python3-rich_7.1.0.bb
>  create mode 100644 recipes-devtools/python/python3-setuptools-scm_6.0.1.bb
>  create mode 100644 recipes-devtools/python/python3-toml_%.bbappend
>
> diff --git a/classes/image-with-hardened-binaries.bbclass b/classes/image-with-hardened-binaries.bbclass
> new file mode 100644
> index 0000000..d7d3908
> --- /dev/null
> +++ b/classes/image-with-hardened-binaries.bbclass
> @@ -0,0 +1,338 @@
> +# Provide qa checks to ensure all applications and libraries shipped with the image
> +# have common compiler security features enabled. In particular there are checks that:
> +# * nx protection is enabled
> +# * relro is enabled
> +# * executables (except for static linked ones) are position independent
> +# * rpath and runpath are not set
> +
> +IMAGE_QA_COMMANDS += "image_check_binary_hardening"
> +
> +DEPENDS += "python3-checksec.py-native"
> +
> +inherit python3native
> +
> +# Add mappings to the path mappers (which determines if a binary is a application or
> +# shared library). To add a mapping append " /path/from/the/root/to/bin:{application,library,ignore}"
> +# to the list
> +HARDENED_BINARIES_EXTRA_MAPPING ?= ""
> +
> +# Config file in TOML format:
> +# [check]
> +# enabled = true
> +# whitelist = [
> +#   "path to some binary",
> +#   "path to some other binary"
> +# ]
> +# supported checks are: nx, relro, pie, rpath, runpath
> +HARDENED_BINARIES_CONFIG_FILE ?= ""
> +
> +# Custom message to show in case of a detected violation
> +# For instace if you want to add whom to contact for support
> +HARDENED_BINARIES_CUSTOM_ERROR_MESSAGE ?= ""
> +
> +# Path to libc used for foritfy source analysis. If fortify_source check is
> +# not enabled, this variable can be ignored.
> +HARDENED_BINARIES_LIBC_PATH ?= "${IMAGE_ROOTFS}${baselib}/libc.so.6"
> +
> +python image_check_binary_hardening () {
> +    import fnmatch
> +    import json
> +    import os
> +    import subprocess
> +    import toml
> +    from collections import defaultdict, OrderedDict
> +    from enum import Enum, auto
> +
> +    from oe.utils import ImageQAFailed
> +
> +    rootfs = d.getVar("IMAGE_ROOTFS")
> +
> +    #################################
> +    ## Data about supported checks ##
> +    #################################
> +
> +    class BinType(Enum):
> +        IGNORE = "ignore"
> +        APPLICATION = "application"
> +        LIBRARY = "library"
> +
> +    # Dict of checks to perform on the analysis result of checksec.py
> +    # Each entry needs to contain the following attributes:
> +    #  - allowed_value: Value in the analysis result that should be accepted
> +    #  - bintypes: List of types on which the check shall be enforced (e.g. PIE check on libraries
> +    #              doesn't make much sense because PIE is only for executables)
> +    #  - errormsg: Message that should be prompted in case violators have been found
> +    #  - ignore_static: Indicates if statically linked applications should be ignored for that check
> +    #  Notes specific checks:
> +    #  - NX: Needs to be enforced on applications and libraries. This is because if only a single shared
> +    #        library doesn't use that, the whole process needs to have a executable stack.
> +    #  - RELRO: Statically linked applications do not make use of relocation, so this check would always
> +    #           fail for statically linked applications.
> +    #  - PIE: This check is only valid for applications (as in "position independent executable" for
> +    #         applications vs. "position independent code" (PIC) for shared libraries)
> +    CHECK_DATA = {
> +        "nx" : {
> +            "allowed_value": True,
> +            "bintypes": [BinType.APPLICATION, BinType.LIBRARY],
> +            "errormsg":
> +                "The following {} binaries do not use nx (not executable) protection. This mechanism is used " \
> +                "to separate data from executable code. Disabling this mechanism is a security issue because " \
> +                "this enables attackers to put code onto the stack. Please also note, if the nx protection is " \
> +                "disabled in a shared library, all binary objects that link against this library will not be " \
> +                "protected. This message usually appears if your binary is linked using the \"-z execstack\" " \
> +                "flag.",
> +            "ignore_static": False,
> +        },
> +        "relro": {
> +            "allowed_value": "Full",
> +            "bintypes": [BinType.APPLICATION, BinType.LIBRARY],
> +            "errormsg":
> +                "The following {} binaries do not make use of the relro (relocation read-only). This feature " \
> +                "prevents attackers from modifying addresses of functions that are located in shared libraries " \
> +                "(which is a common technique to exploit vulnerabilities). Due to this, not making use of this " \
> +                "feature is a security issue. Please make sure your application is linked using " \
> +                "\"-Wl,-z,relro,-z,now\". ",
> +            "ignore_static": True,
> +        },
> +        "rpath": {
> +            "allowed_value": False,
> +            "bintypes": [BinType.APPLICATION, BinType.LIBRARY],
> +            "errormsg":
> +                "The following {} binaries are making use of the rpath feature. This can easily enable an attacker " \
> +                "to get malicious code executed if there is some issue with the file permissions at the specified " \
> +                "location. Due to this, the usage of this feature is generally discouraged and needs approval " \
> +                "by the security team.",
> +            "ignore_static": False,
> +        },
> +        "runpath": {
> +            "allowed_value": False,
> +            "bintypes": [BinType.APPLICATION, BinType.LIBRARY],
> +            "errormsg":
> +                "The following {} binaries are making use of the runpath feature. This can easily enable an attacker" \
> +                " to get malicious code executed if there is some issue with the file permissions at the specified " \
> +                "location. Due to this, the usage of this feature is generally discouraged and needs approval " \
> +                "by the security team.",
> +            "ignore_static": False,
> +        },
> +        "pie": {
> +            "allowed_value": "PIE",
> +            "bintypes": [BinType.APPLICATION],
> +            "errormsg":
> +                "The following {} applications are not compiled to be position independent executables (pie). This " \
> +                "compiler feature compiles the code in a way that it can be mapped to any location in the virtual " \
> +                "memory. Compiling the application this way is required to make use of the Address Space Layout " \
> +                "Randomization (ASLR). This feature maps executable code to a random location, which means an " \
> +                "attacker can not rely on the fact that a specific portion of code is mapped to a specific address. " \
> +                "Please ensure that you application is compiled using \"-fPIE\".",
> +            "ignore_static": True,
> +        },
> +        "canary": {
> +            "allowed_value": True,
> +            "bintypes": [BinType.APPLICATION, BinType.LIBRARY],
> +            "errormsg":
> +                "The following {} binaries seem to be not using stack canaries. These canaries are used to mitigate " \
> +                "stack buffer overflows attacks. To do so the compiler adds checks to the end of a function to " \
> +                "ensure that this function did not overwrite the stack frames of another function. Not using " \
> +                "canaries may allow an attacker to exploit stack based buffer overflows by modifying the stack frame " \
> +                "of other function calls (which simplifies exploiting such vulnerabilities a lot). Please make sure " \
> +                "your components are compiled with the \"-fstack-protector-strong\" compile flag. Please note that " \
> +                "there is a slight possibility for false-positives in this check: The compiler checks if a function " \
> +                "needs canary protection or not. If there is no function that needs proctedtion in your binary, this " \
> +                "check will fail anyway and the binary needs to be whitelisted.",
> +            "ignore_static": False,
> +        },
> +        "fortify_source": {
> +            "allowed_value": True,
> +            "bintypes": [BinType.APPLICATION, BinType.LIBRARY],
> +            "errormsg":
> +                "The following {} binaries seem to be not using the fortify source feature. This feature protects " \
> +                "(some, not all) calls to memory manipulations function like memcpy, strcpy or strcat by adding " \
> +                "checks that prevent buffer overflows. These checks can prevent attackers from exploiting such a " \
> +                "buffer overflow. Please make sure your component is compiled with \"-D_FORTIFY_SOURCE=2\". In " \
> +                "addition the compiler optimizations need to be enabled with \"-O1\" or higher. Please note that " \
> +                "there is a slight possibility for false positives here: Not all occurences of these mentioned " \
> +                "memory calls that can not be protected they will appear as if_FORTIFY_SOURCE has not been set. " \
> +                "In such a case the binary needs to be whitelisted.",
> +            "ignore_static": False,
> +        }
> +    }
> +
> +    #################################
> +    ## Parse data from config file ##
> +    #################################
> +
> +    config_file = d.getVar("HARDENED_BINARIES_CONFIG_FILE", True)
> +    if not config_file:
> +        msg = "Hardend Binary Check: No config file specifed. Please create a config file and set " \
> +              "the variable \"HARDENED_BINARIES_CONFIG_FILE\" accordingly"
> +        raise ImageQAFailed(msg, image_check_binary_hardening)
> +
> +    CHECK_CONFIG_DATA = defaultdict(lambda: {"enabled": False})
> +    CHECK_CONFIG_DATA.update(toml.load(config_file))
> +
> +    # Expand whitelisted paths with rootfs
> +    for check, values in CHECK_CONFIG_DATA.items():
> +        values["whitelist"] = [rootfs + x for x in values["whitelist"]]
> +
> +    ###############################################
> +    ## Classes and functions to perform analysis ##
> +    ###############################################
> +
> +    class PathMapping:
> +        """ Class to map paths to BinTypes """
> +        def __init__(self, rootfs):
> +            self.rootfs = rootfs
> +            self.mapping = OrderedDict()
> +
> +            self.add("/bin/*", BinType.APPLICATION)
> +            self.add("/lib/firmware/*", BinType.IGNORE)
> +            self.add("/lib/modules/*", BinType.IGNORE)
> +            self.add("/lib/systemd/*.so", BinType.LIBRARY)
> +            self.add("/lib/systemd/*", BinType.APPLICATION)
> +            self.add("/lib/*", BinType.LIBRARY)
> +            self.add("/sbin/*", BinType.APPLICATION)
> +            self.add("/usr/bin/*", BinType.APPLICATION)
> +            self.add("/usr/libexec/*", BinType.APPLICATION)
> +            self.add("/usr/lib/firmware/*", BinType.IGNORE)
> +            self.add("/usr/lib/modules/*", BinType.IGNORE)
> +            self.add("/usr/lib/systemd/*.so", BinType.LIBRARY)
> +            self.add("/usr/lib/systemd/*", BinType.APPLICATION)
> +            self.add("/usr/lib/*", BinType.LIBRARY)
> +            self.add("/usr/sbin/*", BinType.APPLICATION)
> +
> +
> +        def add(self, path, bin_type):
> +            """ Add mapping of a path to a FileyType """
> +            self.mapping[self.rootfs + path] = bin_type
> +
> +        def map(self, path):
> +            """ Map a path to a FilesType. Returns None if path can not be mapped. """
> +            for match_path, bin_type in self.mapping.items():
> +                if fnmatch.fnmatch(path, match_path):
> +                    return bin_type
> +            else:
> +                return None
> +
> +    def call_checksec(rootfs):
> +        """ Wrapper to call the checksec.py script
> +
> +            This function returns a list of result dicts, e.g.:
> +            [
> +                ...,
> +                "/bin/systemd-hwdb": {
> +                    "relro": "No",
> +                    "canary": true,
> +                    "nx": true,
> +                    "pie": "PIE",
> +                    "rpath": false,
> +                    "runpath": false,
> +                    "symbols": false,
> +                    "fortify_source": true,
> +                    "fortified": 5,
> +                    "fortify-able": 16,
> +                    "fortify_score": 31
> +                }
> +            ]
> +
> +        """
> +        parallel_make = d.getVar("PARALLEL_MAKE")
> +
> +        cmd = ["python3", "-m", "checksec", "--json", "--recursive", "--ignore-symlinks"]
> +        if parallel_make:
> +            cmd.append(parallel_make.replace("-j", "--workers="))
> +        if CHECK_CONFIG_DATA["foritfy_source"]["enabled"]:
> +            libc_path = d.getVar("HARDENED_BINARIES_LIBC_PATH", True)
> +            cmd.append("--set-libc={}".format(libc_path))
> +        cmd.append(rootfs)
> +
> +        return json.loads(subprocess.check_output(cmd).decode('utf-8'))
> +
> +
> +    class ResultAnalyzer:
> +        """ Class to evaluate the results produced by checksec.py """
> +        def __init__(self, rootfs):
> +            self.rootfs = rootfs
> +            self.violators = defaultdict(list)
> +
> +        @staticmethod
> +        def __is_static(path):
> +            """ Checks if binary at given path is statically linked """
> +            return "statically linked" in subprocess.check_output(["file", path], stderr=subprocess.STDOUT).decode('utf-8')
> +
> +        def check_result(self, path, result, bintype):
> +            """ Perfom checks specified in CHECK_DATA on the given analysis result (of a specific binary) """
> +
> +            for check, values in CHECK_DATA.items():
> +                if CHECK_CONFIG_DATA[check]["enabled"] and bintype in values["bintypes"]:
> +                    for whitelisted in CHECK_CONFIG_DATA[check]["whitelist"]:
> +                        if fnmatch.fnmatch(path, whitelisted):
> +                            break
> +                    else:
> +                        if result[check] != values["allowed_value"] and \
> +                                (not values["ignore_static"] or not self.__is_static(path)):
> +                            self.violators[check].append(path)
> +
> +
> +    def perform_analysis(rootfs):
> +        """ Analyze all binaries in a given rootfs. In case a container shall be analyzed the absolute path to the container_path
> +            rootfs needs to be passed.
> +        """
> +
> +        # Add custom path mapping (for bins in non-standard locations)
> +        path_mapping = PathMapping(rootfs)
> +        extra_mapping = d.getVar("HARDENED_BINARIES_EXTRA_MAPPING")
> +        if extra_mapping:
> +            for mapping in extra_mapping.split():
> +                try:
> +                    path, type = mapping.split(':')
> +                except:
> +                    bb.error("Hardened Binary Checks: Got misformated extra mapping {}. Mapping needs to be " \
> +                             "in form: \"<path regex>:{application,library,ignore}\"".format(mapping))
> +                    raise
> +                path_mapping.add(path, BinType(type))
> +
> +        # Perform analysis of complete rootfs
> +        analysis_result = call_checksec(rootfs)
> +
> +        # Check analysis results and ensure that all we can actually map all binaries to a BinType
> +        result_analyzer = ResultAnalyzer(rootfs)
> +        unmapped_binaries = []
> +        for path, result in analysis_result.items():
> +            bintype = path_mapping.map(path)
> +            if bintype in [BinType.APPLICATION, BinType.LIBRARY]:
> +                result_analyzer.check_result(path, result, bintype)
> +            elif bintype != BinType.IGNORE:
> +                unmapped_binaries.append(path)
> +
> +        # To ensure that we analyze all the binaries lets break the build if we can not map binaries
> +        if unmapped_binaries:
> +            msg = "Hardend Binary Check: Couldn't figure out if the following files are applications " \
> +                  "or libraries. This is probably due to a non standard location for applications or " \
> +                  "libraries. If you think this is required add the mapping to " \
> +                  "HARDENED_BINARIES_EXTRA_MAPPING and/or contact mgu-security-frontdesk@list.bmw.com" \
> +                  "\nUnmapped:\n{}".format("\n".join(unmapped_binaries),
> +                  image_check_binary_hardening)
> +            raise ImageQAFailed(msg, image_check_binary_hardening)
> +
> +        custom_error_message = d.getVar('HARDENED_BINARIES_CUSTOM_ERROR_MESSAGE')
> +
> +        # Break the build and show error message if we detected violators that are not whitelisted
> +        errors = []
> +        for check, violators in result_analyzer.violators.items():
> +            if violators:
> +                errormsg = CHECK_DATA[check]["errormsg"].format(len(violators))
> +                errormsg += "\n{}".format("\n".join(violators))
> +                if custom_error_message:
> +                    errormsg += "\n" + custom_error_message
> +                errors.append(errormsg)
> +
> +        if errors:
> +            raise ImageQAFailed("\n".join(errors), image_check_binary_hardening)
> +
> +    ##############################
> +    ## Start analysis on rootfs ##
> +    ##############################
> +
> +    perform_analysis(rootfs)
> +
> +}
> diff --git a/recipes-devtools/python/files/python3-checksec.py/0001-main-Add-option-to-ignore-symlinks.patch b/recipes-devtools/python/files/python3-checksec.py/0001-main-Add-option-to-ignore-symlinks.patch
> new file mode 100644
> index 0000000..ae434bc
> --- /dev/null
> +++ b/recipes-devtools/python/files/python3-checksec.py/0001-main-Add-option-to-ignore-symlinks.patch
> @@ -0,0 +1,81 @@
> +From 182268203951750dcfb2c134354e801dea472e4c Mon Sep 17 00:00:00 2001
> +From: Maximilian Blenk <Maximilian.Blenk@bmw.de>
> +Date: Fri, 2 Jul 2021 14:42:25 +0200
> +Subject: [PATCH 1/2] main: Add option to ignore symlinks
> +
> +When analyzing a complete rootfs (which might not be the rootfs of the
> +analyzing system) symlinks within that rootfs might be broken. In
> +particular absolute symlinks. However, if by chance such a symlink
> +currently points to a valid binary in your system, this binary pointed
> +to is analyzed. This commit adds the possibility to ignore symlinks to
> +files (symlinks to dirs are already ignored by default). This allows to
> +solve the issue described above, and if the whole rootfs is analyzed
> +there shouldn't be a loss of information (because all the binaries will
> +be analyzed anyway). Additionally, this also saves some time when
> +performing the analysis.
> +
> +Upstream-Status: Submitted https://github.com/Wenzel/checksec.py/pull/106
> +---
> + checksec/__main__.py | 12 +++++++-----
> + 1 file changed, 7 insertions(+), 5 deletions(-)
> +
> +diff --git a/checksec/__main__.py b/checksec/__main__.py
> +index 856d0b3..f1a3445 100644
> +--- a/checksec/__main__.py
> ++++ b/checksec/__main__.py
> +@@ -8,6 +8,7 @@ Options:
> +     -w WORKERS --workers=WORKERS    Specify the number of process pool workers [default: 4]
> +     -j --json                       Display results as JSON
> +     -s LIBC --set-libc=LIBC         Specify LIBC library to use to check for fortify scores (ELF)
> ++    -i --ignore-symlinks            Ignore symlinks to files
> +     -d --debug                      Enable debug output
> +     -h --help                       Display this message
> + """
> +@@ -27,15 +28,15 @@ from .pe import PEChecksecData, PESecurity, is_pe
> + from .utils import lief_set_logging
> + 
> + 
> +-def walk_filepath_list(filepath_list: List[Path], recursive: bool = False) -> Iterator[Path]:
> ++def walk_filepath_list(filepath_list: List[Path], recursive: bool = False, ignore_symlinks: bool = False) -> Iterator[Path]:
> +     for path in filepath_list:
> +         if path.is_dir() and not path.is_symlink():
> +             if recursive:
> +                 for f in os.scandir(path):
> +-                    yield from walk_filepath_list([Path(f)], recursive)
> ++                    yield from walk_filepath_list([Path(f)], recursive, ignore_symlinks)
> +             else:
> +                 yield from (Path(f) for f in os.scandir(path))
> +-        elif path.is_file():
> ++        elif path.is_file() and (not ignore_symlinks or not path.is_symlink()):
> +             yield path
> + 
> + 
> +@@ -72,6 +73,7 @@ def main(args):
> +     json = args["--json"]
> +     recursive = args["--recursive"]
> +     libc_path = args["--set-libc"]
> ++    ignore_symlinks = args["--ignore-symlinks"]
> + 
> +     # logging
> +     formatter = "%(asctime)s %(levelname)s:%(name)s:%(message)s"
> +@@ -107,7 +109,7 @@ def main(args):
> +             # we need to consume the iterator once to get the total
> +             # for the progress bar
> +             check_output.enumerating_tasks_start()
> +-            count = sum(1 for i in walk_filepath_list(filepath_list, recursive))
> ++            count = sum(1 for i in walk_filepath_list(filepath_list, recursive, ignore_symlinks))
> +             check_output.enumerating_tasks_stop(count)
> +             with ProcessPoolExecutor(
> +                 max_workers=workers, initializer=worker_initializer, initargs=(libc_path,)
> +@@ -116,7 +118,7 @@ def main(args):
> +                     check_output.processing_tasks_start()
> +                     future_to_checksec = {
> +                         pool.submit(checksec_file, filepath): filepath
> +-                        for filepath in walk_filepath_list(filepath_list, recursive)
> ++                        for filepath in walk_filepath_list(filepath_list, recursive, ignore_symlinks)
> +                     }
> +                     for future in as_completed(future_to_checksec):
> +                         filepath = future_to_checksec[future]
> +-- 
> +2.31.1
> +
> diff --git a/recipes-devtools/python/files/python3-checksec.py/0002-Elf-Fix-relro-detection.patch b/recipes-devtools/python/files/python3-checksec.py/0002-Elf-Fix-relro-detection.patch
> new file mode 100644
> index 0000000..a891c2b
> --- /dev/null
> +++ b/recipes-devtools/python/files/python3-checksec.py/0002-Elf-Fix-relro-detection.patch
> @@ -0,0 +1,51 @@
> +From f550777f35e178bc16a2ec612b2b39aa2c3946f2 Mon Sep 17 00:00:00 2001
> +From: Maximilian Blenk <Maximilian.Blenk@bmw.de>
> +Date: Fri, 2 Jul 2021 16:16:47 +0200
> +Subject: [PATCH 2/2] Elf: Fix relro detection
> +
> +Currently, relro is only detected when the BIND_NOW is set. If however
> +the NOW flag in the FLAGS_1 section is set, relro is not detected (it
> +does not even tell that relro is enabled partially). With this commit
> +relro is detected correctly.
> +
> +Upstream-Status: Submitted https://github.com/Wenzel/checksec.py/pull/107
> +---
> + checksec/elf.py | 19 +++++++++++++++----
> + 1 file changed, 15 insertions(+), 4 deletions(-)
> +
> +diff --git a/checksec/elf.py b/checksec/elf.py
> +index 78ecacc..ef1850c 100644
> +--- a/checksec/elf.py
> ++++ b/checksec/elf.py
> +@@ -118,13 +118,24 @@ class ELFSecurity(BinarySecurity):
> +     def relro(self) -> RelroType:
> +         try:
> +             self.bin.get(lief.ELF.SEGMENT_TYPES.GNU_RELRO)
> +-            if lief.ELF.DYNAMIC_FLAGS.BIND_NOW in self.bin.get(lief.ELF.DYNAMIC_TAGS.FLAGS):
> +-                return RelroType.Full
> +-            else:
> +-                return RelroType.Partial
> +         except lief.not_found:
> +             return RelroType.No
> + 
> ++        try:
> ++            bind_now = lief.ELF.DYNAMIC_FLAGS.BIND_NOW in self.bin.get(lief.ELF.DYNAMIC_TAGS.FLAGS)
> ++        except lief.not_found:
> ++            bind_now = False
> ++
> ++        try:
> ++            now = lief.ELF.DYNAMIC_FLAGS_1.NOW in self.bin.get(lief.ELF.DYNAMIC_TAGS.FLAGS_1)
> ++        except lief.not_found:
> ++            now = False
> ++
> ++        if bind_now or now:
> ++            return RelroType.Full
> ++        else:
> ++            return RelroType.Partial
> ++
> +     @property
> +     def has_canary(self) -> bool:
> +         canary_sections = ["__stack_chk_fail", "__intel_security_cookie"]
> +-- 
> +2.31.1
> +
> diff --git a/recipes-devtools/python/files/python3-checksec.py/0003-fortify-source-check-Treat-binaries-with-0-fortifiab.patch b/recipes-devtools/python/files/python3-checksec.py/0003-fortify-source-check-Treat-binaries-with-0-fortifiab.patch
> new file mode 100644
> index 0000000..0351f84
> --- /dev/null
> +++ b/recipes-devtools/python/files/python3-checksec.py/0003-fortify-source-check-Treat-binaries-with-0-fortifiab.patch
> @@ -0,0 +1,33 @@
> +From 8de048c0065f8c5890d9e04ef2b32306e2ac4f8c Mon Sep 17 00:00:00 2001
> +From: Maximilian Blenk <Maximilian.Blenk@bmw.de>
> +Date: Thu, 5 Aug 2021 15:21:58 +0200
> +Subject: [PATCH] fortify source check: Treat binaries with 0 fortifiable as
> + fortified
> +
> +Currently, if checksec.py detects 0 fortifiable instances it still
> +treats the binary as not fortified. Semtically it would make sense to
> +treat these binaries as fortified (because there is no evidence that it
> +is not)
> +
> +Upstream-Status: Submitted https://github.com/Wenzel/checksec.py/pull/109
> +---
> + checksec/elf.py | 3 +--
> + 1 file changed, 1 insertion(+), 2 deletions(-)
> +
> +diff --git a/checksec/elf.py b/checksec/elf.py
> +index ef1850c..5914135 100644
> +--- a/checksec/elf.py
> ++++ b/checksec/elf.py
> +@@ -229,8 +229,7 @@ class ELFSecurity(BinarySecurity):
> +                 else:
> +                     score = (fortified_count * 100) / fortifiable_count
> +                     score = round(score)
> +-
> +-            fortify_source = True if fortified_count != 0 else False
> ++            fortify_source = True if fortified_count != 0 or fortifiable_count == 0 else False
> +         return ELFChecksecData(
> +             relro=self.relro,
> +             canary=self.has_canary,
> +-- 
> +2.31.1
> +
> diff --git a/recipes-devtools/python/files/python3-lief/0001-Enable-to-use-pre-compiled-version-of-spdlog.patch b/recipes-devtools/python/files/python3-lief/0001-Enable-to-use-pre-compiled-version-of-spdlog.patch
> new file mode 100644
> index 0000000..af94cfa
> --- /dev/null
> +++ b/recipes-devtools/python/files/python3-lief/0001-Enable-to-use-pre-compiled-version-of-spdlog.patch
> @@ -0,0 +1,154 @@
> +From d2ad8f6108c750c3dbd33ee6d4e4c94ada748b8a Mon Sep 17 00:00:00 2001
> +From: Romain Thomas <me@romainthomas.fr>
> +Date: Mon, 3 May 2021 11:25:49 +0200
> +Subject: [PATCH] Enable to use pre-compiled version of spdlog
> +
> +---
> + CMakeLists.txt               |  8 ++++----
> + cmake/LIEFDependencies.cmake | 36 +++++++++++++++++++++++-------------
> + cmake/LIEFOptions.cmake      |  4 ++++
> + setup.py                     | 17 +++++++++++++++++
> + 4 files changed, 48 insertions(+), 17 deletions(-)
> +
> +diff --git a/CMakeLists.txt b/CMakeLists.txt
> +index d1665cd..b92519a 100644
> +--- a/CMakeLists.txt
> ++++ b/CMakeLists.txt
> +@@ -307,8 +307,7 @@ source_group("mbedtls\\tls" FILES ${mbedtls_src_tls})
> + # Library definition
> + # ==================
> + target_include_directories(
> +-  LIB_LIEF SYSTEM PRIVATE "${SPDLOG_SOURCE_DIR}/include"
> +-                          "${MBEDTLS_INCLUDE_DIRS}")
> ++  LIB_LIEF SYSTEM PRIVATE "${MBEDTLS_INCLUDE_DIRS}")
> + 
> + target_include_directories(
> +   LIB_LIEF
> +@@ -355,7 +354,8 @@ target_sources(LIB_LIEF PRIVATE
> +   ${CMAKE_CURRENT_BINARY_DIR}/include/LIEF/third-party/utfcpp/utf8.h)
> + 
> + 
> +-add_dependencies(LIB_LIEF lief_spdlog lief_mbed_tls)
> ++add_dependencies(LIB_LIEF lief_mbed_tls)
> ++target_link_libraries(LIB_LIEF PRIVATE lief_spdlog)
> + 
> + # Flags definition
> + # ----------------
> +@@ -626,7 +626,7 @@ install(
> +   DESTINATION lib/pkgconfig
> +   COMPONENT libraries)
> + 
> +-export(TARGETS LIB_LIEF FILE LIEFExport.cmake)
> ++export(TARGETS LIB_LIEF lief_spdlog FILE LIEFExport.cmake)
> + 
> + # Package
> + # ======================
> +diff --git a/cmake/LIEFDependencies.cmake b/cmake/LIEFDependencies.cmake
> +index e75326f..37e6987 100644
> +--- a/cmake/LIEFDependencies.cmake
> ++++ b/cmake/LIEFDependencies.cmake
> +@@ -144,21 +144,31 @@ set(mbedtls_src_tls
> +   "${MBEDTLS_SOURCE_DIR}/library/ssl_tls13_keys.c"
> + )
> + 
> +-#set_source_files_properties("${MBEDTLS_SOURCE_DIR}/library/bignum.c" PROPERTIES COMPILE_FLAGS -Wno-overlength-strings)
> ++add_library(lief_spdlog INTERFACE)
> + 
> +-set(SPDLOG_VERSION 1.8.2)
> +-set(SPDLOG_SHA256 SHA256=f0410b12b526065802b40db01304783550d3d20b4b6fe2f8da55f9d08ed2035d)
> +-set(SPDLOG_URL "${THIRD_PARTY_DIRECTORY}/spdlog-${SPDLOG_VERSION}.zip" CACHE STRING "URL to the spdlog lib repo")
> +-ExternalProject_Add(lief_spdlog
> +-  URL               ${SPDLOG_URL}
> +-  URL_HASH          ${SPDLOG_SHA256}
> +-  CONFIGURE_COMMAND ""
> +-  BUILD_COMMAND     ""
> +-  UPDATE_COMMAND    ""
> +-  INSTALL_COMMAND   "")
> ++if(LIEF_EXTERNAL_SPDLOG)
> ++  find_package(spdlog REQUIRED)
> ++  list(APPEND CMAKE_MODULE_PATH "${SPDLOG_DIR}/cmake")
> ++  target_link_libraries(lief_spdlog INTERFACE spdlog::spdlog)
> ++  get_target_property(SPDLOG_INC_DIR spdlog::spdlog INTERFACE_INCLUDE_DIRECTORIES)
> ++  target_include_directories(lief_spdlog SYSTEM INTERFACE ${SPDLOG_INC_DIR})
> ++else()
> ++  set(SPDLOG_VERSION 1.8.2)
> ++  set(SPDLOG_SHA256 SHA256=f0410b12b526065802b40db01304783550d3d20b4b6fe2f8da55f9d08ed2035d)
> ++  set(SPDLOG_URL "${THIRD_PARTY_DIRECTORY}/spdlog-${SPDLOG_VERSION}.zip" CACHE STRING "URL to the spdlog source")
> ++  ExternalProject_Add(lief_spdlog_project
> ++    URL               ${SPDLOG_URL}
> ++    URL_HASH          ${SPDLOG_SHA256}
> ++    CONFIGURE_COMMAND ""
> ++    BUILD_COMMAND     ""
> ++    UPDATE_COMMAND    ""
> ++    INSTALL_COMMAND   "")
> + 
> +-ExternalProject_get_property(lief_spdlog SOURCE_DIR)
> +-set(SPDLOG_SOURCE_DIR "${SOURCE_DIR}")
> ++  ExternalProject_get_property(lief_spdlog_project SOURCE_DIR)
> ++  set(SPDLOG_SOURCE_DIR "${SOURCE_DIR}")
> ++  add_dependencies(lief_spdlog lief_spdlog_project)
> ++  target_include_directories(lief_spdlog SYSTEM INTERFACE ${SPDLOG_SOURCE_DIR}/include)
> ++endif()
> + 
> + # Fuzzing
> + # ~~~~~~~
> +diff --git a/cmake/LIEFOptions.cmake b/cmake/LIEFOptions.cmake
> +index fd6df6c..3bb92c3 100644
> +--- a/cmake/LIEFOptions.cmake
> ++++ b/cmake/LIEFOptions.cmake
> +@@ -45,6 +45,10 @@ option(LIEF_PROFILING "Enable performance profiling" OFF)
> + cmake_dependent_option(LIEF_INSTALL_COMPILED_EXAMPLES "Install LIEF Compiled examples" OFF
> +                        "LIEF_EXAMPLES" OFF)
> + 
> ++# Use a user-provided version of spdlog
> ++# It can be useful to reduce compile time
> ++option(LIEF_EXTERNAL_SPDLOG OFF)
> ++
> + set(LIEF_ELF_SUPPORT 0)
> + set(LIEF_PE_SUPPORT 0)
> + set(LIEF_MACHO_SUPPORT 0)
> +diff --git a/setup.py b/setup.py
> +index b915180..ad70bd8 100644
> +--- a/setup.py
> ++++ b/setup.py
> +@@ -45,6 +45,10 @@ class LiefDistribution(setuptools.Distribution):
> +         ('lief-no-vdex', None, 'Disable VDEX module'),
> +         ('lief-no-oat', None, 'Disable OAT module'),
> +         ('lief-no-dex', None, 'Disable DEX module'),
> ++
> ++        ('lief-no-cache', None, 'Do not use compiler cache (ccache)'),
> ++
> ++        ('spdlog-dir=', None, 'Path to the directory that contains spdlogConfig.cmake'),
> +     ]
> + 
> +     def __init__(self, attrs=None):
> +@@ -66,6 +70,10 @@ class LiefDistribution(setuptools.Distribution):
> + 
> +         self.lief_no_android  = False
> +         self.doc = False
> ++
> ++        self.lief_no_cache  = False
> ++
> ++        self.spdlog_dir = None
> +         super().__init__(attrs)
> + 
> + 
> +@@ -154,6 +162,15 @@ class BuildLibrary(build_ext):
> +         else:
> +             cmake_args += ["-DLIEF_LOGGING_DEBUG=off"]
> + 
> ++        if self.distribution.lief_no_cache:
> ++            cmake_args += ["-DLIEF_USE_CCACHE=off"]
> ++
> ++        # Setup spdlog configuration flags if
> ++        # the user provides --spdlog-dir
> ++        if self.distribution.spdlog_dir is not None:
> ++            cmake_args.append("-DLIEF_EXTERNAL_SPDLOG=ON")
> ++            cmake_args.append("-Dspdlog_DIR={}".format(self.distribution.spdlog_dir))
> ++
> +         # Main formats
> +         # ============
> +         if self.distribution.lief_no_elf:
> +-- 
> +2.31.1
> +
> diff --git a/recipes-devtools/python/python3-asttokens_2.0.5.bb b/recipes-devtools/python/python3-asttokens_2.0.5.bb
> new file mode 100644
> index 0000000..7ac2052
> --- /dev/null
> +++ b/recipes-devtools/python/python3-asttokens_2.0.5.bb
> @@ -0,0 +1,15 @@
> +SUMMARY = "Annotate AST trees with source code positions"
> +HOMEPAGE = "https://github.com/gristlabs/asttokens"
> +AUTHOR = "Dmitry Sagalovskiy, Grist Labs <dmitry@getgrist.com>"
> +LICENSE = "Apache-2.0"
> +LIC_FILES_CHKSUM = "file://LICENSE;md5=e3fc50a88d0a364313df4b21ef20c29e"
> +
> +SRC_URI[md5sum] = "0a2a057b9c9a220bffdb3e7512062f17"
> +SRC_URI[sha256sum] = "9a54c114f02c7a9480d56550932546a3f1fe71d8a02f1bc7ccd0ee3ee35cf4d5"
> +
> +RDEPENDS_${PN} = "python3-six"
> +DEPENDS += "python3-setuptools-scm python3-toml"
> +
> +inherit pypi setuptools3
> +
> +BBCLASSEXTEND += "native"
> diff --git a/recipes-devtools/python/python3-checksec.py-native_0.6.1.bb b/recipes-devtools/python/python3-checksec.py-native_0.6.1.bb
> new file mode 100644
> index 0000000..edce0a6
> --- /dev/null
> +++ b/recipes-devtools/python/python3-checksec.py-native_0.6.1.bb
> @@ -0,0 +1,31 @@
> +SUMMARY = "Tool to verify the security properties of binaries"
> +DESCRIPTION = "checksec.py is a tool verify if certain compiler flags \
> +               have been enabled on compield applications and libraries."
> +HOMEPAGE = "https://github.com/Wenzel/checksec.py"
> +BUGTRACKER = "https://github.com/Wenzel/checksec.py/issues"
> +SECTION = "devel/python"
> +
> +LICENSE = "GPL-3.0"
> +LIC_FILES_CHKSUM = "file://LICENSE;md5=1ebbd3e34237af26da5dc08a4e440464"
> +
> +RDEPENDS_${PN} += " \
> +    python3-docopt-native \
> +    python3-lief-native \
> +    python3-pylddwrap-native \
> +    python3-rich-native \
> +    "
> +
> +# Needs to be pulled from github becuase pypi package is currently broken
> +SRC_URI = " \
> +    git://github.com/Wenzel/checksec.py.git;protocol=https;branch=master \
> +    file://python3-checksec.py/0001-main-Add-option-to-ignore-symlinks.patch \
> +    file://python3-checksec.py/0002-Elf-Fix-relro-detection.patch \
> +    file://python3-checksec.py/0003-fortify-source-check-Treat-binaries-with-0-fortifiab.patch \
> +    "
> +
> +SRCREV = "4335ecd08f6ee13ff4ca9b01e83857ae6a8074e9"
> +
> +S="${WORKDIR}/git"
> +
> +inherit setuptools3 native
> +
> diff --git a/recipes-devtools/python/python3-colorama_%.bbappend b/recipes-devtools/python/python3-colorama_%.bbappend
> new file mode 100644
> index 0000000..d6f5869
> --- /dev/null
> +++ b/recipes-devtools/python/python3-colorama_%.bbappend
> @@ -0,0 +1 @@
> +BBCLASSEXTEND += "native"
> diff --git a/recipes-devtools/python/python3-commonmark_0.9.1.bb b/recipes-devtools/python/python3-commonmark_0.9.1.bb
> new file mode 100644
> index 0000000..a35abc3
> --- /dev/null
> +++ b/recipes-devtools/python/python3-commonmark_0.9.1.bb
> @@ -0,0 +1,14 @@
> +SUMMARY = "Python parser for the CommonMark Markdown spec"
> +HOMEPAGE = "https://github.com/rtfd/commonmark.py"
> +AUTHOR = "Bibek Kafle <bkafle662@gmail.com>, Roland Shoemaker <rolandshoemaker@gmail.com>"
> +LICENSE = "BSD-3-Clause"
> +LIC_FILES_CHKSUM = "file://LICENSE;md5=37e127eb75a030780aefcfc584e78523"
> +
> +SRC_URI[md5sum] = "cd1dc70c4714d9ed4117a40490c25e00"
> +SRC_URI[sha256sum] = "452f9dc859be7f06631ddcb328b6919c67984aca654e5fefb3914d54691aed60"
> +
> +S = "${WORKDIR}/commonmark-0.9.1"
> +
> +inherit pypi setuptools3
> +
> +BBCLASSEXTEND += "native"
> diff --git a/recipes-devtools/python/python3-docopt_0.6.2.bb b/recipes-devtools/python/python3-docopt_0.6.2.bb
> new file mode 100644
> index 0000000..c1b111a
> --- /dev/null
> +++ b/recipes-devtools/python/python3-docopt_0.6.2.bb
> @@ -0,0 +1,18 @@
> +
> +SUMMARY = "Pythonic argument parser, that will make you smile"
> +HOMEPAGE = "http://docopt.org"
> +AUTHOR = "Vladimir Keleshev <vladimir@keleshev.com>"
> +LICENSE = "MIT"
> +LIC_FILES_CHKSUM = "file://LICENSE-MIT;md5=09b77fb74986791a3d4a0e746a37d88f"
> +
> +SRC_URI = "https://github.com/docopt/docopt/archive/refs/tags/${PV}.tar.gz"
> +SRC_URI[md5sum] = "a6c44155426fd0f7def8b2551d02fef6"
> +SRC_URI[sha256sum] = "2113eed1e7fbbcd43fb7ee6a977fb02d0b482753586c9dc1a8e3b7d541426e99"
> +
> +S = "${WORKDIR}/docopt-0.6.2"
> +
> +RDEPENDS_${PN} = ""
> +
> +inherit setuptools3
> +
> +BBCLASSEXTEND += "native"
> diff --git a/recipes-devtools/python/python3-icontract_2.5.3.bb b/recipes-devtools/python/python3-icontract_2.5.3.bb
> new file mode 100644
> index 0000000..88ac2ef
> --- /dev/null
> +++ b/recipes-devtools/python/python3-icontract_2.5.3.bb
> @@ -0,0 +1,14 @@
> +SUMMARY = "Provide design-by-contract with informative violation messages."
> +HOMEPAGE = "https://github.com/Parquery/icontract"
> +AUTHOR = "Marko Ristin <marko.ristin@gmail.com>"
> +LICENSE = "MIT"
> +LIC_FILES_CHKSUM = "file://LICENSE.txt;md5=1d4a9b1f6b84bedf7a38843931e0dd57"
> +
> +SRC_URI[md5sum] = "6f41b9b84e4405374c160836587b3235"
> +SRC_URI[sha256sum] = "b790101c8cc0d9df0105d852a645373c4d90d5049391b6e54db32a0acb4bccd7"
> +
> +inherit pypi setuptools3
> +
> +RDEPENDS_${PN} += "python3-asttokens"
> +
> +BBCLASSEXTEND += "native"
> diff --git a/recipes-devtools/python/python3-lief_0.11.5.bb b/recipes-devtools/python/python3-lief_0.11.5.bb
> new file mode 100644
> index 0000000..5e4b422
> --- /dev/null
> +++ b/recipes-devtools/python/python3-lief_0.11.5.bb
> @@ -0,0 +1,36 @@
> +SUMMARY = "Library to instrument executable formats"
> +DESCRIPTION = " \
> +    This project provides a cross platform library which can parse, modify \
> +    and abstract ELF, PE and MachO formats. \
> +  "
> +SECTION = "devel/python"
> +HOMEPAGE = "https://github.com/lief-project/LIEF"
> +LICENSE = "APACHE-2.0"
> +LIC_FILES_CHKSUM = "file://LICENSE;md5=1809bd489c3dae63aa0cb70070dc308e"
> +
> +SRC_URI = " \
> +    https://github.com/lief-project/LIEF/releases/download/${PV}/lief-${PV}.zip \
> +    file://python3-lief/0001-Enable-to-use-pre-compiled-version-of-spdlog.patch \
> +    "
> +SRC_URI[sha256sum] = "947825134d5dab91df218bb201fa4551814f1da0a47e4a890283716b800c8e8f"
> +
> +S = "${WORKDIR}/lief-${PV}"
> +
> +inherit setuptools3
> +
> +DEPENDS += "cmake-native"
> +
> +BBCLASSEXTEND += "native"
> +
> +DISTUTILS_BUILD_ARGS += " ${PARALLEL_MAKE} "
> +
> +do_compile() {
> +    # From distutils3.bbclass (needs to be modified here to avoid usage of ccache)
> +    cd ${DISTUTILS_SETUP_PATH}
> +    NO_FETCH_BUILD=1 \
> +    STAGING_INCDIR=${STAGING_INCDIR} \
> +    STAGING_LIBDIR=${STAGING_LIBDIR} \
> +    ${STAGING_BINDIR_NATIVE}/${PYTHON_PN}-native/${PYTHON_PN} setup.py \
> +    --lief-no-cache build --build-base=${B} ${DISTUTILS_BUILD_ARGS} || \
> +    bbfatal_log "'${PYTHON_PN} setup.py --lief-no-cache build ${DISTUTILS_BUILD_ARGS}' execution failed."
> +}
> diff --git a/recipes-devtools/python/python3-pylddwrap_1.0.1.bb b/recipes-devtools/python/python3-pylddwrap_1.0.1.bb
> new file mode 100644
> index 0000000..985c424
> --- /dev/null
> +++ b/recipes-devtools/python/python3-pylddwrap_1.0.1.bb
> @@ -0,0 +1,21 @@
> +SUMMARY = "Python wrapper for ldd"
> +DESCRIPTION = " \
> +    Pylddwrap wraps ldd *nix utility to determine shared libraries required by a program. \
> +  "
> +SECTION = "devel/python"
> +HOMEPAGE = "https://github.com/Parquery/pylddwrap"
> +LICENSE = "MIT"
> +LIC_FILES_CHKSUM = "file://LICENSE;md5=48fd6c978d39a38b3a04f45a1456d0fa"
> +
> +SRC_URI[sha256sum] = "171a39fc7feb33e607706c57c08373ceb2f6fd4362af9241ccc65e80c948ccdf"
> +
> +inherit pypi setuptools3
> +
> +RDEPENDS_${PN} += "python3-icontract"
> +
> +do_install_append() {
> +    rm -f "${D}/${datadir}/requirements.txt"
> +    rm -f "${D}/${datadir}/README.rst"
> +}
> +
> +BBCLASSEXTEND += "native"
> diff --git a/recipes-devtools/python/python3-rich_7.1.0.bb b/recipes-devtools/python/python3-rich_7.1.0.bb
> new file mode 100644
> index 0000000..59c26a4
> --- /dev/null
> +++ b/recipes-devtools/python/python3-rich_7.1.0.bb
> @@ -0,0 +1,16 @@
> +SUMMARY = "Render rich text, tables, progress bars, syntax highlighting, markdown and more to the terminal"
> +HOMEPAGE = "https://github.com/willmcgugan/rich"
> +AUTHOR = "Will McGugan <willmcgugan@gmail.com>"
> +LICENSE = "MIT"
> +LIC_FILES_CHKSUM = "file://LICENSE;md5=d0d35d5357392e5bfeb0d0a7e6ba4d83"
> +
> +SRC_URI[md5sum] = "25daeefa226770a84b98c591069b419c"
> +SRC_URI[sha256sum] = "ff701be541be32bcf46e821487c00bf4fa560aa814fc3cc9b3d514fd9b19a6f6"
> +
> +S = "${WORKDIR}/rich-7.1.0"
> +
> +RDEPENDS_${PN} = "python3-typing-extensions python3-pygments python3-commonmark python3-colorama"
> +
> +inherit pypi setuptools3
> +
> +BBCLASSEXTEND += "native"
> diff --git a/recipes-devtools/python/python3-setuptools-scm_6.0.1.bb b/recipes-devtools/python/python3-setuptools-scm_6.0.1.bb
> new file mode 100644
> index 0000000..234694e
> --- /dev/null
> +++ b/recipes-devtools/python/python3-setuptools-scm_6.0.1.bb
> @@ -0,0 +1,17 @@
> +SUMMARY = "the blessed package to manage your versions by scm tags"
> +HOMEPAGE = "https://github.com/pypa/setuptools_scm/"
> +AUTHOR = "Ronny Pfannschmidt <opensource@ronnypfannschmidt.de>"
> +LICENSE = "MIT"
> +LIC_FILES_CHKSUM = "file://LICENSE;md5=838c366f69b72c5df05c96dff79b35f2"
> +
> +SRC_URI = "git://github.com/pypa/setuptools_scm.git;protocol=https;branch=main;tag=v${PV}"
> +
> +SRC_URI[sha256sum] = "8f85bfc7272fb5c04df28f00bde9db8f862c586d25fa155eea90fe62ea6a3302"
> +
> +RDEPENDS_${PN} = "python3-setuptools"
> +
> +inherit setuptools3
> +
> +S = "${WORKDIR}/git"
> +
> +BBCLASSEXTEND += "native"
> diff --git a/recipes-devtools/python/python3-toml_%.bbappend b/recipes-devtools/python/python3-toml_%.bbappend
> new file mode 100644
> index 0000000..d6f5869
> --- /dev/null
> +++ b/recipes-devtools/python/python3-toml_%.bbappend
> @@ -0,0 +1 @@
> +BBCLASSEXTEND += "native"
>
> 
>


^ permalink raw reply	[flat|nested] 5+ messages in thread

end of thread, other threads:[~2021-09-08 14:24 UTC | newest]

Thread overview: 5+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
     [not found] <378fa893-050e-ccf8-82f8-2c6f8a88f51e@gmail.com>
2021-08-19  6:05 ` [yocto] [meta-security][PATCH 1/2] image-with-hardened-binaries: add class Maximilian Blenk
2021-08-18 15:42 blenkmax
2021-08-18 21:44 ` [yocto] " Armin Kuster
  -- strict thread matches above, loose matches on Subject: below --
2021-08-13 13:18 Maximilian Blenk
2021-08-21 15:35 ` [yocto] " Armin Kuster
2021-08-21 16:59   ` Robert Berger
     [not found]     ` <195fee4b-a186-0519-2e77-da854b4f6603@gmail.com>
2021-09-08 14:26       ` Maximilian Blenk

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.