├── content ├── pages │ ├── _index.md │ ├── カーネルビルド中にビルドできる料理の一覧 │ │ ├── namul.jpg │ │ └── _index.md │ ├── バイナリ内の文字列の探し方 │ │ └── _index.md │ ├── pasokey-post-mortem-2024-04-18 │ │ └── _index.md │ └── インラインアセンブラtips集 │ │ └── _index.md ├── docs │ ├── _index.md │ └── 執筆ガイド │ │ └── _index.md └── _index.md ├── archetypes └── default.md ├── layouts └── partials │ └── docs │ ├── html-head-title.html │ └── inject │ └── content-before.html ├── .gitmodules ├── README.md ├── .gitignore ├── assets ├── _custom.scss └── search-data.json ├── config.toml └── i18n └── ja.yaml /content/pages/_index.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: "記事" 3 | --- -------------------------------------------------------------------------------- /archetypes/default.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: "" 3 | date: {{ .Date }} 4 | type: docs 5 | --- -------------------------------------------------------------------------------- /content/docs/_index.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: "ドキュメント" 3 | bookFlatSection: true 4 | --- -------------------------------------------------------------------------------- /layouts/partials/docs/html-head-title.html: -------------------------------------------------------------------------------- 1 | {{ partial "docs/title" . }} - {{ .Site.Title -}} 2 | -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "themes/hugo-book"] 2 | path = themes/hugo-book 3 | url = https://github.com/alex-shpak/hugo-book 4 | -------------------------------------------------------------------------------- /content/pages/カーネルビルド中にビルドできる料理の一覧/namul.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pasokonistan/pasopedia/HEAD/content/pages/カーネルビルド中にビルドできる料理の一覧/namul.jpg -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Pasopedia 2 | 3 | ## これは何? 4 | Pasopediaは[パソコニスタン](https://pasokon.site/)の国民によるオンラインナレッジベースです。 5 | 6 | Pasopediaでは一般的な情報からニッチなハウツーまでの広範なトピックを扱い、人々のパソコンライフをあらゆる側面からカバーすることを目標としています。 -------------------------------------------------------------------------------- /layouts/partials/docs/inject/content-before.html: -------------------------------------------------------------------------------- 1 |
2 |

{{ .Title }}

3 | {{ with .File }} 4 | 編集履歴 5 | {{ end }} 6 |
7 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | tmp/ 2 | 3 | # Generated files by hugo 4 | /public/ 5 | /resources/_gen/ 6 | /assets/jsconfig.json 7 | hugo_stats.json 8 | 9 | # Executable may be added to repository 10 | hugo.exe 11 | hugo.darwin 12 | hugo.linux 13 | 14 | # Temporary lock file while building 15 | /.hugo_build.lock 16 | -------------------------------------------------------------------------------- /assets/_custom.scss: -------------------------------------------------------------------------------- 1 | h1, h2, h3 { 2 | font-weight: bold !important; 3 | } 4 | 5 | .content-top-container { 6 | display: flex; 7 | flex-direction: column; 8 | gap: 0.5rem; 9 | margin: 2rem 0; 10 | } 11 | 12 | .content-top-container * { 13 | margin: 0; 14 | } 15 | 16 | .markdown pre code { 17 | white-space: pre-wrap; 18 | } -------------------------------------------------------------------------------- /config.toml: -------------------------------------------------------------------------------- 1 | baseURL = "/" 2 | languageCode = "ja" 3 | defaultContentLanguage = "ja" 4 | title = "Pasopedia" 5 | theme = "hugo-book" 6 | 7 | [markup] 8 | [markup.goldmark.renderer] 9 | unsafe = true 10 | 11 | [params] 12 | BookTheme = "auto" 13 | BookSection = "*" 14 | BookSearch = true 15 | BookComments = false 16 | BookTranslatedOnly = false 17 | -------------------------------------------------------------------------------- /i18n/ja.yaml: -------------------------------------------------------------------------------- 1 | - id: Search 2 | translation: 検索 3 | 4 | - id: Edit this page 5 | translation: このページを編集する 6 | 7 | - id: Last modified by 8 | translation: 最終更新者 9 | 10 | - id: Expand 11 | translation: 展開 12 | 13 | - id: bookSearchConfig 14 | translation: | 15 | { 16 | encode: false, 17 | tokenize: function(str) { 18 | return str.split(/\W+/).concat(str.replace(/[\x00-\x7F]/g, '').split('')).filter(e => !!e); 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /assets/search-data.json: -------------------------------------------------------------------------------- 1 | [ 2 | {{- $pages := where .Site.Pages "Kind" "in" (slice "page" "section") -}} 3 | {{- $pages = where $pages "Params.booksearchexclude" "!=" true -}} 4 | 5 | {{ range $index, $page := $pages }} 6 | {{ if gt $index 0}},{{end}} { 7 | "id": {{ $index }}, 8 | "href": "{{ $page.RelPermalink }}", 9 | "title": {{ (partial "docs/title" $page) | jsonify }}, 10 | "section": {{ (partial "docs/title" $page.Parent) | jsonify }}, 11 | "content": {{ $page.Plain | jsonify }} 12 | } 13 | {{- end -}} 14 | ] -------------------------------------------------------------------------------- /content/pages/カーネルビルド中にビルドできる料理の一覧/_index.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: "カーネルビルド中にビルドできる料理の一覧" 3 | date: 2023-04-19T07:29:46+09:00 4 | type: docs 5 | --- 6 | 7 | ## 本記事で紹介するもの 8 | 9 | 本記事では、Linuxカーネルをビルドし終わるまでの間に調理が完了するような、短時間でできる料理を掲載する。 10 | 11 | ## 本記事で対象外とする読者 12 | 13 | 以下の読者は本記事で対象外とする。 14 | 15 | - 料理をしたくない人 16 | - 基本的な調理器具が手元にない人 17 | - スリッパマシンなどの強いPCを所持しており、カーネルビルドが秒で終わる人 18 | 19 | ## 料理一覧 20 | 21 | ### もやしのナムル 22 | 23 | ![もやしのナムル](namul.jpg) 24 | 25 | 材料 26 | 27 | - もやし:200g 28 | - 調味料(A) 29 | - しょう油:デザートスプーン2さじ 30 | - ごま油:デザートスプーン2さじ 31 | - 中華スープの素:デザートスプーン2さじ 32 | - 酢:デザートスプーン1さじ 33 | - すりおろしにんにく(チューブ):デザートスプーン1/2さじ 34 | 35 | 調理方法 36 | 37 | 1. もやしを耐熱ボウルに入れてラップをかけ、電子レンジ600Wで約3分加熱する。 38 | 2. 流水で冷やし、水気を切る。 39 | 3. もやしに調味料(A)を入れて混ぜ合わせる。 40 | 41 | ひとこと 42 | 43 | 韓国のりなどをちぎっていれてもよい、ダイエット中にピッタリ。 44 | 45 | --- 46 | 47 | レシピ追記募集中。 48 | -------------------------------------------------------------------------------- /content/_index.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: ホーム 3 | date: 2023-03-19T21:18:59+09:00 4 | type: docs 5 | --- 6 | 7 | ## Pasopediaとは? 8 | Pasopedia(パソペディア)へようこそ。Pasopediaは[パソコニスタン](https://pasokon.site/)の国民によるオンラインナレッジベースです。 9 | 10 | ## 目標 11 | Pasopediaでは一般的な情報からニッチなハウツーまでの広範なトピックを扱い、人々のパソコンライフをあらゆる側面からカバーすることを目標としています。 12 | 13 | ## コントリビュート 14 | Pasopediaは主にパソコニスタンの国民によって運営されていますが、パソコンライフに役立つ情報の提供はパソコニスタン内外を問わず常に歓迎されます。 15 | 16 | もしあなたがPasopediaに貢献したいと考えているのであれば、[PasopediaのGitHubリポジトリ](https://github.com/pasokonistan/pasopedia)をご確認ください。また、ページを作成・編集する際は[Pasopedia:執筆ガイド](/docs/執筆ガイド/)をご一読ください。 17 | 18 | ## 謝辞 19 | - Pasopediaは[pasokey:@sksat](https://pasokey.net/@sksat)さんによってホスティングされています。 20 | - Pasopediaには[Hugo](https://gohugo.io)と[Hugo Book](https://github.com/alex-shpak/hugo-book)テーマが使用されています。 21 | - [コントリビューターのみなさん](https://github.com/pasokonistan/pasopedia/graphs/contributors)に感謝します! -------------------------------------------------------------------------------- /content/pages/バイナリ内の文字列の探し方/_index.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: "バイナリ内の文字列の探し方" 3 | date: 2024-01-26T02:23:48+09:00 4 | type: docs 5 | --- 6 | 7 | ## 概要 8 | 9 | 本記事では、プログラムで利用している文字列リテラルがプログラム内のどこに配置しているのかを確かめるための手法について解説する。 10 | 11 | ## 本記事の実験環境 12 | 13 | - OS: Ubuntu 22.04 14 | - コンパイラ: clang 17.0.6 15 | - アーキテクチャ: x86_64 16 | - GNU readelf: GNU Binutils 2.38 17 | 18 | ## 文字列 19 | 20 | 定番のHello, World!プログラムを使って、文字列がどこにあるかみてみよう。 21 | 22 | ```c 23 | #include 24 | 25 | int main(void) { 26 | puts("Hello, World!\n"); 27 | } 28 | ``` 29 | 30 | まずは-cオプションをつかってリンク前のオブジェクトファイルでみてみよう。 31 | 32 | ```console 33 | $ clang -c helloworld.c 34 | ``` 35 | 36 | バイナリのセクション情報をみるために、ここではGNU readelfプログラムを利用している。 37 | 38 | ```console 39 | $ readelf -WS helloworld.o 40 | There are 11 section headers, starting at offset 0x260: 41 | 42 | Section Headers: 43 | [Nr] Name Type Address Off Size ES Flg Lk Inf Al 44 | [ 0] NULL 0000000000000000 000000 000000 00 0 0 0 45 | [ 1] .strtab STRTAB 0000000000000000 0001e1 00007f 00 0 0 1 46 | [ 2] .text PROGBITS 0000000000000000 000040 000014 00 AX 0 0 16 47 | [ 3] .rela.text RELA 0000000000000000 000198 000030 18 I 10 2 8 48 | [ 4] .rodata.str1.1 PROGBITS 0000000000000000 000054 00000f 01 AMS 0 0 1 49 | [ 5] .comment PROGBITS 0000000000000000 000063 000066 01 MS 0 0 1 50 | [ 6] .note.GNU-stack PROGBITS 0000000000000000 0000c9 000000 00 0 0 1 51 | [ 7] .eh_frame X86_64_UNWIND 0000000000000000 0000d0 000038 00 A 0 0 8 52 | [ 8] .rela.eh_frame RELA 0000000000000000 0001c8 000018 18 I 10 7 8 53 | [ 9] .llvm_addrsig LOOS+0xfff4c03 0000000000000000 0001e0 000001 00 E 10 0 1 54 | [10] .symtab SYMTAB 0000000000000000 000108 000090 18 1 4 8 55 | Key to Flags: 56 | W (write), A (alloc), X (execute), M (merge), S (strings), I (info), 57 | L (link order), O (extra OS processing required), G (group), T (TLS), 58 | C (compressed), x (unknown), o (OS specific), E (exclude), 59 | D (mbind), l (large), p (processor specific) 60 | ``` 61 | 62 | ここで各セクションのフラグに注目してみると、.rodata.str1.1と.commentにはS(strings)というフラグがついていることがわかる。これはヌル終端な文字列データを含んでいることを示すフラグであり、つまり文字列データが内包されている箇所である。ここでついでに.rodata.str1.1にM(merge)フラグがついていることも覚えておいてほしい。 63 | 64 | readelfの-xオプションを使うと、そのセクションの中身のデータをみることができる。 65 | 66 | ```console 67 | $ readelf -x .rodata.str1.1 helloworld.o 68 | 69 | Hex dump of section '.rodata.str1.1': 70 | 0x00000000 48656c6c 6f2c2057 6f726c64 210a00 Hello, World!.. 71 | ``` 72 | 73 | ここで文字列Hello, World!は.rodata.str1.1にあることがわかった。 74 | .rodataは不変なデータを置くグローバルなデータ領域で、文字列はこのセクションに置かれる。 75 | 76 | ちなみに.commentセクションはclangの場合はコンパイルに利用したコンパイラの情報が含まれる。 77 | 78 | ```console 79 | $ readelf -x .comment helloworld.o 80 | 81 | Hex dump of section '.comment': 82 | 0x00000000 00636c61 6e672076 65727369 6f6e2031 .clang version 1 83 | 0x00000010 372e302e 36202868 74747073 3a2f2f67 7.0.6 (https://g 84 | 0x00000020 69746875 622e636f 6d2f6c6c 766d2f6c ithub.com/llvm/l 85 | 0x00000030 6c766d2d 70726f6a 65637420 36303039 lvm-project 6009 86 | 0x00000040 37303862 34333637 31373163 63646266 708b4367171ccdbf 87 | 0x00000050 34623539 30356362 36613830 33373533 4b5905cb6a803753 88 | 0x00000060 66653138 2900 fe18). 89 | ``` 90 | 91 | さて、ここまではリンク前のオブジェクトファイルでバイナリの中身をみてきたが、実行ファイルだとどうだろうか。 92 | 93 | ```console 94 | $ clang -o helloworld helloworld.c 95 | ``` 96 | 97 | 同様にreadelf -WSでセクション情報をみてみる。 98 | 99 | ```console 100 | $ readelf -WS helloworld 101 | (長いので割愛) 102 | [14] .text PROGBITS 0000000000001050 001050 000104 00 AX 0 0 16 103 | [15] .fini PROGBITS 0000000000001154 001154 00000d 00 AX 0 0 4 104 | [16] .rodata PROGBITS 0000000000002000 002000 000013 00 A 0 0 4 105 | [17] .eh_frame_hdr PROGBITS 0000000000002014 002014 00002c 00 A 0 0 4 106 | [18] .eh_frame PROGBITS 0000000000002040 002040 000094 00 A 0 0 8 107 | [19] .init_array INIT_ARRAY 0000000000003de8 002de8 000008 08 WA 0 0 8 108 | [20] .fini_array FINI_ARRAY 0000000000003df0 002df0 000008 08 WA 0 0 8 109 | [21] .dynamic DYNAMIC 0000000000003df8 002df8 0001e0 10 WA 6 0 8 110 | [22] .got PROGBITS 0000000000003fd8 002fd8 000028 08 WA 0 0 8 111 | [23] .got.plt PROGBITS 0000000000004000 003000 000020 08 WA 0 0 8 112 | [24] .data PROGBITS 0000000000004020 003020 000010 00 WA 0 0 8 113 | [25] .bss NOBITS 0000000000004030 003030 000008 00 WA 0 0 1 114 | ``` 115 | 116 | 上記で少しだけ触れたのだが、.rodata.str1.1はM(merge)フラグがついていた。これはそのセクションが他のものと結合されるかもしれないという意味を持つ。その結果、実行ファイル内の.rodataセクションにはすべての.rodata.*な情報がまとめられてしまった。 117 | 118 | ここで特定の文字列がどこに配置されているかを知りたい場合は、readelf -pを利用するとよい。 119 | 120 | ```console 121 | $ readelf -p .rodata helloworld 122 | 123 | String dump of section '.rodata': 124 | [ 4] Hello, World!\n 125 | ``` 126 | 127 | -pオプションは指定したセクションの文字列っぽいものを探索し(stringsコマンドのような動きをする)、それをみつけたときにオフセット情報とともに出力してくれる。 128 | 129 | 今回のプログラムの例では文字列Hello, World!は.rodataセクションの先頭からオフセット4の位置に配置されていることがわかる。 130 | 131 | ```console 132 | $ readelf -x .rodata helloworld 133 | 134 | Hex dump of section '.rodata': 135 | 0x00002000 01000200 48656c6c 6f2c2057 6f726c64 ....Hello, World 136 | 0x00002010 210a00 !.. 137 | ``` 138 | -------------------------------------------------------------------------------- /content/docs/執筆ガイド/_index.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: "Pasopedia:執筆ガイド" 3 | date: 2023-03-19T21:18:59+09:00 4 | type: docs 5 | --- 6 | 7 | この**執筆ガイド**では、Pasopediaの**ページの書き方**と**表記方法のルール**を説明します。 8 | 9 | ## PasopediaとGit 10 | Pasopediaのページとサイト全体のデータは[GitHub](https://github.com)上で[Git](https://ja.wikipedia.org/wiki/Git)というシステムに基づいて管理されており、執筆者はPasopediaのリポジトリに**Pull Request**を送ることによってページの編集・追加の反映を要請する必要があります。 11 | 12 | ## Hugoについて 13 | Pasopediaでは[Hugo](https://gohugo.io)という静的サイトジェネレータを使用しているため、全てのページは[Markdown](https://ja.wikipedia.org/wiki/Markdown)によって記述されます。 14 | 15 | ### ディレクトリ構造 16 | 各ページは`/content/pages/(ページ名)/_index.md`に、Pasopediaの使い方に関わる`Pasopedia:`名前空間のページは`/content/docs/(ページ名)/_index.md`に記述します。 17 | 18 | 以下にディレクトリ構造の例を示します。 19 | 20 | ```plain 21 | pasokonistan/pasopedia 22 | └─content 23 | ├─docs 24 | │ └─執筆ガイド 25 | │ └─_index.md 26 | └─pages 27 | └─パソコニスタン 28 | └─_index.md 29 | ``` 30 | 31 | ### フロントマター 32 | **フロントマター**はMarkdownファイルに文書のタイトルや著者名を記述できるHugo独自の記法です。`hugo new ~.md`コマンドを実行するとテンプレートに基づいてフロントマターが記述済みのMarkdownファイルが生成されますので、ページのタイトルを記入してください。 33 | 34 | 以下にフロントマターの例を示します。 35 | 36 | ```markdown 37 | --- 38 | title: "Pasopedia:執筆ガイド" 39 | date: 1970-01-01T00:00:00+00:00 40 | type: docs 41 | --- 42 | ``` 43 | 44 | ### Shortcode 45 | また、Hugoのテーマには[Hugo Book](https://github.com/alex-shpak/hugo-book)を使用しているため、Markdownに加えて**Shortcode**と呼ばれるテーマ独自の記法を使ったリッチな表現も可能です。 46 | 47 | 以下に利用可能なショートコードとその例を示します。 48 | 49 | - Hint 50 | **Hint**ショートコードを使うことで強調したい情報や注意事項をブロック表示できます。 51 | 52 | ```tpl 53 | {{}} 54 | **日本国憲法 第三章 第十一条** 55 | 国民は、すべての基本的人権の享有を妨げられない。 56 | この憲法が国民に保障する基本的人権は、侵すことのできない永久の権利として、現在及び将来の国民に与へられる。 57 | {{}} 58 | ``` 59 | 60 | 実際の表示はこのようになります。 61 | 62 | {{< hint info >}} 63 | **日本国憲法 第三章 第十一条** 64 | 国民は、すべての基本的人権の享有を妨げられない。 65 | この憲法が国民に保障する基本的人権は、侵すことのできない永久の権利として、現在及び将来の国民に与へられる。 66 | {{< / hint >}} 67 | 68 | {{< hint warning >}} 69 | **日本国憲法 第三章 第十一条** 70 | 国民は、すべての基本的人権の享有を妨げられない。 71 | この憲法が国民に保障する基本的人権は、侵すことのできない永久の権利として、現在及び将来の国民に与へられる。 72 | {{< / hint >}} 73 | 74 | {{< hint danger >}} 75 | **日本国憲法 第三章 第十一条** 76 | 国民は、すべての基本的人権の享有を妨げられない。 77 | この憲法が国民に保障する基本的人権は、侵すことのできない永久の権利として、現在及び将来の国民に与へられる。 78 | {{< /hint >}} 79 | 80 | - Tab 81 | **Tab**ショートコードを使うことで複数の情報を無駄なく表示できます。 82 | 83 | ```tpl 84 | {{}} 85 | {{}} 86 | /* Go Example */ 87 | {{}} 88 | {{}} 89 | /* Python Example */ 90 | {{}} 91 | {{}} 92 | /* FORTRAN Example */ 93 | {{}} 94 | {{}} 95 | ``` 96 | 97 | 実際の表示はこのようになります。 98 | 99 | {{< tabs "helloWorldExamples" >}} 100 | {{< tab "Go" >}} 101 | ```go 102 | package main 103 | 104 | import "fmt" 105 | 106 | func main() { 107 | fmt.Println("Hello world") 108 | } 109 | ``` 110 | {{< /tab >}} 111 | {{< tab "Python" >}} 112 | ```python 113 | print("Hello world") 114 | ``` 115 | {{< /tab>}} 116 | {{< tab "FORTRAN">}} 117 | ```fortran 118 | program helloworld 119 | print *, "Hello world." 120 | end program helloworld 121 | ``` 122 | {{< /tab >}} 123 | {{< /tabs >}} 124 | 125 | - KaTeX 126 | **KaTeX**ショートコードを使うことで数式の組版ができます。 127 | 128 | ```latex 129 | {{}} 130 | f(x) = \int_{-\infty}^\infty\hat f(\xi)\,e^{2 \pi i \xi x}\,d\xi 131 | {{}} 132 | ``` 133 | 134 | 実際の表示はこのようになります。 135 | 136 | {{< katex display >}} 137 | f(x) = \int_{-\infty}^\infty\hat f(\xi)\,e^{2 \pi i \xi x}\,d\xi 138 | {{< /katex >}} 139 | 140 | これらの他にもHugo Bookは**Column**や**Expand**などのショートコードを備えていますが、可読性を保つためにも上記の3つ以外のショートコードを使用することは避けてください。 141 | 142 | ## 表記ガイド(.pasopediarc) 143 | 144 | ### 見出しのレベル 145 | - Pasopediaではページのタイトルがページ先頭に`h1`要素として埋め込まれるため、本文中の見出しにはレベル2(`## Headline`)以下の見出しのみを使ってください。 146 | - またレベル4(`#### Headline`)以下の見出しを使うことは極力避けて、代わりに箇条書き(`- item`)を使ってください。 147 | 148 | ### 改行 149 | - Markdownでは任意の箇所に半角スペースを2つ挿入することでHTMLの`
`要素を使った行内改行ができますが、箇条書きや引用の直後のような改行しないと表示が崩れてしまう場合を除いて段落内では改行しないでください。 150 | - 段落をあらためる場合は改行キーを2回押して、HTMLの`

`要素単位で区切ってください。 151 | 152 | ### 句読点 153 | - 原則として和文中の句読点は`、`と`。`を、欧文中の句読点は`,`と`.`を使います。もちろん、引用した文に含まれる句読点についてはこの限りではありません。 154 | - リーダーは`……`と**3点リーダーを2つ重ねたもの**を使い、`。。。`や`、、、`としないでください。 155 | 156 | ### 約物と数字 157 | - 括弧やクエスチョンマーク、コロンなどの約物は**和文中であれば全角、欧文中であれば半角**とします。(例:× `"パソコニスタン"` → 〇 `「パソコニスタン」`) 158 | - 数字は**半角のアラビア数字**を使います。 159 | - 暦は`YYYY年MM月DD日hh時mm分ss秒(UTC+hh)`というフォーマットに従います。時刻は24時間制で表記し、数字のゼロ埋めは行いません。 160 | - たとえば、日本時間でのUNIXエポックを表すときは`1970年1月1日9時0分0秒(UTC+9)`と表記します。 161 | - 時刻とタイムゾーンは適宜省略してください。 162 | - なお、Markdownの強調表現は約物を含む文字列に対して適切に機能しないことがありますが、その場合は強調表現の直前にゼロ幅スペース(`​`)を挟むことで(やや不誠実ではあるものの)機能させることができます。 163 | 164 | ### 外来語 165 | - プロダクト名や人名など、固有名詞の外来語は原則公式の表記に従います。(例:× `ユニックス` → 〇 `UNIX`) 166 | - ただし、すでにカタカナで広く知られているものに関してはそちらを尊重してください。 167 | - カタカナ表記の末尾にある長音記号(`ー`)については、1991年の内閣告示「[外来語の表記](https://www.bunka.go.jp/kokugo_nihongo/sisaku/joho/joho/kijun/naikaku/gairai/honbun06.html)」に従い、原則として**省略しないものとします。**(例:× `サーバ` → 〇 `サーバー`) 168 | - ただし、長音を省略した形で広く知られているものに関してはそちらを尊重してください。 169 | - 媒体によっては和文中の英単語の前後に半角スペースを挿入して区切る場合がありますが、Pasopediaでは**これを行わないものとします。** 170 | 171 | ### その他 172 | - 実在の人物の名前を挙げるときは、存命であるかなどに関わらず必ず敬称を付けてください。敬称は「氏」で統一します。 173 | - ただし「○○博士」「○○卿」など、学位や爵位などが敬称として定着している場合はそちらを尊重してください。 174 | - `Pasopedia:`名前空間のページでは、敬称は適宜使い分けてください。 175 | - SNS上の人物の名前を挙げるときは`サービス名:@ユーザーID`というフォーマットのアンカー文字列を使います。 176 | - たとえば、パソコニスタンの管理者であるsksatさんの名前を挙げるときは「[pasokey:@sksat](https://pasokey.net/@sksat)氏」あるいは「[Twitter:@sksat](https://twitter.com/sksat_tty)氏」と表記します。 177 | - ページ内リンクは`#リンク先`というフォーマットに従います。 178 | - たとえば、この章に他の章からリンクするときは「[#その他](#その他)」と表記します。 179 | - ページ外リンクのアンカー文字列は**リンクの行き先を具体的に示すものにしてください。**(例: × `[こちら](https://go.dev)のサイトから……` → 〇 `[Go言語の公式サイト](https://go.dev)から……`) -------------------------------------------------------------------------------- /content/pages/pasokey-post-mortem-2024-04-18/_index.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: "2024年4月18日の pasokey インシデント" 3 | date: 2024-04-19T02:15:00+09:00 4 | type: docs 5 | --- 6 | 7 | 2024年4月18日(木)22:15(JST)より、[sksat](https://github.com/sksat) の運用する Kubernetes クラスタのひとつ(以後 "Kubernetes クラスタ")に障害が発生しました。 8 | 9 | これにより、パソコニスタンの主要サービスのひとつである [pasokey](https://pasokey.net) が 140分間利用できませんでした。 10 | 11 | ## 影響を受けたもの 12 | 13 | [sksat](https://github.com) が運用するいくつかのサービスは、今回障害が発生した Kuberenetes クラスタ上で運用されています。 14 | 15 | パソコニスタンに関係のあるものとしては、以下のサービスに影響がありました。 16 | 17 | - [pasokey](https://pasokey.net) 18 | - [misskey.sksat.run](https://misskey.sksat.run/): パソコニスタンとは直接の関連はありませんが、pasokey の staging 環境として運用されています 19 | 20 | ## タイムライン 21 | 22 | *参照されるタイムスタンプはすべて日本標準時(JST)です。* 23 | 24 | | 時間 | 説明 | 25 | | -------------------- | ------------------------------------------------------------ | 26 | | 2024-04-18 22:36 JST | インシデントを認知 | 27 | | 2024-04-18 22:38 JST | スマホのブラウザで開き、Cloudflare Tunnel の接続断ではない未知のインシデントであることを確認 | 28 | | 2024-04-18 23:10 JST | 油淋鶏定食を食べ終わる | 29 | | 2024-04-18 23:12 JST | 調査・復旧の優先順位を決める | 30 | | 2024-04-18 23:15 JST | pasokey だけでなく staging 環境でも同様のインシデントが発生していることを確認 | 31 | | 2024-04-18 23:16 JST | 不自由な計算機しか手元になく、VPN 経由での ArgoCD へのアクセスができないことに悪態を付く | 32 | | 2024-04-18 23:18 JST | Misskey CLI が一応開けたのでテスト投稿を試みる | 33 | | 2024-04-18 23:21 JST | スマホからでも Kubernetes Node に SSH できる可能性に思い至るが、適切な秘密鍵が手元に無いことに気付く | 34 | | 2024-04-18 23:25 JST | 自宅マシンへの任意コード実行によるエスカレーションを考えるが、インシデントの規模と帰宅時間から割に合わないなと思い直す | 35 | | 2024-04-18 23:36 JST | 帰宅 | 36 | | 2024-04-18 23:38 JST | 本格的なインシデント調査開始 | 37 | | 2024-04-18 23:39 JST | ArgoCD にアクセスできないことを確認 | 38 | | 2024-04-18 23:41 JST | Kubernetes コントロールプレーンノードの IP アドレスが変化していることに気付く | 39 | | 2024-04-18 23:44 JST | kubectl で pasokey の Misskey プロセスのログにエラーを確認 | 40 | | 2024-04-18 23:45 JST | kubectl で pasokey および staging 環境の cloudflred のログを確認 | 41 | | 2024-04-18 23:52 JST | 念のため Cloudflare の Dashboard から Cloudflare Tunnel が healthy であることを確認 | 42 | | 2024-04-18 23:54 JST | 念のため Cloudflare System Status が Operational であることを確認 | 43 | | 2024-04-18 23:56 JST | 他の fediverse インスタンスから状況を確認 | 44 | | 2024-04-18 23:58 JST | Kubernetes コントロールプレーンノードの IP アドレス再固定を試みるが、LAN への再接続に失敗し、SSH 不能になる | 45 | | 2024-04-19 00:02 JST | キーボードとモニタを引っ張り出して Kubernetes コントロールプレーンに接続 | 46 | | 2024-04-19 00:05 JST | Kubernetes コントロールプレーンにて `Too many open files` エラーを確認 | 47 | | 2024-04-19 00:09 JST | ファイルディスクリプタ数上限を再設定し、Kubernetes コントロールプレーンノードを LAN に再接続 | 48 | | 2024-04-19 00:10 JST | ArgoCD の復旧を確認 | 49 | | 2024-04-19 00:13 JST | Kubernetes クラスタの一部プロセスがサービスに関わらず CrashLoopBackOff していることを確認 | 50 | | 2024-04-19 00:16 JST | Kubernetes コントロールプレーンノードの再起動を試みる | 51 | | 2024-04-19 00:18 JST | Kubernetes コントロールプレーンノードを強制再起動 | 52 | | 2024-04-19 00:21 JST | `FS-Cache Duplicate cookie detected`エラーを確認 | 53 | | 2024-04-19 00:21 JST | ArgoCD にアクセスできず、NFS の CSI Driver の pod が CrashLoopBackOff していることを確認 | 54 | | 2024-04-19 00:25 JST | NFS ファイルサーバの応答が無いことを確認 | 55 | | 2024-04-19 00:31 JST | また苦労して NFS ファイルサーバにモニタとキーボードを接続するが、まったく反応が無いことを確認し、強制再起動 | 56 | | 2024-04-19 00:33 JST | ArgoCD の復旧を確認 | 57 | | 2024-04-19 00:34 JST | pasokey の復旧を確認 | 58 | 59 | ## 分析 60 | 61 | 現在、各種ログを精査しています。 62 | 63 | 今のところ、NFS ファイルサーバに 2024-04-18 22:15:01 JST~2024-04-18 22:15:40 JST の間にハングを起こす事象があったことが明らかになっています。 64 | 65 | ## 教訓と改善策 66 | 67 | 今回のインシデントは、[pasokey](https://pasokey.net) にとって運用開始から最大規模となる2時間以上の障害を発生させました。趣味で運用しているので SLA などは一切設定しておらず、意図的なメンテナンスで長期間のサービスダウンやデータロストが発生する可能性は常日頃からあるものの、意図しないタイミングでの障害は非常にムカつきます。可能な限りインシデントの発生を抑制し、発生したとしてもインシデントレスポンスを学ぶためのダシとして最大限活用しなければなりません。 68 | 69 | 直接の原因となった NFS ファイルサーバのハングと Kubernetes ノードのファイルディスクリプタ数上限については、より詳細な調査が必要です。しかし、今回のインシデントから学び、これからやるべきことは他にもたくさんあります。 70 | 71 | ### pasokey が Misskey として動作していることまで含めた外形監視 72 | 73 | 現在、pasokey は [README](https://github.com/pasokonistan/pasokey.net) にもあるように、[Better Stack](https://pasokonistan.betteruptime.com/) と [Uptime Robot](https://stats.uptimerobot.com/QLk7XC6Kxv/793928285) による外形監視を行っています。これらは手軽な監視には非常に便利なツールであり、実際にこれまでの pasokey の障害としてよくある Cloudflare Tunnel の接続断の検知にはとても役立ってきました。しかし、今回の障害のように、Misskey がサーバとしては動作しており、Cloudflare Tunnel の接続も問題は無いものの内部的な問題が発生しているようなケースにおいては、必ずしも適切な監視たりえません。これにより、今回の障害を認知するまでに時間がかかりました。そこで、Misskey という実際のサービスのドメインまで含めた正常性確認を伴う外形監視を考えています。 74 | 75 | ### NFS ファイルサーバの監視とアラート 76 | 77 | 今回のインシデントにおいて、調査開始からサービス復旧までに時間がかかった最大の要因は、NFS ファイルサーバのハングという主要因の認識が遅れたことです。NFS ファイルサーバの監視が適切に行われ、アラートが上がっていれば、調査・復旧作業の優先順位をもっと適切に設定できたでしょう。 78 | 79 | また、この監視系は Kubernetes クラスタ本体とは別個に構築する必要があることに注意が必要です。船が沈んでいることを水の中から喚いてもその声は届きません。このような問題に対処するため、物理的にも論理的にも別の場所で動作するプラットフォームが求められています。幸いにしてようやくこのためのプラットフォームはつい先日(1年以上に渡る地団太を踏んだ後)構築を順次開始しているため、まあなんとかなるでしょう。 80 | 81 | ### 各サーバへの物理的アクセス 82 | 83 | 今回のインシデント対応では、各サーバに対するネットワークアクセスが失われるなど、ブラウザと SSH だけでは完結しない対応が必要になる場面がしばしば存在しました。しかし、これらのサーバは sksat の自宅のメタルラック内に乱雑かつ多数配置されており、適切なコンソールや画面出力への物理的アクセスは至難の技となっています。このような問題を解決するため、[PiKVM](https://pikvm.org/) の導入によるコンソール・画面出力のネットワーク化や、メタルラック内のサーバ・ケーブリングの再配置を検討しています。 84 | 85 | ### ログ基盤 86 | 87 | 今回のインシデント対応および事後調査では、各サーバやプロセスのログを横断的に調査しました。これらの調査にあたって、そもそも適切な範囲のログを抜き出すためにスクリプトを書いたり、どこに適切なログファイルがあるかを調べ直したりする時間はよい経験にはなったもののあまり必要な時間であったとは言い難いです。そのため、あらゆるログを収集し検索可能にするログ基盤が求められています。また、このログ基盤についても、監視系と同様本体の Kubernetes クラスタとは別の場所で運用すべきでしょう。 88 | 89 | ## まとめ 90 | 91 | このようなインシデントを起こしてしまったことに別に深くお詫びしたりはしないのですが、status monitor の緑色が減り、睡眠時間が減ったことを悔しく思っております。正直 pasokey の運用をそこまでちゃんとする理由があるわけではないのですが、趣味で運用するサービスのインフラストラクチャをオーバーエンジニアリングすることに非常に関心があり、耐障害性は中でも面白さのあるトピックです。 92 | 93 | フォローアップすべきというわけでもないけれど結構したいことはたくさんあり、やるべきことの合間や特にそうでない時にちまちまと取り組んでいます。 94 | -------------------------------------------------------------------------------- /content/pages/インラインアセンブラtips集/_index.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: "インラインアセンブラtips集" 3 | date: 2023-09-22T05:11:29+09:00 4 | type: docs 5 | --- 6 | 7 | ## 本記事で対象とする環境 8 | 9 | 本記事では以下の環境のインラインアセンブラに関するtipsについて記載する。 10 | 11 | - コンパイラ:gcc 11.4.0 以降 12 | - アーキテクチャ:x86-64 13 | 14 | なお、インラインアセンブラの基本について解説は行わない。 15 | 16 | ## Intel syntaxで記述したい 17 | 18 | gccはデフォルトではAT&T syntaxで記載されたインラインアセンブリをコンパイルすることができる。 19 | しかしIntel syntaxで記載したいときもある。 20 | 21 | その際は、コンパイルオプションに `-masm=intel` を追加すると、Intel syntaxで記載されたインラインアセンブリをコンパイルできる。 22 | 23 | また、一部分だけIntel syntaxで記載したい場合は、コンパイルオプションではなく、インラインアセンブリ中に `.intel_syntax noprefix` を記載することで適用することができる。 24 | `.att_syntax` を記載すれば、AT&T syntaxに戻すこともできる。 25 | 26 | ```c 27 | #include 28 | 29 | int main(void) { 30 | int a = 1, b; 31 | asm ( 32 | ".intel_syntax noprefix\n" 33 | "mov %0, %1\n" 34 | "add %0, 1\n" 35 | ".att_syntax\n" 36 | "add $1, %0\n" 37 | : "=r" (b) 38 | : "r" (a) 39 | ); 40 | 41 | printf ("%d\n", b); 42 | } 43 | ``` 44 | 45 | 上記の例では `3` が出力される。 46 | 47 | ## レジスタに値を割り付けたい 48 | 49 | インラインアセンブラでは、レジスタを指定して値を割り付けることができる。 50 | 例えば以下の例がある。 51 | 52 | ```c 53 | uint64_t inline_asm_syscall( 54 | uint64_t syscall_no, 55 | uint64_t arg1, 56 | uint64_t arg2, 57 | uint64_t arg3, 58 | uint64_t arg4, 59 | uint64_t arg5, 60 | uint64_t arg6, 61 | ) { 62 | uint64_t ret; 63 | 64 | register uint64_t arg4_r10 asm("r10") = arg4; 65 | register uint64_t arg5_r8 asm("r8") = arg5; 66 | register uint64_t arg6_r9 asm("r9") = arg6; 67 | asm ( 68 | "syscall" 69 | : "=a" (ret) 70 | : "a" (syscall_no), 71 | "D" (arg1), "S" (arg2), "d" (arg3), 72 | "r" (arg4_r10), "r" (arg5_r8), "r" (arg6_9) 73 | : "memory", "rcx", "r11" 74 | ); 75 | 76 | return ret; 77 | } 78 | ``` 79 | 80 | 上記の例は `syscall` 命令を発行するインラインアセンブリである。 81 | 82 | - `rax` に `syscall_no` 83 | - `rdi` に `arg1` 84 | - `rsi` に `arg2` 85 | - `rdx` に `arg3` 86 | - `r10` に `arg4` 87 | - `r8` に `arg5` 88 | - `r9` に `arg6` 89 | 90 | を割り当て、 `syscall` 命令を発行し、返り値を `rax` 経由で `ret` に格納している。 91 | 92 | インラインアセンブラでは入力オペランドと出力オペランドでレジスタに値を割り付けることが可能だが、具体的にどのレジスタにどの値を割り付けたいといったことも指定可能である。 93 | 94 | 以下に表を記す。 95 | 96 | | レジスタ名 | オペランド上の表記 | 97 | | ---------- | ------------------ | 98 | | rax | a | 99 | | rbx | b | 100 | | rcx | c | 101 | | rdx | d | 102 | | rsi | S | 103 | | rdi | D | 104 | 105 | このように、x86が32bitだった時代から存在するレジスタには、表記方法が存在する。 106 | 107 | x86-64になってからは、 `r8` から `r15` までのレジスタが増えた。 108 | これらのレジスタは上記のような表記方法が存在しないため、次のようにレジスタを割り当てる。 109 | 110 | ```c 111 | register uint64_t arg4_r10 asm("r10") = arg4; 112 | register uint64_t arg5_r8 asm("r8") = arg5; 113 | register uint64_t arg6_r9 asm("r9") = arg6; 114 | ``` 115 | 116 | 上記の例は、 `register` を用いて `r10` `r8` `r9` レジスタに値を割り当てる表記である。 117 | これらは次のように用いる。 118 | 119 | ```c 120 | asm ( 121 | "syscall" 122 | : "=a" (ret) 123 | : "a" (syscall_no), 124 | "D" (arg1), "S" (arg2), "d" (arg3), 125 | "r" (arg4_r10), "r" (arg5_r8), "r" (arg6_9) 126 | : "memory", "rcx", "r11" 127 | ); 128 | ``` 129 | 130 | 上記のように、 `register` の文で割り当てた名前を用いて、 `"r"` で指定する。 131 | すると、 `syscall` 命令が呼ばれる際に、 `r10` `r8` `r9` に値が割り当てられる。 132 | 133 | また、破壊されるレジスタの記載に関しては、そのままレジスタの名前が使える。 134 | 今回の場合は `rcx` `r11` である。 135 | 136 | ## インラインアセンブラだけの関数で、プロローグとエピローグを抑制したい 137 | 138 | 組み込みなどの特殊環境下では、関数プロローグとエピローグを省略して、インラインアセンブラのみで構成された関数を使いたいといったこともある。 139 | そのような際は、 `__attribute__((naked))` を用いると良い。 140 | 以下が例である。 141 | 142 | ```c 143 | #include 144 | 145 | __attribute__((naked)) 146 | void f(void) { 147 | asm volatile("nop"); 148 | } 149 | 150 | int main(void) { 151 | f(); 152 | printf("hello\n"); 153 | return 0; 154 | } 155 | ``` 156 | 157 | 上記のように、関数に `__attribute__((naked))` でnaked属性を指定すると、関数プロローグが省略される。 158 | `objdump -d` すると、次のような逆アセンブルが確認できる。 159 | 160 | ``` 161 | 0000000000001149 : 162 | 1149: f3 0f 1e fa endbr64 163 | 114d: 90 nop 164 | 114e: 90 nop 165 | 114f: 0f 0b ud2 166 | 167 | 0000000000001151

: 168 | 1151: f3 0f 1e fa endbr64 169 | 1155: 55 push %rbp 170 | 1156: 48 89 e5 mov %rsp,%rbp 171 | 1159: e8 eb ff ff ff call 1149 172 | 115e: 48 8d 05 9f 0e 00 00 lea 0xe9f(%rip),%rax # 2004 <_IO_stdin_used+0x4> 173 | 1165: 48 89 c7 mov %rax,%rdi 174 | 1168: e8 e3 fe ff ff call 1050 175 | 116d: b8 00 00 00 00 mov $0x0,%eax 176 | 1172: 5d pop %rbp 177 | 1173: c3 ret 178 | ``` 179 | 180 | naked属性を指定した関数 `f()` のプロローグとエピローグが消えていることがわかる。 181 | 182 | なお、このプログラムは `f()` に突入した後、 `114f: 0f 0b ud2` でSegmentation faultする。 183 | 184 | ## 追記: `memory` clobberについて 185 | 186 | [レジスタに値を割り付けたい](#レジスタに値を割り付けたい) の節で登場した、 187 | 188 | ```c 189 | asm ( 190 | "some instruction" 191 | : 192 | : 193 | : "memory" 194 | ); 195 | ``` 196 | 197 | この `"memory"` の意味について。 198 | 199 | `memory` は、インラインアセンブラ内で、入出力に直接関係ないメモリへの読み書きが存在する場合にプログラマが記載しなければいけないキーワードである。 200 | `memory` キーワードをつけると、コンパイラは最適化の過程で `asm` 文をまたいだメモリ操作のリオーダリングを抑制する。 201 | 202 | 気を付けるポイントとしては、コンパイラ内部で行う最適化の過程での話なので、プロセッサレベルではリオーダリングが起きる可能性がある。 203 | そのため、プロセッサレベルでメモリ操作のリオーダリングを抑制する場合はfence命令を用いる必要がある。 204 | 205 | ### LLVMにおける `memory` clobberの状況(@kubo39さんからの情報) 206 | 207 | [@kubo39](https://github.com/kubo39) さんが教えてくれたのだが、LLVMのインラインアセンブラでは、 `memory` clobberを無視するらしい。 208 | 実際に教えてもらった [LLVMのコード](https://github.com/llvm/llvm-project/blob/a134abf4be132cfff2fc5132d6226db919c0865b/llvm/lib/CodeGen/GlobalISel/InlineAsmLowering.cpp#L524-L537) を見ると、clobberの部分はレジスタ制約しか見ていない(っぽい)ことがわかる。 209 | 210 | ```cpp 211 | case InlineAsm::isClobber: { 212 | 213 | const unsigned NumRegs = OpInfo.Regs.size(); 214 | if (NumRegs > 0) { 215 | unsigned Flag = InlineAsm::Flag(InlineAsm::Kind::Clobber, NumRegs); 216 | Inst.addImm(Flag); 217 | 218 | for (Register Reg : OpInfo.Regs) { 219 | Inst.addReg(Reg, RegState::Define | RegState::EarlyClobber | 220 | getImplRegState(Reg.isPhysical())); 221 | } 222 | } 223 | break; 224 | } 225 | ``` 226 | 227 | どうやら、LLVMインラインアセンブラはmemory operandを介したメモリアクセスについて記述できるが、memory clobberのような入出力に関係ないメモリアクセスを表現できないようである。 228 | ただし、LLVMのインラインアセンブラは内部的に関数相当の実装をしており、かつ関数属性はデフォルトでメモリ読み書きが起きるという仮定があるのでmemory clobberがない場合でも問題になっていない。 229 | 逆に関数属性として読み込みも書き込みもない・読み込みがあるが書き込みがないといった場合は属性を付与する必要がある。 230 | ちなみにRustだと、[`nomem` 属性をつけることでこれを解除する](https://doc.rust-lang.org/reference/inline-assembly.html#options) ようである。 231 | 232 | > nomem: The asm! blocks does not read or write to any memory. This allows the compiler to cache the values of modified global variables in registers across the asm! block since it knows that they are not read or written to by the asm!. The compiler also assumes that this asm! block does not perform any kind of synchronization with other threads, e.g. via fences. 233 | 234 | `nomem` 属性の実装部分の [Rustコンパイラのコード](https://github.com/rust-lang/rust/blob/558ac1cfb7c214d06ca471885a57caa6c8301bae/compiler/rustc_codegen_llvm/src/asm.rs#L268-L273) を確認すると、ここでもLLVMに無視される旨が書かれている。 235 | 236 | ```rust 237 | if !options.contains(InlineAsmOptions::NOMEM) { 238 | // This is actually ignored by LLVM, but it's probably best to keep 239 | // it just in case. LLVM instead uses the ReadOnly/ReadNone 240 | // attributes on the call instruction to optimize. 241 | constraints.push("~{memory}".to_string()); 242 | } 243 | ``` 244 | 245 | ちなみにこの辺の話は [pasopediaのissue](https://github.com/pasokonistan/pasopedia/issues/17) に寄せられた情報ほぼそのままである、詳しい人はそちらを読んだ方がいいかもしれない。 246 | 247 | ### 参考リンク 248 | 249 | - [Extended Asm (Using the GNU Compiler Collection (GCC))](https://gcc.gnu.org/onlinedocs/gcc/Extended-Asm.html#Clobbers-and-Scratch-Registers-1) 250 | --------------------------------------------------------------------------------