2019/11/12


先日、Gopls の v0.2.0 がリリースされました。

v0.2.0
https://github.com/golang/go/issues/33030#issuecomment-549629508

リリースノートに書かれていますが、このバージョンから completeUnimported に対応しています。fmt が import されていなくても fmt.Println が補完できる様になります。ただしデフォルトでは無効になっています。Visual Studio Code であれば以下を settings.json に含める事で使える様になります。

"gopls": {
    "completeUnimported": true
},
vscode

また vim-lsp をお使いであれば以下の様に設定する事で使える様になります。

if executable('gopls')
  augroup LspGo
    au!
    autocmd User lsp_setup call lsp#register_server({
        \ 'name''go-lang',
        \ 'cmd'{server_info->['gopls']},
        \ 'whitelist': ['go'],
        \ 'workspace_config'{'gopls'{
        \     'staticcheck': v:true,
        \     'completeUnimported': v:true,
        \     'caseSensitiveCompletion': v:true,
        \     'usePlaceholders': v:true,
        \     'completionDocumentation': v:true,
        \     'watchFileChanges': v:true,
        \     'hoverKind''SingleLine',
        \   }},
        \ })
    autocmd FileType go setlocal omnifunc=lsp#complete
    autocmd FileType go nmap <buffer> gd <plug>(lsp-definition)
    autocmd FileType go nmap <buffer> ,n <plug>(lsp-next-error)
    autocmd FileType go nmap <buffer> ,p <plug>(lsp-previous-error)
  augroup END
endif

僕はその他にも実験的なオプションを沢山有効にしています。詳しくは gopls の settings.md を参照下さい。

settings.md
https://github.com/golang/tools/blob/master/gopls/doc/settings.md

これらは Visual Studio Code の gopls セクションでも使えますし、同様に vim-lsp の workspace_config でも使えます。

Posted at by



2019/11/04


はじめに

今年も Vim の国際会議 VimConf 2019 に参加してきました。本格的に国際会議という位置づけに移ってからほぼ4年目、その内3年をスタッフとして参加させて頂きました。

昨年、Vim の作者 Bram Moolenaar 氏を呼べたのはもちろん素晴らしい事ですが、今年も vim-lsp の作者である Prabir Shrestha 氏、neovim のメインメンテナである Justin M. Keyes 氏に登壇頂けたのは、企業スポンサー様の皆さま、個人スポンサーの皆さま、そして当日会場を盛り上げて頂いた皆さまのおかげです。ありがとうございました。

参加したいと思いながらもなんとなく尻込みして来れなかった方、非常に残念です。良い話が沢山聞けました。スライドが後から公開されると思いますが、これだけは言っておきます。熱量やそれを見ている会場の皆さんの期待、懇親会で Vim と関係ない話で盛り上がったり、二次会で Ruby on Ralis のコミッタから OSS とは、英語とは、について聞けるチャンスは、参加しないと得られません。

とまぁ Twitter のタイムラインで「#vimconf」を検索して沢山の感想を頂いているのを見るとスタッフとして関わってきて良かったなぁと毎度思います。

スタッフ業

今年は我々スタッフがこれまで作りたかった物がようやく形として出来上がり始めている感じがしました。

ここ数年、我々は VimConf の敷居をグッと上げました。意図的にではなく我々自身、中途半端な物は出せないだろうと無意識に敷居を上げたのだと思います。発表者の選定、ゲストの選定、パンフレット、色々な物に気を使い、悪くなる可能性を排除し、誰もが納得する最良を目指しました。

一部選定に漏れた方、本当に申し訳ないです。皆さんから数百文字(多い人だと数千字)ある様な熱のこもった プロポーザルを送って頂きました。スタッフも深夜まで何回も読み、議論し、情け容赦なしに決めさせて頂いた結果です。ご了承下さい。

そしてスタッフの皆さんも結構な私生活の時間を割いて VimConf 業に力を注いでくれました。司会者、スタッフ、発表者の3役を担当した mopp さん、ドラ係や懇親会の司会、その他裏で皆を取りまとめ「自分から動く事」を常に忘れなかった aomoriringo さん、そしてそれをサポートし続けた guyon さん、kaoriya さん、ujihisa さん、okuramasafumi さん、tihnca さん、aiya さん、本当に皆さん頑張ったと思います。開催を終えた翌日の今朝、スタッフの一部とアイスコーヒーを飲みながら反省会をしていました。若干燃え尽き症候群ぽかったですが、皆「成功してよかったね」と思っていたに違いないです。

ただ規模が大きくなるにつれ、誰かに負担が偏ってしまいがちになるので、それは今後の課題としなければなりません。落ち着いた頃にスタッフで話し合わないといけないですね。

トークの内容

さて内容ですが、とにかく vim-lsp と Go が沢山出てくる VimConf でした。中には Go を使う為に Vim を触りだしたという方もいらっしゃいました。スタッフとしてウロウロしていたので全ての発表は聞けなかったのが残念ですが、個人的に3つ挙げるとすると以下の様になります。

Prabir Shrestha 氏

vim-lsp の作者としてどの様に vim を複数の言語をシームレスに扱えるエディタにするか、その工夫等をお話頂きました。僕も vim-lsp のメンテナとして興味深く聞かせて頂きました。懇親会でも少しお話させて頂きましたが、編集中にも補完候補がシャカシャカと表示され、間違ったコードにマーカーが付く、こんな事が数年前だと実現できなかった Vim を今の操作感に持って行ったのは vim-lsp による貢献が大きいと個人的には思っています。

Justin M. Keys 氏

Vim に限らずソフトウェアという物を fork する場合、それは既に揺るぎない基本設計が出来上がった物であり、それに乗っかる事のメリットは大きいという話をして頂きました。neovim のメンテナとして、vim 色を残しつつ違う vim を作っていく意気込みが聞けて良かったです。

daisuzu 氏

毎年、安定した発表をされていてそれだけでも凄い事だと思いますが、タグジャンプという Vim 特有の機能を分かりやすく会場にいる多くの皆さん沢山届く発表をして頂いたと思います。タグジャンプは Vimmer の基本です。使った事が無かったのであれば、ぜひ習得してみて欲しいです。

その他にも熱のこもった発表が沢山あり「Vimmer っていっぱいいるんだなぁ」と感じさせて頂ける内容ばかりでした。

懇親会でLTをさせて頂き「RESTサーバを5分で作れる、そう Vim ならね」と題して sqlite3 を使って JSON を返す echo を使ったサーバを5分で作るデモをお見せしました。お酒が入っていたので rows.Close() を呼びだすのを忘れていましたが、普段僕がどんな感じにコーディングしているのかをお伝え出来たと思います。

おわりに

我々スタッフは、こういった素晴らしい発表を皆さんが聞き、また次の回にも参加したい、そう思ってくれる事を願ってスタッフ業をやっています。ブログで VimConf の内容を語って頂くのもよし、会社で「VimConf 楽しかったよ」と同僚にお伝え頂くのもよし、懇親会で Vim にまったく関係ない話で盛り上がって頂くのもよし、今回の VimConf をきっかけにどこかに転職/就職が決まるもよし、すべての Vim をトリガにした動きが我々スタッフの望みです。

個人的には僕の GitHub Sponsors をして頂いている数名の方にご挨拶できた事、古くから Vim の活動をされている kana さんと挨拶だけでもできた事、Go のユーザが沢山いるのを知れた事は、とても良かったです。

これも Vim をトリガにした「人と人が繋がれるキッカケ」ですよね。次の回、どういう風になるのかは分かりませんが、また「人と人が繋がれるキッカケ」が提供される VimConf になる事を願っています。

そして Vim に関してどんどん新しい人が入ってきていて、僕もそろそろアウトプットではなくインプットをしないといけないな、そう感じる VimConf でした。

Posted at by



2019/10/16


Linux の sudo に root 権限を奪取できるバグが見つかった。

Linuxの「sudo」コマンドにroot権限奪取の脆弱性。ユーザーID処理のバグで制限無効化 - Engadget 日本版

この脆弱性は、sudoコマンドのユーザーIDに-1もしくは4294967295を指定すると、誤って0(ゼロ)と認識して処理してしまうというもの。0(ゼロ)はrootのユーザーIDであるため、攻撃者は完全なrootとしてコマンドを実行できることになります。

https://japanese.engadget.com/2019/10/14/linux-sudo-root-id/

既に Ubuntu 等にはパッチが配布され始めているらしいですが、この記事ではこのバグが如何にして起こったのかを調査し今後の為に共有したい。

sudo のコードは以下からダウンロードできる。取得には mercurial が必要。

Sudo Source Repo
https://www.sudo.ws/hg.html

修正差分は以下。

sudo: 83db8dba09e7
https://www.sudo.ws/repos/sudo/rev/83db8dba09e7

差分だと分かりづらいので、この現象が起きうるソースを調べていく。sudo は実行されると plugins/sudoers/sudoers.cinit_vars が呼ばれ、続いて set_runaspwrunas_user ありで呼ばれる。set_runaspw では与えられたユーザID文字列(#-1 の # 以降)を解析する為に sudo_strtoid_v1 が呼ばれる。この sudo_strtoid_v1 が今回バグを生んだ関数。

id_t
sudo_strtoid_v1(const char *p, const char *sep, char **endp, const char **errstr)
{
    char *ep;
    id_t ret = 0;
    long long llval;
    bool valid = false;
    debug_decl(sudo_strtoid, SUDO_DEBUG_UTIL)

    /* skip leading space so we can pick up the sign, if any */
    while (isspace((unsigned char)*p))
        p++;
    if (sep == NULL)
        sep = "";
    errno = 0;
    llval = strtoll(p, &ep, 10);
    if (ep != p) {
        /* check for valid separator (including '\0') */
        do {
            if (*ep == *sep)
                valid = true;
        } while (*sep++ != '\0');
    }
    if (!valid) {
        if (errstr != NULL)
            *errstr = N_("invalid value");
        errno = EINVAL;
        goto done;
    }
    if (errno == ERANGE) {
        if (errstr != NULL) {
            if (llval == LLONG_MAX)
                *errstr = N_("value too large");
            else
                *errstr = N_("value too small");
        }
        goto done;
    }
    ret = (id_t)llval;
    if (errstr != NULL)
        *errstr = NULL;
    if (endp != NULL)
        *endp = ep;
done:
    debug_return_id_t(ret);
}

勘のいい方であれば、これを見ただけで「アーーーッ!」と思うかもしれない。

    llval = strtoll(p, &ep, 10);
    if (ep != p) {
        /* check for valid separator (including '\0') */
        do {
            if (*ep == *sep)
                valid = true;
        } while (*sep++ != '\0');
    }

strtoll は文字列のポインタを基数と共に渡すと、long long 型整数値に変換し戻り値で返却します。数値として解釈された後は数値として解釈できなかった文字まで第二引数で指定されたポインタがシフトします。つまりこのコードでもし -1 が指定されると、正常な数値として扱われます。errno も設定されません。llval の範囲チェックもされていません。epp は異るアドレスとなり、今回呼び出されるケースでは sep が NULL なので -1 という単語のみをチェックする為に呼ばれたこの関数は、valid = true と認識してしまいます。後は時の流れに身を任せ、あなたの色に染められるだけになります。怖いですね。修正内容では strtoll 呼び出し直後に errno の確認が行われ、値の範囲も確認されています。正直なぜこれ strtoul を使わないんだろうなと思ったりもしますがソースの場所からするとユーティリティ関数なのでしょう。wandbox でお試しできる様にしてあるので遊びたい人は遊んで下さい。数字の横が (null) ならパスしたという事になります。

なお -1 が通ってしまうと何がまずいかについてはココを参照下さい。

教訓

境界値チェックを行わないと、死ぬ

Posted at by