Script 'mail_helper' called by obssrc
Hello community,

here is the log from the commit of package klp-build for openSUSE:Factory 
checked in at 2024-08-14 14:16:04
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Comparing /work/SRC/openSUSE:Factory/klp-build (Old)
 and      /work/SRC/openSUSE:Factory/.klp-build.new.7232 (New)
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Package is "klp-build"

Wed Aug 14 14:16:04 2024 rev:7 rq:1193818 version:0~20240812.ad9f0e0

Changes:
--------
--- /work/SRC/openSUSE:Factory/klp-build/klp-build.changes      2024-08-01 
22:05:51.460001070 +0200
+++ /work/SRC/openSUSE:Factory/.klp-build.new.7232/klp-build.changes    
2024-08-14 14:16:50.221520570 +0200
@@ -1,0 +2,29 @@
+Wed Aug 14 06:12:41 UTC 2024 - mvet...@suse.com
+
+- Update to version 0~20240812.ad9f0e0:
+  * setup: Ignore cs_is_affected if CVE is empty
+  * Rename and fix user_path config names for kgraft-patches
+  * ibs: Move kgraft_path to where it's being used
+  * ibs: Do not remove extracted vmlinux and modules
+  * config: Support 'kgraft-patches' in config file
+  * config: Support 'patches-tests' in config file
+  * klp-ccp: Remove KLP_CCP_PATH env variable
+  * config: Support 'ccp-pol-scripts' in config file
+  * config: Support 'kernel-source' in config file
+  * config: Support per-user configuration file
+  * config.py: Check for supported attribute on modinfo by using startswith
+  * setup: Skip codestreams missing backports (not affected)
+  * ksrc: Add 15.6 RT to get the backports
+  * config: Skip symbols with empty names
+  * ibs: Fix typo when validating the livepatch
+  * ksrc: Check if all branch patches are present to mark as not affected
+  * ksrc: Simplify getting patched codestreams
+  * test.sh: Add new test for CVE-2024-40909
+  * Add zstd support
+  * Use pyelftools to parse .modinfo
+  * config: Add support to read gzipped files, like vmlinux
+  * Replace all invocations of nm binary with pyelftools
+  * Use PyElfTools in order to read object symbols
+  * test.sh: Adjust LoC count with recent clang-extract changes
+
+-------------------------------------------------------------------

Old:
----
  klp-build-0~20240731.edfe0bf.tar.xz

New:
----
  klp-build-0~20240812.ad9f0e0.tar.xz

++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Other differences:
------------------
++++++ klp-build.spec ++++++
--- /var/tmp/diff_new_pack.YSDoMN/_old  2024-08-14 14:16:50.753542810 +0200
+++ /var/tmp/diff_new_pack.YSDoMN/_new  2024-08-14 14:16:50.757542978 +0200
@@ -18,7 +18,7 @@
 
 %{!?python_sitelib: %global python_sitelib %(python -c "from 
distutils.sysconfig import get_python_lib; print(get_python_lib())")}
 Name:           klp-build
-Version:        0~20240731.edfe0bf
+Version:        0~20240812.ad9f0e0
 Release:        0
 Summary:        The kernel livepatching creation tool
 License:        GPL-2.0-only

++++++ _service ++++++
--- /var/tmp/diff_new_pack.YSDoMN/_old  2024-08-14 14:16:50.785544148 +0200
+++ /var/tmp/diff_new_pack.YSDoMN/_new  2024-08-14 14:16:50.789544315 +0200
@@ -2,7 +2,7 @@
        <service name="tar_scm" mode="manual">
                <param name="scm">git</param>
                <param name="url">https://github.com/SUSE/klp-build</param>
-               <param 
name="revision">edfe0bfa92a2a247816292a4059c206a2783bd50</param>
+               <param 
name="revision">ad9f0e08623439b67ecfa9b079f9816f10f51562</param>
                <param name="versionformat">0~%cd.%h</param>
                <param name="changesgenerate">enable</param>
         <param name="changesauthor">mvet...@suse.com</param>

++++++ klp-build-0~20240731.edfe0bf.tar.xz -> 
klp-build-0~20240812.ad9f0e0.tar.xz ++++++
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/klp-build-0~20240731.edfe0bf/klpbuild/ccp.py 
new/klp-build-0~20240812.ad9f0e0/klpbuild/ccp.py
--- old/klp-build-0~20240731.edfe0bf/klpbuild/ccp.py    2024-07-31 
22:46:43.000000000 +0200
+++ new/klp-build-0~20240812.ad9f0e0/klpbuild/ccp.py    2024-08-12 
22:38:35.000000000 +0200
@@ -17,30 +17,13 @@
 
         self.env = os.environ
 
-        # Prefer the env var to the HOME directory location
-        ccp_path = os.getenv("KLP_CCP_PATH", "")
-        if ccp_path and not Path(ccp_path).is_file():
-            raise RuntimeError("KLP_CCP_PATH does not point to a file")
-
-        elif not ccp_path:
-            ccp_path = shutil.which("klp-ccp")
-            if not ccp_path:
-                raise RuntimeError("klp-ccp not found. Aborting.")
+        ccp_path = shutil.which("klp-ccp")
+        if not ccp_path:
+            raise RuntimeError("klp-ccp not found. Aborting.")
 
         self.ccp_path = str(ccp_path)
 
-        pol_path = os.getenv("KLP_CCP_POL_PATH")
-        if pol_path and not Path(pol_path).is_dir():
-            raise RuntimeError("KLP_CCP_POL_PATH does not point to a 
directory")
-
-        elif not pol_path:
-            pol_path = Path(Path().home(), "kgr", "scripts", "ccp-pol")
-            if not pol_path.is_dir():
-                raise RuntimeError(
-                    "ccp-pol not found at ~/kgr/scripts/ccp-pol/.  Please set 
KLP_CCP_POL_PATH env var to a valid ccp-pol directory"
-                )
-
-        self.pol_path = str(pol_path)
+        self.pol_path = self.get_user_path('ccp_pol_dir')
 
         # List of symbols that are currently not resolvable for klp-ccp
         avoid_syms = [
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/klp-build-0~20240731.edfe0bf/klpbuild/config.py 
new/klp-build-0~20240812.ad9f0e0/klpbuild/config.py
--- old/klp-build-0~20240731.edfe0bf/klpbuild/config.py 2024-07-31 
22:46:43.000000000 +0200
+++ new/klp-build-0~20240812.ad9f0e0/klpbuild/config.py 2024-08-12 
22:38:35.000000000 +0200
@@ -3,7 +3,10 @@
 # Copyright (C) 2021-2024 SUSE
 # Author: Marcos Paulo de Souza <mpdeso...@suse.com>
 
+import configparser
 import copy
+import gzip
+import io
 import json
 import logging
 import os
@@ -19,16 +22,30 @@
 from klpbuild.utils import ARCH
 from klpbuild.utils import classify_codestreams
 
+from elftools.common.utils import bytes2str
+from elftools.elf.elffile import ELFFile
+from elftools.elf.sections import SymbolTableSection
+
+import zstandard
 
 class Config:
     def __init__(self, lp_name, lp_filter, kdir=False, data_dir=None, 
skips="", working_cs={}):
-        work_dir = os.getenv("KLP_WORK_DIR")
-        if not work_dir:
-            raise ValueError("KLP_WORK_DIR should be defined")
-
-        work = Path(work_dir)
-        if not work.is_dir():
-            raise ValueError("Work dir should be a directory")
+        # FIXME: Config is instantiated multiple times, meaning that the
+        # config file gets loaded and the logs are printed as many times.
+
+        logging.basicConfig(level=logging.INFO, format="%(message)s")
+
+        home = Path.home()
+        self.user_conf_file = Path(home, ".config/klp-build/config")
+        if not self.user_conf_file.is_file():
+            logging.warning(f"Warning: user configuration file not found")
+            # If there's no configuration file assume fresh install.
+            # Prepare the system with a default environment and conf.
+            self.setup_user_env(Path(home, "klp"))
+
+        self.load_user_conf()
+
+        work = self.get_user_path('work_dir')
 
         self.lp_name = lp_name
         self.lp_path = Path(work, self.lp_name)
@@ -54,19 +71,61 @@
         self.kdir = self.conf.get("kdir", False)
         self.data = Path(self.conf.get("data", "non-existent"))
         if not self.data.exists():
-            data_dir = os.getenv("KLP_DATA_DIR", "")
-            if not data_dir:
-                raise ValueError("KLP_DATA_DIR should be defined")
-            self.data = Path(data_dir)
-
-        if not self.data.is_dir():
-            raise ValueError("Data dir should be a directory")
-
-        # will contain the nm output from the to be livepatched object
-        # cache nm calls for the codestream : object
-        self.nm_out = {}
+            self.data = self.get_user_path('data_dir')
 
-        logging.basicConfig(level=logging.INFO, format="%(message)s")
+        # will contain the symbols from the to be livepatched object
+        # cached by the codestream : object
+        self.obj_symbols = {}
+
+
+    def setup_user_env(self, basedir):
+        workdir = Path(basedir, "livepatches")
+        datadir = Path(basedir, "data")
+
+        config = configparser.ConfigParser(allow_no_value=True)
+
+        config['Paths'] = {'work_dir': workdir,
+                           'data_dir': datadir,
+                           '## SUSE internal use only ##': None,
+                           '#kgr_patches_dir': 'kgraft-patches/',
+                           '#kgr_patches_tests_dir': 
'kgraft-patches_testscripts/',
+                           '#kernel_src_dir': 'kernel-src/',
+                           '#ccp_pol_dir': 'kgr-scripts/ccp-pol/'}
+
+        logging.info(f"Creating default user configuration: 
'{self.user_conf_file}'")
+        os.makedirs(os.path.dirname(self.user_conf_file), exist_ok=True)
+        with open(self.user_conf_file, 'w') as f:
+            config.write(f)
+
+        os.makedirs(workdir, exist_ok=True)
+        os.makedirs(datadir, exist_ok=True)
+
+    def load_user_conf(self):
+        config = configparser.ConfigParser()
+        logging.info(f"Loading user configuration from 
'{self.user_conf_file}'")
+        config.read(self.user_conf_file)
+
+        # Check mandatory fields
+        if 'Paths' not in config:
+            raise ValueError(f"config: 'Paths' section not found")
+
+        self.user_conf = config
+
+    def get_user_path(self, entry, isdir=True, isopt=False):
+        if entry not in self.user_conf['Paths']:
+            if isopt:
+                return ""
+            raise ValueError(f"config: '{entry}' entry not found")
+
+        p = Path(self.user_conf['Paths'][entry])
+        if not p.exists():
+            raise ValueError(f"'{p}' file or directory not found")
+        if isdir and not p.is_dir():
+                 raise ValueError("{p} should be a directory")
+        if not isdir and not p.is_file():
+                 raise ValueError("{p} should be a file")
+
+        return p
 
     def lp_out_file(self, fname):
         fpath = f'{str(fname).replace("/", "_").replace("-", "_")}'
@@ -307,9 +366,7 @@
         return self.get_data_dir(arch)
 
     def get_tests_path(self):
-        self.kgraft_tests_path = Path(Path().home(), "kgr", 
"kgraft-patches_testscripts")
-        if not self.kgraft_tests_path.is_dir():
-            raise RuntimeError(f"Couldn't find {self.kgraft_tests_path}")
+        self.kgraft_tests_path = self.get_user_path('kgr_patches_tests_dir')
 
         test_sh = Path(self.kgraft_tests_path, 
f"{self.lp_name}_test_script.sh")
         test_dir_sh = Path(self.kgraft_tests_path, 
f"{self.lp_name}/test_script.sh")
@@ -340,7 +397,13 @@
         if not obj:
             obj = self.find_module_obj(arch, cs, module)
 
-        return str(Path(self.get_mod_path(cs, arch, module), obj))
+        tmp_path = Path(self.get_mod_path(cs, arch, module), obj)
+        if not tmp_path.exists():
+            # For vmlinux files, we can have it uncompress it decompressed
+            if not self.is_mod(module):
+                return Path(str(tmp_path) + ".gz")
+
+        return tmp_path
 
     # Return only the name of the module to be livepatched
     def find_module_obj(self, arch, cs, mod, check_support=False):
@@ -355,19 +418,22 @@
 
         mod_path = self.get_mod_path(cs, arch, mod)
         with open(Path(mod_path, "modules.order")) as f:
-            obj = re.search(rf"([\w\/\-]+\/{mod}.k?o)", f.read())
-            if not obj:
+            obj_match = re.search(rf"([\w\/\-]+\/{mod}.k?o)", f.read())
+            if not obj_match:
                 raise RuntimeError(f"{cs}-{arch} ({kernel}): Module not found: 
{mod}")
 
         # if kdir if set, modules.order will show the module with suffix .o, so
-        # make sure the extension
-        obj = str(PurePath(obj.group(1)).with_suffix(".ko"))
+        # make sure the extension. Also check for multiple extensions since we
+        # can have modules being compressed using different algorithms.
+        for ext in [".ko", ".ko.zst", ".ko.gz"]:
+            obj = str(PurePath(obj_match.group(1)).with_suffix(ext))
+            if Path(mod_path, obj).exists():
+                break
 
         if check_support:
             # Validate if the module being livepatches is supported or not
-            out = subprocess.check_output(["/sbin/modinfo", obj], 
cwd=mod_path, stderr=subprocess.STDOUT).decode()
-
-            if re.search(r"supported:\s+no", out):
+            elffile = self.get_elf_object(Path(mod_path, obj))
+            if "no" == self.get_elf_modinfo_entry(elffile, "supported"):
                 print(f"WARN: {cs}-{arch} ({kernel}): Module {mod} is not 
supported by SLE")
 
         return obj
@@ -405,25 +471,76 @@
         keys = natsorted(full_cs.keys())
         return OrderedDict((k, full_cs[k]) for k in keys)
 
-    # Cache the output of nm by using the object path. It differs for each
+    def get_elf_modinfo_entry(self, elffile, conf):
+        sec = elffile.get_section_by_name(".modinfo")
+        if not sec:
+            return None
+
+        # Iterate over all info on modinfo section
+        for line in bytes2str(sec.data()).split("\0"):
+            if line.startswith(conf):
+                key, val = line.split("=")
+                return val.strip()
+
+        return ""
+
+    def get_elf_object(self, obj):
+        with open(obj, "rb") as f:
+            data = f.read()
+
+        # FIXME: use magic lib instead of checking the file extension
+        if str(obj).endswith(".gz"):
+            io_bytes = io.BytesIO(gzip.decompress(data))
+        elif str(obj).endswith(".zst"):
+            dctx = zstandard.ZstdDecompressor()
+            io_bytes = io.BytesIO(dctx.decompress(data))
+        else:
+            io_bytes = io.BytesIO(data)
+
+        return ELFFile(io_bytes)
+
+    # Load the ELF object and return all symbols
+    def get_all_symbols_from_object(self, obj, defined):
+        syms = []
+
+        elffile = self.get_elf_object(obj)
+        for sec in elffile.iter_sections():
+            if not isinstance(sec, SymbolTableSection):
+                continue
+
+            if sec['sh_entsize'] == 0:
+                continue
+
+            for symbol in sec.iter_symbols():
+                # Somehow we end up receiving an empty symbol
+                if not symbol.name:
+                    continue
+                if str(symbol["st_shndx"]) == "SHN_UNDEF" and not defined:
+                    syms.append(symbol.name)
+                elif str(symbol["st_shndx"]) != "SHN_UNDEF" and defined:
+                    syms.append(symbol.name)
+
+        return syms
+
+    # Cache the symbols using the object path. It differs for each
     # codestream and architecture
     # Return all the symbols not found per arch/obj
     def check_symbol(self, arch, cs, mod, symbols):
-        self.nm_out.setdefault(arch, {})
-        self.nm_out[arch].setdefault(cs, {})
+        self.obj_symbols.setdefault(arch, {})
+        self.obj_symbols[arch].setdefault(cs, {})
 
-        if not self.nm_out[arch][cs].get(mod, ""):
+        if not self.obj_symbols[arch][cs].get(mod, ""):
             obj = self.get_module_obj(arch, cs, mod)
-            self.nm_out[arch][cs][mod] = subprocess.check_output(["nm", 
"--defined-only", obj]).decode().strip()
+            self.obj_symbols[arch][cs][mod] = 
self.get_all_symbols_from_object(obj, True)
 
         ret = []
 
         for symbol in symbols:
-            syms = re.findall(r"[\w]+ \w {}\n".format(symbol), 
self.nm_out[arch][cs][mod])
-            if len(syms) == 0:
+            nsyms = self.obj_symbols[arch][cs][mod].count(symbol)
+            if nsyms == 0:
                 ret.append(symbol)
 
-            elif len(syms) > 1:
+            elif nsyms > 1:
                 kernel = self.get_cs_kernel(cs)
                 print(f"WARNING: {cs}-{arch} ({kernel}): symbol {symbol} 
duplicated on {mod}")
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/klp-build-0~20240731.edfe0bf/klpbuild/extractor.py 
new/klp-build-0~20240812.ad9f0e0/klpbuild/extractor.py
--- old/klp-build-0~20240731.edfe0bf/klpbuild/extractor.py      2024-07-31 
22:46:43.000000000 +0200
+++ new/klp-build-0~20240812.ad9f0e0/klpbuild/extractor.py      2024-08-12 
22:38:35.000000000 +0200
@@ -340,8 +340,8 @@
             if self.apply_patches:
                 self.remove_patches(cs, self.quilt_log)
 
-            # Map all symbols related to each obj, to make it check the output
-            # of nm only once per object
+            # Map all symbols related to each obj, to make it check the symbols
+            # only once per object
             obj_syms = {}
             for f, fdata in self.get_cs_files(cs).items():
                 for obj, syms in fdata["ext_symbols"].items():
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/klp-build-0~20240731.edfe0bf/klpbuild/ibs.py 
new/klp-build-0~20240812.ad9f0e0/klpbuild/ibs.py
--- old/klp-build-0~20240731.edfe0bf/klpbuild/ibs.py    2024-07-31 
22:46:43.000000000 +0200
+++ new/klp-build-0~20240812.ad9f0e0/klpbuild/ibs.py    2024-08-12 
22:38:35.000000000 +0200
@@ -37,10 +37,6 @@
         self.ibs_user = self.osc.username
         self.prj_prefix = f"home:{self.ibs_user}:{self.lp_name}-klp"
 
-        self.kgraft_path = Path(Path().home(), "kgr", "kgraft-patches")
-        if not self.kgraft_path.is_dir():
-            raise RuntimeError("Couldn't find ~/kgr/kgraft-patches")
-
         self.ksrc = GitHelper(self.lp_name, self.filter, False, None)
 
         # Total number of work items
@@ -191,14 +187,14 @@
             for arch in self.get_cs_archs(cs):
                 # Extract modules and vmlinux files that are compressed
                 mod_path = Path(self.get_data_dir(arch), "lib", "modules")
-                for fext, ecmd in [("zst", "unzstd --rm -f -d"), ("xz", "xz 
--quiet -d")]:
+                for fext, ecmd in [("zst", "unzstd -f -d"), ("xz", "xz --quiet 
-d -k")]:
                     cmd = rf'find {mod_path} -name "*ko.{fext}" -exec {ecmd} 
--quiet {{}} \;'
                     subprocess.check_output(cmd, shell=True)
 
                 # Extract all gzipped files under arch//boot, including 
vmlinux,
                 # symvers and maybe others.
                 vmlinux_path = Path(self.get_data_dir(arch), "boot")
-                subprocess.check_output(rf'find {vmlinux_path} -name "*gz" 
-exec gzip -d -f {{}} \;', shell=True)
+                subprocess.check_output(rf'find {vmlinux_path} -name "*gz" 
-exec gzip -k -d -f {{}} \;', shell=True)
 
             # Use the SLE .config
             shutil.copy(self.get_cs_kernel_config(cs, ARCH), 
Path(self.get_odir(cs), ".config"))
@@ -241,21 +237,16 @@
 
     def find_missing_symbols(self, cs, arch, lp_mod_path):
         vmlinux_path = self.get_cs_boot_file(cs, "vmlinux", arch)
-        vmlinux_syms = subprocess.check_output(
-            ["nm", "--defined-only", str(vmlinux_path)], 
stderr=subprocess.STDOUT
-        ).decode()
+        vmlinux_syms = self.get_all_symbols_from_object(vmlinux_path, True)
 
         # Get list of UNDEFINED symbols from the livepatch module
-        out = subprocess.check_output(["nm", "--undefined-only", 
str(lp_mod_path)], stderr=subprocess.STDOUT).decode()
-
-        # Remove the U flag from every line
-        lp_und_symbols = re.findall(r"\s+U\s([\w]+)", out)
+        lp_und_symbols = self.get_all_symbols_from_object(lp_mod_path, False)
 
         missing_syms = []
         # Find all UNDEFINED symbols that exists in the livepatch module that
         # aren't defined in the vmlinux
         for sym in lp_und_symbols:
-            if not re.search(f" {sym}", vmlinux_syms):
+            if sym not in vmlinux_syms:
                 missing_syms.append(sym)
 
         return missing_syms
@@ -278,17 +269,14 @@
         cmd = f"rpm2cpio {fdest} | cpio --quiet -uidm"
         subprocess.check_output(cmd, shell=True, cwd=rpm_dir)
 
-        lp_mod_path = Path(rpm_dir, "lib", "modules", 
f"{self.get_cs_kernel(cs)}-{ktype}", dir_path, lp_file)
-        out = subprocess.check_output(["/sbin/modinfo", str(lp_mod_path)], 
stderr=subprocess.STDOUT).decode()
-
         # Check depends field
         # At this point we found that our livepatch module depends on
         # exported functions from other modules. List the modules here.
-        match = re.search("depends:(.+)", out)
-        if match:
-            deps = match.group(1).strip()
-            if len(deps):
-                logging.warning(f"{cs}:{arch} has dependencies: {deps}.")
+        lp_mod_path = Path(rpm_dir, "lib", "modules", 
f"{self.get_cs_kernel(cs)}-{ktype}", dir_path, lp_file)
+        elffile = self.get_elf_object(lp_mod_path)
+        deps = self.get_elf_modinfo_entry(elffile, "depends")
+        if len(deps):
+            logging.warning(f"{cs}:{arch} has dependencies: {deps}.")
 
         funcs = self.find_missing_symbols(cs, arch, lp_mod_path)
         if funcs:
@@ -545,9 +533,11 @@
 
         self.osc.packages.checkout(prj, "klp", prj_path)
 
+        kgraft_path = self.get_user_path('kgr_patches_dir')
+
         # Get the code from codestream
         subprocess.check_output(
-            ["/usr/bin/git", "clone", "--single-branch", "-b", branch, 
str(self.kgraft_path), str(code_path)],
+            ["/usr/bin/git", "clone", "--single-branch", "-b", branch, 
str(kgraft_path), str(code_path)],
             stderr=subprocess.STDOUT,
         )
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/klp-build-0~20240731.edfe0bf/klpbuild/ksrc.py 
new/klp-build-0~20240812.ad9f0e0/klpbuild/ksrc.py
--- old/klp-build-0~20240731.edfe0bf/klpbuild/ksrc.py   2024-07-31 
22:46:43.000000000 +0200
+++ new/klp-build-0~20240812.ad9f0e0/klpbuild/ksrc.py   2024-08-12 
22:38:35.000000000 +0200
@@ -24,9 +24,7 @@
     def __init__(self, lp_name, lp_filter, kdir, data_dir):
         super().__init__(lp_name, lp_filter, kdir, data_dir)
 
-        self.kern_src = os.getenv("KLP_KERNEL_SOURCE", "")
-        if self.kern_src and not Path(self.kern_src).is_dir():
-            raise ValueError("KLP_KERNEL_SOURCE should point to a directory")
+        self.kern_src = self.get_user_path('kernel_src_dir', isopt=True)
 
         self.kernel_branches = {
             "12.5": "SLE12-SP5",
@@ -36,15 +34,16 @@
             "15.5": "SLE15-SP5",
             "15.5rt": "SLE15-SP5-RT",
             "15.6": "SLE15-SP6",
+            "15.6rt": "SLE15-SP6-RT",
             "cve-5.3": "cve/linux-5.3-LTSS",
             "cve-5.14": "cve/linux-5.14-LTSS",
         }
 
         self.branches = []
 
-        self.kgr_patches = Path(Path().home(), "kgr", "kgraft-patches")
-        if not self.kgr_patches.is_dir():
-            logging.warning("kgraft-patches does not exists in ~/kgr")
+        self.kgr_patches = self.get_user_path('kgr_patches_dir', isopt=True)
+        if not self.kgr_patches:
+            logging.warning("kgr_patches_dir not found")
         else:
             # Filter only the branches related to this BSC
             repo = git.Repo(self.kgr_patches).branches
@@ -55,8 +54,8 @@
     def get_cs_branch(self, cs):
         cs_sle, sp, cs_up, rt = self.get_cs_tuple(cs)
 
-        if not self.kgr_patches.is_dir():
-            logging.warning("kgraft-patches does not exists in ~/kgr")
+        if not self.kgr_patches:
+            logging.warning("kgr_patches_dir not found")
             return ""
 
         branch_name = ""
@@ -114,8 +113,8 @@
         # index 1 will be the test file
         index = 2
 
-        if not self.kgr_patches.is_dir():
-            logging.warning("kgraft-patches does not exists in ~/kgr, patches 
will be incomplete")
+        if not self.kgr_patches:
+            logging.warning("kgr_patches_dir not found, patches will be 
incomplete")
 
         # Remove dir to avoid leftover patches with different names
         patches_dir = Path(self.lp_path, "patches")
@@ -192,7 +191,7 @@
 
     def get_commits(self, cve):
         if not self.kern_src:
-            logging.info("KLP_KERNEL_SOURCE not defined, skip getting SUSE 
commits")
+            logging.info("kernel_src_dir not found, skip getting SUSE commits")
             return {}
 
         # ensure that the user informed the commits at least once per 'project'
@@ -362,7 +361,7 @@
             return []
 
         if not self.kern_src:
-            logging.info("KLP_KERNEL_SOURCE not defined, skip getting SUSE 
commits")
+            logging.info("kernel_src_dir not found, skip getting SUSE commits")
             return []
 
         print("Searching for already patched codestreams...")
@@ -373,24 +372,33 @@
             if not suse_commits:
                 continue
 
+            tag_commits = {}
+
             # Grab only the first commit, since they would be put together
             # in a release either way. The order of the array is backards, the
             # first entry will be the last patch found.
-            suse_commit = suse_commits[-1]
-
-            tags = subprocess.check_output(["/usr/bin/git", "-C", 
self.kern_src, "tag", f"--contains={suse_commit}"])
+            for su in suse_commits:
+                tag_commits[su] = []
 
-            for tag in tags.decode().splitlines():
-                tag = tag.strip()
-                if not tag.startswith("rpm-"):
-                    continue
-
-                # Remove noise around the kernel version, like
-                # rpm-5.3.18-150200.24.112--sle15-sp2-ltss-updates
-                tag = tag.replace("rpm-", "")
-                tag = re.sub("--.*", "", tag)
+                tags = subprocess.check_output(["/usr/bin/git", "-C", 
self.kern_src, "tag",
+                                                f"--contains={su}",
+                                                "rpm-*"])
+
+                for tag in tags.decode().splitlines():
+                    # Remove noise around the kernel version, like
+                    # rpm-5.3.18-150200.24.112--sle15-sp2-ltss-updates
+                    if "--" in tag:
+                        continue
 
-                patched.append(tag)
+                    tag = tag.replace("rpm-", "")
+                    tag_commits.setdefault(tag, [])
+                    tag_commits[tag].append(su)
+
+            # "patched branches" are those who contain all commits
+            total_commits = len(suse_commits)
+            for tag, b in tag_commits.items():
+                if len(b) == total_commits:
+                    patched.append(tag)
 
         # remove duplicates
         return natsorted(list(set(patched)))
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/klp-build-0~20240731.edfe0bf/klpbuild/setup.py 
new/klp-build-0~20240812.ad9f0e0/klpbuild/setup.py
--- old/klp-build-0~20240731.edfe0bf/klpbuild/setup.py  2024-07-31 
22:46:43.000000000 +0200
+++ new/klp-build-0~20240812.ad9f0e0/klpbuild/setup.py  2024-08-12 
22:38:35.000000000 +0200
@@ -166,6 +166,21 @@
 
         return f"{repo}_Products_SLERT_Update"
 
+    def cs_is_affected(self, cs):
+        # We can only check if the cs is affected or not if the CVE was 
informed
+        # (so we can get all commits related to that specific CVE). Otherwise 
we
+        # consider all codestreams as affected.
+        if not self.conf.get("cve", ""):
+            return True
+
+        sle, sp, up, rt = self.get_cs_tuple(cs)
+
+        to_check = f"{sle}.{sp}"
+        if rt:
+            to_check = f"{sle}.{sp}rt"
+
+        return len(self.conf["commits"][to_check]["commits"]) > 0
+
     def setup_codestreams(self):
         # Always get the latest supported.csv file and check the content
         # against the codestreams informed by the user
@@ -185,6 +200,7 @@
         # list of codestreams that matches the file-funcs argument
         self.working_cs = OrderedDict()
         patched_cs = []
+        unaffected_cs = []
 
         if self.no_check:
             logging.info("Option --no-check was specified, checking all 
codestreams that are not filtered out...")
@@ -195,9 +211,14 @@
                 continue
 
             # Skip patched codestreams
-            if data["kernel"] in patched_kernels and not self.no_check:
-                patched_cs.append(cs)
-                continue
+            if not self.no_check:
+                if data["kernel"] in patched_kernels:
+                    patched_cs.append(cs)
+                    continue
+
+                if not self.cs_is_affected(cs):
+                    unaffected_cs.append(cs)
+                    continue
 
             data["files"] = copy.deepcopy(self.file_funcs)
             data["repo"] = self.cs_repo(cs)
@@ -220,6 +241,11 @@
             logging.info("Skipping already patched codestreams:")
             logging.info(f'\t{" ".join(cs_list)}')
 
+        if unaffected_cs:
+            cs_list = utils.classify_codestreams(unaffected_cs)
+            logging.info("Skipping unaffected codestreams (missing 
backports):")
+            logging.info(f'\t{" ".join(cs_list)}')
+
         if not self.working_cs.keys():
             logging.info("All supported codestreams are already patched. 
Exiting klp-build")
             sys.exit(0)
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/klp-build-0~20240731.edfe0bf/setup.py 
new/klp-build-0~20240812.ad9f0e0/setup.py
--- old/klp-build-0~20240731.edfe0bf/setup.py   2024-07-31 22:46:43.000000000 
+0200
+++ new/klp-build-0~20240812.ad9f0e0/setup.py   2024-08-12 22:38:35.000000000 
+0200
@@ -24,6 +24,7 @@
         "console_scripts": ["klp-build=klpbuild.main:main"],
     },
     install_requires=[
+        "configparser",
         "cached_property",
         "GitPython",
         "lxml",
@@ -32,6 +33,8 @@
         "natsort",
         "osc-tiny",
         "requests",
-        "filelock"
+        "filelock",
+        "pyelftools",
+        "zstandard"
     ],
 )
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/klp-build-0~20240731.edfe0bf/tests/test.sh 
new/klp-build-0~20240812.ad9f0e0/tests/test.sh
--- old/klp-build-0~20240731.edfe0bf/tests/test.sh      2024-07-31 
22:46:43.000000000 +0200
+++ new/klp-build-0~20240812.ad9f0e0/tests/test.sh      2024-08-12 
22:38:35.000000000 +0200
@@ -47,28 +47,26 @@
        fi
 }
 
-# FIXME: we should take a look into it to reduce the number of lines generated
-# for:
-#      lp_cve_2024_35950
-#      lp_cve_2021_47378
 LPS=$(cat << EOF
 lp_proc_cmdline_show           105     CONFIG_PROC_FS  vmlinux         
fs/proc/cmdline.c \
                                                                        
cmdline_proc_show
-lp_cve_2021_22600              640     CONFIG_UNIX     af_packet       
net/packet/af_packet.c \
+lp_cve_2021_22600              654     CONFIG_UNIX     af_packet       
net/packet/af_packet.c \
                                                                        
packet_set_ring
-lp_ipv6_route_multipath_add    700     CONFIG_IPV6     ipv6            
net/ipv6/route.c \
+lp_ipv6_route_multipath_add    443     CONFIG_IPV6     ipv6            
net/ipv6/route.c \
                                                                        
ip6_route_multipath_add
 lp_cve_2024_27398              88      CONFIG_BT       bluetooth       
net/bluetooth/sco.c \
                                                                        
sco_sock_timeout
-lp_cve_2024_26923              170     CONFIG_UNIX     vmlinux         
net/unix/garbage.c \
+lp_cve_2024_26923              171     CONFIG_UNIX     vmlinux         
net/unix/garbage.c \
                                                                        unix_gc
-lp_cve_2024_35950              830     CONFIG_DRM      vmlinux         
drivers/gpu/drm/drm_client_modeset.c \
+lp_cve_2024_35950              842     CONFIG_DRM      vmlinux         
drivers/gpu/drm/drm_client_modeset.c \
                                                                        
drm_client_modeset_probe
-lp_cve_2021_47378              2832    CONFIG_NVME_RDMA nvme-rdma      
drivers/nvme/host/rdma.c \
+lp_cve_2021_47378              958     CONFIG_NVME_RDMA nvme-rdma      
drivers/nvme/host/rdma.c \
                                                                        
nvme_rdma_free_queue \
                                                                        
nvme_rdma_cm_handler
-lp_cve_2021_47402              194    CONFIG_NET_CLS_FLOWER cls_flower 
net/sched/cls_flower.c \
+lp_cve_2021_47402              197    CONFIG_NET_CLS_FLOWER cls_flower 
net/sched/cls_flower.c \
                                                                        fl_walk
+lp_cve_2024_40909              155     CONFIG_BPF_SYSCALL  vmlinux     
kernel/bpf/syscall.c \
+                                                                       
bpf_link_free
 EOF
 )
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/klp-build-0~20240731.edfe0bf/tests/test_ccp.py 
new/klp-build-0~20240812.ad9f0e0/tests/test_ccp.py
--- old/klp-build-0~20240731.edfe0bf/tests/test_ccp.py  2024-07-31 
22:46:43.000000000 +0200
+++ new/klp-build-0~20240812.ad9f0e0/tests/test_ccp.py  2024-08-12 
22:38:35.000000000 +0200
@@ -13,8 +13,6 @@
 
 class CcpTesting(utils.TestUtils):
     def setUp(self):
-        os.environ["KLP_KERNEL_SOURCE"] = ""
-
         logging.disable(logging.INFO)
 
     def test_detect_file_without_ftrace_support(self):
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/klp-build-0~20240731.edfe0bf/tests/test_lp_setup.py 
new/klp-build-0~20240812.ad9f0e0/tests/test_lp_setup.py
--- old/klp-build-0~20240731.edfe0bf/tests/test_lp_setup.py     2024-07-31 
22:46:43.000000000 +0200
+++ new/klp-build-0~20240812.ad9f0e0/tests/test_lp_setup.py     2024-08-12 
22:38:35.000000000 +0200
@@ -14,9 +14,6 @@
 
 class LpSetupTest(utils.TestUtils):
     def setUp(self):
-        # Avoid searching for patches kernels
-        os.environ["KLP_KERNEL_SOURCE"] = ""
-
         logging.disable(logging.INFO)
 
     def test_missing_conf_archs(self):
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/klp-build-0~20240731.edfe0bf/tests/test_templ.py 
new/klp-build-0~20240812.ad9f0e0/tests/test_templ.py
--- old/klp-build-0~20240731.edfe0bf/tests/test_templ.py        2024-07-31 
22:46:43.000000000 +0200
+++ new/klp-build-0~20240812.ad9f0e0/tests/test_templ.py        2024-08-12 
22:38:35.000000000 +0200
@@ -13,8 +13,6 @@
 
 class TemplTesting(utils.TestUtils):
     def setUp(self):
-        os.environ["KLP_KERNEL_SOURCE"] = ""
-
         logging.disable(logging.INFO)
         logging.disable(logging.WARNING)
 

Reply via email to