bashが起動しない

秘伝のタレのように継ぎ足しながら運用しているFreeBSDにありがちな問題。以前もあったんですが、またまたupgradeで動かない問題。今回は以下のようなエラーが発生しました

# bash
ld-elf.so.1: Undefined symbol "rl_sort_completion_matches" referenced from COPY relocation in /usr/local/bin/bash

こんな感のエラーです。例によって問題は/lib以下に残っている古いライブラリなんでしょうけど、この探り方についてのメモを残しておきます。まずこのエラーが一体なんなのか?という説明。

多くのプログラムはdynamic linkというものを使ってビルドされています。これは実行時にlibraryをリンクするというもので最近の主流となっているものです。これの真逆はstatic linkで実行ファイルを作成するときにlibraryも一緒にリンクしちゃうことです。dynamic linkにすることでバイナリサイズを小さくできますし、ライブラリにバグが見つかったときでもライブラリだけの更新で済むと言う利点があります。

一方、dynamic linkは正しくlinkされないとダメということで同じ名前のライブラリが別なディレクトリなどにあったりするとうまく整合性が取れずこのようなエラーが発生している・・と予想できます。

実行ファイルやライブラリには、プログラム本体の他に「シンボル」と呼ばれる情報があります。シンボルというのは簡単にいえば関数名のようなもので、実行ファイルとライブラリのシンボル名を実行時にリンクして解決することで初めてプログラムがメモリ上に配置され実行できるようになるわけです。それを出力するコマンドが nmです。

nm -D /usr/local/bin/bash

を実行すると以下のような箇所がありました。

00000000002fac00 B rl_signal_event_hook
00000000002fabdc B rl_sort_completion_matches
00000000002f7b00 B rl_special_prefixes
00000000002fac10 B rl_startup_hook

左の数字はプログラムにおけるアドレスで右がシンボルになります。真ん中のBがそのシンボルの状態を表す記号。この場合BですのでBSSセクションに配置されているということになります。BSSセクションとはなんぞや?とかなるとリンカ沼にハマるので詳しくは解説しません・・(というか解説できません。私が知ってるのはDATAとかTEXTとか古くからあるやつだけでこいつらはプレステでゲーム作ってるときは重要だった。今はどうなんだろ?)。まぁ状態ということで認識しておけばよいかと思います。ちなみにBは解決済みです。じゃぁなんでエラーがでるんでしょうか?

そこでエラーメッセージに戻ります

COPY

の文字。これは「COPY relocation」という仕組みに関するエラーで領域はプログラム側に予約されているけれど、実体はライブラリ側にあるということです。それがうまく解決できていないと。

名称からしてreadlineの保管の問題っぽいので /libのあたりから探りをいれていきます。

ldd コマンドで何がリンクされているのかを確認します

# ldd /usr/local/bin/bash
/usr/local/bin/bash:
 libreadline.so.8 => /lib/libreadline.so.8 (0x3762cef30000)
 libhistory.so.8 => /usr/lib/libhistory.so.8 (0x3762cf42e000)
 libncursesw.so.9 => /lib/libncursesw.so.9 (0x3762d0296000)
 libintl.so.8 => /usr/local/lib/libintl.so.8 (0x3762d1029000)
 libdl.so.1 => /usr/lib/libdl.so.1 (0x3762d1e18000)
 libc.so.7 => /lib/libc.so.7 (0x3762d2de0000)
 libncurses.so.8 => /lib/libncurses.so.8 (0x3762d33ca000)
 libthr.so.3 => /lib/libthr.so.3 (0x3762d3d5e000)
 [vdso] (0x7ffffffff650)

ここで/libの下をみてみると

-r--r--r--  1 root  wheel   273064 Aug 28  2018 libreadline.so.8

というファイルがありました。あやしいです。これだけ2018年。

こではFreeBSDのアップデートの仕組みが関係しているようです。FeeBSDはfreebsd-update でアップデートをしたとしても古いライブラリをアップデートの際に削除しないようです(あるいはしていなかった?裏とってません)。つまりバージョンがあがって最新バージョンで無くなったとしてもそのライブラリは残しているわけです。削除してしまうとそのライブラリをリンクして動作していたプログラムが動かなくなるからということかと思いますがこれが秘伝のタレのような運用をしているサーバに悪影響を与えるわけです。

bashに関していえば /usr/local/lib/以下にもpkgから入れられたlibreadlineが存在しています。こちらをリンクするようにすれば解決するものと思われます。念の為コマンドをタイプ

# nm -D /usr/local/lib/libreadline.so.8 | grep rl_sort_completion_
0000000000051114 D rl_sort_completion_matches
# nm -D /lib/libreadline.so.8 | grep rl_sort_completion_

/usr/loca/lib/以下のほうには存在するようです。そこで強引にこちらのライブラリを優先的に検索するようにしてみます

env LD_LIBRARY_PATH=/usr/local/lib bash

はい、動きました。あとは /lib/libreadline.so.8をどうするかだけを考えればよいわけですが、基本的にpkgだけでアプリをいれているサーバなんでそんなものを使っているものが残っているはずもない・・ということでガッツリ削除することにしました。 ls -ltでタイムスタンプで並べ直してみると

-r--r--r--  1 root  wheel   314744 Dec 30  2022 libzfs.so.3
-r--r--r--  1 root  wheel    31800 Dec 30  2022 libufs.so.6
-r--r--r--  1 root  wheel   387320 Dec 30  2022 libncursesw.so.8
-r--r--r--  1 root  wheel   349640 Dec 30  2022 libncurses.so.8
-r--r--r--  1 root  wheel   216728 Dec 30  2022 libedit.so.7
-r--r--r--  1 root  wheel   273064 Aug 28  2018 libreadline.so.8
-r--r--r--  1 root  wheel    37000 Aug 28  2018 libkvm.so.6
-r--r--r--  1 root  wheel     7736 Aug 28  2018 libipx.so.5
-r--r--r--  1 root  wheel  2055072 Aug 28  2018 libcrypto.so.7
-r--r--r--  1 root  wheel   192040 Aug 28  2018 libcam.so.6
-r--r--r--  1 root  wheel  1722192 Apr  9  2014 libcrypto.so.6
-r--r--r--  1 root  wheel    34728 Dec  4  2012 libkvm.so.5
-r--r--r--  1 root  wheel    68360 Dec  4  2012 libmd.so.5

いやー結構ありますね。10年以上前から残っている秘伝のタレlibraryがたくさん・・・

これら全部削除してよいものだと思います。トラブルのもとなので。というか、たまたま動いているだけで、意図せずメンテナンスされていない古いライブラリが使われている可能性もあります。これはこれで問題ですよね?

OpenAIにイラスト描いてもらいました

Posted by issei

Category : BSD