From 729f6f66ac041f359499e30d78a33cedc51497bf Mon Sep 17 00:00:00 2001 From: AndrewQuijano Date: Sat, 9 Nov 2024 21:49:55 -0500 Subject: [PATCH 1/2] libcapstone packaging is working correctly --- libcapstone/.gitignore | 2 + libcapstone/Dockerfile | 69 +++++++++++++++++++++++++++++++++++ libcapstone/check_capstone.sh | 46 +++++++++++++++++++++++ libcapstone/control | 34 +++++++++++++++++ libcapstone/postinst | 6 +++ libcapstone/setup.sh | 59 ++++++++++++++++++++++++++++++ 6 files changed, 216 insertions(+) create mode 100644 libcapstone/.gitignore create mode 100644 libcapstone/Dockerfile create mode 100644 libcapstone/check_capstone.sh create mode 100644 libcapstone/control create mode 100644 libcapstone/postinst create mode 100644 libcapstone/setup.sh diff --git a/libcapstone/.gitignore b/libcapstone/.gitignore new file mode 100644 index 0000000000..c636824af1 --- /dev/null +++ b/libcapstone/.gitignore @@ -0,0 +1,2 @@ +*.deb +*.txt \ No newline at end of file diff --git a/libcapstone/Dockerfile b/libcapstone/Dockerfile new file mode 100644 index 0000000000..29f139e30d --- /dev/null +++ b/libcapstone/Dockerfile @@ -0,0 +1,69 @@ +ARG VERSION="" +ARG LIBCAPSTONE_NAME="" + +# Assume this is run from capstone/debian directory +# Run in the root of the repo +# docker build -f ./debian/Dockerfile -t packager . +FROM debian:bookworm-slim + +# Install necessary tools for packaging +RUN apt-get -qq update && \ + DEBIAN_FRONTEND=noninteractive apt-get -qq install -y \ + fakeroot dpkg-dev dos2unix cmake + +# Copy your project files into the container +RUN mkdir /capstone +COPY . /capstone +WORKDIR /capstone/ + +# Using cmake, see BUILDING.md file +# For debug build change "Release" to "Debug" +RUN cmake -B build -DCMAKE_BUILD_TYPE=Release -DCAPSTONE_BUILD_SHARED_LIBS=1 +RUN cmake --build build + +# List files before cmake install +# RUN find / -type f > /before-install.txt + +# Run cmake install, by default everything goes into /usr/local +RUN cmake --install build + +# List files after cmake install +# RUN find / -type f > /after-install.txt + +# Make directories as needed +ARG LIBCAPSTONE_NAME +RUN mkdir -p /package-root/usr/lib/x86_64-linux-gnu/ +RUN mkdir -p /package-root/usr/share/doc/${LIBCAPSTONE_NAME} + +# Copy files to the package root +RUN cp -r /usr/local/lib/libcapstone* /package-root/usr/lib/x86_64-linux-gnu/ +# RUN cp /usr/share/doc/${LIBCAPSTONE_NAME} + +# Check if there is exactly one file in /package-root/usr/local/lib and rename it +RUN files=$(ls /package-root/usr/lib/x86_64-linux-gnu/libcapstone*.so) && \ + if [ $(echo "$files" | wc -l) -eq 1 ]; then \ + mv $files /package-root/usr/lib/x86_64-linux-gnu/${LIBCAPSTONE_NAME}.so; \ + else \ + echo "Error: Expected exactly one file in /package-root/usr/local/lib, found $(echo "$files" | wc -l)"; \ + exit 1; \ + fi + +# Create DEBIAN directory and control file +COPY ./libcapstone/control /package-root/DEBIAN/control + +# Update capstone.pc file with the correct version and remove archs field +# Update control file with the correct version +ARG VERSION +ARG LIBCAPSTONE_NAME +RUN sed -i "s/^Version:.*/Version: ${VERSION}/" /package-root/DEBIAN/control +RUN sed -i "s/Package: libcapstone/Package: ${LIBCAPSTONE_NAME}/" /package-root/DEBIAN/control + +# Add postinst script to run ldconfig after installation +COPY ./debian/postinst /package-root/DEBIAN/postinst +RUN chmod 755 /package-root/DEBIAN/postinst + +# Build the package +RUN fakeroot dpkg-deb --build /package-root /${LIBCAPSTONE_NAME}.deb + +# The user can now extract the .deb file from the container with something like +# docker run --rm -v $(pwd):/out packager bash -c "cp /libcapstone-dev.deb /out" diff --git a/libcapstone/check_capstone.sh b/libcapstone/check_capstone.sh new file mode 100644 index 0000000000..d5e50268f4 --- /dev/null +++ b/libcapstone/check_capstone.sh @@ -0,0 +1,46 @@ +#!/bin/bash + +# Usage: ./check_capstone_pc.sh + +DEB_FILE=$1 +EXPECTED_VERSION=$2 + +# Check if the deb file exists +if [[ ! -f "$DEB_FILE" ]]; then + echo "Debian package file not found!" + exit 1 +fi + +# Create a temporary directory to extract the deb file +TEMP_DIR=$(mktemp -d) + +# Extract the deb file +dpkg-deb -x "$DEB_FILE" "$TEMP_DIR" + +# Remove leading 'v' if present, e. g. v1.5.1 -> 1.5.1 +if [[ "$EXPECTED_VERSION" =~ ^v[0-9]+\.[0-9]+\.[0-9]+$ ]]; then + EXPECTED_VERSION=${EXPECTED_VERSION:1} +fi + +# Check if the version follows the format X.Y.Z, e. g. 1.5.1 or 1.9.1 +if [[ ! "$EXPECTED_VERSION" =~ ^[0-9]+\.[0-9]+\.[0-9]+$ ]]; then + echo "ERROR: Version must be in the format X.Y.Z" + exit 1 +fi + +# Extract the major version +major_version=$(echo "$EXPECTED_VERSION" | cut -d. -f1) +# Create the variable with the major version +libcapstone_name="libcapstone${major_version}" + +# Check if libcapstone.so is included in the package +LIBCAPSTONE_SO="$TEMP_DIR/usr/lib/x86_64-linux-gnu/${libcapstone_name}.so" +if [[ ! -f "$LIBCAPSTONE_SO" ]]; then + echo "${libcapstone_name}.so not found in the package!" + rm -rf "$TEMP_DIR" + exit 1 +fi + +echo "${libcapstone_name}.deb file is correct." +rm -rf "$TEMP_DIR" +exit 0 \ No newline at end of file diff --git a/libcapstone/control b/libcapstone/control new file mode 100644 index 0000000000..9ccd035d9e --- /dev/null +++ b/libcapstone/control @@ -0,0 +1,34 @@ +Package: libcapstone +Version: +Architecture: all +Priority: optional +Section: universe/libs +Source: capstone +Origin: Ubuntu +Maintainer: Ubuntu Developers +Original-Maintainer: Debian Security Tools +Bugs: https://bugs.launchpad.net/ubuntu/+filebug +Installed-Size: 6623 kB +Depends: libc6 (>= 2.14) +Homepage: https://www.capstone-engine.org/ +Download-Size: 664 kB +APT-Sources: http://archive.ubuntu.com/ubuntu jammy/universe amd64 Packages +Description: lightweight multi-architecture disassembly framework - library + Capstone is a lightweight multi-platform, multi-architecture disassembly + framework. + . + Features: + - Support hardware architectures: ARM, ARM64 (aka ARMv8), Mips, PowerPC & + Intel. + - Clean/simple/lightweight/intuitive architecture-neutral API. + - Provide details on disassembled instructions (called "decomposer" by some + others). + - Provide some semantics of the disassembled instruction, such as list of + implicit registers read & written. + - Implemented in pure C language, with bindings for Java, OCaml and Python + ready to use and Ruby, C#, GO & Vala available on git repos. + - Native support for Windows & *nix (with OS X, Linux, *BSD & Solaris + confirmed). + - Thread-safe by design. + - Special support for embedding into firmware or OS kernel. + - Distributed under the open source BSD license. diff --git a/libcapstone/postinst b/libcapstone/postinst new file mode 100644 index 0000000000..35ec39b8a2 --- /dev/null +++ b/libcapstone/postinst @@ -0,0 +1,6 @@ +#!/bin/bash +# postinst script for capstone package +set -e + +# Update the shared library cache +ldconfig diff --git a/libcapstone/setup.sh b/libcapstone/setup.sh new file mode 100644 index 0000000000..752f04fbfc --- /dev/null +++ b/libcapstone/setup.sh @@ -0,0 +1,59 @@ +# !/bin/bash +set -eu + +# Function to get the current Ubuntu version +get_os_version() { + lsb_release -i -s 2>/dev/null +} + +# Check if the script is running in the ./debian folder +if [[ $(basename "$PWD") != "libcapstone" ]]; then + echo "ERROR: Script must be run from the ./libcapstone directory" + exit 1 +fi + +OS_VERSION=$(get_os_version) +if [[ "$OS_VERSION" != "Ubuntu" && "$OS_VERSION" != "Debian" ]]; then + echo "ERROR: OS is not Ubuntu or Debian and unsupported" + exit 1 +fi + +# Get the version number as an input +# Check if version argument is provided +if [[ $# -ne 1 ]]; then + echo "ERROR: Version argument is required" + exit 1 +fi + +# Get the version number as an input +version=$1 + +# Remove leading 'v' if present, e. g. v1.5.1 -> 1.5.1 +if [[ "$version" =~ ^v[0-9]+\.[0-9]+\.[0-9]+$ ]]; then + version=${version:1} +fi + +# Check if the version follows the format X.Y.Z, e. g. 1.5.1 or 1.9.1 +if [[ ! "$version" =~ ^[0-9]+\.[0-9]+\.[0-9]+$ ]]; then + echo "ERROR: Version must be in the format X.Y.Z" + exit 1 +fi + +# Extract the major version +major_version=$(echo "$version" | cut -d. -f1) +# Create the variable with the major version +libcapstone_name="libcapstone${major_version}" + +# Now build the packager container from that +pushd ../ +docker build -f ./libcapstone/Dockerfile -t packager --build-arg VERSION="${version}" --build-arg LIBCAPSTONE_NAME="${libcapstone_name}" . +popd + +# Copy deb file out of container to host +docker run --rm -v $(pwd):/out packager bash -c "cp /${libcapstone_name}.deb /out" +mv ${libcapstone_name}.deb ${libcapstone_name}_${version}_amd64.deb + +# Check which files existed before and after 'make install' was executed. +# docker run --rm -v $(pwd):/out packager bash -c "cp /before-install.txt /out" +# docker run --rm -v $(pwd):/out packager bash -c "cp /after-install.txt /out" +# diff before-install.txt after-install.txt \ No newline at end of file From abeb90eac5a21fcab83db48cec78f2afa4b537aa Mon Sep 17 00:00:00 2001 From: AndrewQuijano Date: Sat, 9 Nov 2024 22:33:53 -0500 Subject: [PATCH 2/2] Need to ask about capstone.pc, softlink, and documents. But the main thing is working as intended --- libcapstone-dev/.gitignore | 2 + libcapstone-dev/Dockerfile | 61 +++++++++++++++++++++++++++++++ libcapstone-dev/check_capstone.sh | 59 ++++++++++++++++++++++++++++++ libcapstone-dev/control | 20 ++++++++++ libcapstone-dev/setup.sh | 58 +++++++++++++++++++++++++++++ libcapstone/Dockerfile | 19 ++++------ libcapstone/control | 2 +- libcapstone/setup.sh | 4 +- 8 files changed, 210 insertions(+), 15 deletions(-) create mode 100644 libcapstone-dev/.gitignore create mode 100644 libcapstone-dev/Dockerfile create mode 100644 libcapstone-dev/check_capstone.sh create mode 100644 libcapstone-dev/control create mode 100644 libcapstone-dev/setup.sh diff --git a/libcapstone-dev/.gitignore b/libcapstone-dev/.gitignore new file mode 100644 index 0000000000..c636824af1 --- /dev/null +++ b/libcapstone-dev/.gitignore @@ -0,0 +1,2 @@ +*.deb +*.txt \ No newline at end of file diff --git a/libcapstone-dev/Dockerfile b/libcapstone-dev/Dockerfile new file mode 100644 index 0000000000..2eaef60dfb --- /dev/null +++ b/libcapstone-dev/Dockerfile @@ -0,0 +1,61 @@ +ARG VERSION="" +ARG LIBCAPSTONE_NAME="" + +# Assume this is run from capstone/debian directory +# Run in the root of the repo +# docker build -f ./debian/Dockerfile -t packager . +FROM debian:bookworm-slim + +# Install necessary tools for packaging +RUN apt-get -qq update && \ + DEBIAN_FRONTEND=noninteractive apt-get -qq install -y \ + fakeroot dpkg-dev dos2unix cmake + +# Copy your project files into the container +RUN mkdir /capstone +COPY . /capstone +WORKDIR /capstone/ + +# Using cmake, see BUILDING.md file +# For debug build change "Release" to "Debug" +RUN cmake -B build -DCMAKE_BUILD_TYPE=Release -DCAPSTONE_BUILD_SHARED_LIBS=1 +RUN cmake --build build + +# List files before cmake install +# RUN find / -type f > /before-install.txt + +# Run cmake install, by default everything goes into /usr/local +RUN cmake --install build + +# List files after cmake install +# RUN find / -type f > /after-install.txt + +# Make directories as needed +RUN mkdir -p /package-root/usr/include/capstone/ +RUN mkdir -p /package-root/usr/lib/x86_64-linux-gnu/pkgconfig/ +RUN mkdir -p /package-root/usr/share/doc/libcapstone-dev/ + +# Copy /usr/local/include/capstone/ to /package-root/usr/local/include/capstone/ and all other cases +RUN cp -r /usr/local/include/capstone/* /package-root/usr/include/capstone/ +RUN cp -r /usr/local/lib/pkgconfig/capstone* /package-root/usr/lib/x86_64-linux-gnu/pkgconfig/ +RUN cp -r /usr/local/lib/libcapstone.a /package-root/usr/lib/x86_64-linux-gnu/ +# Need libcapstone.a too + +# Create DEBIAN directory and control file +COPY ./libcapstone-dev/control /package-root/DEBIAN/control + +# Update capstone.pc file with the correct version and remove archs field +# Update control file with the correct version +# TODO, I think pkgconfig needs to point from /usr/local to /usr? +ARG VERSION +ARG LIBCAPSTONE_NAME +RUN sed -i "s/^Version:.*/Version: ${VERSION}/" /package-root/DEBIAN/control +RUN sed -i "s/^Version:.*/Version: ${VERSION}/" /package-root/usr/lib/x86_64-linux-gnu/pkgconfig/capstone.pc +RUN sed -i "s/Depends: (= )/Depends: ${LIBCAPSTONE_NAME} (= ${VERSION})/" /package-root/DEBIAN/control +RUN sed -i "/^archs=/d" /package-root/usr/lib/x86_64-linux-gnu/pkgconfig/capstone.pc + +# Build the package +RUN fakeroot dpkg-deb --build /package-root /libcapstone-dev.deb + +# The user can now extract the .deb file from the container with something like +# docker run --rm -v $(pwd):/out packager bash -c "cp /libcapstone-dev.deb /out" diff --git a/libcapstone-dev/check_capstone.sh b/libcapstone-dev/check_capstone.sh new file mode 100644 index 0000000000..3624182139 --- /dev/null +++ b/libcapstone-dev/check_capstone.sh @@ -0,0 +1,59 @@ +#!/bin/bash + +# Usage: ./check_capstone_pc.sh + +DEB_FILE=$1 +EXPECTED_VERSION=$2 + +# Check if the deb file exists +if [[ ! -f "$DEB_FILE" ]]; then + echo "Debian package file not found!" + exit 1 +fi + +# Create a temporary directory to extract the deb file +TEMP_DIR=$(mktemp -d) + +# Extract the deb file +dpkg-deb -x "$DEB_FILE" "$TEMP_DIR" + +# Remove leading 'v' if present, e. g. v1.5.1 -> 1.5.1 +if [[ "$EXPECTED_VERSION" =~ ^v[0-9]+\.[0-9]+\.[0-9]+$ ]]; then + EXPECTED_VERSION=${EXPECTED_VERSION:1} +fi + +# Check if the version follows the format X.Y.Z, e. g. 1.5.1 or 1.9.1 +if [[ ! "$EXPECTED_VERSION" =~ ^[0-9]+\.[0-9]+\.[0-9]+$ ]]; then + echo "ERROR: Version must be in the format X.Y.Z" + exit 1 +fi + +# Path to the capstone.pc file +CAPSTONE_PC="$TEMP_DIR/usr/lib/x86_64-linux-gnu/pkgconfig/capstone.pc" + +# Check if the capstone.pc file exists +if [[ ! -f "$CAPSTONE_PC" ]]; then + echo "capstone.pc file not found in the package!" + rm -rf "$TEMP_DIR" + exit 1 +fi + +# Check the version in the capstone.pc file +ACTUAL_VERSION=$(grep "^Version:" "$CAPSTONE_PC" | awk '{print $2}') +if [[ "$ACTUAL_VERSION" != "$EXPECTED_VERSION" ]]; then + echo "Version mismatch! Expected: $EXPECTED_VERSION, Found: $ACTUAL_VERSION" + rm -rf "$TEMP_DIR" + exit 1 +fi + +# Check if libcapstone.a is included in the package +LIBCAPSTONE_A="$TEMP_DIR/usr/lib/x86_64-linux-gnu/libcapstone.a" +if [[ ! -f "$LIBCAPSTONE_A" ]]; then + echo "libcapstone.a not found in the package!" + rm -rf "$TEMP_DIR" + exit 1 +fi + +echo "libcapstone-dev.deb file is correct." +rm -rf "$TEMP_DIR" +exit 0 \ No newline at end of file diff --git a/libcapstone-dev/control b/libcapstone-dev/control new file mode 100644 index 0000000000..2f57bb9cf7 --- /dev/null +++ b/libcapstone-dev/control @@ -0,0 +1,20 @@ +Package: libcapstone-dev +Version: +Architecture: amd64 +Priority: optional +Section: universe/libdevel +Source: capstone +Origin: Ubuntu +Maintainer: Ubuntu Developers +Original-Maintainer: Debian Security Tools +Bugs: https://bugs.launchpad.net/ubuntu/+filebug +Installed-Size: 8255 kB +Depends: (= ) +Homepage: https://www.capstone-engine.org/ +Download-Size: 795 kB +APT-Sources: http://archive.ubuntu.com/ubuntu jammy/universe amd64 Packages +Description: lightweight multi-architecture disassembly framework - devel files + Capstone is a lightweight multi-platform, multi-architecture disassembly + framework. + . + These are the development headers and libraries. diff --git a/libcapstone-dev/setup.sh b/libcapstone-dev/setup.sh new file mode 100644 index 0000000000..0f7c5f3c65 --- /dev/null +++ b/libcapstone-dev/setup.sh @@ -0,0 +1,58 @@ +# !/bin/bash +set -eu + +# Function to get the current Ubuntu version +get_os_version() { + lsb_release -i -s 2>/dev/null +} + +# Check if the script is running in the ./debian folder +if [[ $(basename "$PWD") != "libcapstone-dev" ]]; then + echo "ERROR: Script must be run from the ./libcapstone-dev directory" + exit 1 +fi + +OS_VERSION=$(get_os_version) +if [[ "$OS_VERSION" != "Ubuntu" && "$OS_VERSION" != "Debian" ]]; then + echo "ERROR: OS is not Ubuntu or Debian and unsupported" + exit 1 +fi + +# Get the version number as an input +# Check if version argument is provided +if [[ $# -ne 1 ]]; then + echo "ERROR: Version argument is required" + exit 1 +fi + +# Get the version number as an input +version=$1 + +# Remove leading 'v' if present, e. g. v1.5.1 -> 1.5.1 +if [[ "$version" =~ ^v[0-9]+\.[0-9]+\.[0-9]+$ ]]; then + version=${version:1} +fi + +# Check if the version follows the format X.Y.Z, e. g. 1.5.1 or 1.9.1 +if [[ ! "$version" =~ ^[0-9]+\.[0-9]+\.[0-9]+$ ]]; then + echo "ERROR: Version must be in the format X.Y.Z" + exit 1 +fi + +# Extract the major version +major_version=$(echo "$version" | cut -d. -f1) +# Create the variable with the major version +libcapstone_name="libcapstone${major_version}" + +# Now build the packager container from that +pushd ../ +docker build -f ./libcapstone-dev/Dockerfile -t packager --build-arg VERSION="${version}" --build-arg LIBCAPSTONE_NAME="${libcapstone_name}" . +popd + +# Copy deb file out of container to host +docker run --rm -v $(pwd):/out packager bash -c "cp /libcapstone-dev.deb /out" + +# Check which files existed before and after 'make install' was executed. +# docker run --rm -v $(pwd):/out packager bash -c "cp /before-install.txt /out" +# docker run --rm -v $(pwd):/out packager bash -c "cp /after-install.txt /out" +# diff before-install.txt after-install.txt \ No newline at end of file diff --git a/libcapstone/Dockerfile b/libcapstone/Dockerfile index 29f139e30d..6d46f54d12 100644 --- a/libcapstone/Dockerfile +++ b/libcapstone/Dockerfile @@ -22,32 +22,27 @@ RUN cmake -B build -DCMAKE_BUILD_TYPE=Release -DCAPSTONE_BUILD_SHARED_LIBS=1 RUN cmake --build build # List files before cmake install -# RUN find / -type f > /before-install.txt +RUN find / -type f > /before-install.txt # Run cmake install, by default everything goes into /usr/local RUN cmake --install build # List files after cmake install -# RUN find / -type f > /after-install.txt +RUN find / -type f > /after-install.txt # Make directories as needed ARG LIBCAPSTONE_NAME RUN mkdir -p /package-root/usr/lib/x86_64-linux-gnu/ RUN mkdir -p /package-root/usr/share/doc/${LIBCAPSTONE_NAME} +# TODO: at the moment, I get /usr/local/lib/libcapstone.so.6.0 +# My question is, where is the .so.6.0 being populated? Should a fix be made to only have a .5, .6, etc? +# With that said, I will have to assume the version based as an argument is correct in populating the control file + # Copy files to the package root -RUN cp -r /usr/local/lib/libcapstone* /package-root/usr/lib/x86_64-linux-gnu/ +RUN cp -r /usr/local/lib/libcapstone.so* /package-root/usr/lib/x86_64-linux-gnu/ # RUN cp /usr/share/doc/${LIBCAPSTONE_NAME} -# Check if there is exactly one file in /package-root/usr/local/lib and rename it -RUN files=$(ls /package-root/usr/lib/x86_64-linux-gnu/libcapstone*.so) && \ - if [ $(echo "$files" | wc -l) -eq 1 ]; then \ - mv $files /package-root/usr/lib/x86_64-linux-gnu/${LIBCAPSTONE_NAME}.so; \ - else \ - echo "Error: Expected exactly one file in /package-root/usr/local/lib, found $(echo "$files" | wc -l)"; \ - exit 1; \ - fi - # Create DEBIAN directory and control file COPY ./libcapstone/control /package-root/DEBIAN/control diff --git a/libcapstone/control b/libcapstone/control index 9ccd035d9e..3ee0875037 100644 --- a/libcapstone/control +++ b/libcapstone/control @@ -1,6 +1,6 @@ Package: libcapstone Version: -Architecture: all +Architecture: amd64 Priority: optional Section: universe/libs Source: capstone diff --git a/libcapstone/setup.sh b/libcapstone/setup.sh index 752f04fbfc..d5e89cfda3 100644 --- a/libcapstone/setup.sh +++ b/libcapstone/setup.sh @@ -54,6 +54,6 @@ docker run --rm -v $(pwd):/out packager bash -c "cp /${libcapstone_name}.deb /ou mv ${libcapstone_name}.deb ${libcapstone_name}_${version}_amd64.deb # Check which files existed before and after 'make install' was executed. -# docker run --rm -v $(pwd):/out packager bash -c "cp /before-install.txt /out" -# docker run --rm -v $(pwd):/out packager bash -c "cp /after-install.txt /out" +docker run --rm -v $(pwd):/out packager bash -c "cp /before-install.txt /out" +docker run --rm -v $(pwd):/out packager bash -c "cp /after-install.txt /out" # diff before-install.txt after-install.txt \ No newline at end of file