ruby-dev (Japanese) list archive (unofficial mirror)
 help / color / mirror / Atom feed
* [ruby-dev:50231] [Ruby trunk Bug#13885] Random.urandom と securerandom について
       [not found] <redmine.issue-13885.20170909154049@ruby-lang.org>
@ 2017-09-09 15:40 ` mame
  2017-09-10  2:59 ` [ruby-dev:50232] " kosaki.motohiro
                   ` (6 subsequent siblings)
  7 siblings, 0 replies; 8+ messages in thread
From: mame @ 2017-09-09 15:40 UTC (permalink / raw
  To: ruby-dev

Issue #13885 has been reported by mame (Yusuke Endoh).

----------------------------------------
Bug #13885: Random.urandom と securerandom について
https://bugs.ruby-lang.org/issues/13885

* Author: mame (Yusuke Endoh)
* Status: Open
* Priority: Normal
* Assignee: 
* Target version: 
* ruby -v: ruby 2.5.0dev (2017-09-09 trunk 59792) [x86_64-linux]
* Backport: 2.2: UNKNOWN, 2.3: UNKNOWN, 2.4: UNKNOWN
----------------------------------------
遠藤です。

Random.urandom と securerandom の仕様について卜部さんと話していて、いくつか気になる点が出てきたので挙げておきます。

1. Random.urandom は、getrandom(2) や (/dev/urandom に対する) read(2) システムコールを 1 回しか呼ばないようです。よって、要求量が大きくて 1 回では文字列を準備できないとき(例えば Random.urandom(100_000_000) )、失敗して nil を返します。これは意図的でしょうか。要求量が得られるまで(または他の要因で失敗するまで)繰り返し呼ぶべきではないでしょうか。
2. Random.urandom は失敗するとき、nil ではなく例外を投げるほうがよいのではないでしょうか。nil を返して実行が進んで幸せになるケースはあまり思い浮かびませんでした。
3. Random.urandom が nil を返す可能性があることは rdoc で明記されるべきではないでしょうか。(とりあえず r59803 で書き足しました。まずかったらすみません)
4. securerandom は、初回の呼び出しで Random.urandom が成功したらその後ずっと Random.urandom を使い、失敗したらずっと openssl を使うようになっています。これは本当に初回の呼び出しだけで振り分けるのでよいのでしょうか。具体的には、Random.urandom(0) は常に成功する(空文字列を返す)ので、実際には urandom が使えない環境でも urandom に固定される可能性があります。
5. 逆に、securerandom のバックエンドを動的に切り替えるようにしたら問題あるでしょうか。最初は成功していた Random.urandom が途中から失敗するようになったとき、openssl へフォールバックしても良いものでしょうか。また、Random.urandom が復活した場合、openssl から Random.urandom に戻すのは問題ないでしょうか。



-- 
https://bugs.ruby-lang.org/

^ permalink raw reply	[flat|nested] 8+ messages in thread

* [ruby-dev:50232] [Ruby trunk Bug#13885] Random.urandom と securerandom について
       [not found] <redmine.issue-13885.20170909154049@ruby-lang.org>
  2017-09-09 15:40 ` [ruby-dev:50231] [Ruby trunk Bug#13885] Random.urandom と securerandom について mame
@ 2017-09-10  2:59 ` kosaki.motohiro
  2017-09-10 12:24 ` [ruby-dev:50234] " shyouhei
                   ` (5 subsequent siblings)
  7 siblings, 0 replies; 8+ messages in thread
From: kosaki.motohiro @ 2017-09-10  2:59 UTC (permalink / raw
  To: ruby-dev

Issue #13885 has been updated by kosaki (Motohiro KOSAKI).


小崎です
このへんあんまり詳しくないんですが。

>1.Random.urandom は、getrandom(2) や (/dev/urandom に対する) read(2) システムコールを 1 回しか呼ばないようです。よって、要求量が大きくて 1 回では文字列を準備できないとき(例えば
> Random.urandom(100_000_000) )、失敗して nil を返します。これは意図的でしょうか。要求量が得られるまで(または他の要因で失敗するまで)繰り返し呼ぶべきではないでしょうか。

そんな気がします。一瞬エントロピー枯渇について心配しましたが、Rubyの側で小さいurandomを大量に呼べばどうせ枯渇するんだし


>2.Random.urandom は失敗するとき、nil ではなく例外を投げるほうがよいのではないでしょうか。nil を返して実行が進んで幸せになるケースはあまり思い浮かびませんでした。

同意します
どうせ実アプリケーションでurandom直接呼んでる人なんていないのだから気にせず変えてしまっていいと思います

>4.securerandom は、初回の呼び出しで Random.urandom が成功したらその後ずっと Random.urandom を使い、失敗したらずっと openssl を使うようになっています。
>これは本当に初回の呼び出しだけで振り分けるのでよいのでしょうか。具体的には、Random.urandom(0) は常に成功する(空文字列を返す)ので、実際には urandom が
>使えない環境でも urandom に固定される可能性があります。
>逆に、securerandom のバックエンドを動的に切り替えるようにしたら問題あるでしょうか。最初は成功していた Random.urandom が途中から失敗するようになったとき、
>openssl へフォールバックしても良いものでしょうか。また、Random.urandom が復活した場合、openssl から Random.urandom に戻すのは問題ないでしょうか。

途中でurandomが使えなくなったり使えるようになったりってのは、1の長大な引数のケースぐらいしか思いつかないので、
固定でいいのではないでしょうか。
それはそれとしてRandom.urandom(0) の件はバグじゃないのかと思います。




----------------------------------------
Bug #13885: Random.urandom と securerandom について
https://bugs.ruby-lang.org/issues/13885#change-66572

* Author: mame (Yusuke Endoh)
* Status: Open
* Priority: Normal
* Assignee: 
* Target version: 
* ruby -v: ruby 2.5.0dev (2017-09-09 trunk 59792) [x86_64-linux]
* Backport: 2.2: UNKNOWN, 2.3: UNKNOWN, 2.4: UNKNOWN
----------------------------------------
遠藤です。

Random.urandom と securerandom の仕様について卜部さんと話していて、いくつか気になる点が出てきたので挙げておきます。

1. Random.urandom は、getrandom(2) や (/dev/urandom に対する) read(2) システムコールを 1 回しか呼ばないようです。よって、要求量が大きくて 1 回では文字列を準備できないとき(例えば Random.urandom(100_000_000) )、失敗して nil を返します。これは意図的でしょうか。要求量が得られるまで(または他の要因で失敗するまで)繰り返し呼ぶべきではないでしょうか。
2. Random.urandom は失敗するとき、nil ではなく例外を投げるほうがよいのではないでしょうか。nil を返して実行が進んで幸せになるケースはあまり思い浮かびませんでした。
3. Random.urandom が nil を返す可能性があることは rdoc で明記されるべきではないでしょうか。(とりあえず r59803 で書き足しました。まずかったらすみません)
4. securerandom は、初回の呼び出しで Random.urandom が成功したらその後ずっと Random.urandom を使い、失敗したらずっと openssl を使うようになっています。これは本当に初回の呼び出しだけで振り分けるのでよいのでしょうか。具体的には、Random.urandom(0) は常に成功する(空文字列を返す)ので、実際には urandom が使えない環境でも urandom に固定される可能性があります。
5. 逆に、securerandom のバックエンドを動的に切り替えるようにしたら問題あるでしょうか。最初は成功していた Random.urandom が途中から失敗するようになったとき、openssl へフォールバックしても良いものでしょうか。また、Random.urandom が復活した場合、openssl から Random.urandom に戻すのは問題ないでしょうか。



-- 
https://bugs.ruby-lang.org/

^ permalink raw reply	[flat|nested] 8+ messages in thread

* [ruby-dev:50234] [Ruby trunk Bug#13885] Random.urandom と securerandom について
       [not found] <redmine.issue-13885.20170909154049@ruby-lang.org>
  2017-09-09 15:40 ` [ruby-dev:50231] [Ruby trunk Bug#13885] Random.urandom と securerandom について mame
  2017-09-10  2:59 ` [ruby-dev:50232] " kosaki.motohiro
@ 2017-09-10 12:24 ` shyouhei
  2017-09-10 14:52 ` [ruby-dev:50235] " mame
                   ` (4 subsequent siblings)
  7 siblings, 0 replies; 8+ messages in thread
From: shyouhei @ 2017-09-10 12:24 UTC (permalink / raw
  To: ruby-dev

Issue #13885 has been updated by shyouhei (Shyouhei Urabe).


kosaki (Motohiro KOSAKI) wrote:
> >1.Random.urandom は、getrandom(2) や (/dev/urandom に対する) read(2) システムコールを 1 回しか呼ばないようです。よって、要求量が大きくて 1 回では文字列を準備できないとき(例えば
> > Random.urandom(100_000_000) )、失敗して nil を返します。これは意図的でしょうか。要求量が得られるまで(または他の要因で失敗するまで)繰り返し呼ぶべきではないでしょうか。
> 
> そんな気がします。一瞬エントロピー枯渇について心配しましたが、Rubyの側で小さいurandomを大量に呼べばどうせ枯渇するんだし

昔のLinuxのmanに "Users should be very economical in the amount of seed material that they read  from /dev/urandom" とか書いてあったのがループしない経緯ではないかと想像しています。その記述はなくなったので、今となってはループしない理由はないんではないかなと思いますがいかがでしょうか。

(まあループの中でエントロピー吸い出すなら当然ブロッキングIOということになるわけで、GVL放した方がいいんじゃないのとか思わなくもないのでパッチはやや大きそうではあると感じますが)

> >2.Random.urandom は失敗するとき、nil ではなく例外を投げるほうがよいのではないでしょうか。nil を返して実行が進んで幸せになるケースはあまり思い浮かびませんでした。
> 
> 同意します
> どうせ実アプリケーションでurandom直接呼んでる人なんていないのだから気にせず変えてしまっていいと思います

Random.urandomという名前になったのは2.5からなので、今ならまだ実アプリケーションがどうとか悩む必要もなく、いきなり変えてOKのはずです。

> >4.securerandom は、初回の呼び出しで Random.urandom が成功したらその後ずっと Random.urandom を使い、失敗したらずっと openssl を使うようになっています。
> >これは本当に初回の呼び出しだけで振り分けるのでよいのでしょうか。具体的には、Random.urandom(0) は常に成功する(空文字列を返す)ので、実際には urandom が
> >使えない環境でも urandom に固定される可能性があります。
> >逆に、securerandom のバックエンドを動的に切り替えるようにしたら問題あるでしょうか。最初は成功していた Random.urandom が途中から失敗するようになったとき、
> >openssl へフォールバックしても良いものでしょうか。また、Random.urandom が復活した場合、openssl から Random.urandom に戻すのは問題ないでしょうか。
> 
> 途中でurandomが使えなくなったり使えるようになったりってのは、1の長大な引数のケースぐらいしか思いつかないので、
> 固定でいいのではないでしょうか。

0の件は後述。Random.urandomがきちんとループして要求されたバイト数まで読むようになった場合、Random.urandomの実行結果は以下の2パターンのいずれかになるはずです。

- 成功して、必要なだけのデータが入手できる
- 失敗して、例外が上がる

さて、この整理が済んだ後、urandomが「折に触れて成功したり失敗したりする」というのは考えられるでしょうか。なんか失敗する時はずっと失敗するのではないかという気がします。なので、バックエンドの切り替えが固定かどうかはさほど重要な論点ではなくなる気がしています。

> それはそれとしてRandom.urandom(0) の件はバグじゃないのかと思います。

これに関してはまず、urandom(0)で何が返るべきかですが、空文字列だと思います。

同様の例としてread(0)で何が返るべきかという問題が「APIデザインケーススタディ」の21ページ付近に載っているので読むといいと思うんですが、要は可変長の文字列が欲しいという場合がありえて、意味のある引数として0が渡ってくる可能性がある。そこで戻り値にnilを返しうることにしてしまうと、呼び出し側でnilかどうか毎回チェックせねばならず面倒なわけです。なのでこれは食う文字列であるべき。

一方で、そうすると、初回の引数が0だったときにSecureRandomが意図しない動きになってしまうじゃないかという話はあって、これは回避する必要がありそうです。思いつくのは、

- たとえ引数が0であってもシステムコールやデバイスファイル読み出しを律儀に行い、きちんと例外をあげていく
- urandomとは別に現在利用可能な乱数元の一覧を得るAPIを新設する

くらいですが、後者はやや話が大きいので、前者かなあと思います。


----------------------------------------
Bug #13885: Random.urandom と securerandom について
https://bugs.ruby-lang.org/issues/13885#change-66581

* Author: mame (Yusuke Endoh)
* Status: Open
* Priority: Normal
* Assignee: 
* Target version: 
* ruby -v: ruby 2.5.0dev (2017-09-09 trunk 59792) [x86_64-linux]
* Backport: 2.2: UNKNOWN, 2.3: UNKNOWN, 2.4: UNKNOWN
----------------------------------------
遠藤です。

Random.urandom と securerandom の仕様について卜部さんと話していて、いくつか気になる点が出てきたので挙げておきます。

1. Random.urandom は、getrandom(2) や (/dev/urandom に対する) read(2) システムコールを 1 回しか呼ばないようです。よって、要求量が大きくて 1 回では文字列を準備できないとき(例えば Random.urandom(100_000_000) )、失敗して nil を返します。これは意図的でしょうか。要求量が得られるまで(または他の要因で失敗するまで)繰り返し呼ぶべきではないでしょうか。
2. Random.urandom は失敗するとき、nil ではなく例外を投げるほうがよいのではないでしょうか。nil を返して実行が進んで幸せになるケースはあまり思い浮かびませんでした。
3. Random.urandom が nil を返す可能性があることは rdoc で明記されるべきではないでしょうか。(とりあえず r59803 で書き足しました。まずかったらすみません)
4. securerandom は、初回の呼び出しで Random.urandom が成功したらその後ずっと Random.urandom を使い、失敗したらずっと openssl を使うようになっています。これは本当に初回の呼び出しだけで振り分けるのでよいのでしょうか。具体的には、Random.urandom(0) は常に成功する(空文字列を返す)ので、実際には urandom が使えない環境でも urandom に固定される可能性があります。
5. 逆に、securerandom のバックエンドを動的に切り替えるようにしたら問題あるでしょうか。最初は成功していた Random.urandom が途中から失敗するようになったとき、openssl へフォールバックしても良いものでしょうか。また、Random.urandom が復活した場合、openssl から Random.urandom に戻すのは問題ないでしょうか。



-- 
https://bugs.ruby-lang.org/

^ permalink raw reply	[flat|nested] 8+ messages in thread

* [ruby-dev:50235] [Ruby trunk Bug#13885] Random.urandom と securerandom について
       [not found] <redmine.issue-13885.20170909154049@ruby-lang.org>
                   ` (2 preceding siblings ...)
  2017-09-10 12:24 ` [ruby-dev:50234] " shyouhei
@ 2017-09-10 14:52 ` mame
  2017-09-11  1:29 ` [ruby-dev:50237] " shyouhei
                   ` (3 subsequent siblings)
  7 siblings, 0 replies; 8+ messages in thread
From: mame @ 2017-09-10 14:52 UTC (permalink / raw
  To: ruby-dev

Issue #13885 has been updated by mame (Yusuke Endoh).


shyouhei (Shyouhei Urabe) wrote:
> (まあループの中でエントロピー吸い出すなら当然ブロッキングIOということになるわけで、GVL放した方がいいんじゃないのとか思わなくもないのでパッチはやや大きそうではあると感じますが)

/dev/urandom はブロックしない(少なくとも最近の OS なら)、という前提があっても、GVL 放すべきですかね?

> なんか失敗する時はずっと失敗するのではないかという気がします。

小崎さんと卜部さんの 2 人がそういうなら、大丈夫な気がしてきました。

> - たとえ引数が0であってもシステムコールやデバイスファイル読み出しを律儀に行い、きちんと例外をあげていく

これはちょっと安心できない気がします。0 バイトの読み出しに対して何もせずに成功を返すというのは Ruby に限らずありがちな実装だと思うので、getrandom(2) システムコールが同じことをしても驚かないです(仮に今の実装がそうなっていなくても、man などで明記されていない限り、将来的に変わるかもしれない)。

Random.urandom の挙動は今のまま変えず、securerandom は初回の読み出しで(要求が 0 バイトであろうとも)必ず 1 バイト以上読み出してみる、というのが手軽な対策だと思ってます。異論なければ以下のパッチをコミットしようと思いますが、どうでしょうか。

~~~~
diff --git a/lib/securerandom.rb b/lib/securerandom.rb
index 6a5720c44e..e20591a64f 100644
--- a/lib/securerandom.rb
+++ b/lib/securerandom.rb
@@ -52,7 +52,7 @@ def bytes(n)
     end
 
     def gen_random(n)
-      ret = Random.urandom(n)
+      ret = Random.urandom(1)
       if ret.nil?
         begin
           require 'openssl'
@@ -67,10 +67,6 @@ class << self
           end
           return gen_random(n)
         end
-      elsif ret.length != n
-        raise NotImplementedError, \
-              "Unexpected partial read from random device: " \
-              "only #{ret.length} for #{n} bytes"
       else
         @rng_chooser.synchronize do
           class << self
~~~~

----------------------------------------
Bug #13885: Random.urandom と securerandom について
https://bugs.ruby-lang.org/issues/13885#change-66586

* Author: mame (Yusuke Endoh)
* Status: Open
* Priority: Normal
* Assignee: 
* Target version: 
* ruby -v: ruby 2.5.0dev (2017-09-09 trunk 59792) [x86_64-linux]
* Backport: 2.2: UNKNOWN, 2.3: UNKNOWN, 2.4: UNKNOWN
----------------------------------------
遠藤です。

Random.urandom と securerandom の仕様について卜部さんと話していて、いくつか気になる点が出てきたので挙げておきます。

1. Random.urandom は、getrandom(2) や (/dev/urandom に対する) read(2) システムコールを 1 回しか呼ばないようです。よって、要求量が大きくて 1 回では文字列を準備できないとき(例えば Random.urandom(100_000_000) )、失敗して nil を返します。これは意図的でしょうか。要求量が得られるまで(または他の要因で失敗するまで)繰り返し呼ぶべきではないでしょうか。
2. Random.urandom は失敗するとき、nil ではなく例外を投げるほうがよいのではないでしょうか。nil を返して実行が進んで幸せになるケースはあまり思い浮かびませんでした。
3. Random.urandom が nil を返す可能性があることは rdoc で明記されるべきではないでしょうか。(とりあえず r59803 で書き足しました。まずかったらすみません)
4. securerandom は、初回の呼び出しで Random.urandom が成功したらその後ずっと Random.urandom を使い、失敗したらずっと openssl を使うようになっています。これは本当に初回の呼び出しだけで振り分けるのでよいのでしょうか。具体的には、Random.urandom(0) は常に成功する(空文字列を返す)ので、実際には urandom が使えない環境でも urandom に固定される可能性があります。
5. 逆に、securerandom のバックエンドを動的に切り替えるようにしたら問題あるでしょうか。最初は成功していた Random.urandom が途中から失敗するようになったとき、openssl へフォールバックしても良いものでしょうか。また、Random.urandom が復活した場合、openssl から Random.urandom に戻すのは問題ないでしょうか。



-- 
https://bugs.ruby-lang.org/

^ permalink raw reply related	[flat|nested] 8+ messages in thread

* [ruby-dev:50237] [Ruby trunk Bug#13885] Random.urandom と securerandom について
       [not found] <redmine.issue-13885.20170909154049@ruby-lang.org>
                   ` (3 preceding siblings ...)
  2017-09-10 14:52 ` [ruby-dev:50235] " mame
@ 2017-09-11  1:29 ` shyouhei
  2017-09-11 12:46 ` [ruby-dev:50241] " mame
                   ` (2 subsequent siblings)
  7 siblings, 0 replies; 8+ messages in thread
From: shyouhei @ 2017-09-11  1:29 UTC (permalink / raw
  To: ruby-dev

Issue #13885 has been updated by shyouhei (Shyouhei Urabe).


mame (Yusuke Endoh) wrote:
> shyouhei (Shyouhei Urabe) wrote:
> > (まあループの中でエントロピー吸い出すなら当然ブロッキングIOということになるわけで、GVL放した方がいいんじゃないのとか思わなくもないのでパッチはやや大きそうではあると感じますが)
> 
> /dev/urandom はブロックしない(少なくとも最近の OS なら)、という前提があっても、GVL 放すべきですかね?

それってO_NBLOCKのディスクリプタをビジーループで読み込みってことですよね。ユーザーランドからへんにビジーループするよりカーネル側で適切に生成されてくるのをユーザーランド側はすなおにブロッキングIOしたほうがトータルのコンテキストスイッチが少なそうな気がするんですが、まあ気がするだけで定量的評価ではないです。

> > - たとえ引数が0であってもシステムコールやデバイスファイル読み出しを律儀に行い、きちんと例外をあげていく
> 
> これはちょっと安心できない気がします。0 バイトの読み出しに対して何もせずに成功を返すというのは Ruby に限らずありがちな実装だと思うので、getrandom(2) システムコールが同じことをしても驚かないです(仮に今の実装がそうなっていなくても、man などで明記されていない限り、将来的に変わるかもしれない)。
> 
> Random.urandom(0) の挙動は今のまま変えず、securerandom は初回の読み出しで(要求が 0 バイトであろうとも)必ず 1 バイト以上読み出してみる、というのが手軽な対策だと思ってます。異論なければ以下のパッチをコミットしようと思いますが、どうでしょうか。

これは特に反対ありません。

----------------------------------------
Bug #13885: Random.urandom と securerandom について
https://bugs.ruby-lang.org/issues/13885#change-66591

* Author: mame (Yusuke Endoh)
* Status: Open
* Priority: Normal
* Assignee: 
* Target version: 
* ruby -v: ruby 2.5.0dev (2017-09-09 trunk 59792) [x86_64-linux]
* Backport: 2.2: UNKNOWN, 2.3: UNKNOWN, 2.4: UNKNOWN
----------------------------------------
遠藤です。

Random.urandom と securerandom の仕様について卜部さんと話していて、いくつか気になる点が出てきたので挙げておきます。

1. Random.urandom は、getrandom(2) や (/dev/urandom に対する) read(2) システムコールを 1 回しか呼ばないようです。よって、要求量が大きくて 1 回では文字列を準備できないとき(例えば Random.urandom(100_000_000) )、失敗して nil を返します。これは意図的でしょうか。要求量が得られるまで(または他の要因で失敗するまで)繰り返し呼ぶべきではないでしょうか。
2. Random.urandom は失敗するとき、nil ではなく例外を投げるほうがよいのではないでしょうか。nil を返して実行が進んで幸せになるケースはあまり思い浮かびませんでした。
3. Random.urandom が nil を返す可能性があることは rdoc で明記されるべきではないでしょうか。(とりあえず r59803 で書き足しました。まずかったらすみません)
4. securerandom は、初回の呼び出しで Random.urandom が成功したらその後ずっと Random.urandom を使い、失敗したらずっと openssl を使うようになっています。これは本当に初回の呼び出しだけで振り分けるのでよいのでしょうか。具体的には、Random.urandom(0) は常に成功する(空文字列を返す)ので、実際には urandom が使えない環境でも urandom に固定される可能性があります。
5. 逆に、securerandom のバックエンドを動的に切り替えるようにしたら問題あるでしょうか。最初は成功していた Random.urandom が途中から失敗するようになったとき、openssl へフォールバックしても良いものでしょうか。また、Random.urandom が復活した場合、openssl から Random.urandom に戻すのは問題ないでしょうか。



-- 
https://bugs.ruby-lang.org/

^ permalink raw reply	[flat|nested] 8+ messages in thread

* [ruby-dev:50241] [Ruby trunk Bug#13885] Random.urandom と securerandom について
       [not found] <redmine.issue-13885.20170909154049@ruby-lang.org>
                   ` (4 preceding siblings ...)
  2017-09-11  1:29 ` [ruby-dev:50237] " shyouhei
@ 2017-09-11 12:46 ` mame
  2017-09-14 11:40 ` [ruby-dev:50243] " mame
  2017-12-16  0:43 ` [ruby-dev:50353] [Ruby trunk Bug#13885][Closed] " mame
  7 siblings, 0 replies; 8+ messages in thread
From: mame @ 2017-09-11 12:46 UTC (permalink / raw
  To: ruby-dev

Issue #13885 has been updated by mame (Yusuke Endoh).


shyouhei (Shyouhei Urabe) wrote:
> これは特に反対ありません。

ありがとうございます。r59840 でコミットしました。(コミットログにチケット番号書き忘れた……)

----------------------------------------
Bug #13885: Random.urandom と securerandom について
https://bugs.ruby-lang.org/issues/13885#change-66604

* Author: mame (Yusuke Endoh)
* Status: Open
* Priority: Normal
* Assignee: 
* Target version: 
* ruby -v: ruby 2.5.0dev (2017-09-09 trunk 59792) [x86_64-linux]
* Backport: 2.2: UNKNOWN, 2.3: UNKNOWN, 2.4: UNKNOWN
----------------------------------------
遠藤です。

Random.urandom と securerandom の仕様について卜部さんと話していて、いくつか気になる点が出てきたので挙げておきます。

1. Random.urandom は、getrandom(2) や (/dev/urandom に対する) read(2) システムコールを 1 回しか呼ばないようです。よって、要求量が大きくて 1 回では文字列を準備できないとき(例えば Random.urandom(100_000_000) )、失敗して nil を返します。これは意図的でしょうか。要求量が得られるまで(または他の要因で失敗するまで)繰り返し呼ぶべきではないでしょうか。
2. Random.urandom は失敗するとき、nil ではなく例外を投げるほうがよいのではないでしょうか。nil を返して実行が進んで幸せになるケースはあまり思い浮かびませんでした。
3. Random.urandom が nil を返す可能性があることは rdoc で明記されるべきではないでしょうか。(とりあえず r59803 で書き足しました。まずかったらすみません)
4. securerandom は、初回の呼び出しで Random.urandom が成功したらその後ずっと Random.urandom を使い、失敗したらずっと openssl を使うようになっています。これは本当に初回の呼び出しだけで振り分けるのでよいのでしょうか。具体的には、Random.urandom(0) は常に成功する(空文字列を返す)ので、実際には urandom が使えない環境でも urandom に固定される可能性があります。
5. 逆に、securerandom のバックエンドを動的に切り替えるようにしたら問題あるでしょうか。最初は成功していた Random.urandom が途中から失敗するようになったとき、openssl へフォールバックしても良いものでしょうか。また、Random.urandom が復活した場合、openssl から Random.urandom に戻すのは問題ないでしょうか。



-- 
https://bugs.ruby-lang.org/

^ permalink raw reply	[flat|nested] 8+ messages in thread

* [ruby-dev:50243] [Ruby trunk Bug#13885] Random.urandom と securerandom について
       [not found] <redmine.issue-13885.20170909154049@ruby-lang.org>
                   ` (5 preceding siblings ...)
  2017-09-11 12:46 ` [ruby-dev:50241] " mame
@ 2017-09-14 11:40 ` mame
  2017-12-16  0:43 ` [ruby-dev:50353] [Ruby trunk Bug#13885][Closed] " mame
  7 siblings, 0 replies; 8+ messages in thread
From: mame @ 2017-09-14 11:40 UTC (permalink / raw
  To: ruby-dev

Issue #13885 has been updated by mame (Yusuke Endoh).


特に反対もなかったので、nil を返すのではなく RuntimeError を投げるようにしました(r59858)。

残るはシステムコールをループする点だけですが、

> それってO_NBLOCKのディスクリプタをビジーループで読み込みってことですよね。ユーザーランドからへんにビジーループするよりカーネル側で適切に生成されてくるのをユーザーランド側はすなおにブロッキングIOしたほうがトータルのコンテキストスイッチが少なそうな気がするんですが、まあ気がするだけで定量的評価ではないです。

これはちょっとよくわかりませんでした。ブロッキング IO にしても、getrandom(2) や read(2) システムコールは途中で終わる可能性がある(つまりカーネル側で要求量きっかり生成してくれることは保証されない)ので、ユーザランドでのループはどのみち必要です。

GVL を放すかどうかは、放してもいいとは思いますが、

* getrandom(2) などがブロックすることはない(はず)
* 普通のユースケース(数十バイト程度の urandom 取得)では、ループが必要になることもほぼない

ということで、オーバーヘッドになるだけのような気はしてます。
あと、この辺の関数はスレッド周りが初期化されていないプロセス起動時にも呼ばれるので、rb_thread_call_without_gvl が単純に呼べず、さらにパッチがでかくなりそうでした。

----------------------------------------
Bug #13885: Random.urandom と securerandom について
https://bugs.ruby-lang.org/issues/13885#change-66658

* Author: mame (Yusuke Endoh)
* Status: Open
* Priority: Normal
* Assignee: 
* Target version: 
* ruby -v: ruby 2.5.0dev (2017-09-09 trunk 59792) [x86_64-linux]
* Backport: 2.2: UNKNOWN, 2.3: UNKNOWN, 2.4: UNKNOWN
----------------------------------------
遠藤です。

Random.urandom と securerandom の仕様について卜部さんと話していて、いくつか気になる点が出てきたので挙げておきます。

1. Random.urandom は、getrandom(2) や (/dev/urandom に対する) read(2) システムコールを 1 回しか呼ばないようです。よって、要求量が大きくて 1 回では文字列を準備できないとき(例えば Random.urandom(100_000_000) )、失敗して nil を返します。これは意図的でしょうか。要求量が得られるまで(または他の要因で失敗するまで)繰り返し呼ぶべきではないでしょうか。
2. Random.urandom は失敗するとき、nil ではなく例外を投げるほうがよいのではないでしょうか。nil を返して実行が進んで幸せになるケースはあまり思い浮かびませんでした。
3. Random.urandom が nil を返す可能性があることは rdoc で明記されるべきではないでしょうか。(とりあえず r59803 で書き足しました。まずかったらすみません)
4. securerandom は、初回の呼び出しで Random.urandom が成功したらその後ずっと Random.urandom を使い、失敗したらずっと openssl を使うようになっています。これは本当に初回の呼び出しだけで振り分けるのでよいのでしょうか。具体的には、Random.urandom(0) は常に成功する(空文字列を返す)ので、実際には urandom が使えない環境でも urandom に固定される可能性があります。
5. 逆に、securerandom のバックエンドを動的に切り替えるようにしたら問題あるでしょうか。最初は成功していた Random.urandom が途中から失敗するようになったとき、openssl へフォールバックしても良いものでしょうか。また、Random.urandom が復活した場合、openssl から Random.urandom に戻すのは問題ないでしょうか。



-- 
https://bugs.ruby-lang.org/

^ permalink raw reply	[flat|nested] 8+ messages in thread

* [ruby-dev:50353] [Ruby trunk Bug#13885][Closed] Random.urandom と securerandom について
       [not found] <redmine.issue-13885.20170909154049@ruby-lang.org>
                   ` (6 preceding siblings ...)
  2017-09-14 11:40 ` [ruby-dev:50243] " mame
@ 2017-12-16  0:43 ` mame
  7 siblings, 0 replies; 8+ messages in thread
From: mame @ 2017-12-16  0:43 UTC (permalink / raw
  To: ruby-dev

Issue #13885 has been updated by mame (Yusuke Endoh).

Status changed from Open to Closed

開発者会議で議論し、GVL 開放せずにループで良いだろうということになりました。
そしてさきほど r61292 で修正したので閉じます。(コミットログに書き忘れました。すみません)

----------------------------------------
Bug #13885: Random.urandom と securerandom について
https://bugs.ruby-lang.org/issues/13885#change-68454

* Author: mame (Yusuke Endoh)
* Status: Closed
* Priority: Normal
* Assignee: 
* Target version: 
* ruby -v: ruby 2.5.0dev (2017-09-09 trunk 59792) [x86_64-linux]
* Backport: 2.2: UNKNOWN, 2.3: UNKNOWN, 2.4: UNKNOWN
----------------------------------------
遠藤です。

Random.urandom と securerandom の仕様について卜部さんと話していて、いくつか気になる点が出てきたので挙げておきます。

1. Random.urandom は、getrandom(2) や (/dev/urandom に対する) read(2) システムコールを 1 回しか呼ばないようです。よって、要求量が大きくて 1 回では文字列を準備できないとき(例えば Random.urandom(100_000_000) )、失敗して nil を返します。これは意図的でしょうか。要求量が得られるまで(または他の要因で失敗するまで)繰り返し呼ぶべきではないでしょうか。
2. Random.urandom は失敗するとき、nil ではなく例外を投げるほうがよいのではないでしょうか。nil を返して実行が進んで幸せになるケースはあまり思い浮かびませんでした。
3. Random.urandom が nil を返す可能性があることは rdoc で明記されるべきではないでしょうか。(とりあえず r59803 で書き足しました。まずかったらすみません)
4. securerandom は、初回の呼び出しで Random.urandom が成功したらその後ずっと Random.urandom を使い、失敗したらずっと openssl を使うようになっています。これは本当に初回の呼び出しだけで振り分けるのでよいのでしょうか。具体的には、Random.urandom(0) は常に成功する(空文字列を返す)ので、実際には urandom が使えない環境でも urandom に固定される可能性があります。
5. 逆に、securerandom のバックエンドを動的に切り替えるようにしたら問題あるでしょうか。最初は成功していた Random.urandom が途中から失敗するようになったとき、openssl へフォールバックしても良いものでしょうか。また、Random.urandom が復活した場合、openssl から Random.urandom に戻すのは問題ないでしょうか。



-- 
https://bugs.ruby-lang.org/

^ permalink raw reply	[flat|nested] 8+ messages in thread

end of thread, other threads:[~2017-12-16  0:43 UTC | newest]

Thread overview: 8+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
     [not found] <redmine.issue-13885.20170909154049@ruby-lang.org>
2017-09-09 15:40 ` [ruby-dev:50231] [Ruby trunk Bug#13885] Random.urandom と securerandom について mame
2017-09-10  2:59 ` [ruby-dev:50232] " kosaki.motohiro
2017-09-10 12:24 ` [ruby-dev:50234] " shyouhei
2017-09-10 14:52 ` [ruby-dev:50235] " mame
2017-09-11  1:29 ` [ruby-dev:50237] " shyouhei
2017-09-11 12:46 ` [ruby-dev:50241] " mame
2017-09-14 11:40 ` [ruby-dev:50243] " mame
2017-12-16  0:43 ` [ruby-dev:50353] [Ruby trunk Bug#13885][Closed] " mame

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).