[Security Issue] rbs_string_strip_whitespace reads past empty ranges
メンテナーはふだん 1 日以内に返信
まだ誰も着手していません。
評価
調査の方向性
src/string.c の rbs_string_strip_whitespace から始め、integer-literal とアノテーションのパースにおけるその呼び出し元を確認します。付属の AddressSanitizer ハーネスを実行し、その後 test/rbs/type_parsing_test.rb を実行します。空の範囲によって out-of-bounds read が発生しなくなり、記載されたテストが通れば作業完了です。
索引モデルが issue の本文から書いたものです。
説明
Summary
rbs_string_strip_whitespace dereferences the start of a string range before checking whether the range is empty. An empty range therefore produces an out-of-bounds read under AddressSanitizer. The parser calls this helper for annotation bodies, whose grammar permits an empty body (<>).
Affected current master: 5de6ecda19eaec2bd225db301674dc650dc220c3
Affected release checked: RBS 4.2.0 (8aee3b6fa6231dbd6fefe01f2ba20e3104228a6f)
Source
The current loop condition reads *new_start before evaluating new_start < self->end:
while (isspace(*new_start) && new_start < self->end) {
new_start++;
}
The trailing-whitespace loop uses the same unsafe evaluation order. Call sites are in integer-literal and annotation parsing.
Reproduction
This small harness invokes the helper with a valid empty half-open range at the end of a one-byte allocation:
#include <stdlib.h>
#include "rbs/string.h"
int main(void) {
char *storage = malloc(1);
rbs_string_t empty = rbs_string_new(storage + 1, storage + 1);
rbs_string_t stripped = rbs_string_strip_whitespace(&empty);
free(storage);
return stripped.start == stripped.end ? 0 : 1;
}
Compile with AddressSanitizer against src/string.c and run it. On macOS/arm64 with Apple clang 17.0.0:
ERROR: AddressSanitizer: heap-buffer-overflow
READ of size 1
#0 rbs_string_strip_whitespace
#1 main
0 bytes after 1-byte region
Suggested fix
Check the range before dereferencing it, and cast through unsigned char before passing bytes to isspace:
-while (isspace(*new_start) && new_start < self->end) {
+while (new_start < self->end && isspace((unsigned char) *new_start)) {
...
-while (isspace(*new_end) && new_start < new_end) {
+while (new_start < new_end && isspace((unsigned char) *new_end)) {
With that change, the ASan harness exits successfully. The native extension compiles on Ruby 4.0.6, and test/rbs/type_parsing_test.rb passes 40 tests / 525 assertions. I have not established code-execution impact; the demonstrated failure is an out-of-bounds read on an empty parser string range.
- 主要言語
- Ruby
- スター
- 2.2k
- フォーク
- 258
- 平均マージ
- 1日 4時間
- マージ済み PR(30日)
- 52
環境構築
- Dockerfile・Docker Compose ファイルなし
- プルリクエストのテンプレートなし
- コントリビューションガイドを読む
はじめの一歩
- issue を最後まで読み、次にプロジェクトのコントリビューションガイドを読みます。
- 着手することを issue にコメントします — 二人が同じ作業をするのを防げます。
- リポジトリをフォークし、ブランチを切って変更します。
- issue 番号を参照したプルリクエストを送ります。
ruby/rbs のほかの issue
-
InlineParser: `@rbs @ivar` annotation is reported as unused unless it is the first thing in the class body対応中かも @ksss が 15 日前に担当しました。 オープン
難易度 2/5 1〜3時間 初心者へのやさしさ 82/100
メンテナーはふだん 1 日以内に返信
-
難易度 1/5 1時間未満 初心者へのやさしさ 78/100
メンテナーはふだん 1 日以内に返信
-
難易度 2/5 1〜3時間 初心者へのやさしさ 72/100
メンテナーはふだん 1 日以内に返信
-
難易度 4/5 3〜5日 初心者へのやさしさ 57/100
メンテナーはふだん 1 日以内に返信
-
難易度 3/5 1〜2日 初心者へのやさしさ 72/100
メンテナーはふだん 1 日以内に返信
似ている issue
-
bug
難易度 2/5 1〜3時間 初心者へのやさしさ 82/100
メンテナーはふだん 1 日以内に返信
-
難易度 2/5 1〜3時間 初心者へのやさしさ 75/100
GantMan/jail-monkey#380 ·
-
難易度 2/5 1〜3時間 初心者へのやさしさ 62/100
voxpupuli/puppet-wireguard#151 ·
-
bug
難易度 2/5 1〜3時間 初心者へのやさしさ 72/100
メンテナーはふだん 1 日以内に返信
-
bug f:search
難易度 2/5 1〜3時間 初心者へのやさしさ 78/100
メンテナーはふだん 1 日以内に返信