セキュリティキャンプ2023 参加記(講師)

ドッタンバッタン大騒ぎして結局今までろくにまとめられなかったセキュリティキャンプの参加記。
感想も交えて詳しく書けたらいいなと思っています。

セキュリティキャンプ2017参加記

今年もやってきました、あの夏、と言いたいところですが今年は待ちに待った4年ぶりのオフライン開催です。今回は幸運にも講師として参加させていただくことができました。(責任重大)
毎回のごとく、参加記録をまとめたいと思います。
これまでの記録
セキュリティキャンプ2017参加記
セキュリティキャンプ2019参加記(チューター)
セキュリティ・ネクストキャンプ2020参加記(チューター)

朝から適当な食事をすまし、体調を壊しました。アホです。

1日目

京王八王子から分倍河原、分倍河原から徒歩という恐らく誰も移動しないルートできました。

講師控え室に移動してから昼ご飯になりました。

相変わらず、おいしいご飯で体調は一気に良くなりした。
ご飯を食べた後は、受講生の方は名詞交換会をしていました。
13:00から開講式がありました。
相変わらず、有り難いお話ばかりで、受講生の方はとても心に響いたと思います。

開講式の後はLT大会、グループワークがありました。

グループワークの後は夕食と、スイーツ食べながら名刺交換会がありました。
おいしい夕食をモグモグ食べているとスイーツ食べる時間が無くなって、名詞交換せずにモグモグ食べていました、いいのかそれで…

交流会用のスイーツ

お部屋は相変わらずいい部屋でした。

スイーツを食べた後は、早速皆さんでOS開発を取り組みました。1時間半もあったのですが、あっという間に終了。
初日から疲れて23:00に就寝

2日目

朝一番乗り、またも確保しました。
チュータ時にやらかした経験を踏まえ、カーテンを開けて寝るようにしたら日の出と共に目が覚めてしまいました。
ご飯を食べたら早速講義開始です。

講義開始前

皆さん真剣に開発されており、有能なチュータさんのパワーも借りながらデバッグをしていきます。
他の講義の受講生の皆さんがたまに覗きに来られて、活発に名刺交換会が行われていました。
あっという間にお昼ご飯です。

昼ごはん後、もくもくと開発をしていると、あっという間に夜御飯です。
夜御飯はすごい中華でした。

ご飯の後は、企業説明の時間です。
セキュリティキャンプに協賛して下さっている企業のお話です。
ガチガチの企業説明ではなく、会社で実際に対応した内応などを説明されているところが多く、受講生の方は楽しく聞けたと思います。
私も大学院生なのでひっそりと聞いてました。
一番びっくりしたのは、2017年に受講生と一緒に参加した方が協賛企業枠で参加されていて、久しぶりの再会があったことです。

最後の8:30から9:00のホームルームでは、同じくOS自作ゼミの講師のhikalium先生が、講師である私をチュータと間違えまくるので、OS自作ゼミのチュータである1010さんと、名刺ストラップ(講師は緑色、チュータは橙色)と無線機(チュータと一部の講師が持っている)を交換するなどのコスプレをしてました。
他の受講生・チュータの皆様曰く、似合っているらしい、どうして…

そんなわけで2日目もあっという間に終わりました。

3日目

今日は社会見学ですが講師は(一部を除いて)付いていくことが出来ません。大人しく待機です。
IPAの設備を観ることができるらしく、2017年参加時には見たことがないのでとても羨ましいです。
受講生がいない間に洗濯を行います。

B1Fの洗濯機

洗濯の間は、同じ講師の方や協賛企業の方と近況報告を行いました。

その後、持ってきていたTinker Board2というシングルボードコンピュータを維持ろうと思ってたのですが、開発環境が置いてある自宅サーバにつながらなくなるしTinker Board2は起動しなくなるし、さんざんでした…(Tinker Board2は復活した。)

受講生の皆さんが社会見学から戻ってこられる前に講師陣は昼食を食べます。
ラーメン、美味しかったです。

ご飯を食べて待っていると、受講生の方が戻ってこられて早速開発に取り組まれておりました。
頭をフル回転させてできる限りのサポートをしているとあっという間に夕食です。

夜ご飯の後も皆さんすぐに開発に戻り、もくもくと作業されていました。
皆さんの熱意を見ると、なんだか受講生だったころを思い出して懐かしくなりました。

途中、他のコースやNOCの見学に行き、それぞれのコースもとても濃い内容の開発を行われている事を目の当たりにしました。

そんなこんなであっという間に9時、開発終了です。
因みに今日は講師兼チュータという謎の役職がつきました、このネタ気に入ってきました。

4日目

前日寝付きが悪かったですが、またも一番乗りを獲得しました。

開発最終日ということもあり、開発コース受講生の皆さんには目標を達成するために熱が入ります。
皆さん真剣にデバッグを行い、こちらもアップアップになりながら対応します。自分にもっとデバッグ能力があればすっと解決できたのになぁと思いつつネットワークの設定がうまくいかなかったり、元からあるprintfの実装がいい加減なのに気付くのが遅れたり、様々なバグがありました。
そんなこんなであっという間に昼食です。

開発コースの方は急いで食事を終わらせて、開発に戻られている方も多かったです。
開発に熱がこもり熱中しちゃう気持ち、受講生のころを思い出して懐かしく思います。
ラストスパートの開発を終え、「こんな状態じゃ終われない、今日の夜は寝ずにデバッグだぁ」とおっしゃっていた方も多かったです。夜遅くまでやりすぎて寝過ごさないようにね…(思い出すチュータのトラウマ)。
16:00からYトラック内で成果発表会を行いました。皆さん、自分がセキュリティキャンプで実現した事を活き活きと語り、とても輝いていました。
成果発表会の後は、夕食です。

夕飯の後は、LT発表会です。自分も少し発表しましたが、皆さん個性的な発表でとても楽しめました。
LT大会の後はグループワークです。
グループワークでは、それぞれの目的を達成するためにどうするべきかチームで熱心に取り組んでいました。グループワークではなりたての講師なのに色々アドバイスを求められて上機嫌で答えてしまいました、恥ずかしい…
グループワークの後は30分のホームルームで見学に来られる方がいらっしゃいました。
皆さん、OS自作について興味深々で是非ともOS自作をやってほしいと布教しました。
そんなこんなで4日目もあっという間に終了です。
…と思ったら名刺交換会が自然発生し、皆さんの熱気で気温が上がるくらい密集した名刺交換が1時間近く行われました。11:00におやすみです。

5日目

最後の朝食です。6:20に行ったのに4番乗りでした。みんな早い。

ご飯の後は、グループワークです。前半のほうは講義部屋の撤収作業をしていたので聞けなかったですが、後半から聞いても皆さん継続的にセキュリティに取り組もうという心持ちが見られてとても温かい気持ちになりました。セキュリティキャンプの繋がりはのちの人生で役に立つので是非大切にしてもらいたいです。
グループワーク後は急いで移動して集合写真を撮影します。
全国大会・ネクストキャンプ・ジュニアキャンプ・ALLの受講生のみ、講師込みでつぎつぎに写真を取っていきます。皆さんいい笑顔でセキュリティキャンプを楽しめた事がわかります。

撮影後は専門コースの成果発表です。
受講生時代から専門コースとの関わりは薄かったので、毎回新鮮な気持ちで聞いてます。

AクラスはIoTセキュリティコースで、セキュリティがおろそかになりがちなC言語などのプログラミングでいかにセキュリティを担保するかを病院や車載ネットワークを例に検証したそうです。
IoT機器には脆弱性が残っているとのことで、それが社会に与える影響がいかに大きいかを実感しました。ファイルが削除されてもFAT32などでは単に削除マークがついているだけで復元ができるなどOS自作と馴染み深い話もありました。

Bクラスは、Webセキュリティクラスで広さと深さをどちらも追求した講義をされているそうです。
仮想的な企業を立ち上げてその会社になりすましメールを送って権限を得ようとする試みをやって、Webでどのようにセキュリティを担保するか講義とハンズオン両方で理解を深めたそうです。

Cクラスでは、Linux Kernelのエクスプロイトや脅威度の数値化などをローレイヤーミドルレイヤーの解析をウイルスの検知をされていたそうです。オンラインの時期に参加された方が発表されてましたが、毎年講義の内容が変わっており一筋縄ではうまくいかなかったと笑顔で話していました。デジタルフォレンジックなどは攻撃者がいかにシステムに侵入したかを調べる上で幅広いレイヤーの知識が必要だというのが発表者の知識から感じました。

Dクラスでは、ハードウェア・ソフトェアと法律・倫理という二つの観点からAIとセキュリティについて勉強したそうです。近年急速に発達する生成系AIをどう扱うかを議論したり、画像にノイズを加えてAIの判定を間違えさせるという技術よりの話までAIを隅から隅まで研究しておりこれからの時代を生きるのに重要な事を学ばれているな感じました。AIでもAttack And Defenceをされており情報セキュリティはどこの分野にも存在するということを実感しました。中にはPythonを分からない中でAIをいじるためにPythonを勉強した方がいらっしゃって受講生の皆さんの熱意を感じました。セキュリティキャンプを通じてより精力的に取り組もうと言う気持ちになるのはとても良いことだと思います。

ジュニアキャンプでは、自分たちの作りたいアプリをセキュアに作るというプロジェクトを開発していました。自分が中学生の頃にはとても難しくて利用できなかったPHPフレームワークやNode.JSなどを使われていて最近の中学生の凄さに感心しました。しかもその上にしっかりとセキュリティを意識した設計になっており、脱帽モノでした。

ネクストキャンプでは、世界でユニークな事を専門とする講師陣による濃い講義が行われたようです。GPUを低レイヤーの観点から一からプログラムを設計し、高速なプログラムを設計したそうです。GPUのSIMDの最適化は私も勉強途中なので是非受けてみたいものです。GPUの次はCPUを作り上げるという講義で機械語を作る作業などは低レイヤーをやっている身としては共感できました。テスト駆動開発やモブプログラミングなど普段1人で開発しているときは経験しにくい開発スタイルについて学べた様でより柔軟な考え方ができるようになったと思います。

午前中の成果発表はこれで終わりで、セキュリティキャンプ最後の食事が始まります。

午後からは、我々開発コースの成果発表です。
トップバッターはOS自作ゼミです。NICドライバを書かれていた受講生の方が発表されてました。自作OSのデモもやって大盛況で終わりとても大盛り上がりでした。
CPU自作ゼミの方もRISC-Vのカスタム命令を実装し、ユニークな実装をしていました。
分散合意ゼミではRaftという分散合意アルゴリズムの実装されていました。分散合意はコードレベルでは非同期処理で、その中で同期処理を行うのでとても難しいのだと感じました。
CPU+コンパイラ自作ゼミでは、CPUとコンパイラを並行して作るというなかなかハードな事をされていました。Cコンパイラで吐き出したコードをCPUで実行し、結果を得られるのはとても楽しいだろうなと思いました。

次はXトラックでIoT機器の分解・改造をやっているようです。
リバースエンジニアリングゼミでは、デバイスを解体して、基板の読み込みをしたりファームウェアを解析してました、毎年熱い講義です。
電子回路・プリント基板を作ろうゼミでは、JTAG Debuggerを作るというハードウェア自作を行うゼミでした。お米より小さな部品を基板に配置する作業など、はたから聞いているととても難しそうに聞こえます。
ハードウェア魔改造ゼミは恒例の走るルータです。ハードウェアからソフトウェアまで全て弄るのは夢があり自分も一度やってみたいものです。今回は加速度センサを使って制御していて利便性(?)も上がっていました。
無線通信ハッキングゼミでは電波法令に気をつけながら電波を攪乱するジャミング攻撃をしたり、未知の信号波を解析してどういうプロトコルなのかを検証していました。

Zトラックでは、様々な講義が開講されています。
Rust製Linux向けアンチウィルス実装ゼミでは、マルウェアを解析するために実行してログを取得し、解析するコードを作成していました。挙動が正しいか怪しいかを区別する作業に苦心しているようでした。
アイデアを形にするWindowsアンチウイルス実装ゼミでは、Windowsの仕組みを受講生自身が試行錯誤して理解していたそうです。Windows APIは難しいイメージが多く、前のトラックと同じく正常な動作か怪しい挙動かを判定するのに苦労しているようでした。
EDR強化ゼミでは実際にWIndowsPCに攻撃してもらい、それを検知して分析して対応する講義をされていたそうです。検知にはシグマルールというものを作成し、それが上手く動いた時の爽快感が良かったそうです。
ブロックチェーンゲームを作って学ぶWebセキュリティゼミでは、Ethereum VMなどを用いてゲームを作り、ゲームにクリアできたらトークンや、報酬をゲットできるものらしいです。ゲームを作りながらそれをブロックチェーンに結びつけるという作業はとても大変だったらしく、受講生の方はさぞかし熱中できたでしょう。
OSINTによるランサムウェア攻撃者の攻撃戦術特定ゼミでは、検知ルールを用いてどんな製品が狙われたかを検知する講義をされているようです。

Lトラックは暗号系の講義が開講されています。
暗号化通信ゼミでは、学校のネットワークなどSSHなどを通さないネットワークのVPNをTLSでトンネリングするソフトウェアを作成されていました。また、既に破られた暗号を自分の手で破っている方もいました。
暗号のままで計算しようゼミでは、準同型暗号を実際に計算してNAND計算ができる事を確認しているようでした。NANDができれば任意の計算ができます。高速化についても研究されたそうです。
Cコンパイラゼミでは、ゼロからCコンパイラをアセンブリで書くという熱意ある方がいらっしゃいました。残念ながら配列などは実装できなかったですが、アセンブリが分からない中でそこまで作り上げたのはすごいことだと思います。
分散型アプリケーション脆弱性解析ゼミでは、ブロックチェーンへの攻撃を解析する、というゼミのようです。攻撃を解析するためにEthereum VMを実装されており、コンパイラ脆弱性を解析されているとのことでした。
TEEの活用と攻撃実践ゼミでは、Intel SGXを使って信頼可能な実行環境を作るという低レイヤーゼミでした。SGXではEDLという独自の言語で記述しないといけない部分があり大変そうだなと思いました。実際に攻撃も実践しており、攻防どちらも経験しているようでした。

NOCからはNOCの概要と今回の通信の概要が説明されました。

短い休憩時間を挟んで閉講式が始まります。
閉講式ではIPAの方から自身の経験を踏まえた熱いエールを頂き、講師でも心に来ました。また修了証書と激励文の授与が行われていました。受講生代表の皆さんの一言スピーチは心に響きました。
あとはセキュリティキャンプのグループの紹介などがあり、終了宣言を以て終わりました。

感想

初めての講師ということで受講生の皆さんのサポートができるか不安でした。そのためチュータの経験を生かして受講生の皆さんがどういうバグでつまっているかを確認しながらデバッグ作業の補助をしました。受講生の方の中には私が経験したことあるバグで詰まる方がいらっしゃったり、私のやったことのない事をされており、何をしようとしているか理解するのに精一杯だったこともあります。Yコースの講師の方々からチュータと間違えられることも多かったですが、自分自身受講生の皆さんにはチュータみたいに扱ってもらえたらなと思っていたので割と良かったと思っています。終わってみて正直受講生の皆さんが満足できたか不安だったのですが、皆さんが楽しかったとおっしゃっていたので、こちらも嬉しくなりました。ですが、改めて自分の技術力の不足を感じました。これからも進捗を出さないとなと思いました。来年も講師ができるかわかりませんが、より受講生の皆さんをサポートできるようになって参加できたらなと思います。

3回とも違う身分での参加

Open Build System(OBS)で依存関係のソースのリポジトリを指定する

普段、サーバでNAXSIというWeb Application Firewallを使ってるので、せっかくだからディストリビューション開発もくもく会に参加したので、勢いでOBSにリポジトリを作ってみました。 作ったリポジトリがhttps://build.opensuse.org/package/show/home:Manami:nginx-modules/nginx-module-naxsiです。

この際に困ったのが、Nginxのバージョンです。Nginxには公式のリポジトリで提供されている安定版とOBSのServer:httpで提供されている最新版があって、Server:httpではNginxのいろいろなモジュールが公開されていることから、自分は後者を使っています。ところが、普通にSpecファイルでBuildRequiresを書くと安定版のNginxを使用されます。それだと実際にインストールしようとした時にバージョンが違うとコンフリクトを起こすので困ります。そこで、特定のリポジトリから提供されているパッケージを使用してほしいのですが設定にやや戸惑ったので記録しておきます。

まず、リポジトリのページに行き、”Repositories”に移動し、”You can configure individual flags for this package here. The repositories are inherited from the project (Repository Name)”の(Repository Name)のリンクをクリックします。
すると、以下の様に追加したターゲットのRepository pathsが表示されているので、各た0ゲットの”+”ボタンをクリックします。

そこで、リポジトリ名をいれるところがでるので、”server:http”とか”Virtualization”などいれます。Repositoryはターゲットのバージョンに合わせて選びます。

これで、Acceptを押せば、追加されるので、追加されたパスの横にある”↑”ボタンを押して優先度を上げてやれば完了です。

残念ながらプロジェクト毎の調整はできないみたいですが、OBSにはサブプロジェクトというものがあるそうです。(クロスディストロの方々に教えていただきました。)

“Your Home Project”をクリックして、”Overview”の欄にある”Subprojects”をクリックして、右側の”Actions on this page”にある、”Create subproject”をクリックして適宜作ってください。

あと、先にビルドしちゃうとこの変更に伴う再ビルドはされないみたいなのでファイルのアップデートやRelease番号のインクリメントなどで対応してみてください。

将来の夢とか何とか

最近ブログを書いてなかったな〜などと思いながら過ごしてたらGWが終わりかけていた。
相変わらず精神状態は上向かず、ただ極端に下向くことはなくで生きている。
GWもさんざん遊んだのにもかかわらず「楽しい!」と思ったことがなく「これは楽しい事なんだよ」と思いこんで少し心が楽になったりならなかったりそんなことをしていた。
新しい病院に言ったら、心理検査を受けて、「ASDのボーダーラインでADHDのグレーゾーンですね」なんて言われて微妙な気持ちになってそれも未だに引きづっていたり…

追記(2023/05/16):昨日、主治医さんと長く話すことが出来き、心理検査の結果を見せてもらったWAIS-IVの結果は、語彙・言い換え・暗算が平均ラインを上回り、暗唱・記号転写などワーキングメモリを測る項目が平均ラインを下回って凸凹していた。コミュニケーションなどの自閉傾向を測るテスト(AQだったような)はすべての項目がカットオフポイント以上であり自閉傾向が強いと出て、タスク管理と人とのコミュニケーションはうまく向き合って行かないといけないということがわかった。

さて、皆さん将来の夢ってなんだろうか。
子供の頃、周りがケーキ屋さんなどとキラキラした目で語っていた横で、表では車掌などと行っておきながら、内面では貧困に苦しみたくないと漠然と思っていた。その頃家庭で収入がなく苦しんでいたのもあるかもしれない。中学の頃からは将来の夢というものを何も考えなくなってきていた。
ゆるふわな将来の夢から人生設計図というものを書くよう求められる年代になって、自分は大学卒業後の進路を全く書くことがなかった。周りは2X歳で結婚・出産などと語ってる中で、自分は果たして年金開始は65歳なのか70歳なのか、それともさらに後になるのかなどを憂いていた。将来というものに単純に興味がなかったというか、大人になるという事に何の夢もなかった。まるで別世界の話のごとく自分には縁がないかのように思っていた。
そんな事を置いておいてプログラミングや動画制作などにひたすら励み、思いつく事をひたすらに具現化していっていたら時は過ぎ、貧困は嫌なので勉学には励んだ。
プログラミングは幸いにも技術が伸びていき、イベント参加を通して、人と関わっておおくの知識を得たいと思うようになった。後に大学を関東圏にしたいという希望が出て来る。

無事、関東の大学に行きさまざまなイベントに参加したのも束の間、新型コロナウイルス感染症が流行しだし、全てのやりとりはオンラインとなり、イベントごとも無くなった。実家に引きこもりそうこうしているうちに、大学生活が過ぎて行った。
このころから更に物事に関する関心が低下していき、消極的になっていった。
その後、なんやかんやあって双極性障害を発病し、脳のリソースが制限され(今までコードをガリガリかけていたのは躁状態だったのかもしれない)、うまくプログラミングができなくなった。そんでもって、将来の夢はプログラマーというのにも疑念が出てきた。
それとは別に将来のことも真面目に考えないといけなくなった。1人暮らしをして気が付いたが、自分は一人で部屋にこもっているのが苦手らしい。元々低い自己肯定感が更に低くなって、人間の本能というか恥ずかしいものだな、俗っぽいものだなと思いながら、誰か存在を肯定してくれる人がいるといいな、と思うようになった。それでは相手を見つけないといけないということになるが、そんな能力は持ち合わせてなかった。それでは、一人で生きていくという事をしなければならないが、正直自己肯定感の低い自分にエサをやり続けるために働くというのが何とも言えない感覚がある。こんな自分に価値はあるのだろうかと自問している間が何とも辛い。

趣味にしてもプログラミングが一人で自走できる趣味だったので、これができなくなると一人でやる趣味というのがなくなって、他人から声をかけてもらうのを待っている。なかなか1人ではやる気が起きず、それでもって声がかかったタイミングでは体調が悪かったりと土日は布団の上でボーっとしていることが多い。旅も段々疲れて気力がそがれるし、観光地を見ても何も感じなくなってきた。(これは鬱のせいかもしれない。)
やることがなく、土日を過ごすことは平日の張りも失って、淡々と生きている感じがある。

本当は色々書きたいのだが、とにかく根気というものがそがれてだらだらと文章を書く気力もない。
自分は社会人をやっていけるのだろうか、支えあえる人を見つけられるのだろうか、一人ならその暮らしに耐えられるだろうか、今日も漠然とした不安を抱えて夜を過ごす。

Ethernetで一対一でデバイスと通信

ルータなどを介さずにIoTデバイスと直接やり取りする場合に必要な設定などを記録しておきます。
具体的に言うと、本来は IoT Device <—> Router <—> PCと通信するものをIoT Device <–> PCと通信する場合に必要に設定です。環境はopenSUSEを想定しています。

まずdhcp-serverをインストールします。その後設定を以下のように書き換えます。
なお、今回IoT Deviceに割り当てるIPアドレスレンジは192.168.0.2 ~ 192.168.0.100までとし、PC側のIPv4アドレスは192.168.0.1とします。また使用するネットワークインターフェイスの名前は”enp1s0f1″とします。また必要に応じてfirewalldは落としておいてください。

“/etc/dhcpd.conf”に以下のように設定します。

option subnet-mask 255.255.255.0;
subnet 192.168.0.0 netmask 255.255.255.0 {
        range 192.168.0.2 192.168.0.100;
}

次に”/etc/sysconfig/dhcpd”に使用するネットワークインターフェイスを指定します。

DHCPD_INTERFACE="enp1s0f1"

IPコマンドでIPアドレスレンジを割り当ててからDHCPサーバを起動します。

sudo ip addr flush dev enp1s0f1
sudo ip addr add 192.168.0.1/24 dev enp1s0f1
sudo systemctl start dhcpd

IoT DeviceがARPに対応していてIPアドレスの問い合わせのブロードキャストに対して適切に応答してくれる場合はいいんですが、無視してしまうようなデバイスの場合IPアドレス直指定で通信してもPCの方がARPパケットを飛ばしまくって結局通信できない、ということになります。
その場合、無理やりパケットがIoT Deviceに到達するように調整します。

IoT DeviceとのDHCPでのやり取り(Discover・Request・ACK)の中でIPアドレスとMACアドレスがわかるはずなのでそれを記録しておいてください。もしくはデバイスに記載されている場合はそちらを参照してください。
ipコマンド群を実行する前にIoTデバイスのIPアドレスとMACアドレスを変数として以下のように定義しておいてください。

IOT_IP_ADDRESS=192.168.0.2
IOT_MAC_ADDRESS=00:00:5E:00:53:11

DHCPによるIoT DeviceのIPアドレス取得が完了したの見計らってDHCPサーバを停止し、ipコマンドでネットワークの調整を行います。以下のコマンドを実行していきます。

sudo systemctl stop dhcpd
sudo ip addr flush dev enp1s0f1
sudo ip addr add 192.168.0.1/24 dev enp1s0f1
sudo ip route add ${IOT_IP_ADDRESS} dev enp1s0f1
sudo ip neigh add ${IOT_IP_ADDRESS} dev enp1s0f1 lladdr ${IOT_MAC_ADDRESS}

これでARPを飛ばさずにMACアドレスとIPアドレス直指定でIoT Deviceと通信できるようになるはずです。

openSUSEデスクトップ環境設定Etc

久しぶりにopenSUSEのほうをいじったら動かなくなったので色々動かなくなっていたので設定し直した時の備忘録

KDEでIBusが起動しない

~/.config/autostart/にibus-autostart.desktopなどで以下を作成

[Desktop Entry]
Comment[ja_JP]=Start IBus daemon
Comment=Start IBus daemon
Exec=/usr/bin/ibus-daemon -rxR
GenericName[ja_JP]=IBus Daemon
GenericName=IBus Daemon
Icon=ibus-setup
MimeType=
Name[ja_JP]=IBus
Name=IBus
Path=
StartupNotify=false
Terminal=false
TerminalOptions=
Type=Application
Version=1.0
X-DBUS-ServiceName=
X-DBUS-StartupType=
X-GNOME-Autostart-Delay=10
X-KDE-StartupNotify=false
X-KDE-SubstituteUID=false
X-KDE-Username=
X-KDE-autostart-after=panel

手癖で/usr/bin/ibus-daemon -drxRとしていたけど、それはコマンドラインから起動させる場合であってautostartでは”-d”はいらない。

PulseAudioじゃなくてPipeWireを使う

ヘッドホンのコーディックがHFPしか選択できず、音質に耐えられなかったのでごにょごにょしてたら、最近はPulseAudioじゃ無くてPipeWireを使うらしいというわけで以下を実行

Remove: pulseaudio pulseaudio-lang pulseaudio-module-* alsa-plugins-pulse mpg123-pulse pulseaudio-bash-completion pulseaudio-setup pulseaudio-zsh-completion system-user-pulse pulseaudio-utils

Install: pipewire pipewire-moudles-*  pipewire-alsa pipewire-pulseaudio  bluez-auto-enable-devices libdac2 libpulse0 libsbc1 gstreamer-plugin-pipewire

そんでもって一応以下のコマンドを実行

sudo mkdir -p /etc/pipewire/media-session.d/ && sudo touch /etc/pipewire/media-session.d/with-pulseaudio

再起動すると結構豊富にコーディックプロファイルが選べるようになっていた。

アセンブリでラベルを関数として認識させる

OS自作などでアセンブリでなにかの処理を書いた後に、これをCやRustなどから呼び出すことがあると思います。
このようなことをしている時に稀にリンカが超巨大エラーメッセージを吐いてズッコケることがありませんか?私はあります。
さて、このエラーをチンタラ解読するとアセンブリで書いた関数が再配置で呼び出し元の関数と離れすぎて相対ジャンプできないんだけど、みたいなことが書いてあります。例えば以下のようなエラーを吐いている場合などです。

relocation R_X86_64_PLT32 out of range: -549755221402 is not in [-2147483648, 2147483647]

「じゃあアセンブリの関数を呼び出し元の近くに配置してくれればええやんけ…」と思ってもやってくれないので、どうにかするしかないわけです。

手始めにstripなどされてないバイナリをobjdump -xでアセンブリのラベルがどう認識されているかを調べてみます。
アセンブリで

.section .text
hoge: 
        mov rax, rdi
        mul rdi
        ret

などと書いたとします。
すると、objdump -xでは
ffffff8000100000 l .text 0000000000 hoge
などと表示されます。
ここでCやRustで書かれた関数を見ると
ffffff8000200000 l F .text 000000003f foo
という感じの表示になっています。

さて、違いを見比べるとアセンブリで書いた関数は「Fのマークがない」「サイズが0」という点が異なるとわかります。特にサイズが0だと言うことはリロケーションができそうになさそうです。これで関数の再配置ができなくてリンカがコケるのではないかと思うわけです。
ここでアセンブリのラベルを高級言語での関数と同等の表示がされるようにしてみます。

まずは、「F」のマークをつけたいと思います。おそらく「Function」の略でしょうが、これは単に.textセクションに置くだけではつかないようです。
ここでELF形式で出力する場合は、.typeという擬似命令を使用できます。hogeの上に.typeを追加してみます。

.section .text
.type    hoge, %function
hoge: 
        mov rax, rdi
        mul rdi
        ret

これで再度objdumpの結果を見てみると
ffffff8000100000 l F .text 0000000000 hoge
などと表示されているはずです。ひとまずは関数として認識させられたようです。

問題は関数のサイズをどう認識させるかです。これがないと、どこまでがhogeなのかがリンカからわかりません。
ネットを探し回っていると.sizeという擬似命令を見つけました。
これは
.size label_name, size
label_nameのサイズをsizeであると指定する命令のようです。
これでsizeにhogeのretまでのバイト数を明記すれば良さそうです。
ただ、毎度計算するのは面倒なので”.“を使って、楽をします。

.section .text
.type    hoge, %function
hoge: 
        mov rax, rdi
        mul rdi
        ret
.size   hoge, . - hoge

.“は現在のアドレスを示すので、関数の先頭のアドレスを示すラベルとの引き算で関数のサイズが計算できます。

これでビルドしてobjdumpの結果を見ると、
ffffff8000100000 l F .text 0000000007 hoge
というふうにサイズもしっかり記載されてます。
これでhogeがリロケーションされ呼び出し元の近くに配置してリンカのエラーがなくなることもあります。(別のことが原因の場合もある)

この記事の元ツイート: https://twitter.com/PG_MANA_/status/1550674356929724416

Mini Web ServerをC言語で書いた

自作OSでopenとかreadのSystemCallを実装していましたが、何か面白いものを作りたくなったので、最近の自作OSでは一つの目標(?)とされているWebサーバを動かすことを目標とすることにしました。
とりあえず使用するシステムコールを探るためにC言語で超簡易版のWeb Serverを書いてみました。

使用するSystemCallを最小限にするためにfopenやmallocなどは使用せず、open/readなどのSystemCallに近い関数のみ使用するようにしました。本当はmallocは既にOS側でメモリ管理ができているので使いたかったのですがこの世のLinux向けのlibc実装はメモリを確保する際にbrkやmprotectを使用するらしく、現在の自分のOSでは紆余曲折あってLinux ABI互換で、これらの実装がやや面倒だったので(頑張ればできないことはないが)、とりあえず端折ることにしました。

コードは以下のとおりです。

#include <fcntl.h>
#include <netinet/in.h>
#include <stdio.h>
#include <string.h>
#include <sys/socket.h>
#include <unistd.h>

//#define DEBUG

#ifdef DEBUG
#include <arpa/inet.h>
#endif

#define HTTP_VERSION "HTTP/1.1"
#define GET_METHOD "GET"
#define SERVER_HEADER_ENTRY "Server: Mini Web Server"
#define HTTP_200 HTTP_VERSION " 200 OK"
#define HTTP_404 HTTP_VERSION " 404 Not Found"
#define HTTP_500 HTTP_VERSION " 500 Internal Server Error"

int main() {
  puts("Mini Web Server");

  int receive_socket = socket(AF_INET, SOCK_STREAM, 0);
  if (receive_socket < 0) {
    fprintf(stderr, "Failed to open the socket(ret: %d)\n", receive_socket);
    return 1;
  }

  struct sockaddr_in host;
  host.sin_family = AF_INET;
  host.sin_port = htons(8080);
  host.sin_addr.s_addr = INADDR_ANY;
  if (bind(receive_socket, (struct sockaddr *)&host, sizeof(host)) < 0) {
    fprintf(stderr, "Failed to bind\n");
    return 1;
  }

  if (listen(receive_socket, 10) < 0) {
    fprintf(stderr, "Failed to listen the socket.\n");
    return 1;
  }

  while (1) {
    struct sockaddr_in client_address;
    socklen_t client_address_length;
    int client_socket =
        accept(receive_socket, (struct sockaddr *)&client_address,
               &client_address_length);
#ifdef DEBUG
    printf("Client: {\"Address\": \"%s\", \"Port\": %d}\n",
           inet_ntoa(client_address.sin_addr), client_address.sin_port);
#endif
    char buffer[0x1000];
    buffer[sizeof(buffer) - 1] = '\0';

    int received = recv(client_socket, buffer, sizeof(buffer), 0);
    if (received < 0) {
      fprintf(stderr, "Failed to receive data(ret: %d)\n", received);
      return 1;
    }

    /* Check method */
    if (received <= (sizeof(GET_METHOD) - 1) ||
        strncmp(buffer, GET_METHOD, sizeof(GET_METHOD) - 1) != 0) {
      close(client_socket);
      continue;
    }
    size_t pointer = sizeof(GET_METHOD) - 1;

    if (buffer[pointer] != ' ' || buffer[pointer + 1] != '/') {
      close(client_socket);
      continue;
    }
    pointer += 1;
    /* remove "/"(root) */
    pointer += 1;
    char *file_name = buffer + pointer;
    size_t file_name_size = 0;
    for (; (pointer + file_name_size) < received &&
           buffer[pointer + file_name_size] != ' ';
         file_name_size++)
      ;
    pointer += file_name_size + 1;

    if (received <= (pointer + sizeof(HTTP_VERSION) - 1) ||
        strncmp(buffer + pointer, HTTP_VERSION, sizeof(HTTP_VERSION) - 1) !=
            0) {
      close(client_socket);
      continue;
    }
    if (file_name_size == 0) {
      const char index_name[] = "index.htm";
      strcpy(file_name, index_name);
      file_name_size = sizeof(index_name) - 1;
    }
    file_name[file_name_size] = '\0';
#ifdef DEBUG
    printf("URL: %s\n", file_name);
#endif
    /* Create Response */
    int fd = open(file_name, O_RDONLY);
    if (fd < 0) {
      const char not_found_text[] =
          HTTP_404 "\r\n" SERVER_HEADER_ENTRY "\r\n\r\nFile is not found.";
      send(client_socket, not_found_text, sizeof(not_found_text) - 1, 0);
    } else {
      size_t size = lseek(fd, 0, SEEK_END);
      lseek(fd, 0, SEEK_SET);
      if (size > sizeof(buffer)) {
        const char error_text[] =
            HTTP_500 "\r\n" SERVER_HEADER_ENTRY
                     "\r\n\r\nFile size is exceeded the buffer size.";
        send(client_socket, error_text, sizeof(error_text) - 1, 0);
      } else {
        sprintf(buffer,
                HTTP_200 "\r\n" SERVER_HEADER_ENTRY
                         "\r\nContent-Length: %zu\r\n\r\n",
                size);
        send(client_socket, buffer, strlen(buffer), 0);
        read(fd, buffer, size);
        send(client_socket, buffer, size, 0);
      }
    }
    close(client_socket);
  }
  return 0;
}

straceで呼ばれているシステムコールを確認すると起動処理以外では、

  • wrtiev(puts, fprintf)
  • socket
  • bind
  • listen
  • accept
  • recvfrom
  • open
  • lseek
  • sendto
  • read
  • close

のみとなってます。

とりあえずLinuxでビルドしたところまあまあ動いているようのなのでこれが動くように頑張ります。

と言っても、まずはネットワークデバイスのドライバ書くところから始めないといけないのですが…

追記: 一応動きました。 https://twitter.com/PG_MANA_/status/1533812030582292481

MouseProのLTEモジュール(Telit LN940)をLinuxで使う(ATコマンド編)

旅先や出先で大活躍のLTEモジュール付きノートパソコンですが、妙に電波のつかみが悪いので更に調査していたところ別の方法で認識させることができたので記録しておきます。

環境

  • MousePro-NB510HL
  • openSUSE Tumbleweed
  • KDE Plasma Desktop

注意

前回の方法(MouseProのLTEモジュール(Telit LN940)をLinuxで使う)をすでに適用されている場合は一旦取り消して再起動してください。
具体的には以下のコマンドを実行してください。

sudo rm /etc/udev/rules.d/15-lte.rules
sudo systemctl disable wwan-sleep-hook
sudo rm /etc/systemd/system/wwan-sleep-hook.service

また今回の方法はモジュールのファームウェアの設定を変更します。そのため場合によってはモジュールが動作不能になる恐れがあります。以下の内容は全て自己責任で行ってください。

手順

まずはlibqmiやmodemmanagerをインストールします。
ModemManagerは起動させずに停止させたままにします。
(sudo systemctl stop ModemManager)

次に/dev/ttyUSB2に接続します。(screenコマンドがない場合はインストールしてください)

sudo screen /dev/ttyUSB2 115200

接続したらATE1と入力し改行します。(アルファベットは大文字で)、リターンキーを押すまでエコーバックはないのでお気をつけください。この作業でエコーバックを有効にします。成功すればOKと返ってきます。

(ATE1と入力し改行)
OK

次にATIと入力し改行してみます。成功すれば各情報とOKが返ってきます。(改行)はリターンキーのことを指します。

ATI(改行)

Manufacturer: QUALCOMM INCORPORATED
Model: 4105
Revision: (ファームウェアのリビジョン番号)
+GCAP: +CGSM

OK

モデルが4105であることを確認し次の作業に進みます。
AT^SETMODE?で現在のファームウェアの状態を確認します。成功すれば現在のファームウェアのモードとOKが返ってきます。マニュアルによれば0がNormal Mode、1がExtension Mode、2がLegacy Modeだそうです。

AT^SETMODE?(改行)
^SETMODE: 0

OK

次にモードを1(Extension Mode)に変更します。
AT^SETMODE=1でモードを変更します。成功すればOKが返ってきます。

AT^SETMODE=1
OK

ここまで来たらCtrl+a, k, yの順に入力しscreenを終了し、最後に再起動します。


再起動後ModemManagerを起動するとKDEのネットワーク設定でLTEモジュールを認識していることを確認します。
あとはMouseProのLTEモジュール(Telit LN940)をLinuxで使うを参考にKDEの設定を行ってください。
まれに接続が成功してもDNSの名前解決ができない場合があります。(curl https://1.1.1.1/ は接続できるけど curl http://example.com はできないなど)
この際は、resolv.confにPublic DNSを追記してやると接続できるようになる場合があります。

sudo sh -c "echo nameserver 1.1.1.1 >> /etc/resolv.conf"

以上の方法でusb_switchを使う場合よりより安定してつながるようになりました。
もし、不具合が発生した場合は上記の手順をAT^SETMODE=0に変更して行えば元に戻るはずです。

あけましておめでとうございます

今年もあけてしまったらしいです。新型コロナウイルス感染症もあってか2020から時の進みが速い気がします。

去年は東京に戻って引っ越しをしたり、またまた実家に帰ったり、お仕事を頂いたり、本の謝辞に載せていただいたりと色々なことがありました。とても貴重な体験でした。それでもオフラインの勉強会やイベントに参加することはかないませんでしたが…

初日の出を見て写真を撮り、飛行機で東京に戻るところです。元旦は妙に飛行機が安くて助かります(?)

年越しはOS自作をやっておりました。今年少しずつ進めていければと思います。

今年もよろしくおねがいします。