hey Product Blog

こだわりを持ったお商売を支えるプラットフォーム「STORES」の開発チームによる技術ブログです。

業務の中で出会った default gem のアップグレードによる CVE 対応と rubygems 3.2.0 未満の不具合の話

f:id:hogelog:20211221114906p:plain

こんにちは! CTO 室所属エンジニアの id:hogelog です。

もういくつ寝るとクリスマスというわけで毎年クリスマスのお楽しみ、新バージョンの Ruby がリリースされます。次バージョンの Ruby 3.1 では { foo:, bar: } のようなハッシュのショートハンドや改善されたエラーハイライトが導入されるなど、Ruby の使い心地を改善する機能がいくつも組み込まれておりとても楽しみですね!

そんな Ruby 3.1 がもうすぐリリースされるというタイミングですが、ここでは先日リリースされた Ruby 3.0.3, 2.7.5, 2.6.9 に関連して hey 社内で進めたちょっとした業務とそこで出会った不具合について紹介します。

Ruby 3.0.3, 2.7.5, 2.6.9 のリリースと CVE-2021-41817, CVE-2021-41816, CVE-2021-41819

2021/11/24 にリリースされた Ruby 3.0.3, 2.7.5, 2.6.9 のリリースは CVE-2021-41817, CVE-2021-41816, CVE-2021-41819脆弱性に対応するためのセキュリティリリースです。

脆弱性対応のセキュリティリリースというものは速やかにアップグレードすることが望ましいです。リリースがされた時点で STORES のサービス (https://stores.jp/ec) は Ruby 2.7.4 を利用していました。 STORES も速やかに Ruby 2.7.5 にアップグレードすることが望ましいのですが、 STORES は現在 EC2 インスタンス上で Rails アプリを動かす構成となっており、Ruby のアップグレードをするにも「ソースコードを一行書き換えるだけ」では済みません。

しかし Ruby 2.7.4 -> 2.7.5 で対応している CVE-2021-41817, CVE-2021-41816, CVE-2021-41819 は date gem, cgi gem という2つの default gem のアップグレードでも対応可能となっています。*1 gem のアップグレードだけならば普段のデプロイフローの中でしていることなので対応は非常に容易です。gem のアップデートだけでも標準ライブラリの更新をできるようにしていっている Ruby 処理系改善の成果ですね。

rubygems < 3.2.0 ✕ bundler --path の不具合

そんなわけで Gemfile, Gemfile.lock を更新し date gem, cgi gem を脆弱性対応版に更新しデプロイ作業を進めたところ、bundle install 後の bundle exec … 実行ステップで以下のようなエラーを出力して終了してしまいました。

Bundler::GemNotFound: Could not find date-3.2.2 in any of the sources
  /path/to/ruby/lib/ruby/2.7.0/bundler/spec_set.rb:86:in `block in materialize'
  /path/to/ruby/lib/ruby/2.7.0/bundler/spec_set.rb:80:in `map!'
  /path/to/ruby/lib/ruby/2.7.0/bundler/spec_set.rb:80:in `materialize'
  /path/to/ruby/lib/ruby/2.7.0/bundler/definition.rb:170:in `specs'
  /path/to/ruby/lib/ruby/2.7.0/bundler/definition.rb:237:in `specs_for'
  /path/to/ruby/lib/ruby/2.7.0/bundler/definition.rb:226:in `requested_specs'
  /path/to/ruby/lib/ruby/2.7.0/bundler/runtime.rb:101:in `block in definition_method'
  /path/to/ruby/lib/ruby/2.7.0/bundler/runtime.rb:20:in `setup'
  /path/to/ruby/lib/ruby/2.7.0/bundler.rb:149:in `setup'
  /path/to/ruby/lib/ruby/2.7.0/bundler/setup.rb:20:in `block in <top (required)>'
  /path/to/ruby/lib/ruby/2.7.0/bundler/ui/shell.rb:136:in `with_level'
  /path/to/ruby/lib/ruby/2.7.0/bundler/ui/shell.rb:88:in `silence'
  /path/to/ruby/lib/ruby/2.7.0/bundler/setup.rb:20:in `<top (required)>'

非常に不可解なエラーだったので一旦 date gem, cgi gem のアップグレードはリバートし調査を進めたのですが、以下の条件下において bundler の実行に不具合が発生していることがわかりました。

  • rubygems < 3.2.0
  • 他 gem への依存性のない default gem を gem install でインストールした後、 BUNDLE_PATH 設定した bundler でインストール

一行で示すと以下のコマンドラインがエラーとなってしまいます。

gem install date:3.2.2 && bundle init && echo 'gem "date", "3.2.2"' >> Gemfile && bundle config set --local path gems && bundle install && bundle check

$ ruby -v
ruby 2.7.4p191 (2021-07-07 revision a21a3b7d23) [arm64-darwin20]
$ gem -v
3.1.6
$ gem install date:3.2.2
Fetching date-3.2.2.gem
Building native extensions. This could take a while...
Successfully installed date-3.2.2
Parsing documentation for date-3.2.2
Installing ri documentation for date-3.2.2
Done installing documentation for date after 0 seconds
1 gem installed
$ bundle init
Writing new Gemfile to /Users/hogelog/repos/hey/tmp/blog/Gemfile
$ echo 'gem "date", "3.2.2"' >> Gemfile
$ bundle config set --local path gems
$ bundle install # gems/ 以下にインストールされるはずがインストール済とされる
Fetching gem metadata from https://rubygems.org/.
Resolving dependencies...
Using bundler 2.1.4
Using date 3.2.2
Bundle complete! 1 Gemfile dependency, 2 gems now installed.
Bundled gems are installed into `./gems`
$ bundle check # bundle install 済なので本来はインストール済とされるはず
The following gems are missing
 * date (3.2.2)
Install missing gems with `bundle install`
$ echo $?
1

状況としては非常に限定的ですがサーバーへのデプロイなどではしばしばあり得る条件です。

デプロイできないのは困るのですが、こちらの不具合は rubygems をアップグレードすることで回避可能でした。rubygems のアップグレードは以下のように gem update --system コマンドで実施できます。

$ gem update --system 3.2.33
Updating rubygems-update
Fetching rubygems-update-3.2.33.gem
Successfully installed rubygems-update-3.2.33
…
$ bundle install
Fetching gem metadata from https://rubygems.org/.
Using bundler 2.2.33
Fetching date 3.2.2
Installing date 3.2.2 with native extensions
Bundle complete! 1 Gemfile dependency, 2 gems now installed.
Bundled gems are installed into `./gems`
$ bundle check
The Gemfile's dependencies are satisfied

というわけで STORES ではアップグレードした rubygems を利用して date gem 3.2.2, cgi gem 0.3.1 を導入し、速やかに脆弱性対応を済ませることができました。

Ruby 3.0 はデフォルトの rubygems バージョンが 3.2.3 なのでこの不具合に当たるアクティブな Ruby は 2.6, 2.7 のみです。*2 あまり大きな仕事ではなく、最新バージョンの Ruby の話でもなく、非常に限定的な状況でしか踏まない不具合対応の話です。しかしおそらくあまり広く知られた不具合ではなく、とても困っている人もいるかもしれませんし、ブログの形で周知してみました。どこかの誰かの参考になれば幸いです。

hey では不具合の原因を丁寧に調査し着実に業務を前に進めるエンジニアを募集しています。少しでも興味を持ってくれた方は以下のウェブサイトからオンライン会社説明会やカジュアル面談への応募、エントリーなどお待ちしております。

hello.hey.jp

この記事は hey アドベントカレンダー21日目の記事として書かれました。heyの色々なポジションな人が様々なことについて記事を書いているので、ぜひ一度眺めにきてみてください。 tech.hey.jp

*1:Ruby 2.6 では cgi gem が default gem 化されていなかったので Ruby アップグレードが必要です。

*2:意味はありませんが Ruby 3.0.0 であえて gem update --system 3.1.6 すればこの不具合は再現可能です