1. はじめに
picoCTFのGeneral Skills問題「fixme 2」の解説(Writeup)です。
2. 問題の概要
Easy問題です。
「The Rust saga continues? I ask you, can I borrow that, pleeeeeaaaasseeeee?」という問題文で、「borrow(借用)」というヒントが隠されています。
コードをダウンロードして実行すると、エラーが発生するので、コードを修正し、再実行していく流れです。
- rustの実行方法は過去記事をご参照ください
【picoCTF_CyLab】「rust fixme 3」WriteUPとrust環境構築
https://qiita.com/Wakako19972899/items/8c08a812d12d4b1b9d69
3. エラーとの格闘と解決のプロセス
一つ目のエラー:関数側で変更できない
- エラー内容:
cannot borrow `*borrowed_string` as mutable, as it is behind a `&` reference
-
原因:
関数decryptの引数がborrowed_string: &Stringのように不変参照になっていたため、関数内で.push_str()を使って文字列を書き換えることができなかった。 -
修正内容:
引数の型を&mut String(可変参照)に変更。
(修正前)
fn decrypt(encrypted_buffer:Vec<u8>, borrowed_string: &String){
(修正後)
fn decrypt(encrypted_buffer:Vec<u8>, borrowed_string: &mut String){
2つ目のエラー:呼び出し側の型が合わない
- エラー内容:
mismatched types
-
原因:
関数側を&mut(可変参照)を要求するように直したのに、呼び出し側が&party_foul(不変参照)のままだったため、型ミスマッチが発生した。 -
修正内容:
呼び出し部分を&mut party_foulに変更。
(修正前)
decrypt(encrypted_buffer, &party_foul);
(修正後)
decrypt(encrypted_buffer, &mut party_foul);
3つ目のエラー:変数自体が変更不可
- エラー内容:
cannot borrow `party_foul` as mutable, as it is not declared as mutable
-
原因:
可変参照(&mut)として貸し出そうとしたが、大元の変数party_foulがletで宣言されており、不変(変更不可能な変数)になっていた。 -
修正内容:
変数宣言をlet mut party_foul = ...に変更。
(修正前)
let party_foul = String::from("Using memory unsafe languages is a: ");
(修正後)
let mut party_foul = String::from("Using memory unsafe languages is a: ");
これで再実行(PowerShellでcargo run)すると、flag文字列が得られました。
4. まとめ
Rustで関数に渡したデータを書き換えてもらうには、以下の3箇所すべてに mut(可変)の意思表示が必要。
-
大元の変数:
let mut party_foul = ...(変更を許可する変数にする) -
渡す側(呼び出し):
decrypt(..., &mut party_foul)(変更可能な形で貸し出す) -
受ける側(関数定義):
fn decrypt(..., borrowed_string: &mut String)(変更可能な形で受け取る)
どれか1つでも欠けると、Rustのコンパイラが安全性のために止めてくれる。
5. おわりに
Rustの基礎を学べる良問でした。