https://qiita.com/tueda/items/75c931f4b6773a13836e

CVE-2020-10735とその「修正」

2022年9月7日にPythonのセキュリティアップデートがリリースされました。

修正された脆弱性はCVE-2020-10735です。ざっくりと言うと、Pythonで使われている整数・文字列間変換アルゴリズムがあまりイケてなく1、たとえば10進法で100,000桁の文字列を整数に変換すると50ミリ秒、1,000,000桁の場合は5秒もかかってしまうということが起こるので2、DoS攻撃に使えてしまうというものでした。

ここで、Python開発チームのとった対処法はアルゴリズムの改良ではなく3、大きな整数と文字列を変換しようとするとエラーになるような「修正」です。

>>> n = 10**4300
>>> str(n)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
ValueError: Exceeds the limit (4300) for integer string conversion

西暦10^4300年問題

さて、次のようなPythonプログラムを考えましょう。

import calendar

calendar.TextCalendar().prmonth(eval(input("year?")), eval(input("month?")))

ユーザーに年と月を入力してもらい6calendarモジュールTextCalendarクラスを使ってその年・月のカレンダーを出力しています。たとえば、

と入力すると、2022年9月のカレンダーが標準出力に出力されます。

   September 2022
Mo Tu We Th Fr Sa Su
          1  2  3  4
 5  6  7  8  9 10 11
12 13 14 15 16 17 18
19 20 21 22 23 24 25
26 27 28 29 30

December 99999999999999999999999999999999999999999999999999999999999999999999999
... (省略) ...
9999999999999999
Mo Tu We Th Fr Sa Su
       1  2  3  4  5
 6  7  8  9 10 11 12
13 14 15 16 17 18 19
20 21 22 23 24 25 26
27 28 29 30 31

Traceback (most recent call last):
  File "//prog.py", line 3, in <module>
    calendar.TextCalendar().prmonth(eval(input("year?")), eval(input("month?")))
  File "/usr/local/lib/python3.10/calendar.py", line 352, in prmonth
    print(self.formatmonth(theyear, themonth, w, l), end='')
  File "/usr/local/lib/python3.10/calendar.py", line 360, in formatmonth
    s = self.formatmonthname(theyear, themonth, 7 * (w + 1) - 1)
  File "/usr/local/lib/python3.10/calendar.py", line 345, in formatmonthname
    s = "%s %r" % (s, theyear)
ValueError: Exceeds the limit (4300) for integer string conversion

もうちょっとマシなアルゴリズムにしようよという議論は[こちら](<https://github.com/python/cpython/issues/90716>)。 [↩](<https://qiita.com/tueda/items/75c931f4b6773a13836e#fnref-algorithm>)
[セマンティック バージョニング](<https://semver.org/lang/ja/>)によると、パッチバージョンを上げるときは後方互換性を伴ったバグ修正しかしてはいけないはず。 [↩](<https://qiita.com/tueda/items/75c931f4b6773a13836e#fnref-patch>)
ユーザー入力をサニタイズせずそのまま`eval()`に食わせていますが、良い子は真似しないでね。 [↩](<https://qiita.com/tueda/items/75c931f4b6773a13836e#fnref-vulnerability>)
本当は、年と月を入力しなくても勝手に現在日時を取得してカレンダーを表示するプログラムにしようと思ったのですが、Python標準の[`datetime`モジュール](<https://docs.python.org/ja/3/library/datetime.html>)は[9999年までしか扱えない](<https://docs.python.org/ja/3/library/datetime.html#datetime.MAXYEAR>)のでした。恐るべし、[西暦10000年問題](<https://ja.wikipedia.org/wiki/%E8%A5%BF%E6%9A%A610000%E5%B9%B4%E5%95%8F%E9%A1%8C>)。 [↩](<https://qiita.com/tueda/items/75c931f4b6773a13836e#fnref-limitation>)