Guest User

Untitled

a guest
Aug 27th, 2026
61
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 8.49 KB | None | 0 0
  1. #!/usr/bin/env bash
  2. #
  3. # openvas-compile.sh
  4. #
  5. # Rebuilds the Kali/Debian package that provides ospd/ospd.py (the "ospd"
  6. # source package, binary python3-ospd) with the multiprocessing start-method
  7. # fix baked in, so the patch survives inside the installed package instead of
  8. # being applied to files on disk afterwards.
  9. #
  10. # It downloads the Debian source with apt, adds a quilt patch equivalent to
  11. # ospd-openvas v22.10.5 commit a99fe321:
  12. #
  13. # multiprocessing.set_start_method('fork', force=True)
  14. #
  15. # then builds a .deb with dpkg-buildpackage. It only compiles the package;
  16. # installing the resulting .deb is left to you.
  17. #
  18. # This is the "proper package" counterpart of openvas.sh (which live-patches
  19. # the installed files). Target platform: Kali Linux (Debian based).
  20. #
  21. # Usage: sudo ./openvas-compile.sh
  22. #
  23. set -euo pipefail
  24.  
  25. RED=$'\e[31m'; GREEN=$'\e[32m'; YELLOW=$'\e[33m'; BOLD=$'\e[1m'; RESET=$'\e[0m'
  26. info() { printf '%s[*]%s %s\n' "$BOLD" "$RESET" "$*"; }
  27. ok() { printf '%s[+]%s %s\n' "$GREEN" "$RESET" "$*"; }
  28. warn() { printf '%s[!]%s %s\n' "$YELLOW" "$RESET" "$*"; }
  29. die() { printf '%s[x]%s %s\n' "$RED" "$RESET" "$*" >&2; exit 1; }
  30.  
  31. # --- 1. Must run as root ----------------------------------------------------
  32. if [[ ${EUID:-$(id -u)} -ne 0 ]]; then
  33. die "Please run as root: sudo $0"
  34. fi
  35.  
  36. # Building Debian packages as root is discouraged; allow it explicitly.
  37. export DEB_BUILD_OPTIONS="${DEB_BUILD_OPTIONS:-} nocheck"
  38.  
  39. # --- 2. Install build tooling ----------------------------------------------
  40. info "Installing build tooling (devscripts, quilt, dpkg-dev, build-essential)..."
  41. export DEBIAN_FRONTEND=noninteractive
  42. apt-get update -qq
  43. apt-get install -y --no-install-recommends \
  44. devscripts build-essential dpkg-dev quilt fakeroot dh-python \
  45. >/dev/null || die "Failed to install build tooling."
  46. ok "Build tooling ready."
  47.  
  48. # --- 3. Ensure a deb-src source is available -------------------------------
  49. if ! grep -Rqs '^\s*deb-src' /etc/apt/sources.list /etc/apt/sources.list.d/ 2>/dev/null \
  50. && ! grep -Rqs 'Types:.*deb-src' /etc/apt/sources.list.d/ 2>/dev/null; then
  51. warn "No deb-src entry found. Adding Kali source repository."
  52. cat >/etc/apt/sources.list.d/kali-src.list <<'EOF'
  53. deb-src http://http.kali.org/kali kali-rolling main contrib non-free non-free-firmware
  54. EOF
  55. apt-get update -qq || die "apt-get update failed after adding deb-src."
  56. ok "Kali deb-src repository added."
  57. fi
  58.  
  59. # --- 4. Work out which source package actually ships ospd/ospd.py ----------
  60. # The installed file may be owned by a binary package (e.g. ospd-openvas)
  61. # whose Debian *source* de-vendors the module. So we build a candidate list
  62. # and pick the first source package whose tree really contains ospd/ospd.py.
  63. info "Locating the installed ospd module and its source package..."
  64. OSPD_PY="$(python3 - <<'PY' 2>/dev/null || true
  65. import importlib.util
  66. spec = importlib.util.find_spec("ospd.ospd")
  67. print(spec.origin if spec and spec.origin else "")
  68. PY
  69. )"
  70. if [[ -z "${OSPD_PY}" || ! -f "${OSPD_PY}" ]]; then
  71. for cand in \
  72. /usr/lib/python3/dist-packages/ospd/ospd.py \
  73. /usr/local/lib/python3*/dist-packages/ospd/ospd.py \
  74. /usr/lib/python3*/site-packages/ospd/ospd.py; do
  75. [[ -f "$cand" ]] && { OSPD_PY="$cand"; break; }
  76. done
  77. fi
  78. [[ -n "${OSPD_PY}" && -f "${OSPD_PY}" ]] \
  79. || die "ospd/ospd.py is not installed. Is ospd-openvas installed?"
  80.  
  81. CANDIDATES=()
  82. BINPKG="$(dpkg -S "${OSPD_PY}" 2>/dev/null | cut -d: -f1 | tr ',' '\n' | head -n1)"
  83. if [[ -n "${BINPKG}" ]]; then
  84. SRC="$(dpkg-query -W -f='${source:Package}\n' "${BINPKG}" 2>/dev/null | head -n1)"
  85. [[ -n "${SRC}" ]] && CANDIDATES+=("${SRC}")
  86. fi
  87. # Debian de-vendors ospd into its own source package; try it explicitly too.
  88. CANDIDATES+=("ospd" "ospd-openvas")
  89. ok "ospd/ospd.py is provided by '${BINPKG:-unknown}'. Candidate sources: ${CANDIDATES[*]}"
  90.  
  91. # --- 5. Prepare an isolated work directory ---------------------------------
  92. WORKDIR="$(mktemp -d /tmp/openvas-src-build.XXXXXX)"
  93. # _apt drops privileges when downloading; make the dir readable to it.
  94. chmod 755 "${WORKDIR}"
  95. trap 'info "Build artifacts left in: ${WORKDIR}"' EXIT
  96. info "Working directory: ${WORKDIR}"
  97. cd "${WORKDIR}"
  98.  
  99. # --- 6. Download candidate sources until one contains ospd/ospd.py ----------
  100. PKG=""; SRCDIR=""; TARGET=""
  101. declare -A SEEN=()
  102. for cand in "${CANDIDATES[@]}"; do
  103. [[ -n "${SEEN[$cand]:-}" ]] && continue
  104. SEEN[$cand]=1
  105. info "Downloading source package '${cand}'..."
  106. if ! apt-get source -o APT::Sandbox::User=root "${cand}" 2>/dev/null; then
  107. warn "Could not fetch source for '${cand}'; skipping."
  108. continue
  109. fi
  110. d="$(find "${WORKDIR}" -maxdepth 1 -type d -name "${cand}-*" | head -n1)"
  111. [[ -n "$d" && -d "$d" ]] || continue
  112. t="$(cd "$d" && find . -type f -path '*/ospd/ospd.py' -printf '%P\n' 2>/dev/null | head -n1)"
  113. if [[ -n "$t" ]]; then
  114. PKG="${cand}"; SRCDIR="$d"; TARGET="$t"
  115. break
  116. fi
  117. warn "Source '${cand}' does not contain ospd/ospd.py."
  118. done
  119.  
  120. [[ -n "${SRCDIR}" ]] \
  121. || die "None of the candidate source packages contain ospd/ospd.py: ${CANDIDATES[*]}"
  122. ok "Using source package '${PKG}' (${SRCDIR}), target: ${TARGET}"
  123.  
  124. info "Installing build dependencies for ${PKG}..."
  125. apt-get build-dep -y "${PKG}" >/dev/null 2>&1 \
  126. || warn "apt-get build-dep reported issues; continuing."
  127.  
  128. cd "${SRCDIR}"
  129.  
  130. # --- 7. Skip if the upstream source already contains the fix ---------------
  131. if grep -Eq "set_start_method\(\s*['\"]fork['\"]" "${TARGET}"; then
  132. ok "Source already contains the fork start-method fix (>= v22.10.5)."
  133. warn "Rebuilding anyway would not change behaviour; installing stock is enough."
  134. warn "Run: apt-get install --only-upgrade ${PKG}"
  135. exit 0
  136. fi
  137.  
  138. # --- 8. Add the fix as a quilt patch ---------------------------------------
  139. info "Creating quilt patch with the multiprocessing fix..."
  140. export QUILT_PATCHES=debian/patches
  141. export QUILT_PATCH_OPTS="--reject-format=unified"
  142. mkdir -p debian/patches
  143.  
  144. quilt new fix-multiprocessing-start-method.patch
  145. quilt add "${TARGET}"
  146.  
  147. # Edit the tracked file: ensure the import exists and insert the fix line
  148. # right after the module logger definition (matching upstream a99fe321).
  149. python3 - "${TARGET}" <<'PY'
  150. import io, re, sys
  151.  
  152. path = sys.argv[1]
  153. with io.open(path, "r", encoding="utf-8") as f:
  154. src = f.read()
  155.  
  156. fix_line = "multiprocessing.set_start_method('fork', force=True)\n"
  157.  
  158. if not re.search(r"^\s*import\s+multiprocessing\b", src, re.MULTILINE):
  159. lines = src.splitlines(keepends=True)
  160. last_import = 0
  161. for i, line in enumerate(lines):
  162. if re.match(r"^\s*(import|from)\s+\S", line):
  163. last_import = i + 1
  164. lines.insert(last_import, "import multiprocessing\n")
  165. src = "".join(lines)
  166.  
  167. if "set_start_method('fork'" not in src and 'set_start_method("fork"' not in src:
  168. anchor = re.search(r"^logger\s*=\s*logging\.getLogger\(__name__\).*$",
  169. src, re.MULTILINE)
  170. if anchor:
  171. idx = anchor.end()
  172. src = src[:idx] + "\n\n" + fix_line + src[idx:]
  173. else:
  174. lines = src.splitlines(keepends=True)
  175. last_import = 0
  176. for i, line in enumerate(lines):
  177. if re.match(r"^\s*(import|from)\s+\S", line):
  178. last_import = i + 1
  179. lines.insert(last_import, "\n" + fix_line)
  180. src = "".join(lines)
  181.  
  182. with io.open(path, "w", encoding="utf-8") as f:
  183. f.write(src)
  184. PY
  185.  
  186. quilt refresh
  187. ok "Patch recorded in debian/patches/."
  188.  
  189. # --- 9. Add a changelog entry (required to produce a versioned build) ------
  190. info "Adding changelog entry..."
  191. DEBEMAIL="${DEBEMAIL:-openvas-fix@localhost}" \
  192. DEBFULLNAME="${DEBFULLNAME:-OpenVAS Local Fix}" \
  193. dch --local "+fork" \
  194. "Force multiprocessing 'fork' start method (backport of v22.10.5 a99fe321)."
  195.  
  196. # --- 10. Build the binary package ------------------------------------------
  197. info "Building the package with dpkg-buildpackage (binary only)..."
  198. dpkg-buildpackage -us -uc -b -rfakeroot \
  199. || die "Package build failed. See output above."
  200. ok "Package built."
  201.  
  202. # --- 11. Report the produced .deb(s) ---------------------------------------
  203. shopt -s nullglob
  204. DEBS=( "${WORKDIR}"/*.deb )
  205. shopt -u nullglob
  206. [[ ${#DEBS[@]} -gt 0 ]] || die "No .deb produced in ${WORKDIR}."
  207.  
  208. echo
  209. ok "Done. Patched ${PKG} package(s) built:"
  210. for deb in "${DEBS[@]}"; do
  211. info " ${deb}"
  212. done
  213. info "Install manually with:"
  214. info " sudo apt-get install --allow-downgrades ${DEBS[*]}"
  215.  
Advertisement
Add Comment
Please, Sign In to add comment