rsync 学习笔记(一)编译

一、背景

  rsync二进制程序依赖外部库,由于安全问题,有时会单独升级依赖的外部库。另外为了防止因为栈溢出攻击导致服务器被黑,需要对rsync及其依赖的外部库重新编译,开启安全编译选项,增加黑客破解的复杂度。

  所有的库编译必须要求加上如下编译选项:

  • 栈保护(-fstack-protector-all/-fstack-protector-strong)
  • 堆栈不可执行(-Wl,-z,noexecstack)
  • GOT表保护(-Wl,-z,relro)
  • 地址无关代码/地址无关可执行(-fPIC/-fPIE -pie)
  • 立即加载(-Wl,-z,now)
  • strip
  • 指定动态库搜索路径(-Wl,--disable-new-dtags,–rpath,./)

栈保护选项,编译器如果支持strong则开启 -fstack-protector-strong,编译器如果不支持则开启-fstack-protector-all

-Wl,--disable-new-dtags,–rpath,./  指定动态库搜索路径,根据实际引用的库的相对路径配置,如果组件不依赖其它库则不需要

二、操作步骤

1、 rsync依赖的开源库

(1)   通过 ldd rsync 命令查看 rsync二进制软件依赖的库

远程到安装rsync的服务器上,执行 ldd rsync,查看rsync依赖哪些库。

 

通过上图的执行结果,可以看到 rsync 依赖的开源库包括如下:

  • libattr
  • libacl
  • libz
  • liblz4
  • libzstd
  • libxxhash
  • libcrypto

(2)   访问 rsync的github代码库,查看其说明再次确认依赖的库情况

访问地址:https://github.com/RsyncProject/rsync/blob/master/INSTALL.md

从上面可以看到官方介绍依赖的开源库是:

  • acl
  • xattr
  • xxhash
  • zstd
  • lz4
  • openssl crypto

和 ldd 查看比较发现缺少一个libz,而这个对应的是zlib,观察rsync的代码库可以发现其内置了zlib,但是我们需要安全编译,也方便日后可以单独升级 zlib,因此需要关闭不使用其内置的zlib,直接依赖外部的zlib库。

总结以上,rsync依赖的开源库如下

  • acl
  • xattr
  • xxhash
  • zstd
  • lz4
  • openssl crypto
  • zlib

2、 准备工作

2.1 准备编译服务器

准备一台编译服务器,其上已经安装了gcc,用于开源库编译,这里以 10.33.43.42服务器为例,该服务器为一台x64结构服务器。

2.2 下载所有开源库源码

2.2.1 下载 rsync 开源库源码

 

 

 

这里选择 3.3.0 版本。

2.2.2 下载 Acl  开源库源码

  • 远程到编译服务器
  •  执行yum info acl

 

可以看到其中有两个版本,第一个地址访问不了,所以选择第二个地址

 

点击 download 可以看到所有能下载的源码:

https://download.savannah.nongnu.org/releases/acl/

 

选择下载最新 2.3.2 版本。

2.2.3 下载 xxHash 开源库源码

https://github.com/Cyan4973/xxHash

https://github.com/Cyan4973/xxHash/releases

点击 右下角的 release链接可以看到所有的发布版本

 

这里选择 0.8.2 版本

2.2.4 下载 attr 开源库源码

  •  在编译服务器上通过yum info attr方式,发现找不到它的rmp文件,基于此,从网上直接查找
  •  网络搜索 libattr.so 官网,可以找到如下

 

 

 

这里选择使用 2.5.2 版本。

2.2.5 下载 zstd 开源库源码

  • 在 rsync 的install.cmd 上直接点击 zstd 的链接,跳转到 zstd 官网

 

  • 直接在官网上点击github

  • Github上点击 右下角的 release 链接可以看到多个发布版本

 

这里选择 1.5.6 版本

2.2.6 下载 lz4 开源库源码

  • 在 rsync 的install.cmd 上直接点击 lz4的链接,跳转到lz4官网

 

这里选择 1.10.0版本

2.2.7 下载 zlib 开源库源码

 

 

2.2.8 下载 openssl 开源库源码

 

 

这里使用 openssl 3.0.15 版本

3、 开源库编译

  通过第二章节,准备的开源库源码包或者已经编译好的库如下:

  

3.1 准备工作

 远程到编译服务器,创建如下目录

/opt/wf

     |-- openssl

     |--rsync

         |--include

         |--lib

  •  将本地准备的openssl(已经编译好的)目录下的所有目录和文件上传到编译服务器/opt/wf/openssl目录下;
  • 将本地准备的 libz.so.1 文件上传到编译服务器/opt/wf/rsync/lib目录下;
  • 将本地准备的所有tar.gz包上传到编译服务器/opt/wf/rsync/include目录下;

3.1 attr开源库编译

远程到编译服务器,执行以下命令

  • 解压源码

cd /opt/wf/rsync/include

tar -zxvf attr-2.5.2.tar.gz

mv attr-2.5.2 attr

  • ./configure

cd attr

./configure CFLAGS="-fstack-protector-all -fPIC"  CPPFLAGS="-fstack-protector-strong -fPIC  "  LDFLAGS="-pie -Wl,-z,noexecstack -Wl,-z,relro -Wl,-z,now -Wl,--disable-new-dtags,-rpath,./"

 

  • make
  • make install

 

可以看到so文件被安装到了/usr/lib目录下,编译好的库文件为libattr.so.1.1.2502

  • 将libattr.so.1.1.2502拷贝并重命名到指定目录下

cp /usr/lib/libattr.so.1.1.2502 /opt/wf/rsync/lib/libattr.so.1

3.2 acl 开源库编译

远程到编译服务器,执行以下命令

  • 解压源码

cd /opt/wf/rsync/include

tar -zxvf acl-2.3.2.tar.gz

mv acl-2.3.2 acl

  • ./configure

cd acl

./configure CFLAGS="-fstack-protector-all -fPIC"  CPPFLAGS="-fstack-protector-strong -fPIC  "  LDFLAGS="-pie -Wl,-z,noexecstack -Wl,-z,relro -Wl,-z,now -Wl,--disable-new-dtags,-rpath,./"

 

  • make
  • make install

 

可以看到so文件被安装到了/usr/lib目录下,编译好的库文件为libacl.so.1.1.2302

  • 将libacl.so.1.1.2302拷贝并重命名到指定目录下

cp /usr/lib/libacl.so.1.1.2302 /opt/wf/rsync/lib/libacl.so.1

3.3 xxHash 开源库编译

xxHash 源码中没有提供configure,已经存在MakeFile文件,所以需要将编译选项直接作为make 的参数传递进去。

 远程到编译服务器,执行以下命令

  • 解压源码

cd /opt/wf/rsync/include

tar -zxvf xxHash-0.8.2.tar.gz

mv xxHash-0.8.2 xxHash

cd xxHash

  •  make

make CFLAGS="-fstack-protector-all -fPIC"  CPPFLAGS="-fstack-protector-strong -fPIC  "  LDFLAGS="-shared -Wl,-z,noexecstack -Wl,-z,relro -Wl,-z,now -Wl,--disable-new-dtags,-rpath,./"

  •  make install

可以看到xxHash目录下有编译好的so文件libxxhash.so.0.8.2

  • 将libxxhash.so.0.8.2拷贝并重命名到指定目录下

cp libxxhash.so.0.8.2 /opt/wf/rsync/lib/libxxhash.so.0

3.4 zstd 开源库编译

zstd源码中没有提供configure,已经存在MakeFile文件,所以需要将编译选项直接作为make 的参数传递进去。

远程到编译服务器,执行以下命令

  • 解压源码

cd /opt/wf/rsync/include

tar -zxvf zstd-1.5.6.tar.gz

mv zstd-1.5.6 zstd

cd zstd

  • make

make CFLAGS="-fstack-protector-all -fPIC"  CPPFLAGS="-fstack-protector-strong -fPIC  "  LDFLAGS="-shared -Wl,-z,noexecstack -Wl,-z,relro -Wl,-z,now -Wl,--disable-new-dtags,-rpath,./"

  • make install

 

可以看到zstd/lib目录下有编译好的so文件libzstd.so.1.5.6

  • 将libzstd.so.1.5.6拷贝并重命名到指定目录下

cp lib/libzstd.so.1.5.6 /opt/wf/rsync/lib/libzstd.so.1

3.5 lz4 开源库编译

Lz4源码中没有提供configure,已经存在MakeFile文件,所以需要将编译选项直接作为make 的参数传递进去。

远程到编译服务器,执行以下命令

  • 解压源码

cd /opt/wf/rsync/include

tar -zxvf lz4-1.10.0.tar.gz

mv lz4-1.10.0 lz4

cd lz4

  • make

make  CFLAGS="-fstack-protector-all -fPIC -I/opt/wf/rsync/include/lz4/lib"  CPPFLAGS="-fstack-protector-strong -fPIC -I/opt/wf/rsync/include/lz4/lib"  LDFLAGS="-pie -Wl,-z,noexecstack -Wl,-z,relro -Wl,-z,now -Wl,--disable-new-dtags,-rpath,./"

  • make install

 

可以看到lz4/lib目录下有编译好的so文件liblz4.so.1.10.0

  • 将liblz4.so.1.10.0拷贝并重命名到指定目录下

cp lib/liblz4.so.1.10.0 /opt/wf/rsync/lib/liblz4.so.1

3.6 rsync 开源库编译

远程到编译服务器,执行以下命令

  • 解压源码

cd /opt/wf/rsync/include

tar -zxvf rsync-3.3.0.tar.gz

mv rsync-3.3.0 rsync

cd rsync

  • 修改checksum.c 中的源码

将文件中的 EVP_MD_CTX_create 全部修改成 EVP_MD_CTX_new

 

  • 指定openssl库的位置

先通过export 指定 openssl 的库路径,这里使用的是openssl 3 ,位置在/opt/wf/openssl

export LD_LIBRARY_PATH=/opt/wf/openssl/lib:$LD_LIBRARY_PATH

  • ./configure

./configure --disable-md2man --with-included-zlib=no --with-included-popt CFLAGS="-fstack-protector-all -fPIC -I/opt/wf/openssl/include"  CPPFLAGS="-fstack-protector-strong -fPIC  "  LDFLAGS="-pie -Wl,-z,noexecstack -Wl,-z,relro -Wl,-z,now -Wl,--disable-new-dtags,-rpath,./  -L/opt/wf/openssl/lib -lssl -lcrypto"

  • 修改configure.status

将该文件拿到本地,搜索关键字SIZEOF_,将其内容修改成如下:

 

  • make

 

可以看到编译好的rsync文件就在当前目录下

ldd rsync 可以看到这个二进制文件依赖的库

 

  • 将openssl/lib下的libcrypto.so.3\libssl.so.3 以及 rsync 移动到 /opt/wf/rsync/lib下

cp rsync /opt/wf/rsync/lib/

cp /opt/wf/openssl/lib/libssl.so.3 /opt/wf/rsync/lib/

cp /opt/wf/openssl/lib/libcrypto.so.3 /opt/wf/rsync/lib/

  • 进入到/opt/wf/rsync/lib 下,再次执行ldd rsync ,查看其依赖的库是否都在当前目录下(最好重新打开一个远程)

 

可以看到到此rsync编译完毕,只要将 /opt/wf/rsync/lib 下所有库和文件拿到本地即可,这样rsync 编译完成。

3.7 检查编译出来的库是否都是安全的

使用公共安全库提供的checksec.sh-2.7.1.zip 程序进行校验,将该包放置到编译服务器/opt/wf下,进行如下操作:

cd /opt/wf

unzip checksec.sh-2.7.1.zip

mv checksec.sh-2.7.1 check

cd check

./checksec  --dir=/opt/wf/rsync/lib    #如果检查单个文件使用 --file=xxxx.so

 

明显以上库是安全的。

四、问题与总结

1、Acl 编译报错提示缺失“attr/error_context.h”

  在执行 ./configure 命令时,直接报错了,配置不通过,如下:

 

原因分析

提示缺失 attr/error_context.h 找不到,因此acl 依赖attr,需要先编译attr开源库和安装。

解决办法

先编译和安装attr开源库,再编译acl 开源库。

2、xxHash编译报错提示“undefined reference to main”

现象

在执行make(make CFLAGS="-fstack-protector-all -fPIC"  CPPFLAGS="-fstack-protector-strong -fPIC  "  LDFLAGS="-pie -Wl,-z,noexecstack -Wl,-z,relro -Wl,-z,now -Wl,--disable-new-dtags,-rpath,./")命令时,直接报错,具体如下

 

解决办法

   将make命令中的系列参数 –pie修改成 -shared

make CFLAGS="-fstack-protector-all -fPIC"  CPPFLAGS="-fstack-protector-strong -fPIC  "  LDFLAGS="-shared -Wl,-z,noexecstack -Wl,-z,relro -Wl,-z,now -Wl,--disable-new-dtags,-rpath,./" 将-pie去掉换成-shared 才正常  (分析出来是这个原因是直接make可以成功,将直接make过程与添加编译选择的执行过程做了比较,发现需要改成shared)

3、zstd编译报错提示“undefined reference to main”

现象

在执行make(make CFLAGS="-fstack-protector-all -fPIC"  CPPFLAGS="-fstack-protector-strong -fPIC  "  LDFLAGS="-pie -Wl,-z,noexecstack -Wl,-z,relro -Wl,-z,now -Wl,--disable-new-dtags,-rpath,./")命令时,直接报错,具体如下

 

解决办法

   将make命令中的系列参数 –pie修改成 -shared

make CFLAGS="-fstack-protector-all -fPIC"  CPPFLAGS="-fstack-protector-strong -fPIC  "  LDFLAGS="-shared -Wl,-z,noexecstack -Wl,-z,relro -Wl,-z,now -Wl,--disable-new-dtags,-rpath,./" 将-pie去掉换成-shared 才正常  (分析出来是这个原因是直接make可以成功,将直接make过程与添加编译选择的执行过程做了比较,发现需要改成shared)

 

4、 lz4编译报错提示“fatal error:xxhash.h:No such file or directory”

现象

在执行make(make CFLAGS="-fstack-protector-all -fPIC"  CPPFLAGS="-fstack-protector-strong -fPIC  "  LDFLAGS="-pie -Wl,-z,noexecstack -Wl,-z,relro -Wl,-z,now -Wl,--disable-new-dtags,-rpath,./")命令时,直接报错,具体如下

根据错误提示,貌似是在提示找不到 xxhash.h 文件

分析

   深入会发现xxhash.h 文件其实在 lz4的lib目录下,也就是说make时其无法自动搜索到lib目录,找到这个文件,为此编译时需要加上-I指定追加的文件搜索路径。

 

解决办法

make  CFLAGS="-fstack-protector-all -fPIC -I/opt/wf/rsync/include/lz4/lib"  CPPFLAGS="-fstack-protector-strong -fPIC -I/opt/wf/rsync/include/lz4/lib"  LDFLAGS="-pie -Wl,-z,noexecstack -Wl,-z,relro -Wl,-z,now -Wl,--disable-new-dtags,-rpath,./"

在CFLAGS和CPPFLAGS上都加上-I/opt/wf/rsync/include/lz4/lib选项,在进行编译可以成功。

 

5、 rsync configure命令执行完之后,make报错“error:unknown type name ‘int32’”

现象

首先执行:./configure --disable-md2man --with-included-zlib=no --with-included-popt CFLAGS="-fstack-protector-all -fPIC"  CPPFLAGS="-fstack-protector-strong -fPIC  "  LDFLAGS="-pie -Wl,-z,noexecstack -Wl,-z,relro -Wl,-z,now -Wl,--disable-new-dtags,-rpath,./"

再次执行make命令,执行的时候报如下错误

 

分析

   在rsync github issue 上查到有人提过这个问题,查看作者的回复发现是因为rsync默认是32位上编译的,而我们当前编译服务器是64位操作系统,所以检测不通过,需要手动更改configure命令执行完成之后生成的config.status文件。

 

从图上可以看到这些值全是0,需要修改成正确的值。

解决方案

   将config.status文件拿到本地,按照关键字“SIZEOF_”,将对应的key值修改成如下的值。

 

6、 rsync 编译需要指定openssl

现象

由于openssl 也需要重新安全编译,因此rsync只能依赖我们编译好的openssl,不能使用系统默认的openssl。对此,rsync编译的时候需要指定openssl,否则会出现如下错误:

配置的命令为

 ./configure --disable-md2man --with-included-zlib=no --with-included-popt CFLAGS="-fstack-protector-all -fPIC"  CPPFLAGS="-fstack-protector-strong -fPIC  "  LDFLAGS="-pie -Wl,-z,noexecstack -Wl,-z,relro -Wl,-z,now -Wl,--disable-new-dtags,-rpath,./"

  make 之后 生成的 rsync文件使用 ldd 查看依赖的库

 

提示:version ‘libcrypto.so.10’ not found (required by ./rsync)

通过查看资料和网上百度,需要在LDFLAGS上添加-lssl –lcrypto 表示使用指定的openssl 库进行编译,添加-L/opt/wf/openssl/lib表示在编译的时候从指定的openssl 的库目录加载库文件;在CFLAGS上添加-I/opt/wf/openssl11/openssl/include表示在编译的时候从指定的openssl的头文件目录加载需要的头文件。

因此 最终的configure命令调整成如下:

./configure --disable-md2man --with-included-zlib=no --with-included-popt CFLAGS="-fstack-protector-all -fPIC -I/opt/wf/openssl/include"  CPPFLAGS="-fstack-protector-strong -fPIC  "  LDFLAGS="-pie -Wl,-z,noexecstack -Wl,-z,relro -Wl,-z,now -Wl,--disable-new-dtags,-rpath,./  -L/opt/wf/openssl/lib -lssl -lcrypto"

7、 rsync configure时提示“./configtest:error while loading shared libraries:libssl.so.1”

现象

    执行了./configure --disable-md2man --with-included-zlib=no --with-included-popt CFLAGS="-fstack-protector-all -fPIC -I/opt/wf/openssl/include"  CPPFLAGS="-fstack-protector-strong -fPIC  "  LDFLAGS="-pie -Wl,-z,noexecstack -Wl,-z,relro -Wl,-z,now -Wl,--disable-new-dtags,-rpath,./  -L/opt/wf/openssl/lib -lssl -lcrypto" 命令过程中,发现自行失败,提示的具体信息如下:

 

分析

    通过界面提示的错误分析,发现 gcc 编译成功生成了configtest二进制文件,但是在执行的时候提示configtest需要libssl.so.1 库,但是加载不到这个库。在编译configtest二进制文件,虽然在编译的时候通过rpath指定了./ 相对路径,但是libssl.so.1 文件的确不在configtest 所属当前目录下,其在 /opt/wf/openssl/lib 下,因此想到使用export 的方式指定库搜索路径。

解决方案

为了解决上述找不到ssl库的问题,需要在执行configure命令之前,先通过export 指定 openssl 的库路径,export LD_LIBRARY_PATH=/opt/wf/openssl/lib

8、 rsync configure时提示”libssl.so:file format not recognized;treating as linker script”

现象

  执行了./configure --disable-md2man --with-included-zlib=no --with-included-popt CFLAGS="-fstack-protector-all -fPIC -I/opt/wf/openssl/include"  CPPFLAGS="-fstack-protector-strong -fPIC  "  LDFLAGS="-pie -Wl,-z,noexecstack -Wl,-z,relro -Wl,-z,now -Wl,--disable-new-dtags,-rpath,./  -L/opt/wf/openssl/lib -lssl -lcrypto" 命令过程中,发现自行失败,提示的具体信息如下:

分析

   通过查找相关资料,发现是 openssl/lib 下的libssl.so 文件是 ASCII text 格式的

  执行命令 file libssl.so

 

解决方案

  不能在本地解压 openssl.zip 文件之后再上传到编译服务器上,需要将zip包直接上传到编译服务器上,然后通过 unzip 命令进行解压,才不会改变so文件的编码格式。

 

五、小知识点

1、查看so的编码信息

  file xxx.so

2、编译时可指定 头文件路径

gcc xxx xxx -I/opt/wf/test/include

3、编译时可指定依赖库的所在路径

gc xxx xxx -L/opt/wf/test/lib

4、编译时可指定运行的时候从哪个目录搜索依赖的库

gc xxx xxx -Wl,-rpath=.       

-Wl,-rpath=.  表示从运行文件的当前目录去搜索库

 

posted @ 2024-09-11 11:43  夏之夜  阅读(82)  评论(0编辑  收藏  举报