From patchwork Sun May 3 15:33:30 2015 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Stephan Mueller X-Patchwork-Id: 6321131 X-Patchwork-Delegate: herbert@gondor.apana.org.au Return-Path: X-Original-To: patchwork-linux-crypto@patchwork.kernel.org Delivered-To: patchwork-parsemail@patchwork1.web.kernel.org Received: from mail.kernel.org (mail.kernel.org [198.145.29.136]) by patchwork1.web.kernel.org (Postfix) with ESMTP id 5D92E9F32E for ; Sun, 3 May 2015 15:38:57 +0000 (UTC) Received: from mail.kernel.org (localhost [127.0.0.1]) by mail.kernel.org (Postfix) with ESMTP id 52413203AC for ; Sun, 3 May 2015 15:38:56 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.kernel.org (Postfix) with ESMTP id 441D2203A4 for ; Sun, 3 May 2015 15:38:55 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1750812AbbECPiv (ORCPT ); Sun, 3 May 2015 11:38:51 -0400 Received: from mail.eperm.de ([89.247.134.16]:34690 "EHLO mail.eperm.de" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1751122AbbECPh5 (ORCPT ); Sun, 3 May 2015 11:37:57 -0400 Received: from tachyon.chronox.de (mail.eperm.de [89.247.134.16]) by mail.eperm.de (Postfix) with ESMTPSA id 0DC9A2A005F; Sun, 3 May 2015 17:37:52 +0200 (CEST) From: Stephan Mueller To: herbert@gondor.apana.org.au Cc: Paul Bolle , Andreas Steffen , tytso@mit.edu, Sandy Harris , linux-kernel@vger.kernel.org, linux-crypto@vger.kernel.org Subject: [PATCH v4 1/6] random: Addition of kernel_pool Date: Sun, 03 May 2015 17:33:30 +0200 Message-ID: <1943994.Bq1YkXRtQR@tachyon.chronox.de> User-Agent: KMail/4.14.6 (Linux/3.19.5-200.fc21.x86_64; KDE/4.14.6; x86_64; ; ) In-Reply-To: <1626703.0h1HzJAx4d@tachyon.chronox.de> References: <1626703.0h1HzJAx4d@tachyon.chronox.de> MIME-Version: 1.0 Sender: linux-crypto-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-crypto@vger.kernel.org X-Spam-Status: No, score=-6.9 required=5.0 tests=BAYES_00, RCVD_IN_DNSWL_HI, T_RP_MATCHES_RCVD, UNPARSEABLE_RELAY autolearn=ham version=3.3.1 X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on mail.kernel.org X-Virus-Scanned: ClamAV using ClamSMTP The kernel pool is intended to serve kernel-internal callers only. Its purpose and usage is identical to the blocking_pool. As the kernel_pool is not available to user space, user space cannot directly interfere with the blocking behavior when obtaining data from the kernel_pool. Thus, if entropy is present in the kernel_pool, user space can hog /dev/random and yet the kernel internal requestor of random numbers that are generated equally to the blocking_pool (i.e. with the blocking behavior) will not be affected until data is needed from the input_pool. The patch treats the kernel_pool fully equally to the blocking and nonblocking pool with respect to the initialization and update. As now there are three output pools, the patch adds a round-robin logic for processing additional entropy when the input_pool is nearly full. CC: Andreas Steffen CC: Theodore Ts'o CC: Sandy Harris Signed-off-by: Stephan Mueller --- drivers/char/random.c | 52 ++++++++++++++++++++++++++++++++++++++------------- 1 file changed, 39 insertions(+), 13 deletions(-) diff --git a/drivers/char/random.c b/drivers/char/random.c index 9cd6968..0b139dc 100644 --- a/drivers/char/random.c +++ b/drivers/char/random.c @@ -407,6 +407,7 @@ static struct poolinfo { static DECLARE_WAIT_QUEUE_HEAD(random_read_wait); static DECLARE_WAIT_QUEUE_HEAD(random_write_wait); static DECLARE_WAIT_QUEUE_HEAD(urandom_init_wait); +static DECLARE_WAIT_QUEUE_HEAD(random_kernel_wait); static struct fasync_struct *fasync; /********************************************************************** @@ -442,6 +443,7 @@ static void push_to_pool(struct work_struct *work); static __u32 input_pool_data[INPUT_POOL_WORDS]; static __u32 blocking_pool_data[OUTPUT_POOL_WORDS]; static __u32 nonblocking_pool_data[OUTPUT_POOL_WORDS]; +static __u32 kernel_pool_data[OUTPUT_POOL_WORDS]; static struct entropy_store input_pool = { .poolinfo = &poolinfo_table[0], @@ -472,6 +474,17 @@ static struct entropy_store nonblocking_pool = { push_to_pool), }; +static struct entropy_store kernel_pool = { + .poolinfo = &poolinfo_table[1], + .name = "kernel", + .limit = 1, + .pull = &input_pool, + .lock = __SPIN_LOCK_UNLOCKED(kernel_pool.lock), + .pool = kernel_pool_data, + .push_work = __WORK_INITIALIZER(kernel_pool.push_work, + push_to_pool), +}; + static __u32 const twist_table[8] = { 0x00000000, 0x3b6e20c8, 0x76dc4190, 0x4db26158, 0xedb88320, 0xd6d6a3e8, 0x9b64c2b0, 0xa00ae278 }; @@ -674,29 +687,41 @@ retry: /* should we wake readers? */ if (entropy_bits >= random_read_wakeup_bits) { + wake_up_interruptible(&random_kernel_wait); wake_up_interruptible(&random_read_wait); kill_fasync(&fasync, SIGIO, POLL_IN); } /* If the input pool is getting full, send some - * entropy to the two output pools, flipping back and + * entropy to the output pools, flipping back and * forth between them, until the output pools are 75% * full. */ if (entropy_bits > random_write_wakeup_bits && r->initialized && r->entropy_total >= 2*random_read_wakeup_bits) { - static struct entropy_store *last = &blocking_pool; - struct entropy_store *other = &blocking_pool; - - if (last == &blocking_pool) - other = &nonblocking_pool; - if (other->entropy_count <= - 3 * other->poolinfo->poolfracbits / 4) - last = other; - if (last->entropy_count <= - 3 * last->poolinfo->poolfracbits / 4) { - schedule_work(&last->push_work); - r->entropy_total = 0; +#define NUM_OUTPUT_POOLS 3 + /* as we will recalculate this variable first thing in + * the loop, it will point to the first output pool + * after the first recalculation */ + static int selected_pool = (NUM_OUTPUT_POOLS - 1); + int i = 0; + struct entropy_store *output_pools[NUM_OUTPUT_POOLS] = { + &blocking_pool, + &nonblocking_pool, + &kernel_pool}; + /* select the next pool that has less than 75% fill + * rate */ + for (i = 0; NUM_OUTPUT_POOLS > i; i++) { + struct entropy_store *p = NULL; + selected_pool = + (selected_pool + 1) % NUM_OUTPUT_POOLS; + p = output_pools[selected_pool]; + if (p->entropy_count <= + 3 * p->poolinfo->poolfracbits / 4) { + schedule_work(&p->push_work); + r->entropy_total = 0; + break; + } } } } @@ -1318,6 +1343,7 @@ static int rand_initialize(void) init_std_data(&input_pool); init_std_data(&blocking_pool); init_std_data(&nonblocking_pool); + init_std_data(&kernel_pool); return 0; } early_initcall(rand_initialize);