首页 > 其他分享 >01.Alpine编译glibc

01.Alpine编译glibc

时间:2024-06-02 20:43:54浏览次数:24  
标签:compat bin 01 pkgdir glibc apk usr Alpine

概要

本文档采用glibc2.28版本作为示例,模拟内网环境无法访问github等开源社区

为精简docker容器镜像,采用Alpine镜像,需要手动编译glibc源代码

制作编译好的glibc二进制文件

获取glibc二进制文件构建工具

# 内网环境可下载该工具包手动上传到服务器
git pull https://github.com/sgerrand/docker-glibc-builder.git

该构建工具中需要采用wget命令从第三方仓库下载glibc源代码,由于内网环境无法访问第三方仓库,我们需要对构建工具做一些修改

修改Dockerfile

本例采用修改过的openeuler-x86镜像,在原生的基础上安装了一些常用的命令例如vimtartelnet

FROM euleros-x86:202405V1
ENV DEBIAN_FRONTEND=noninteractive \
    GLIBC_VERSION=2.28 \
    PREFIX_DIR=/usr/glibc-compat
COPY configparams /glibc-build/configparams
COPY builder /builder
# 内网环境 手动下载glibc源代码上传至根目录
COPY glibc-2.28.tar.gz /glibc-2.28.tar.gz
# gcc bison make m4 都是编译所必须的命令
RUN yum -y install gcc bison make m4
ENTRYPOINT ["/builder"]

修改bulider脚本

#!/usr/bin/env bash

set -eo pipefail; [[ "$TRACE" ]] && set -x

main() {
		# 声明 version 和 prefix 如果不存在入参指定version和prefix就使用环境变量 GLIBC_VERSION 和 PREFIX_DIR
        declare version="${1:-$GLIBC_VERSION}" prefix="${2:-$PREFIX_DIR}"

        : "${version:?}" "${prefix:?}"

        {
        		# 此处只删除了使用wget从第三方仓库下载glibc的步骤
                tar zxf /glibc-$version.tar.gz
                mkdir -p /glibc-build && cd /glibc-build
                "/glibc-$version/configure" \
                        --prefix="$prefix" \
                        --libdir="$prefix/lib" \
                        --libexecdir="$prefix/lib" \
                        --enable-multi-arch \
                        --enable-stack-protector=strong
                make && make install
                tar --dereference --hard-dereference -zcf "/glibc-bin-$version.tar.gz" "$prefix"
        } >&2

        [[ $STDOUT ]] && cat "/glibc-bin-$version.tar.gz"
}

main "$@"

构建编译glibc的镜像

# 首先进入Dockerfile文件同级目录
docker build -t "euler-glibc:2.28" .

运行 euler-glibc:2.28 镜像

# docker run --rm --env STDOUT=1 euler-glibc:2.28 {version} {prefix} > glibc-bin.tar.gz
# 上述命令的 {version} 和{prefix}即 builder脚本的入参,如果在Dockerfile中写好了环境变量,这两个值可以不要
# 直接运行该镜像,编译时间可能比较长,要稍微等待一段时间
docker run --rm --env STDOUT=1 euler-glibc:2.28 > glibc-bin.tar.gz
# 编译完成就会在当前文件夹内获得 名为 glibc-bin.tar.gz 的 libc二进制文件

制作alpine镜像apk包

获取apk包构建工具

# 内网环境同样手动下载 2.28 版本APKBUILD 有问题,建议直接使用2.35版本
git https://github.com/sgerrand/alpine-pkg-glibc.git

获取alpine镜像并配置apk源

构建apk包需要用的apk-sdk,apk是alpine的包管理工具,此处需要获取一个alpine镜像并配置apk仓库地址。

  1. 获取alpine镜像
    可以直接从dockerhub拉取一个和alpine镜像,也可以下载rootfs自己构建,此处不赘述拉取过程

  2. 配置apk源

    # 此处是我自己构建的alpine镜像所以tag是v1,具体名字根据实际的填写
    FROM alpine:v1
    RUN sed -i 's/dl-cdn.alpinelinux.org/mirrors.ustc.edu.cn/g' /etc/apk/repositories && apk update && apk add build-base alpine-sdk
    
    

    编写完成Dockerfile之后构建该镜像并命名为 alpine:v2

修改APKBUILD文件

# Maintainer: Sasha Gerrand <[email protected]>

pkgname="glibc"
pkgver="2.28"
_pkgrel="0"
pkgrel="0"
pkgdesc="GNU C Library compatibility layer"
arch="x86"
url="https://github.com/sgerrand/alpine-pkg-glibc"
license="LGPL"
source="$pkgname-bin.tar.gz
nsswitch.conf
ld.so.conf"
subpackages="$pkgname-bin $pkgname-dev $pkgname-i18n"
triggers="$pkgname-bin.trigger=/lib:/usr/lib:/usr/glibc-compat/lib"

package() {
  echo "----------------------------package  start"
  echo "$pkgdir  $srcdir $builddir"
  mkdir -p "$pkgdir/lib" "$pkgdir/usr/glibc-compat/lib/locale"  "$pkgdir"/usr/glibc-compat/lib64 "$pkgdir"/etc
  cp -a "$srcdir"/usr "$pkgdir"
  cp "$srcdir"/ld.so.conf "$pkgdir"/usr/glibc-compat/etc/ld.so.conf
  rm "$pkgdir"/usr/glibc-compat/etc/rpc
  rm -rf "$pkgdir"/usr/glibc-compat/bin
  rm -rf "$pkgdir"/usr/glibc-compat/sbin
  rm -rf "$pkgdir"/usr/glibc-compat/lib/gconv
  rm -rf "$pkgdir"/usr/glibc-compat/lib/getconf
  rm -rf "$pkgdir"/usr/glibc-compat/lib/audit
  rm -rf "$pkgdir"/usr/glibc-compat/share
  rm -rf "$pkgdir"/usr/glibc-compat/var
  ln -s /usr/glibc-compat/lib/ld-linux-x86-64.so.2 ${pkgdir}/lib/ld-linux-x86-64.so.2
  ln -s /usr/glibc-compat/lib/ld-linux-x86-64.so.2 ${pkgdir}/usr/glibc-compat/lib64/ld-linux-x86-64.so.2
  ln -s /usr/glibc-compat/etc/ld.so.cache ${pkgdir}/etc/ld.so.cache
  echo "----------------------------package  end"
}

bin() {
  echo "----------------------------bin start"
  depends="$pkgname libgcc"
  mkdir -p "$subpkgdir"/usr/glibc-compat
  cp -a "$srcdir"/usr/glibc-compat/bin "$subpkgdir"/usr/glibc-compat
  cp -a "$srcdir"/usr/glibc-compat/sbin "$subpkgdir"/usr/glibc-compat
  echo "----------------------------bin end"
}

i18n() {
  echo "----------------------------i18n start"
  depends="$pkgname-bin"
  arch="noarch"
  mkdir -p "$subpkgdir"/usr/glibc-compat
  cp -a "$srcdir"/usr/glibc-compat/share "$subpkgdir"/usr/glibc-compat
  echo "----------------------------i18n end"
}


编写构建apk包的Dockerfile

FROM alpine:v2
LABEL maintainer="su.yingjun" email="[email protected]"
VOLUME ["/home/docker/alpine-pkg-glibc","/tmp"]
# 创建构建用户
RUN adduser -D packager && addgroup packager abuild && echo 'packager ALL=(ALL) NOPASSWD:ALL' >> /etc/sudoers.d/packager && chmod o+w /tmp
#RUN adduser -D -s /bin/sh build && echo "build:build2024" | chpasswd && adduser build abuild && apk add alpine-sdk build-base abuild cmake git
COPY APKBUILD /home/packager/APKBUILD
COPY glibc-bin.tar.gz /home/packager/glibc-bin.tar.gz
COPY glibc-bin.trigger /home/packager/glibc-bin.trigger
COPY ld.so.conf /home/packager/ld.so.conf
COPY nsswitch.conf /home/packager/nsswitch.conf
USER packager
WORKDIR /home/packager
RUN abuild-keygen -n --append --install

dockerbuild -t alpine-apk-build:v1 .

运行构建apk包容器

# 此处挂载目录的原因是方便取出apk包和公钥文件,也可以使用docker cp取出
docker run --rm -it -v /home/docker/alpine-pkg-glibc:/tmp  alpine-apk-build:v1 sh
# 下方为登录容器后的命令 保证处于 /home/packager 目录下
abuild checksum
abuild -r
# 执行完成之后会在构建目录下出现 packages目录,该目录中存放打包好的apk文件,公钥文件存放在当前用户家目录下的.abuild 文件夹中,执行cp命令拷贝到挂载的目录中
cp ~/.abuild/*.rsa.pub ~/packages/glibc*.apk /tmp
# 退出容器
exit

参考资料

  1. GNU下载地址
  2. https://github.com/sgerrand/alpine-pkg-glibc
  3. https://github.com/sgerrand/docker-glibc-builder
  4. Alpine apk源
  5. Alpine Wiki
  6. https://www.youtube.com/watch?v=ibeqoQpO33w&t=697s

附录

abuild -r 构建流程

abuild 是 Alpine Linux 的构建工具,用于构建 APK 包。执行 abuild -r 命令的全流程涉及多个步骤,包括准备构建环境、构建包、运行测试和创建最终的 APK 包。以下是 abuild -r 的详细流程:

1. 准备构建环境

更新并安装依赖

  • abuild 会根据 APKBUILD 文件中的依赖定义安装构建所需的包。

初始化环境变量

  • 设置必要的环境变量,如 srcdirbuilddirpkgdir 等。

2. 提取源代码

  • 下载源代码:根据 APKBUILD 文件中的 source 字段下载源代码和补丁文件。
  • 校验文件完整性:通过校验和文件(如 sha512sums)验证下载的文件是否完整。
  • 解压源代码:将下载的源代码文件解压到 srcdir

3. 运行构建流程

prepare() 函数

  • 这是一个可选的函数,用于在实际构建之前应用补丁或进行其他准备工作。

build() 函数

  • 执行构建过程。这通常包括配置、编译和链接源代码。
  • 具体步骤由 APKBUILD 文件中的 build() 函数定义。例如,可能使用 ./configure 脚本、make 命令等。

4. 安装步骤

package() 函数

  • 安装构建好的文件到 pkgdir
  • 设置文件的权限和属性。
  • 安装文档文件(如 READMELICENSE 等)。

5. 创建 APK 包

  • abuild 会将 pkgdir 中的内容打包成一个 APK 文件。
  • 生成的 APK 文件会放在 packages 目录下。

6. 签名 APK 包

  • 如果你有签名密钥,abuild 会对生成的 APK 包进行签名。签名密钥通常存储在 ~/.abuild/ 目录中。

7. 运行测试(可选)

  • abuild 也可以运行测试(如果定义了 check() 函数)。这通常在构建后执行,用于验证包的正确性。

8. 清理

  • 清理临时文件和目录,确保构建环境干净。

标签:compat,bin,01,pkgdir,glibc,apk,usr,Alpine
From: https://www.cnblogs.com/code9xs/p/18227582

相关文章

  • P7311 [COCI2018-2019#2] Maja题解
    [COCI2018-2019#2]Maja题目描述蜜蜂Maja在一个神奇的牧场里为花朵传粉。牧场可用一个\(N\timesM\)的矩阵表示。在第\(i\)行第\(j\)列有\(C_{i,j}\)朵未传粉的花。Maja从位于第\(A\)行第\(B\)列的蜂巢出发,并前往牧场的一些区域后返回。Maja可以在\(1\)步内......
  • 23201228-第二次Blog
    一、前言:从上一次Blog到现在又完成了三次PTA大作业,这三次大作业相较于第一次Blog中的三次PTA作业而言平均难度要稍微低一点,除了本次的第一个大作业外其余两个都较为简单,也许是因为更清晰的理解了类与类之间的关系,本次的第一个大作业是基于第一次Blog中的题目迭代而来,相较于第一次......
  • 高版本glibc堆fd指针加密绕过
    高版本glibc堆fd指针加密绕过参考资料:[原创]glibc高版本堆题攻击之safeunlink-Pwn-看雪-安全社区|安全招聘|kanxue.com堆指针加密是在2.32版本引进的,作用在tcache和fastbin。主要是对fd指针进行异或操作来使得不好利用UAF等需要fd指针的手法。从一个例子了解这个保护机制bin......
  • 南昌航空大学大一下学期java题目集4-6总结性Blog-苏礼顺23201608
    一、前言——总结三次题目集的知识点、题量、难度等情况 关于知识点  这次的三次题目集更加进一步体现了面向对象程序设计的思想方法。主要是之前的三次题目集就只是利用了面向对象三大基础特性中的封装特性,而这三次的题目集增加了继承与多态,这正是面向对象设计的精髓所......
  • 【程序异常记录】01 --- python编码问题
    问题描述df=pd.read_csv(meter_path,encoding='utf-8')指定utf-8编码读取后赋值到rosmsg进行topicpublish报错error:fieldmeters_result[].task_meter_id.meter_id.alias_nameisanon-asciistringtips:str通过encode()方法可以编码为指定的bytes。反过来,当从网络或......
  • day44 01背包问题 416. 分割等和子集
    背包问题01背包有n件物品和一个最多能背重量为w的背包。第i件物品的重量是weight[i],得到的价值是value[i]。每件物品只能用一次,求解将哪些物品装入背包里物品价值总和最大。暴力的解法每一件物品其实只有两个状态,取或者不取,所以可以使用回溯法搜索出所有的情况,那么......
  • Exercise 01
    Exercise01Exercise01An1inputdeviceisanypieceof2hardwarethatallowsustosenddatatoacomputer.Soifyoutypeamessageona3keyboardortouchascreentomakesomethinghappenyouareusinganinputdevice.An4output......
  • 01 分数规划
    1问题概述分数规划是用于求一类分式的极值问题。给定两个数列\(a_i,b_i\),求出一个数列\(w_i\in\{0,1\}\),最小(大)化下列式子:\[\dfrac{\sum\limits_{i=1}^na_i\timesw_i}{\sum\limits_{i=1}^nb_i\timesw_i}\]再说直白点就是每个物品有\(a,b\)两个权值,选出当中一些物品,使......
  • ACWing算法基础课刷题记录2024-06-01--2day
    831.KMP字符串给定一个字符串 S......
  • CSP历年复赛题-P1981 [NOIP2013 普及组] 表达式求值
    原题链接:https://www.luogu.com.cn/problem/P1981题意解读:中缀表达式求值,只有+,*,没有括号,保留后4位。解题思路:中缀表达式求值的典型应用,采用两个栈:符号栈、数字栈,对于没有括号的情况,只需要如下步骤:1、遍历表达式每一个字符2、如果遇到数字,则持续提取数字,保存整数到数字栈3、......