I know I believe in nothing but it is my sweet nothing.:最新 5 日分

2022/09/28(Wed)

[ソースコード考古学] bsearch_sのプロトタイプの混乱

kbkさんとこより

このC11で導入された(ただしオプションで実装しなくてもいいという扱い)bsearch_sを含む*_s関数は ISO/IEC TR 24731-1で検討されたものすね。

そんでこれに先行する実装であるVisual Studio 2005(Whidbey)と差異があるのは当時記事を 書いた通りでございます、あれ?bsearch_sってrsize_tやerrno_tの扱い以外にもプロトタイプそのものに違いあったんだっけか、もう覚えてないゾ。

ちなみにVisual Studio 2005の次に実装したのはOpen Watcomだったのも当時記事を 書いた、なおこっちもTR 24731-1と微妙に挙動が違うという話も 書いた、今どうなってんだろこれ。

そもそもVisual Studio 2005の場合、これらの*_s関数ってのはcl.exeのオプションに/GSスイッチつけた場合(デフォルト)、事前定義マクロ_CRT_SECURE_CPP_OVERLOAD_STANDARD_NAMESがONになりマクロの黒魔術で暗黙的に非_s関数は置き換えられるというものだったのよね(これも記事 書いた)。

つまりはgcc4.1で導入されたgcc -fstack-protectorによるスタック保護(a.k.a ProPolice)と同じアイデアなんですよこれ。 こっちは*_sではなく*_chkという関数に置き換えられるのだけども。

ということで本来*_s関数ってやつはコーダーが直接呼ぶもんじゃないんです(断言)、にもかかわらずISO/IEC JTC1/SC22/WG14のピーどもがキャッキャとテクニカルレポート書いてしまったことによる混乱がこれだよ! そしてそれに追従して *_s関数の使用を推奨するセキュアコーディングガイドとかいうピーども、もうCごと滅びろ。

少なくともコンパイラが勝手に置き換えるならプロトタイプ違っても勝手に吸収されるから問題にならないからね、直接bsearch_sを呼ぶ愚か者だけが移植性でトラブるのだ(戒め)。

ちなみに過去記事の通りN向けのTR 24731-1実装も当時ワイ書いたんだけど、Nがgccを使う限りマージする意味ねえなぁと 放置すんべとあれから16年が経過しました、あれワイ自称17歳なのに時空が歪む。

2022/09/27(Tue)

[宗教] 続ThinkPad X61とWindows 10とホットキー機能統合

ベイ軍ヤ党に歯が立たず壊走、CSは横須賀に突如現れた大型助っ人ズムウォルト先発で報復や!

しかしこうも直接対決で勝てないとCS無理っぽいよね、太平洋戦線はソ軍がマジック5だけど2017年のベイソ冷戦再びは無さげ。 やはり監督の経験値ですかね、ミゥラー少佐よりタカーツ大佐の方が階級上だし。

それでは 前回続き、ThinkPad X61 + Windows 10/11でホットキー機能統合のFn+F5キーを有効にするには

のいずれかが必要と書いたけど、8jvu43wjはX61ではFn+F5キーだけでなくミュートボタンが効かないという問題もあるのに気づいた。

よって前者しか選択肢が無いのねこれ、そして非互換性についてはWindows 10対応したAuto Scroll Utiltyの最新版(gfvv33ew/2.23)が存在して、こいつを先にインストールしとけば警告は出ずにサイレントインストールの邪魔にならない事がわかった。

"[extracted dir]\gfvv33ww.exe" /PARAM="/S" /SP- /VERYSILENT /NORESTART /SUPPRESSMSGBOXES
"[extracted dir]\HOTKEY\SETUP.EXE" /S

とでもunattend.xmlから呼び出すbatchスクリプトに書いとけばおk。

そんでこのアプリがなぜ必要なのかも理解、中ボタン押下でスクロールする機能でホイールスクロール代わりに必要なやつだった。

ちっLenovo pkgmgrのSWI.XMLおよびインストール用のinfファイルの読み方とか書き方とかの解説を用意しようと思ったが洋梨になってしまったぜ。 やっぱり和梨がいいよね幸水と豊水どっちも好きです。

あとX61はUSBメモリが3.0なやつだとブートできない病があるっぽいのに気づいた、F12押してからの起動メディア選択でてこねーんですわ。 つーかブートメディアとしてでなくても普通に読書きが異常に低速だし頻繁にデバイスが見えなくなるわで使い物にならんぞこいつ。

少なくとも手元に転がってるHIDISC製のHDUF114C32G3とHDUF133C32G3はだめみたい、他のメーカーのやつ発掘して試すか…

2022/09/26(Mon)

[宗教] ThinkPad X61とWindows 10とホットキー機能統合

ThinkPadのホットキー機能統合、X61向けの最終バージョン(8jvu43wj/3.89.0100)だとWindows 10でFn+F5キーが有効にならないのだよね。

これはOSのバージョンの問題で、Windows 7まではFn+F5キーは有効になるのだがWindows 8以降だとFn+F5キー拡張はインストールされなくなっているのである。

このホットキー機能統合はいくつかのソフトの集合体なのだが、このファンクションキーについてはOSD(オンスクリーン表示)ってのが相当する。

展開したファイル中のOSD\tphk_tp.infというセットアップファイルを覗いてみると

[DefaultInstall.LH.NTamd64]
CopyFiles=SHTCTKY.files,MKR.files,MKR.Res.files,UEFIOSD.files,OSD.files,OSD.Res.files,FnF5-OLD.files,FnF5.Res.files,FnF8.files,FnF9.files,FnF2.files,Runtime.files,AVAYA.files,FNF5.Qualcomm.Runtime.files,MicMute.files,NumLock.files,FNF6.files
DelFiles=Drivers.2KXP.files
...
[DefaultInstall.W8.NTamd64]
CopyFiles=SHTCTKY.files,MKR.files,MKR.Res.files,UEFIOSD.W8.files,OSD.W8.files,OSD.Res.files,FnF2.files,MicMute.files,FNF6.files,NumLock.files,EXTAPSUP.files

DelFiles=FnF5-OLD.files,FnF5.Res.files,FNF5.Qualcomm.Runtime.files,FnF8.files,FnF9.files
...

はい、インストールスクリプト中のLH(LongHornつまりWindows Vista)とW8(Windows 8)の差をみるとFn+F5以外にも

も消されてるもよう、前者はよくわからんけど後者はWindows 7の時点でスタートメニューの電源ボタンから解除できたから不要だねってところか。

同様に無線のOn/OffもWindows 8以降はタスクトレイから無線の機内モードの制御ができるようになったので、重複機能として消しちゃおうってなったんだろか。 ちょうど同じタイミングでWindows 7の時点でタスクトレイからアクセスポイント選べるしこれ要る?感のあったAccess Connectionも提供されなくなったしね。

ちなみに今のThinkPadを名乗るノートパソコン(絶対に許さないよ)ではFn+Fキーの割り当ては 一新したのだね、欲しいと思わんしそもそも買う金もねーからどうでもいいけど。

ところがこれで困るのがThinkPad X61のBluetoothなのだ、不思議なことにこの機種は

という謎挙動を示すので、Fn+F5キー拡張が削除されてしまうとBluetoothがどうやっても有効にできなくなってしまうのだ。 まぁワイはBluetoothデバイスひとつも持っておらんのでどうでもいいっちゃいいのだが。

この対策について最も簡単な方法は、Windows 8以前にリリースされた古いバージョン(8jvu23wj/3.81.0100)を使うこと。 OSチェックなしに問答無用でFn+F5キー拡張をインストールしやがるのでこの問題を回避できる。

ただし8jvu23wjについてはWindows 10 1903以降だと

という問題がある、前者については互換性データベースに登録されるてるようで警告ダイアログまで出てしまうのだ。

手動インストールであれば警告を無視してセットアップを続行し、インストールするアプリから両者をを除外すればいいだけである。 そもそも前者は何してるのか効果のほどがさっぱり判らん(ウインドウ位置やスクロールバーを調節するらしいが)。 後者はSystem Update経由でBIOSやドライバの更新に必要なやつっぽいけど、サポート切れのハードに更新が降ってくるわけでもないのでな。 つーかどっちも8jvu43wjで消されとるし不要なんやな。

しかしこの互換性データベースによる警告、こいつが自宅システム管理者からすると困るのだ。 というのもunattended.xmlなどで実行するサイレントインストールがこの警告ダイアログによって無効になってしまうのよね。

ホットキー機能統合のドキュメントには

コマンド ラインによるインストール (Unattended インストール)

  この方法は、システム管理者のみが使用します。

  1.「手動インストール」の章を参照して、ファイルのダウンロードと展開を行います。
  2.「インストール」の手順 12.で「...をインストールする」に付いているチェックマ
     ークを外し、「完了」をクリックします。インストールがキャンセルされて、ファ
     イルの展開で終了します。
  3. /S オプションを追加して、コマンド ラインで setup.exe を実行します。
     (例) [パッケージを展開した先のパス]\setup /S

とあるのだけど、警告ダイアログで遮られてバッチインストールが止まってしまうんですわ。

とはいえシステム管理者がいまだにX61を使い続けて、しかもWindows 10/11のインストールに自動セットアップを用意する酔狂な真似をするはずもないのでこれは仕方無い、俺を除いてな!

ということで自動セットアップのために

という作業が必要なのだ、アークソクソ。

あと以前のThinkPadにはActive Protection Systemという本体の加速度センサーで衝撃を検知してヘッドを退避するんだかでハードディスクの損傷を防ぐソフトがあったんだけど消えちゃったんだな。 まぁ最後のバージョンが1.82.0.20/n1msk20wと判ってればLenovoのサーバーから拾ってくるのは容易いのだけど。

もうSSDが当たり前で未だにHDD使ってる貧乏人とか知るかって話なんだろうけど、ワイんちでは現役だからな ただWindows 10対応してるはずなんだがタスクトレイの通知とコントロールパネルにアイコンが表示されない問題があって動いてるのかよくわからんのだよな。 マシン揺さぶってみるとHDDのランプ消えるから動いてはいるみたいなんだけどね

ということでこのへんの非互換性もそのうち調べんとな、あーあほくさ。

2022/09/21(Wed)

[386BSD(の子孫)ソースコードシリーズ (334)] sys/cdefs.hとは何ですか?番外編 - __UNCONST()マクロとは何か?

以前書きかけてもう長いこと放置してる 連載記事をちょっとだけ復活、というのも128bitポインタ時代に備えよみたいなことを6億円振込を待つ世界緊急放送で受信したので。

要はUN*X方面だとILP32/LP64を前提としてポインタをlongとして扱うクソコードが大量に残っていて

というお話でいいんだっけ、つーかお前ら128bitポインタ時代にまだC言語使う気ですか(戦慄) intwidest_tといいもうCは捨てようぜ。

まぁワイは将来P128/LP128と呼ぶのか知らんがその頃には生きてないからどうでもよろしい、生き延びてもSandyおじさんだろうし…というか現在C2Dおじさんまで退化している(X61でこれ書いてる)。 ところで128bit CPUって命令セットはx86_128なんですかやっぱり。

ちなみにCの仕様だとint64_tは対応するbuilt-in typeが無いなら実装してはならない、なので代わりにint_{fast,least}64_tを使えが正しい。しかし世の中そんなコードはまず存在しないというのは 以前にも書いた通り。そうintN_tを使ってる時点でそれはILP32とLP64の間でしか移植性は無いのだ(無慈悲)。

ところでワイにとってはカーネルって道頓堀に沈んでたおじさんの像でしかないので、sysの下とか全く知らんからそんなに大量にポインタをlongで扱ってるコードが生き残ってるの?という感じではあるな。 クッソ適当に知識多く知恵少なきインターネットを検索すると通信用語の基礎知識の LP64の項に

ポインターをint型に代入するようなプログラムは移植できないが、long型に代入するようなプログラムは
データ長が同じため問題が顕著化せず、そのまま移植することができる。

UNIXでは伝統的にポインターをlong型変数に入れて使う傾向にある。
例えばコールバック関数の引数でunsigned longにポインターが入っており、これを(void *)などで
キャストして使う、といったこともよくある。そのため、このデータ型モデルが採用されたものと思われる。

なんて書かれてるけどさ、今年ってさぁ ISO/IEC西暦2022年だよね…

あっそうだ(唐突に本題)、ワイの知ってる範囲でもconst外し(関節外しみたいなんやなw)マクロであるcdefs.hの__UNCONST()でポインタをunsigned longで扱っとるから移植性ないよねこれ。

/*
 * The following macro is used to remove const cast-away warnings
 * from gcc -Wcast-qual; it should be used with caution because it
 * can hide valid errors; in particular most valid uses are in
 * situations where the API requires it, not to cast away string
 * constants. We don't use *intptr_t on purpose here and we are
 * explicit about unsigned long so that we don't have additional
 * dependencies.
 */
#define __UNCONST(a)    ((void *)(unsigned long)(const void *)(a))

まぁマクロなのでここ一か所だけ修正すりゃ終わりなんだが、逆にマクロ使わずにconst外しをunsigned longでやられてると修正が大変になるパターンではある。

なおこの__UNCONST()マクロ、なぜダイレクトに非const型にキャストせずこんなもんを介すのかというと、gccに-Wcast-qualというオプションつけるとconstから非constへのキャストは警告の対象になってるからなんよね。 そしてNではbsd.sys.mkでWARNS>2がMakefileで指定されてると-Wcast-qualが有効になりかつ-Werrorがデフォルトで有効なのでコンパイルエラーになるのだ。

.if ${WARNS} > 2
CFLAGS+=        -Wcast-qual -Wwrite-strings
CFLAGS+=        -Wextra -Wno-unused-parameter
...
.endif

でもさ、そもそもconstから非constへのキャストは何らかのミスの可能性があるってだけで、仕様としては合法なので-Werror -Wcast-qualして警告をエラーとして扱ってるのが間違いなんじゃね?ではあるんだよね。 ということで脳死でいたずらに警告レベルを上げた結果、いらんマクロを発明してしまったんじゃねえかなぁこれ。

ちなみにOでは__UNCONSTみたいなものは用意せずそのまま非constにキャストして-Wno-cast-qualしてたはず。

とはいえ合法だがconstを外すなと古事記とセキュアコーディングガイドにも 書かれているよねって原則論が無いわけではない、しかしmalloc(3)したメモリをconstポインタに代入したけど、free(3)する時に元の非constポインタが残ってなくてconstポインタで開放したくてconstを外すなんてコードにはよく遭遇するからな。 というかそういうコードが出す警告のために__UNCONST()の99%は使われてるんですわ。

そしてNだとサードパーティー製のソフトウェアをsrc/external以下に大量に抱えてるのだけど、いちいち-Wcast-qual対策で__UNCONST入れてってるのよね。 非常にめんどくさい作業だし、バージョン上げる際にvendor importするとその部分でconflictも発生しかねないわけでさ、なるべく差分は最小にとどめたいのに。 できればオレオレN6ではOみたいに-Wcast-qualをエラー扱いにするの止めたいんというお気持ち。

そんで128bitポインタ問題に話は戻るけど、Fにおける同機能に__DECONST()マクロがあるんだけどこっちは__uintptr_t(C99のintptr_tの内部型)を使ってるのでこちらでは発生しない、ただしいちいち_types.hもインクルードする必要があってより差分が増えるのである。

#ifndef __DECONST
#define __DECONST(type, var)    ((type)(__uintptr_t)(const void *)(var))
#endif

つーか_types.hはcdefs.hをインクルードしてるので本来なら循環参照じゃねえのこれ、ガード入ってるから誰も気づかないだけで。 そもそもcdefs.hはMI/MDを扱わない *1のでこの中でintptr_tを使うのは実装として変なんだよな。

でもこのシリーズ中で以前も説明したけど、cdefs.hの役割というのは

の黒魔術、よってコンパイラの警告対応だからcdefs.hに実装するのはそれはそうであって悩ましいのである。

本来ならコンパイラ側に局所的に警告を抑制するpragmaなりattributeが欲しいとこ、lint(1)なら/*LINTED*/コメントで抑制できるんだけど。 いまだと翻訳単位(ソース単位)でしか警告オプション切り替えられないからな。

ただコードを書き換えるにつれ一度は警告を抑止した部分が突然牙を剥いたりすることもあるので、やっぱりコードそのものを正しく書き直せが正解かな。

*1:ただしa.out/ELFのようなobject formatの差異はここで扱う

2022/09/20(Tue)

[セキュリティ] doas(1)のpersistオプションはなぜOでしか有効にならないのか

昨日の件、Oのtty(4)にVERAUTHというユーザーセッションで認証が成功したかを表すフラグ持ってるんだな。

TIOCSETVERAUTH int *secs
	Indicate that the current user has successfully authenticated to this session.
	Future authentication checks may then be bypassed by performing a TIOCCHKVERAUTH check.
	The verified authentication status will expire after secs seconds.
	Only root may perform this operation.

TIOCCLRVERAUTH void
	Clear any verified auth status associated with this session.

TIOCCHKVERAUTH void
	Check the verified auth status of this session.
	The calling process must have the same real user ID and parent process as the process which called TIOCSETVERAUTH.
	A zero return indicates success.

そりゃOにしかない機能だからFやNでは動かんですわ、ってかdoas.conf(5)のマニュアルのpersist周りの記述にちゃんと書いておいてほしい。

ただこいつをオレオレN6で取り込んでもダメ、というのもVERAUTHのチェックとセットをやってるのがBSD/OS由来の認証システムであるBSD Authを呼び出す関数の中に入ってるから。 なおFやNはBSD Authを採用せず、Linuxなどでも使われてるよりメジャーなPAMのBSDL実装である OpenPAMを採用してるのでこの部分のコードは通過しないのやな。

224 #if defined(USE_BSD_AUTH)
225 static void
226 authuser(char *myname, char *login_style, int persist)
227 {
228         char *challenge = NULL, *response, rbuf[1024], cbuf[128];
229         auth_session_t *as;
230         int fd = -1;
231
232         if (persist)
233                 fd = open("/dev/tty", O_RDWR);
234         if (fd != -1) {
235                 if (ioctl(fd, TIOCCHKVERAUTH) == 0)
236                         goto good;
237         }
238
239         if (!(as = auth_userchallenge(myname, login_style, "auth-doas",
240             &challenge)))
241                 errx(1, "Authorization failed");
...
263 good:
264         if (fd != -1) {
265                 int secs = 5 * 60;
266                 ioctl(fd, TIOCSETVERAUTH, &secs);
267                 close(fd);
268         }
269 }
270 #endif

上記の235行目、もしdoas.confにpersistが含まれていればtty(4)にVERAUTHフラグが立ってたら認証済みとして認証を行わない。 そして266行目、5分間のタイムアウトを指定してVERAUTHフラグを立てるちゅー感じ。

機能としては独立したものなのでBSD Auth vs PAM関係ないのだけども、いちいちtty(4)をかってに改造(尻穴に乾電池感)して新機能を追加するのも手間だなぁという。

ちょっと調べたら Oのdoas(1)ではなくそのfork版の OpenDoasはPAMでもpersistをサポートしているもよう、というかforkしてOとは無関係なのにさらにOpenがつくのでもはやOpenとは何かという宇宙猫の顔になる。

というかOpenをforkしたら次はLibreってのも意味わからんけどな!(OpenOffice/LibreOfficeやOpenSSL/LibreSSLの方を見ながら)

こっちの認証済チェックの実装は/var/run/doas以下に一時ファイル作ってそのタイムスタンプを確認という方法なもよう、詳しくは これ、かつてsudo(1)でも散々認証バイパスの脆弱性やらかした不安を感じる方式だけど、妥当な実装かはまた次回sudo(1)と共にコードちゃんと読みますかね。

余談であるがPAMとBSD Authの最も大きな違いは

である、Oは基本的に

あたりでPAMを採用する理由が一ミリもないと考えてると思われる。ちなみにOがCitrus XPG4DLを採用しなかった原因も同じ。 正直言ってパラノイアすぎるがまぁ部外者がどうこういってもしゃーないので以下略。

ちなみにNの場合full dynamicaly linked rootだけど、/libを消してしまったみたいな事故が起きても/rescue以下にcrunch binary化(すべて単一の実行ファイルにしてハードリンクで呼ばれた名前で動作を変える)された/binおよび/sbinのコマンドがあるので困ることは無いはず。