/* The state must not straddle a page, since pages can be zeroed at any time. */ if (unlikely(((unsignedlong)opaque_state & ~PAGE_MASK) + sizeof(*state) > PAGE_SIZE)) return -EFAULT;
/* Handle unexpected flags by falling back to the kernel. */ if (unlikely(flags & ~(GRND_NONBLOCK | GRND_RANDOM | GRND_INSECURE))) goto fallback_syscall;
/* If the caller passes the wrong size, which might happen due to CRIU, fallback. */ if (unlikely(opaque_len != sizeof(*state))) goto fallback_syscall;
/* *Ifthekernel'sRNGisnotyetready,thenit'snotpossibletoproviderandombytesfrom *userspace,becauseA)thevarious@flagsrequirethistoblock,ornot,dependingon *variousfactorsunavailabletouserspace,andB)thekernel'sbehaviorbeforetheRNGis *readyistoreseedfromtheentropypoolateveryinvocation.
*/ if (unlikely(!READ_ONCE(rng_info->is_ready))) goto fallback_syscall;
/* *Thisconditionischeckedafter@rng_info->is_ready,becausebeforethekernel'sRNGis *initialized,the@flagsparametermayrequirethistoblockorreturnanerror,evenwhen *leniszero.
*/ if (unlikely(!len)) return0;
/* *@state->in_useisbasicreentrancyprotectionagainstthisrunninginasignalhandler *withthesame@opaque_state,butobviouslynotatomicwrtmultipleCPUsormorethanone *levelofreentrancy.Ifasignalinterruptsthisafterreading@state->in_use,butbefore *writing@state->in_use,thereisstillnorace,becausethesignalhandlerwillrunto *itscompletionbeforereturningexecution.
*/
in_use = READ_ONCE(state->in_use); if (unlikely(in_use)) /* The syscall simply fills the buffer and does not touch @state, so fallback. */ goto fallback_syscall;
WRITE_ONCE(state->in_use, true);
/* Set len to the total amount of bytes that this function is allowed to read, ret. */
len = ret;
more_batch: /* *Firstusebytesoutof@state->batch,whichmayhavebeenfilledbythelastcalltothis *function.
*/
batch_len = min_t(size_t, sizeof(state->batch) - state->pos, len); if (batch_len) { /* Zeroing at the same time as memcpying helps preserve forward secrecy. */
memcpy_and_zero_src(buffer, state->batch + state->pos, batch_len);
state->pos += batch_len;
buffer += batch_len;
len -= batch_len;
}
if (!len) { /* Prevent the loop from being reordered wrt ->generation. */
barrier();
/* Refill the batch and overwrite the key, in order to preserve forward secrecy. */
__arch_chacha20_blocks_nostack(state->batch_key, state->key, counter, sizeof(state->batch_key) / CHACHA_BLOCK_SIZE);
/* Since the batch was just refilled, set the position back to 0 to indicate a full batch. */
state->pos = 0; goto more_batch;
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.