Help us understand the problem. What is going on with this article?

glibc アップデート方法 まとめ

More than 1 year has passed since last update.

【環境】

Ubuntu16.04にUbuntu18.04で使用されているglibcを適用させる。
現在、Ubuntu16.04はglibc-2.23でUbuntu18.04はglibc-2.27だった。

【前提知識】

ELFローダ

ELFローダのパスはバイナリに埋め込まれている。
通常、そのパスはシンボリックリンクになっていて、その先を変更することで全バイナリをロードするローダを変更することができる。
バイナリ実行時にはELFローダのバージョンと同一のバージョンのglibc(ELFローダと同一ディレクトリ上のglibc)が使用される。

【手順1】glibcソースコードのダウンロード

https://ftp.gnu.org/gnu/glibc/ からwgetなどで落とすか、もしくは新しいバージョンのディストリビューションでapt source libc6して落としたソースコードをscpなどで送信

方法1
$ cd ~/src/
$ wget https://ftp.gnu.org/gnu/glibc/glibc-2.27.tar.gz
$ tar zxvf glibc-2.27.tar.gz
方法2
$ cd ~/src/
$ apt source libc6
$ scp -r ./glibc-2.27/* hoge@123.123.123.123:~/src/glibc-2.27/

【手順2】ビルド用のディレクトリを作成

$ mkdir ~/src/build

【手順3】install先のディレクトリを作成

mkdir ~/program/glibc-2.27

【手順4】configure

buildディレクトリに移動し、そこからglibc-2.27ディレクトリ上のconfigureを叩く。
../glibc-2.27/configure --prefix=/home/miyagaw61/program/glibc-2.27でも大丈夫だとは思うが、Ubuntu18でapt sourceで入れたlibc6のビルド方法とできるだけ近づけたオプションでUbuntu16でビルドしたい、といった場合は、Ubuntu18上のglibc-2.27ディレクトリでdpkg-buildpackage -us -ucを実行し、ちょっとしたらCtrl+Cで止め、find -name *config.log*で出力される./build-tree/amd64-libc/config.logに書いてあるオプションを参考にビルドすると良い。
今回は

../glibc-2.27/configure --host=x86_64-linux-gnu --build= --prefix=/usr --enable-add-ons=libidn, --without-selinux --enable-stackguard-randomization --enable-stack-protector=strong --enable-obsolete-rpc --enable-obsolete-nsl --with-pkgversion=Ubuntu GLIBC 2.27-3ubuntu1 --with-bugurl=https://bugs.launchpad.net/ubuntu/+source/glibc/+bugs --with-headers=/home/miyagaw61/src/glibc-2.27/glibc-2.27/debian/include --enable-kernel=3.2 --with-selinux --enable-systemtap --enable-multi-arch --enable-static-pie

だった。
Ubuntu16でこれをそのまま実行してしまうと、色々と問題が発生するため、所々修正する必要がある。
修正後はこちら。

../glibc-2.27/configure --host=x86_64-linux-gnu --build= --prefix=/home/miyagaw61/program/glibc-2.27 --enable-add-ons=libidn, --without-selinux \
--enable-stackguard-randomization --enable-stack-protector=strong --enable-obsolete-rpc --enable-obsolete-nsl \
--with-pkgversion=Ubuntu GLIBC 2.27-3ubuntu1 --with-bugurl=https://bugs.launchpad.net/ubuntu/+source/glibc/+bugs \
--enable-kernel=3.2 --with-selinux --enable-systemtap --enable-multi-arch

変更箇所:
・--prefixの値の修正
・--with-headersの削除
・--enable-static-pieの削除

【手順5】install

そのままmakemake installを実行する。

【手順6】不足しているライブラリを追加

このglibc-2.27には結構不足しているライブラリがあり、それらを既存のライブラリで補完する必要がある。
一番最初に述べた「バイナリ実行時にはELFローダのバージョンと同一のバージョンのglibc(ELFローダと同一ディレクトリ上のglibc)が使用される。」という文章を思い出してほしい。/lib/x86_64-linux-gnuディレクトリや/usr/lib/x86_64-linux-gnuディレクトリに存在していて~/program/glibc-2.27ディレクトリに存在しない名前のファイルは、全て~/program/glibc-2.27ディレクトリに集めなければならない。

$ cd ~/program
$ cp -a /lib/x86_64-linux-gnu lib-glibc.org
$ cp -a /usr/lib/x86_64-linux-gnu usr-lib-glibc.org
$ sudo chown miyagaw61:miyagaw61 -R lib-glibc.org usr-lib-glibc.org
$ cp -a usr-lib-glibc.org new-glibc
$ cp -a lib-glibc.org/* new-glibc/
$ cp -a glibc-2.27/lib/* new-glibc/
$ cp -a new-glibc/* glibc-2.27/lib/
$ rm -rf new-glibc

【手順7】root化

この後、ダイナミックリンクされている全てのバイナリが動かなくなるので、root状態でbusyboxが使えるようにするため、事前にrootになっておく(busyboxにsudoが存在しないため)。

【手順8】glibcのパスを変更後ldconfig

ld.so.confを編集し、ldconfigでld.so.cacheに反映させる。

# echo "/home/miyagaw61/program/glibc-2.27/lib" > tmp
# cat /etc/ld.so.conf >> tmp
# mv tmp /etc/ld.so.conf 
# ldconfig

この時点で、現在のELFローダのバージョンとld.so.cacheに設定されているライブラリのバージョンの不整合で、ダイナミックリンクされている全てのバイナリは正常に動かなくなる(ELFローダ:2.23, ライブラリ:2.27)。

【手順9】busyboxを用いてELFローダのバージョンをライブラリに合わせる

ELFローダのシンボリックリンク先を新しいバージョンのELFローダのパスに変更することで、ELFローダのバージョンをライブラリのバージョンと同じにすることができる。

busybox ln -sf /home/miyagaw61/program/glibc-2.27/lib/ld-linux-x86-64.so.2 /lib64/ld-linux-x86-64.so.2

これで、新しいバージョンのglibcを使用して全てのバイナリを正常に動かすことが可能になる。

【補足】元のlibcの退避には注意

「なんかの拍子で/lib/x86_64-linux-gnuとかが使われたら面倒くさいので、一応わかりやすくするために/lib/x86_64-linux-gnu.orgとかに退避させておこう」とかすると、sudoをするたびにsudo: policy plugin failed session initializationというエラーが出るようになってしまう。原因はわからないが、

$ sudo su
# cd /lib/
# mv x86_64-linux-gnu x86_64-linux-gnu.org
# cp -a /home/miyagaw61/program/glibc-2.27/lib x86_64-linux-gnu

とすれば大丈夫ではあった。

/usr/lib/x86_64-linux-gnuはも同様に、普通に退避させるだけだとapt installでエラーを吐くようになる。

$ sudo su
# cd /usr/lib/
# mv x86_64-linux-gnu x86_64-linux-gnu.org
# cp -a /home/miyagaw61/program/glibc-2.27/lib x86_64-linux-gnu

【追記】linux-headers-$(uname -r)の再インストール

このままだと、ビルド時に問題が発生する可能性があることが判明した。
例えばWalBというOSSのビルドを例にすると

$ make
DEBUG=0 DYNAMIC_DEBUG=0 OVERLAP=1
DEBFLAGS=-O2 -g -DWALB_OVERLAPPED_SERIALIZE
make clean
make[1]: Entering directory '/home/miyagawa/src/github.com/miyagaw61/walb/module'
rm -f build_date.h
rm -f version.h
cd test; rm -rf *.o *~ core .depend .*.cmd *.ko *.mod.c .tmp_versions
rm -rf *.o *~ core .depend .*.cmd *.ko *.mod.c .tmp_versions modules.order Module.symvers
make[1]: Leaving directory '/home/miyagawa/src/github.com/miyagaw61/walb/module'
make buildmodule
make[1]: Entering directory '/home/miyagawa/src/github.com/miyagaw61/walb/module'
cat build_date.h.template | sed "s/XXXXX/`env LC_ALL=C date`/" > build_date.h
make -C /lib/modules/4.15.0-24-generic/build M=/home/miyagawa/src/github.com/miyagaw61/walb/module modules
make[2]: Entering directory '/usr/src/linux-headers-4.15.0-24-generic'
make[2]: *** No rule to make target 'modules'.  Stop.
make[2]: Leaving directory '/usr/src/linux-headers-4.15.0-24-generic'
Makefile:96: recipe for target 'buildmodule' failed
make[1]: *** [buildmodule] Error 2
make[1]: Leaving directory '/home/miyagawa/src/github.com/miyagaw61/walb/module'
Makefile:90: recipe for target 'default' failed
make: *** [default] Error 2

というようなエラーが出る。
次のコマンドを実行することで対応することに成功した。

$ sudo apt install linux-headers-$(uname -r) --reinstall
miyase256
SoftwareDvelopment, LinuxKernelReading, MalwareAnalysis, Exploit, AtCoder / seccamp'17'18, SecHack365'18, GlobalCybersecurityCamp'18
https://miyase256.github.io
ipfactory
情報科学専門学校 情報技術サークル「IPFactory」のOrganizationです。それぞれのアウトプット活動を促進するために発足されました。
https://twitter.com/_ipfactory_
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away