2019年1月30日水曜日

ポストスクリプトのプログラミング(5) : runコマンドの問題と利用

Postscriptはプログラミング言語であることを、ずっと前に取り上げた。一通り幾何学模様を描いて遊んでみた後、基本部分はマスターできたと思う。最近は、幾何学の問題を解くときにときどき利用している程度だったが、パワーポイントやキーノートで図形を描くのはストレスが溜まる作業だということがわかったので、思い切ってpostscriptsで図形作成をすべてやってみる方向に切り替えることにした。そもそも、プログラミングというのはうまくいったら楽しいし、また、うまくいったプログラムは再利用できるから、最初は大変だが、だんだん楽になっていくという利点もある。

ということで、今回は、プログラム(リソース)の再利用、 つまりライブラリと呼ばれるものを使う方法を採用しようと考えた。いろいろ調べてみると、runというコマンドが使えることがわかった。これについては、後で詳述することにして、まずはrunを使うことになった経緯について述べておく。



Postscriptには「関数」という概念がない。その代わりに、procedure(「手続き」と訳している人もいる)という、コマンドのまとまりを再定義する方法を利用する。ただ、procedureへの変数の受け渡しは定義されてない。たとえば、円を2つ書くコマンドをdarc(=="double arc")というprocedureにまとめる方法は、

/darc {
  x0 y0 r0 0 360 arc
  x1 y1 r1 0 360 arc
} def

とする。こうすると、procedureである"double_circle"が定義される。

では、このprocedureの中で定義されている「変数」x0, y0, ...などはどうやって渡すのか、というと、スタックを利用するのだ。たとえば、procedureの定義において、

/darc {
 /r1 exch def
 /y1 exch def
 /x1 exch def
 /r0 exch def
 /y0 exch def
 /x0 exch def

 x0 y0 r0 0 360 arc
 x1 y1 r1 0 360 arc
} def

という具合に、スタックからデータを受け取るコマンドを書き込む。注意するのは、取り込む順番だ。このprocedureを使う段になって、

0 1 5 10 12 7 darc

とやると、(x0, y0, r0, x1, y1, r1)=(0, 1, 5, 10, 12, 7)という対応でprocedureに取り込まれる。procedureの中では、7, 12, 10, 5, 1, 0という順番でスタックの取り込みが行われるので、r1, y1, x1, y0, y0, x0の順番で「変数」を定義する。

このように、procedureをたくさん定義しておけば、次にプログラムを書くときに、それを再利用することができる。しかし、ファイルの中に長々とcut&pasteするのは、見栄えと読みやすさを犠牲にする。一般のプログラミング言語のようにライブラリにまとめて一括読み取りができると便利だ。例えば、C言語の#includeとか、LaTeXのusepackageみたいな機能だ。

Postscriptに関する古い解説文書を読むと、この機能に対応するのは"run"だと書いてある。たとえば、先ほどのdarcのprocedureを別のファイルdarc.psに書いておき、それを新しいファイルappli_darc.psで再利用するときは、appli_darc.psの中で、

(darc.ps) run

とすれば、darc.psの内容がappli_darc.psで再利用できるというわけだ。



ところが、この手法を用いてmacOSで、appli_darc.psをopenすると、エラーが発生して読み込むことができない。書式が悪いのか、読み込みの定義が間違っていたのか、といろいろと疑ってみたが、どうもどこもおかしくない。長いこと検索してみると、ついにこの問題の核心をついていると思われるdiscussionを見つけることができた。

この議論で引用されているMITの元記事はリンク切れしていて読めなかったが、こちらのページで内容は大体わかった。ghostscriptの脆弱性(vulnerability)が、2018年8月にgoogleのエンジニアによって発見されたという内容だ。

結局、runコマンドによって外部ファイルを読み込めるようにしてしまうと、悪意のあるコードや命令を埋め込まれてしまうという内容だ。これを受けて、macOSのpreviewや、Adobeシステムの製品では、runを含むpsファイルはエラーが出るように修正されている、ということらしい。

天体観測の画像処理などでもよく利用するImage Magickもgsのライブラリを利用しているので、同じ脆弱性をはらんでいるそうだ。パッチが公開されているらしい。

ただ、macOSにデフォルトで入っているgsコマンドを利用すれば、runを含むposgtscriptファイルを実行することがは可能である、とdiscussionに書いてあった。そこで、試してみるとちゃんとrunコマンドが動くことが確認できた。

また、ps2pdf -dNOSAFERでもrun付きpsファイルをpdfに変換することができる。ちょっと手間だが、ps2pdf -dNOSAFER ps_with_run.ps; open ps_with_run.pdfと打ち込むか、次にようなbashスクリプトを書いて(psviewと命名し、chmod 755 psviewとしておく)、利用すればよい。

[psview]

#!/bin/bash

if [ $# -eq 1 ]; then
  fname=`head -1 $1.ps`
  if [ ${fname} == "%!PS-Adobe-3.0" -o ${fname} == "%!PS-adobe-3.0" ]; then
      ps2pdf -dNOSAFER $1.ps; open -a preview $1.pdf
      exit 1
  else 
      echo "Error. File must be of Postscript."
      exit 0
  fi
  exit 1
fi

cat << __EOF__
The argument must be the name of the postscript file 
to be processed with ghostview, and to be opened with preview.
__EOF__

exit 0

runコマンドのvulnerabilityがあることを認識し、あくまでpsviewで開くのは自作のpostscriptファイルだけとわきまえておけば、これでrunを利用した自作のprocedureのライブラリを使ってプログラム群を構築することができる!
 

0 件のコメント: