commit klp-build for openSUSE:Factory
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 - mvetter@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">mvetter@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 <mpdesouza@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)
participants (1)
-
Source-Sync