投稿

XKB で遊んでみよう (2)

xkb_keymap xkb_keymap エントリーは、xkb で使われる設定一式です。中身は
xkb_keycodesxkb_typesxkb_compatxkb_symbols の各エントリーからなります。おまけとして
xkb_geometry というエントリーも存在しますが、単に各種設定ツールでキーボードの絵を表示するのに必要な情報が入ってるだけなので、キーマップをいじるという観点ではガン無視でオッケーです。
xkb_keycodes デバイスから受け取ったスキャンコードに抽象的な名前、シンボル名を与えるための設定です。他のところの設定において、スキャンコードではなくここで設定されたシンボル名を使うことで、「Ctrl と Caps を入れ替える場合、US キーボードではスキャンコード 11 を Caps に、JP106キーボードの場合はスキャンコード 22 を Capsに」といった、キーボードとオプション設定の組み合わせ全てでスキャンコードを列挙する必要がなくなります。
ただし、抽象化の目的によって大きく分けて2種類のシンボル名が用意されています。一つは物理的な位置に基づくものです。最下段のキーは左から順に <AA00>, <AA01>, ... (ただし、最下段は特殊キーしかないのが普通なので、<AA00> 以外が使われることは稀)、下から2段目は <AB00> (左Shiftキーの位置), <AB01>, ... となっていきます。
もう一つは機能に基づくもので、<HKTG> (Hiragana-Katakana ToGgle) や <TLDE> (tilde) みたいなものがあります。ただし、あくまでもスキャンコードにシンボル名を与えるだけなので、<TLDE> が実際に ~ である必要はありません。というか、わざとややこしい例を出したのですが、<TLDE> は手前から5段目の右端のキー(US キーボードなら ~ キーがある位置)という、位置にあるキーのためのくシンボル名です。ややこしい。そういう意味であれば、単純に <AE00> にしとけと思うんですけどね。

日本語キーボードは、1 の隣は「半角/全角キー」なので、実際の設定ファイルか…

XKB で遊んでみよう (1)

元ネタは私の G+ポスト です。

Emacs を使ってるとどうしても小指が痛い。解決方法として

Emacsを使わない指の付け根でCtrlキーを押すフットペダルを使うなどが挙げられますが、 Emacs以外は考えられない体にされてしまっている。試してみてはいるけれど、ちょっとまだ慣れないあまり一般的でないハードウェアには依存したくないなどの理由により、X11 上でキーマップをゴニョゴニョしてなんとかしのげないかと考えるに至りました。
で、X11 上でキーマップをゴニョゴニョするといえば大昔は xmodmap 一択だったのですが、近年では XKB を使うのが一般的ではないかと思います。Fedora でモニョモニョしてた頃、とりあえずあら探しした記憶があるのですが、さすがに10年も触らないと忘れてしまいます。あと、個人的に X11 と djb の書いたコードは読まないことにしているので、こんなん書いている割に理解は浅いです。
XKB 使ってユーザーがキーマップをいじる場合、基本的に使うのは xkbcomp コマンドです。setxkbmap は xkbcomp の簡易ラッパーコマンドという認識でいいと思います。
setxkbmap, xkbcomp などで色々と検索すると何やら出てきますが、とりあえず「無変換」キーを Control キーとして (US キーボードで) 使うには
xkb_keymap {
        xkb_keycodes  { include "evdev+aliases(qwerty)" };
        xkb_types     { include "complete"      };
        xkb_compat    { include "complete"      };
        xkb_symbols   {
                include "pc+us+inet(evdev)"
key <MUHE>{ [Control_L] };
                modifier_map Control { <MUHE>};
        };
        xkb_geometry  { include "pc(…

glibc getaddrinfo() 問題 (CVE-2015-7547) について

さて、いつも同じですが、今回もあくまでも個人としての投稿です。会社としては CVE-2015-7547: glibc getaddrinfo stack-based buffer overflow 読んでということで。

脆弱性の内容、各ディストリビューションからのアップデートは各テック系サイトのニュースをご参照ください。

さて、大人の事情によりすぐに直せないよーという場合の緩和策(あくまでも緩和策です)として [PATCH] CVE-2015-7547 --- glibc getaddrinfo() stack-based buffer overflow では以下のものが挙げられてます:
UDP513 バイト以上の UDP DNS パケットを firewall で落とす(略) `options edns0` を /etc/resolv.conf で使わない。EDNS0 は 512 バイトより大きいレスポンスを許可するので、正当な DNS レスポンスでも overflow を発生させることが出来てしまいます(略)元のメールの想定読者がシステム管理者ではないので、クライアントコードでの mitigation は省略しました。

TCPDNS リプライを 1024 バイトまでに制限するこれはちょっと理由が分からなかった。なんでこれでいけるん?fragment が発生しない最小値 (MTU の最小値) は IPv4 なら 576 バイト、IPv6 なら 1280 バイト。DNS/TCP パケットを再構成した上で処理する firewall なら、2048 バイトじゃね?

read() のバッファサイズと発行回数の都合で、1 packet が 1024 バイトまでならバッファがあふれる前に処理できる可能性が高い? でも、「パケット」については言及されてない。

ちゃんと読んでから後で訂正するかもですが、単に A と AAAA の合計で 2048 バイト超えないようにしろってことだと思う。
有効でない緩和策
ちなみに、意味のない緩和策として

`options single-request` は内部でのバッファー管理方法に変わりはないので意味なし。`options single-request-reopen` も 1. と同様。IPv6 を無効にしても、(AF_UNSPEC が使われていると)AAA…

Bash の脆弱性について

CVE-2014-6271 の件について、何かわかってない記事が散見されるので簡単にまとめ。

問題点 環境変数が特殊な文字列の場合、Bash はそれを関数定義とみなす(この仕様がそもそもどうなのよ、と思う人は/bin/shをbashにするのはもうやめましょう)。そのロジックに誤りがあり、関数定義でない部分も読み込み、その部分が実行されてしまう。

影響範囲 /bin/sh が bash でないシステムの場合 明示的に bash スクリプトとして起動されたスクリプトだけが影響を受ける。ただし SSH サーバーの場合、ユーザープログラムを実行する場合にユーザーのシェルを使用するので、そこで影響を受けることがある。
/bin/sh が bash であるシステムの場合system(3) や popen(3) が内部で /bin/sh を利用しているので、影響は広範に渡る。
CGI
特に話題になってるのが CGI である。CGIは仕様 (RFC3875) により、外部から受け取った情報を環境変数に入れた上で (section 4.1.18 参照) 外部コマンドを実行することになっている。ウェブサーバーの実装によるが、このとき system(3) (またはそれに類する) を使って外部コマンドを実行していれば今回の脆弱性の影響を受ける(が、普通は system(3) は使わないし、少なくともapacheはそんなことしない)。
また、環境変数は明示的に制限しない限り子供のプロセスにも引き継がれるので、ウェブサーバーが system(3) を使っていなくても、そこから起動されたプログラムがさらに外部コマンドを system(3) 相当で起動した場合、同じように脆弱性の影響を受ける。 SSH openssh はサーバー側の AcceptEnv の設定(とクライアント側の SendEnv)によっては手元の環境変数をリモートに送ることができる。環境変数が評価されるのは認証後なので、通常はあまり大きな問題ではないが、サーバー側で ForceCommand で特定のコマンドしか実行しないようにしていた場合、それをバイパスすることができる。なお、ForceCommand はそのユーザーのシェルで実行されるので、zsh とかにしていると影響を受けない。
<追記>
bugレポートちゃんと…

ターミナルウィンドウに雪を降らせよう! - Bash Advent Calendar - Day 13

いまは、ぼくのこころの中では 12 月 13 日の 210時ぐらいです。もはや Advent Calendar の体をなしてない気がしますが、細かいことは気にしないで行きましょう。
terminfo 端末エミューレーター(以下「ターミナル」)は色々と標準、デファクトスタンダードが存在します。これから使う ANSI エスケープシーケンスについては、それと同等の機能のあるターミナルであれば、まずもって ANSI エスケープシーケンスに対応しています。
が、ターミナルの機能は ANSI エスケープシーケンスでサポートされているものだけではなく色々あるので、そうした色々な機能を抽象化して定義したのが terminfo です。昔は termcap が主流でしたが、最近は terminfo の方が Linux 界隈では優勢だと思います。 tputコマンド tputコマンドは、terminfoで定義されている機能名を引数にとり、使用しているターミナルに対応するコマンドを出力します。
たとえば、画面クリア "clear" では clear="$(tput clear)"
printf "%q\n" "$clear"
$'\E[H\E[2J' となります。ちなみに、printf %q とか $'...' 記法に「Bashらしさ」があるので、それで記事が書けそうな気がしてきました。 乱数 $RANDOM を参照すると Bash は擬似乱数を返してくれます。が、値は[0, 32767]の範囲とかなりしょぼい仕様です。以下では、頑張って[0, ターミナルカラム数)で一様に分布するっぽい乱数を生成していますが、実用上、Linux であれば rand() {
  local -i r="0x$(
    dd if=/dev/urandom bs=4 count=1 2>/dev/null |
    od -A n -t x4 |
    tr -d ' ')"
  echo $((r % $1))
} でいいでしょう。64bit 環境であれば dd と od の引数に出てくる 4 は 8 に変えてください。
さて、[0, 32767] の範囲でしか値を返さ…

タブ補完(その1) - Bash Advent Calendar - Day 12

いまは、ぼくのこころの中では 12 月 12 日の 234 時ぐらいです。当然「昨日」とは 12 月 11 日のことです(すべて US 太平洋時間)。
compgen関数昨日は補完の仕様をさらっと説明しましたが、実際に補完をどう生成すればいいのかというのを説明していませんでした。COMPREPLYは配列変数なので、この Bash Advent Calendar を初日から読めば、自力でかなりのことができるはずです。

とは言え、Bashさんも鬼ではありません。ありがちなパターンに簡単に対応する関数 compgen 関数が予め用意されてます。、一般的には
COMPREPLY=($(compgen オプション... -- 補完したい単語)) という形で使います。

たとえば "-foo", "-bar", "-buzz" というオプション名を補完させたいとしましょう。そしてユーザーが "-" まで入力している場合には
COMPREPLY=($(compgen -W "-foo -bar -buzz" -- "-")) となります。compgen だけを動作させると以下のようになります
$ compgen -W "-foo -bar -buzz" -- "-"
-foo
-bar
-baz
$ compgen -W "-foo -bar -buzz" -- "-b"
-bar
-baz
$ compgen -W "-foo -bar -buzz" -- "f"
$ echo $?
1 候補が何もなかった場合に、終了ステータスが1になります。

ではよく使うオプションについて説明します。

-W文字列
引数で与えられた文字列を「単語分割」($IFS のいずれかの文字で区切る)して、それを候補とみなします。 補完候補の中に空白が含まれる場合は、IFSを適宜変更しておく必要があります。何を言ってるかわからない人は諦めてくださいw-P文字列
引数で与えられた文字列を、補完候補それぞれの先頭に挿入します。

例えばディレクトリ名を ":" 区切りで入力するとします。…

タブ補完(その0) - Bash Advent Calendar - Day 11

ネタがない。
準備 基本的にありものを使ってね、というのは嫌なのですが、まずは bash-completion というパッケージを導入するのが近道です。そこで共通で使われてる関数達が超絶便利なんです。とりあえず、それをインストールしたら今日はおしまいです。続きは明日。
仕様 ユーザーが入力している情報 とりあえず、自作関数で補完をしようとした場合、以下の変数のお世話になります。

COMP_WORDS
現在入力中の行が、単語分割されて、配列として格納されています。ただし、単語分割は Bash の文法とは関係なく、readline というライブラリが好き勝手に分割してくれます。COMP_WORDBREAKS
上記 readline ライブラリが単語と単語の区切りとみなす文字のリスト。 参照オンリーです。この値を変更することは可能ですが、この値を変更しても readline ライブラリは何もしてくれません。昔は変更すると Bash が死んで楽しかったのですが、最近はそんなことはさすがにないみたいです。COMP_CWORD
現在カーソルがある場所の、その単語が COMP_WORDS で格納されている位置。COMP_LINE
現在入力中の行全体。COMP_POINT
現在のカーソルの場所、COMP_LINEでの文字位置に相当(0スタートなので、行末にカーソルがある場合はCOMP_POINTの長さに同じ) 他にも少し、名前が COMP_ で始まる変数があるのですが、使い道がよくわかりません。
とりあえず ${COMP_WORDS[COMP_CWORD]} で「何となく」のカーソル位置の単語が取れるのですが、COMP_WORDBREAKS に中の文字がカーソル位置の単語に含まれている場合にうまくいきません。 補完候補をユーザーに返す方法 COMPREPLYという配列変数に文字列をセットすると、それらが補完候補とみなされます。これはグローバル変数なので、なんの気にもせず上書きしてオッケーです。 TABでの補完時に自作関数が使われるようにする complete -F 関数名 [-o オプション [-o オプション]... ] コマンド名 で登録が可能です。オプションは以下から複数指定が可能です、というか機能的にどうみても複数指定可能じゃないとおかしいだけど、man ページ読んだだけじゃ分からな…