in nsm-driver/nsm.c [563:658]
static int nsm_rng_read(struct hwrng *rng, void *data, size_t max, bool wait)
{
int rc = 0;
uint8_t *resp_ptr = NULL;
uint64_t resp_len = 0;
uint8_t *rand_data = NULL;
struct nsm_kernel_message message;
/*
* 69 # text(9)
* 47657452616E646F6D # "GetRandom"
*/
const uint8_t request[] = { 0x69, 0x47, 0x65, 0x74, 0x52, 0x61, 0x6E, 0x64, 0x6F, 0x6D };
/*
* A1 # map(1)
* 69 # text(9) - Name of field
* 47657452616E646F6D # "GetRandom"
* A1 # map(1) - The field itself
* 66 # text(6)
* 72616E646F6D # "random"
* # The rest of the response should be a byte array
*/
const uint8_t response[] = { 0xA1, 0x69, 0x47, 0x65, 0x74, 0x52, 0x61, 0x6E, 0x64,
0x6F, 0x6D, 0xA1, 0x66, 0x72, 0x61, 0x6E, 0x64, 0x6F, 0x6D };
if (wait == true) {
mutex_lock(&nsm_lock);
} else {
if (mutex_trylock(&nsm_lock) == 0)
return -EBUSY;
}
/* The kernel message structure must be cleared */
memset(&message, 0, sizeof(message));
/* Set request message */
message.request.iov_len = sizeof(request);
message.request.iov_base = kmalloc(message.request.iov_len, GFP_KERNEL);
if (message.request.iov_base == NULL)
goto out;
memcpy(message.request.iov_base, request, sizeof(request));
/* Allocate space for response */
message.response.iov_len = NSM_RESPONSE_MAX_SIZE;
message.response.iov_base = kmalloc(message.response.iov_len, GFP_KERNEL);
if (message.response.iov_base == NULL)
goto out;
/* Send/receive message */
rc = nsm_communicate_with_device(&message);
if (rc != 0)
goto out;
resp_ptr = (uint8_t *) message.response.iov_base;
resp_len = message.response.iov_len;
if (resp_len < sizeof(response) + 1) {
pr_err("NSM RNG: Received short response from NSM: Possible error message or invalid response");
rc = -EFAULT;
goto out;
}
if (memcmp(resp_ptr, response, sizeof(response)) != 0) {
pr_err("NSM RNG: Invalid response header: Possible error message or invalid response");
rc = -EFAULT;
goto out;
}
resp_ptr += sizeof(response);
resp_len -= sizeof(response);
if (!cbor_object_is_array(resp_ptr, resp_len)) {
/* not a byte array */
pr_err("NSM RNG: Invalid response type: Expecting a byte array response");
rc = -EFAULT;
goto out;
}
rc = cbor_object_get_array(resp_ptr, resp_len, &rand_data);
if (rc < 0) {
pr_err("NSM RNG: Invalid CBOR encoding\n");
goto out;
}
max = max > INT_MAX ? INT_MAX : max;
rc = rc > max ? max : rc;
memcpy(data, rand_data, rc);
pr_info("NSM RNG: returning rand bytes = %d\n", rc);
out:
message_delete(&message);
mutex_unlock(&nsm_lock);
return rc;
}