■linuxのshellに含まれていた脆弱性、通称shellshockとか呼ばれていますが、その対策はyumなどで適時適用かけていて対応はしているのですが、気が付いたらatコマンドが使えなくなっていました。エラーも何もでないのですが、機能しない。atコマンドはコマンド実行をキューイングして指定した時刻で非同期実行させるのですが、バックグラウンド処理になるためエラーメッセージが拾いにくい。atで実行させるコマンドのエラーであればmailキューに送信されるはずなのですが、そちらにもメッセージはなく、OSのログメッセージのmessagesにも何も出ない。atそのものは正常に動作しているように見えていて、その実何も動いていないという、調査するのに面倒な状態でした。
atコマンドのキューは/var/spool/atで、ここに実行コマンドがシェルスクリプトとなって格納されます。atデーモン(atd)がそのシェルスクリプトを適時実行する、と理解しています。とりあえず調査の一歩としてそのシェルスクリプトを動かすことにしました。
atサービスを停止(service atd stop)して、atで何か適当なコマンドをスケジューリングさせると、スプールにシェルスクリプトが作成されました。そのスクリプトを直接実行してみると、エラーが出ました。
行 56: 予期しないトークン `$'=\\(\\)\\ {\\ \\ eval\\ \\`/usr/bin/modulecmd\\ bash\\ \\$\\*\\`"\n"}'' 周辺に構文エラーがあります
行 56: `"}; export BASH_FUNC_module()'
このエラーがでた箇所の構文パターンには見覚えがあります。shellshockで対策が入ったのがこの手の構文でした。構文そのものではないですが、チェック強化でエラー判定されるようになったのでしょう。
スプールに入ったエラー行を外すと、実行させたかったコマンドに影響することなく、動作しました。エラースクリプトを作成するのはatコマンドそのもので、その状態でatdが拾うとエラーを出して動かないものの、シスログにもメールにも情報が残らない状態になっているわけです。
atdに渡る前にエラー行を除外できればいいわけですが、atコマンドの即時実行処理(非同期処理させたくてよく使う)の場合はその余裕がありません。ただ、atdにはデーモン動作ではなく、シングル実行する機能(atd -s)があります。atのサービスは止めて、cronにはエラー行を排除した後にatd -s を実行するシェルスクリプトを登録することにしました。
中心となるロジックはこんな感じです。
TMP=/tmp/adjx.$$
OWN=`stat -c %U $1`
GRP=`stat -c %G $1`
grep -v BASH_FUNC_module $1 > $TMP
mv $TMP $1
chown $OWN:$GRP $1
chmod 700 $1
atd -s
このロジックをfindで拾ったキューの中のスクリプトに適用してエラー行を排除して実行させます。