Move substantive part of rnd_ioctl to kern_rndq.c.

This commit is contained in:
riastradh 2015-04-14 12:51:30 +00:00
parent 2ade1483d8
commit e75aac8fa3
3 changed files with 323 additions and 315 deletions

View File

@ -1,4 +1,4 @@
/* $NetBSD: rndpseudo.c,v 1.30 2015/04/14 12:27:02 riastradh Exp $ */
/* $NetBSD: rndpseudo.c,v 1.31 2015/04/14 12:51:30 riastradh Exp $ */
/*-
* Copyright (c) 1997-2013 The NetBSD Foundation, Inc.
@ -31,7 +31,7 @@
*/
#include <sys/cdefs.h>
__KERNEL_RCSID(0, "$NetBSD: rndpseudo.c,v 1.30 2015/04/14 12:27:02 riastradh Exp $");
__KERNEL_RCSID(0, "$NetBSD: rndpseudo.c,v 1.31 2015/04/14 12:51:30 riastradh Exp $");
#if defined(_KERNEL_OPT)
#include "opt_compat_netbsd.h"
@ -63,9 +63,6 @@ __KERNEL_RCSID(0, "$NetBSD: rndpseudo.c,v 1.30 2015/04/14 12:27:02 riastradh Exp
#include <sys/rnd.h>
#include <sys/rndpool.h>
#include <sys/rndsource.h>
#ifdef COMPAT_50
#include <compat/sys/rnd.h>
#endif
#include <dev/rnd_private.h>
@ -498,322 +495,17 @@ rnd_write(struct file *fp, off_t *offp, struct uio *uio,
return (ret);
}
static void
krndsource_to_rndsource(krndsource_t *kr, rndsource_t *r)
{
memset(r, 0, sizeof(*r));
strlcpy(r->name, kr->name, sizeof(r->name));
r->total = kr->total;
r->type = kr->type;
r->flags = kr->flags;
}
static void
krndsource_to_rndsource_est(krndsource_t *kr, rndsource_est_t *re)
{
memset(re, 0, sizeof(*re));
krndsource_to_rndsource(kr, &re->rt);
re->dt_samples = kr->time_delta.insamples;
re->dt_total = kr->time_delta.outbits;
re->dv_samples = kr->value_delta.insamples;
re->dv_total = kr->value_delta.outbits;
}
static void
krs_setflags(krndsource_t *kr, uint32_t flags, uint32_t mask)
{
uint32_t oflags = kr->flags;
kr->flags &= ~mask;
kr->flags |= (flags & mask);
if (oflags & RND_FLAG_HASENABLE &&
((oflags & RND_FLAG_NO_COLLECT) != (flags & RND_FLAG_NO_COLLECT))) {
kr->enable(kr, !(flags & RND_FLAG_NO_COLLECT));
}
}
int
rnd_ioctl(struct file *fp, u_long cmd, void *addr)
{
krndsource_t *kr;
rndstat_t *rst;
rndstat_name_t *rstnm;
rndstat_est_t *rset;
rndstat_est_name_t *rsetnm;
rndctl_t *rctl;
rnddata_t *rnddata;
uint32_t count, start;
int ret = 0;
int estimate_ok = 0, estimate = 0;
switch (cmd) {
case FIONBIO:
case FIOASYNC:
case RNDGETENTCNT:
break;
case RNDGETPOOLSTAT:
case RNDGETSRCNUM:
case RNDGETSRCNAME:
case RNDGETESTNUM:
case RNDGETESTNAME:
ret = kauth_authorize_device(curlwp->l_cred,
KAUTH_DEVICE_RND_GETPRIV, NULL, NULL, NULL, NULL);
if (ret)
return (ret);
break;
case RNDCTL:
ret = kauth_authorize_device(curlwp->l_cred,
KAUTH_DEVICE_RND_SETPRIV, NULL, NULL, NULL, NULL);
if (ret)
return (ret);
break;
case RNDADDDATA:
ret = kauth_authorize_device(curlwp->l_cred,
KAUTH_DEVICE_RND_ADDDATA, NULL, NULL, NULL, NULL);
if (ret)
return (ret);
estimate_ok = !kauth_authorize_device(curlwp->l_cred,
KAUTH_DEVICE_RND_ADDDATA_ESTIMATE, NULL, NULL, NULL, NULL);
break;
return 0;
default:
#ifdef COMPAT_50
return compat_50_rnd_ioctl(fp, cmd, addr);
#else
return ENOTTY;
#endif
return rnd_system_ioctl(fp, cmd, addr);
}
switch (cmd) {
/*
* Handled in upper layer really, but we have to return zero
* for it to be accepted by the upper layer.
*/
case FIONBIO:
case FIOASYNC:
break;
case RNDGETENTCNT:
mutex_spin_enter(&rndpool_mtx);
*(uint32_t *)addr = rndpool_get_entropy_count(&rnd_pool);
mutex_spin_exit(&rndpool_mtx);
break;
case RNDGETPOOLSTAT:
mutex_spin_enter(&rndpool_mtx);
rndpool_get_stats(&rnd_pool, addr, sizeof(rndpoolstat_t));
mutex_spin_exit(&rndpool_mtx);
break;
case RNDGETSRCNUM:
rst = (rndstat_t *)addr;
if (rst->count == 0)
break;
if (rst->count > RND_MAXSTATCOUNT)
return (EINVAL);
mutex_spin_enter(&rndpool_mtx);
/*
* Find the starting source by running through the
* list of sources.
*/
kr = LIST_FIRST(&rnd_sources);
start = rst->start;
while (kr != NULL && start >= 1) {
kr = LIST_NEXT(kr, list);
start--;
}
/*
* Return up to as many structures as the user asked
* for. If we run out of sources, a count of zero
* will be returned, without an error.
*/
for (count = 0; count < rst->count && kr != NULL; count++) {
krndsource_to_rndsource(kr, &rst->source[count]);
kr = LIST_NEXT(kr, list);
}
rst->count = count;
mutex_spin_exit(&rndpool_mtx);
break;
case RNDGETESTNUM:
rset = (rndstat_est_t *)addr;
if (rset->count == 0)
break;
if (rset->count > RND_MAXSTATCOUNT)
return (EINVAL);
mutex_spin_enter(&rndpool_mtx);
/*
* Find the starting source by running through the
* list of sources.
*/
kr = LIST_FIRST(&rnd_sources);
start = rset->start;
while (kr != NULL && start > 1) {
kr = LIST_NEXT(kr, list);
start--;
}
/* Return up to as many structures as the user asked
* for. If we run out of sources, a count of zero
* will be returned, without an error.
*/
for (count = 0; count < rset->count && kr != NULL; count++) {
krndsource_to_rndsource_est(kr, &rset->source[count]);
kr = LIST_NEXT(kr, list);
}
rset->count = count;
mutex_spin_exit(&rndpool_mtx);
break;
case RNDGETSRCNAME:
/*
* Scan through the list, trying to find the name.
*/
mutex_spin_enter(&rndpool_mtx);
rstnm = (rndstat_name_t *)addr;
kr = LIST_FIRST(&rnd_sources);
while (kr != NULL) {
if (strncmp(kr->name, rstnm->name,
MIN(sizeof(kr->name),
sizeof(rstnm->name))) == 0) {
krndsource_to_rndsource(kr, &rstnm->source);
mutex_spin_exit(&rndpool_mtx);
return (0);
}
kr = LIST_NEXT(kr, list);
}
mutex_spin_exit(&rndpool_mtx);
ret = ENOENT; /* name not found */
break;
case RNDGETESTNAME:
/*
* Scan through the list, trying to find the name.
*/
mutex_spin_enter(&rndpool_mtx);
rsetnm = (rndstat_est_name_t *)addr;
kr = LIST_FIRST(&rnd_sources);
while (kr != NULL) {
if (strncmp(kr->name, rsetnm->name,
MIN(sizeof(kr->name),
sizeof(rsetnm->name))) == 0) {
krndsource_to_rndsource_est(kr,
&rsetnm->source);
mutex_spin_exit(&rndpool_mtx);
return (0);
}
kr = LIST_NEXT(kr, list);
}
mutex_spin_exit(&rndpool_mtx);
ret = ENOENT; /* name not found */
break;
case RNDCTL:
/*
* Set flags to enable/disable entropy counting and/or
* collection.
*/
mutex_spin_enter(&rndpool_mtx);
rctl = (rndctl_t *)addr;
kr = LIST_FIRST(&rnd_sources);
/*
* Flags set apply to all sources of this type.
*/
if (rctl->type != 0xff) {
while (kr != NULL) {
if (kr->type == rctl->type) {
krs_setflags(kr,
rctl->flags, rctl->mask);
}
kr = LIST_NEXT(kr, list);
}
mutex_spin_exit(&rndpool_mtx);
return (0);
}
/*
* scan through the list, trying to find the name
*/
while (kr != NULL) {
if (strncmp(kr->name, rctl->name,
MIN(sizeof(kr->name),
sizeof(rctl->name))) == 0) {
krs_setflags(kr, rctl->flags, rctl->mask);
mutex_spin_exit(&rndpool_mtx);
return (0);
}
kr = LIST_NEXT(kr, list);
}
mutex_spin_exit(&rndpool_mtx);
ret = ENOENT; /* name not found */
break;
case RNDADDDATA:
/*
* Don't seed twice if our bootloader has
* seed loading support.
*/
if (!boot_rsp) {
rnddata = (rnddata_t *)addr;
if (rnddata->len > sizeof(rnddata->data))
return EINVAL;
if (estimate_ok) {
/*
* Do not accept absurd entropy estimates, and
* do not flood the pool with entropy such that
* new samples are discarded henceforth.
*/
estimate = MIN((rnddata->len * NBBY) / 2,
MIN(rnddata->entropy,
RND_POOLBITS / 2));
} else {
estimate = 0;
}
mutex_spin_enter(&rndpool_mtx);
rndpool_add_data(&rnd_pool, rnddata->data,
rnddata->len, estimate);
mutex_spin_exit(&rndpool_mtx);
rnd_wakeup_readers();
}
#ifdef RND_VERBOSE
else {
printf("rnd: already seeded by boot loader\n");
}
#endif
break;
default:
return ENOTTY;
}
return (ret);
}
static int

View File

@ -1,4 +1,4 @@
/* $NetBSD: kern_rndq.c,v 1.52 2015/04/14 12:35:44 riastradh Exp $ */
/* $NetBSD: kern_rndq.c,v 1.53 2015/04/14 12:51:30 riastradh Exp $ */
/*-
* Copyright (c) 1997-2013 The NetBSD Foundation, Inc.
@ -32,7 +32,7 @@
*/
#include <sys/cdefs.h>
__KERNEL_RCSID(0, "$NetBSD: kern_rndq.c,v 1.52 2015/04/14 12:35:44 riastradh Exp $");
__KERNEL_RCSID(0, "$NetBSD: kern_rndq.c,v 1.53 2015/04/14 12:51:30 riastradh Exp $");
#include <sys/param.h>
#include <sys/atomic.h>
@ -60,6 +60,10 @@ __KERNEL_RCSID(0, "$NetBSD: kern_rndq.c,v 1.52 2015/04/14 12:35:44 riastradh Exp
#include <dev/rnd_private.h>
#ifdef COMPAT_50
#include <compat/sys/rnd.h>
#endif
#if defined(__HAVE_CPU_COUNTER)
#include <machine/cpu_counter.h>
#endif
@ -1309,3 +1313,310 @@ rnd_seed(void *base, size_t len)
rnd_printf_verbose("rnd: not ready, deferring seed feed.\n");
}
}
static void
krndsource_to_rndsource(krndsource_t *kr, rndsource_t *r)
{
memset(r, 0, sizeof(*r));
strlcpy(r->name, kr->name, sizeof(r->name));
r->total = kr->total;
r->type = kr->type;
r->flags = kr->flags;
}
static void
krndsource_to_rndsource_est(krndsource_t *kr, rndsource_est_t *re)
{
memset(re, 0, sizeof(*re));
krndsource_to_rndsource(kr, &re->rt);
re->dt_samples = kr->time_delta.insamples;
re->dt_total = kr->time_delta.outbits;
re->dv_samples = kr->value_delta.insamples;
re->dv_total = kr->value_delta.outbits;
}
static void
krs_setflags(krndsource_t *kr, uint32_t flags, uint32_t mask)
{
uint32_t oflags = kr->flags;
kr->flags &= ~mask;
kr->flags |= (flags & mask);
if (oflags & RND_FLAG_HASENABLE &&
((oflags & RND_FLAG_NO_COLLECT) != (flags & RND_FLAG_NO_COLLECT))) {
kr->enable(kr, !(flags & RND_FLAG_NO_COLLECT));
}
}
int
rnd_system_ioctl(struct file *fp, u_long cmd, void *addr)
{
krndsource_t *kr;
rndstat_t *rst;
rndstat_name_t *rstnm;
rndstat_est_t *rset;
rndstat_est_name_t *rsetnm;
rndctl_t *rctl;
rnddata_t *rnddata;
uint32_t count, start;
int ret = 0;
int estimate_ok = 0, estimate = 0;
switch (cmd) {
case RNDGETENTCNT:
break;
case RNDGETPOOLSTAT:
case RNDGETSRCNUM:
case RNDGETSRCNAME:
case RNDGETESTNUM:
case RNDGETESTNAME:
ret = kauth_authorize_device(curlwp->l_cred,
KAUTH_DEVICE_RND_GETPRIV, NULL, NULL, NULL, NULL);
if (ret)
return (ret);
break;
case RNDCTL:
ret = kauth_authorize_device(curlwp->l_cred,
KAUTH_DEVICE_RND_SETPRIV, NULL, NULL, NULL, NULL);
if (ret)
return (ret);
break;
case RNDADDDATA:
ret = kauth_authorize_device(curlwp->l_cred,
KAUTH_DEVICE_RND_ADDDATA, NULL, NULL, NULL, NULL);
if (ret)
return (ret);
estimate_ok = !kauth_authorize_device(curlwp->l_cred,
KAUTH_DEVICE_RND_ADDDATA_ESTIMATE, NULL, NULL, NULL, NULL);
break;
default:
#ifdef COMPAT_50
return compat_50_rnd_ioctl(fp, cmd, addr);
#else
return ENOTTY;
#endif
}
switch (cmd) {
case RNDGETENTCNT:
mutex_spin_enter(&rndpool_mtx);
*(uint32_t *)addr = rndpool_get_entropy_count(&rnd_pool);
mutex_spin_exit(&rndpool_mtx);
break;
case RNDGETPOOLSTAT:
mutex_spin_enter(&rndpool_mtx);
rndpool_get_stats(&rnd_pool, addr, sizeof(rndpoolstat_t));
mutex_spin_exit(&rndpool_mtx);
break;
case RNDGETSRCNUM:
rst = (rndstat_t *)addr;
if (rst->count == 0)
break;
if (rst->count > RND_MAXSTATCOUNT)
return (EINVAL);
mutex_spin_enter(&rndpool_mtx);
/*
* Find the starting source by running through the
* list of sources.
*/
kr = LIST_FIRST(&rnd_sources);
start = rst->start;
while (kr != NULL && start >= 1) {
kr = LIST_NEXT(kr, list);
start--;
}
/*
* Return up to as many structures as the user asked
* for. If we run out of sources, a count of zero
* will be returned, without an error.
*/
for (count = 0; count < rst->count && kr != NULL; count++) {
krndsource_to_rndsource(kr, &rst->source[count]);
kr = LIST_NEXT(kr, list);
}
rst->count = count;
mutex_spin_exit(&rndpool_mtx);
break;
case RNDGETESTNUM:
rset = (rndstat_est_t *)addr;
if (rset->count == 0)
break;
if (rset->count > RND_MAXSTATCOUNT)
return (EINVAL);
mutex_spin_enter(&rndpool_mtx);
/*
* Find the starting source by running through the
* list of sources.
*/
kr = LIST_FIRST(&rnd_sources);
start = rset->start;
while (kr != NULL && start > 1) {
kr = LIST_NEXT(kr, list);
start--;
}
/* Return up to as many structures as the user asked
* for. If we run out of sources, a count of zero
* will be returned, without an error.
*/
for (count = 0; count < rset->count && kr != NULL; count++) {
krndsource_to_rndsource_est(kr, &rset->source[count]);
kr = LIST_NEXT(kr, list);
}
rset->count = count;
mutex_spin_exit(&rndpool_mtx);
break;
case RNDGETSRCNAME:
/*
* Scan through the list, trying to find the name.
*/
mutex_spin_enter(&rndpool_mtx);
rstnm = (rndstat_name_t *)addr;
kr = LIST_FIRST(&rnd_sources);
while (kr != NULL) {
if (strncmp(kr->name, rstnm->name,
MIN(sizeof(kr->name),
sizeof(rstnm->name))) == 0) {
krndsource_to_rndsource(kr, &rstnm->source);
mutex_spin_exit(&rndpool_mtx);
return (0);
}
kr = LIST_NEXT(kr, list);
}
mutex_spin_exit(&rndpool_mtx);
ret = ENOENT; /* name not found */
break;
case RNDGETESTNAME:
/*
* Scan through the list, trying to find the name.
*/
mutex_spin_enter(&rndpool_mtx);
rsetnm = (rndstat_est_name_t *)addr;
kr = LIST_FIRST(&rnd_sources);
while (kr != NULL) {
if (strncmp(kr->name, rsetnm->name,
MIN(sizeof(kr->name),
sizeof(rsetnm->name))) == 0) {
krndsource_to_rndsource_est(kr,
&rsetnm->source);
mutex_spin_exit(&rndpool_mtx);
return (0);
}
kr = LIST_NEXT(kr, list);
}
mutex_spin_exit(&rndpool_mtx);
ret = ENOENT; /* name not found */
break;
case RNDCTL:
/*
* Set flags to enable/disable entropy counting and/or
* collection.
*/
mutex_spin_enter(&rndpool_mtx);
rctl = (rndctl_t *)addr;
kr = LIST_FIRST(&rnd_sources);
/*
* Flags set apply to all sources of this type.
*/
if (rctl->type != 0xff) {
while (kr != NULL) {
if (kr->type == rctl->type) {
krs_setflags(kr,
rctl->flags, rctl->mask);
}
kr = LIST_NEXT(kr, list);
}
mutex_spin_exit(&rndpool_mtx);
return (0);
}
/*
* scan through the list, trying to find the name
*/
while (kr != NULL) {
if (strncmp(kr->name, rctl->name,
MIN(sizeof(kr->name),
sizeof(rctl->name))) == 0) {
krs_setflags(kr, rctl->flags, rctl->mask);
mutex_spin_exit(&rndpool_mtx);
return (0);
}
kr = LIST_NEXT(kr, list);
}
mutex_spin_exit(&rndpool_mtx);
ret = ENOENT; /* name not found */
break;
case RNDADDDATA:
/*
* Don't seed twice if our bootloader has
* seed loading support.
*/
if (!boot_rsp) {
rnddata = (rnddata_t *)addr;
if (rnddata->len > sizeof(rnddata->data))
return EINVAL;
if (estimate_ok) {
/*
* Do not accept absurd entropy estimates, and
* do not flood the pool with entropy such that
* new samples are discarded henceforth.
*/
estimate = MIN((rnddata->len * NBBY) / 2,
MIN(rnddata->entropy,
RND_POOLBITS / 2));
} else {
estimate = 0;
}
mutex_spin_enter(&rndpool_mtx);
rndpool_add_data(&rnd_pool, rnddata->data,
rnddata->len, estimate);
mutex_spin_exit(&rndpool_mtx);
rnd_wakeup_readers();
}
#ifdef RND_VERBOSE
else {
printf("rnd: already seeded by boot loader\n");
}
#endif
break;
default:
return ENOTTY;
}
return (ret);
}

View File

@ -1,4 +1,4 @@
/* $NetBSD: rnd.h,v 1.48 2015/04/13 22:52:52 riastradh Exp $ */
/* $NetBSD: rnd.h,v 1.49 2015/04/14 12:51:30 riastradh Exp $ */
/*-
* Copyright (c) 1997 The NetBSD Foundation, Inc.
@ -35,12 +35,17 @@
#ifdef _KERNEL
#include <sys/types.h>
struct file;
#define RND_DEV_RANDOM 0 /* minor for blocking until unpredictable */
#define RND_DEV_URANDOM 1 /* minor for randomly generating data */
void rnd_init(void);
void rnd_init_softint(void);
void rnd_seed(void *, size_t);
int rnd_system_ioctl(struct file *, u_long, void *);
extern int rnd_initial_entropy;