xref: /xnu-8796.101.5/osfmk/prng/entropy.c (revision aca3beaa3dfbd42498b42c5e5ce20a938e6554e5)
1 /*
2  * Copyright (c) 2019 Apple Inc. All rights reserved.
3  *
4  * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
5  *
6  * This file contains Original Code and/or Modifications of Original Code
7  * as defined in and that are subject to the Apple Public Source License
8  * Version 2.0 (the 'License'). You may not use this file except in
9  * compliance with the License. The rights granted to you under the License
10  * may not be used to create, or enable the creation or redistribution of,
11  * unlawful or unlicensed copies of an Apple operating system, or to
12  * circumvent, violate, or enable the circumvention or violation of, any
13  * terms of an Apple operating system software license agreement.
14  *
15  * Please obtain a copy of the License at
16  * http://www.opensource.apple.com/apsl/ and read it before using this file.
17  *
18  * The Original Code and all software distributed under the License are
19  * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
20  * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
21  * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
22  * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
23  * Please see the License for the specific language governing rights and
24  * limitations under the License.
25  *
26  * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
27  */
28 
29 #include <libkern/crypto/sha2.h>
30 #include <libkern/crypto/crypto.h>
31 #include <os/atomic_private.h>
32 #include <kern/assert.h>
33 #include <kern/percpu.h>
34 #include <kern/zalloc.h>
35 #include <kern/lock_group.h>
36 #include <kern/locks.h>
37 #include <kern/misc_protos.h>
38 #include <pexpert/pexpert.h>
39 #include <prng/entropy.h>
40 #include <machine/machine_routines.h>
41 #include <libkern/section_keywords.h>
42 #include <sys/cdefs.h>
43 
44 // The number of samples we can hold in an entropy buffer.
45 #define ENTROPY_MAX_SAMPLE_COUNT (2048)
46 
47 // The length of a bitmap_t array with one bit per sample of an
48 // entropy buffer.
49 #define ENTROPY_MAX_FILTER_COUNT (BITMAP_LEN(ENTROPY_MAX_SAMPLE_COUNT))
50 
51 // The threshold of approximate linearity used in the entropy
52 // filter. See the entropy_filter function for more discussion.
53 #define ENTROPY_FILTER_THRESHOLD (8)
54 
55 // The state for a per-CPU entropy buffer.
56 typedef struct entropy_cpu_data {
57 	// A buffer to hold entropy samples.
58 	entropy_sample_t samples[ENTROPY_MAX_SAMPLE_COUNT];
59 
60 	// A count of samples resident in the buffer. It also functions as
61 	// an index to the buffer. All entries at indices less than the
62 	// sample count are considered valid for consumption by the
63 	// reader. The reader resets this to zero after consuming the
64 	// available entropy.
65 	uint32_t _Atomic sample_count;
66 } entropy_cpu_data_t;
67 
68 // This structure holds the state for an instance of a FIPS continuous
69 // health test. In practice, we do not expect these tests to fail.
70 typedef struct entropy_health_test {
71 	// The initial sample observed in this test instance. Tests look
72 	// for some repetition of the sample, either consecutively or
73 	// within a window.
74 	entropy_sample_t init_observation;
75 
76 	// The count of times the initial observation has recurred within
77 	// the span of the current test.
78 	uint64_t observation_count;
79 
80 	// The statistics are only relevant for telemetry and parameter
81 	// tuning. They do not drive any actual logic in the module.
82 	entropy_health_stats_t *stats;
83 } entropy_health_test_t;
84 
85 typedef enum health_test_result {
86 	health_test_failure,
87 	health_test_success
88 } health_test_result_t;
89 
90 // Along with various counters and the buffer itself, this includes
91 // the state for two FIPS continuous health tests.
92 typedef struct entropy_data {
93 	// State for a SHA256 computation. This is used to accumulate
94 	// entropy samples from across all CPUs. It is finalized when
95 	// entropy is provided to the consumer of this module.
96 	SHA256_CTX sha256_ctx;
97 
98 	// Since the corecrypto kext is not loaded when this module is
99 	// initialized, we cannot initialize the SHA256 state at that
100 	// time. Instead, we initialize it lazily during entropy
101 	// consumption. This flag tracks whether initialization is
102 	// complete.
103 	bool sha256_ctx_init;
104 
105 	// A buffer to hold a bitmap with one bit per sample of an entropy
106 	// buffer. We are able to reuse this instance across all the
107 	// per-CPU entropy buffers to save space.
108 	bitmap_t filter[ENTROPY_MAX_FILTER_COUNT];
109 
110 	// A total count of entropy samples that have passed through this
111 	// structure. It is incremented as new samples are accumulated
112 	// from the various per-CPU structures. The "current" count of
113 	// samples is the difference between this field and the "read"
114 	// sample count below (which see).
115 	uint64_t total_sample_count;
116 
117 	// Initially zero, this flag is reset to the current sample count
118 	// if and when we fail a health test. We consider the startup
119 	// health tests to be complete when the difference between the
120 	// total sample count and this field is at least 1024. In other
121 	// words, we must accumulate 1024 good samples to demonstrate
122 	// viability. We refuse to provide any entropy before that
123 	// threshold is reached.
124 	uint64_t startup_sample_count;
125 
126 	// The count of samples from the last time we provided entropy to
127 	// the kernel RNG. We use this to compute how many new samples we
128 	// have to contribute. This value is also reset to the current
129 	// sample count in case of health test failure.
130 	uint64_t read_sample_count;
131 
132 	// The lock group for this structure; see below.
133 	lck_grp_t lock_group;
134 
135 	// This structure accumulates entropy samples from across all CPUs
136 	// for a single point of consumption protected by a mutex.
137 	lck_mtx_t mutex;
138 
139 	// State for the Repetition Count Test.
140 	entropy_health_test_t repetition_count_test;
141 
142 	// State for the Adaptive Proportion Test.
143 	entropy_health_test_t adaptive_proportion_test;
144 } entropy_data_t;
145 
146 static entropy_cpu_data_t PERCPU_DATA(entropy_cpu_data);
147 
148 int entropy_health_startup_done;
149 entropy_health_stats_t entropy_health_rct_stats;
150 entropy_health_stats_t entropy_health_apt_stats;
151 uint64_t entropy_filter_accepted_sample_count;
152 uint64_t entropy_filter_rejected_sample_count;
153 uint64_t entropy_filter_total_sample_count;
154 
155 static entropy_data_t entropy_data = {
156 	.repetition_count_test = {
157 		.init_observation = -1,
158 		.stats = &entropy_health_rct_stats,
159 	},
160 	.adaptive_proportion_test = {
161 		.init_observation = -1,
162 		.stats = &entropy_health_apt_stats,
163 	},
164 };
165 
166 #if ENTROPY_ANALYSIS_SUPPORTED
167 
168 __security_const_late int entropy_analysis_enabled;
169 __security_const_late entropy_sample_t *entropy_analysis_buffer;
170 __security_const_late uint32_t entropy_analysis_buffer_size;
171 __security_const_late uint32_t entropy_analysis_filter_size;
172 __security_const_late uint32_t entropy_analysis_max_sample_count;
173 uint32_t entropy_analysis_sample_count;
174 
175 __startup_func
176 static void
entropy_analysis_init(uint32_t sample_count)177 entropy_analysis_init(uint32_t sample_count)
178 {
179 	entropy_analysis_enabled = 1;
180 	entropy_analysis_max_sample_count = sample_count;
181 	entropy_analysis_buffer_size = sample_count * sizeof(entropy_sample_t);
182 	entropy_analysis_buffer = zalloc_permanent(entropy_analysis_buffer_size, ZALIGN(entropy_sample_t));
183 	entropy_analysis_filter_size = (uint32_t) BITMAP_SIZE(entropy_analysis_max_sample_count);
184 }
185 
186 static void
entropy_analysis_store(entropy_sample_t sample)187 entropy_analysis_store(entropy_sample_t sample)
188 {
189 	uint32_t sample_count;
190 	uint32_t next_sample_count;
191 
192 	os_atomic_rmw_loop(&entropy_analysis_sample_count, sample_count, next_sample_count, relaxed, {
193 		if (sample_count >= entropy_analysis_max_sample_count) {
194 		        os_atomic_rmw_loop_give_up(return );
195 		}
196 
197 		next_sample_count = sample_count + 1;
198 	});
199 
200 	entropy_analysis_buffer[sample_count] = sample;
201 }
202 
203 #endif  // ENTROPY_ANALYSIS_SUPPORTED
204 
205 __startup_func
206 void
entropy_init(void)207 entropy_init(void)
208 {
209 	lck_grp_init(&entropy_data.lock_group, "entropy-data", LCK_GRP_ATTR_NULL);
210 	lck_mtx_init(&entropy_data.mutex, &entropy_data.lock_group, LCK_ATTR_NULL);
211 
212 #if ENTROPY_ANALYSIS_SUPPORTED
213 	// The below path is used only for testing. This boot arg is used
214 	// to collect raw entropy samples for offline analysis.
215 	uint32_t sample_count = 0;
216 	if (__improbable(PE_parse_boot_argn(ENTROPY_ANALYSIS_BOOTARG, &sample_count, sizeof(sample_count)))) {
217 		entropy_analysis_init(sample_count);
218 	}
219 #endif  // ENTROPY_ANALYSIS_SUPPORTED
220 }
221 
222 void
entropy_collect(void)223 entropy_collect(void)
224 {
225 	// This function is called from within the interrupt handler, so
226 	// we do not need to disable interrupts.
227 
228 	entropy_cpu_data_t *e = PERCPU_GET(entropy_cpu_data);
229 
230 	uint32_t sample_count = os_atomic_load(&e->sample_count, relaxed);
231 
232 	assert(sample_count <= ENTROPY_MAX_SAMPLE_COUNT);
233 
234 	// If the buffer is full, we return early without collecting
235 	// entropy.
236 	if (sample_count == ENTROPY_MAX_SAMPLE_COUNT) {
237 		return;
238 	}
239 
240 	entropy_sample_t sample = (entropy_sample_t)ml_get_timebase_entropy();
241 	e->samples[sample_count] = sample;
242 
243 	// If the consumer has reset the sample count on us, the only
244 	// consequence is a dropped sample. We effectively abort the
245 	// entropy collection in this case.
246 	(void)os_atomic_cmpxchg(&e->sample_count, sample_count, sample_count + 1, release);
247 
248 #if ENTROPY_ANALYSIS_SUPPORTED
249 	// This code path is only used for testing. Its use is governed by
250 	// a boot arg; see its initialization above.
251 	if (__improbable(entropy_analysis_buffer)) {
252 		entropy_analysis_store(sample);
253 	}
254 #endif  // ENTROPY_ANALYSIS_SUPPORTED
255 }
256 
257 // This filter looks at the 1st differential (differences of subsequent
258 // timestamp values) and the 2nd differential (differences of subsequent
259 // 1st differentials). This filter will detect sequences of timestamps
260 // that are linear (that is, the 2nd differential is close to zero).
261 // Timestamps with a 2nd differential above the threshold ENTROPY_FILTER_THRESHOLD
262 // will be marked in the filter bitmap. 2nd differentials below the threshold
263 // will not be counted nor included in the filter bitmap.
264 //
265 // For example imagine the following sequence of 8-bit timestamps:
266 //
267 //  [25, 100, 175, 250, 69, 144, 219, 38, 113, 188]
268 //
269 // The 1st differential between timestamps is as follows:
270 //
271 //  [75, 75, 75, 75, 75, 75, 75, 75, 75]
272 //
273 // The 2nd differential is as follows:
274 //
275 //  [0, 0, 0, 0, 0, 0, 0, 0]
276 //
277 // The first two samples of any set of samples are always included as
278 // there is no 2nd differential to compare against. Thus all but
279 // the first two samples in this example will be removed.
280 uint32_t
entropy_filter(uint32_t sample_count,entropy_sample_t * samples,__assert_only uint32_t filter_count,bitmap_t * filter)281 entropy_filter(uint32_t sample_count, entropy_sample_t *samples, __assert_only uint32_t filter_count, bitmap_t *filter)
282 {
283 	assert(filter_count >= BITMAP_LEN(sample_count));
284 
285 	bitmap_zero(filter, sample_count);
286 
287 	// We always keep the first one (or two) sample(s) if we have at least one (or more) samples
288 	if (sample_count == 0) {
289 		return 0;
290 	} else if (sample_count == 1) {
291 		bitmap_set(filter, 0);
292 		return 1;
293 	} else if (sample_count == 2) {
294 		bitmap_set(filter, 0);
295 		bitmap_set(filter, 1);
296 		return 2;
297 	} else {
298 		bitmap_set(filter, 0);
299 		bitmap_set(filter, 1);
300 	}
301 
302 	uint32_t filtered_sample_count = 2;
303 
304 	// We don't care about underflows when computing any differential
305 	entropy_sample_t prev_1st_differential = samples[1] - samples[0];
306 
307 	for (uint i = 2; i < sample_count; i++) {
308 		entropy_sample_t curr_1st_differential = samples[i] - samples[i - 1];
309 
310 		entropy_sample_t curr_2nd_differential = curr_1st_differential - prev_1st_differential;
311 
312 		if (curr_2nd_differential > ENTROPY_FILTER_THRESHOLD && curr_2nd_differential < ((entropy_sample_t) -ENTROPY_FILTER_THRESHOLD)) {
313 			bitmap_set(filter, i);
314 			filtered_sample_count += 1;
315 		}
316 
317 		prev_1st_differential = curr_1st_differential;
318 	}
319 
320 	return filtered_sample_count;
321 }
322 
323 // For information on the following tests, see NIST SP 800-90B 4
324 // Health Tests. These tests are intended to detect catastrophic
325 // degradations in entropy. As noted in that document:
326 //
327 // > Health tests are expected to raise an alarm in three cases:
328 // > 1. When there is a significant decrease in the entropy of the
329 // > outputs,
330 // > 2. When noise source failures occur, or
331 // > 3. When hardware fails, and implementations do not work
332 // > correctly.
333 //
334 // Each entropy accumulator declines to release entropy until the
335 // startup tests required by NIST are complete. In the event that a
336 // health test does fail, all entropy accumulators are reset and
337 // decline to release further entropy until their startup tests can be
338 // repeated.
339 
340 static health_test_result_t
add_observation(entropy_health_test_t * t,uint64_t bound)341 add_observation(entropy_health_test_t *t, uint64_t bound)
342 {
343 	t->observation_count += 1;
344 	t->stats->max_observation_count = MAX(t->stats->max_observation_count, (uint32_t)t->observation_count);
345 	if (__improbable(t->observation_count >= bound)) {
346 		t->stats->failure_count += 1;
347 		return health_test_failure;
348 	}
349 
350 	return health_test_success;
351 }
352 
353 static void
reset_test(entropy_health_test_t * t,entropy_sample_t observation)354 reset_test(entropy_health_test_t *t, entropy_sample_t observation)
355 {
356 	t->stats->reset_count += 1;
357 	t->init_observation = observation;
358 	t->observation_count = 1;
359 	t->stats->max_observation_count = MAX(t->stats->max_observation_count, (uint32_t)t->observation_count);
360 }
361 
362 // 4.4.1 Repetition Count Test
363 //
364 // Like the name implies, this test counts consecutive occurrences of
365 // the same value.
366 //
367 // We compute the bound C as:
368 //
369 // A = 2^-40
370 // H = 1
371 // C = 1 + ceil(-log(A, 2) / H) = 41
372 //
373 // With A the acceptable chance of false positive and H a conservative
374 // estimate for the min-entropy (in bits) of each sample.
375 //
376 // For more information, see tools/entropy_health_test_bounds.py.
377 
378 #define REPETITION_COUNT_BOUND (41)
379 
380 static health_test_result_t
repetition_count_test(entropy_sample_t observation)381 repetition_count_test(entropy_sample_t observation)
382 {
383 	entropy_health_test_t *t = &entropy_data.repetition_count_test;
384 
385 	if (t->init_observation == observation) {
386 		return add_observation(t, REPETITION_COUNT_BOUND);
387 	} else {
388 		reset_test(t, observation);
389 	}
390 
391 	return health_test_success;
392 }
393 
394 // 4.4.2 Adaptive Proportion Test
395 //
396 // This test counts occurrences of a value within a window of samples.
397 //
398 // We use a non-binary alphabet, giving us a window size of 512. (In
399 // particular, we consider the least-significant byte of each time
400 // sample.)
401 //
402 // Assuming one bit of entropy, we can compute the binomial cumulative
403 // distribution function over 512 trials and choose a bound such that
404 // the false positive rate is less than our target.
405 //
406 // For false positive rate and min-entropy estimate as above:
407 //
408 // A = 2^-40
409 // H = 1
410 //
411 // We have our bound:
412 //
413 // C = 336
414 //
415 // For more information, see tools/entropy_health_test_bounds.py.
416 
417 #define ADAPTIVE_PROPORTION_BOUND (336)
418 #define ADAPTIVE_PROPORTION_WINDOW (512)
419 
420 // This mask definition requires the window be a power of two.
421 static_assert(__builtin_popcount(ADAPTIVE_PROPORTION_WINDOW) == 1);
422 #define ADAPTIVE_PROPORTION_INDEX_MASK (ADAPTIVE_PROPORTION_WINDOW - 1)
423 
424 static health_test_result_t
adaptive_proportion_test(entropy_sample_t observation,uint32_t offset)425 adaptive_proportion_test(entropy_sample_t observation, uint32_t offset)
426 {
427 	entropy_health_test_t *t = &entropy_data.adaptive_proportion_test;
428 
429 	// We work in windows of size ADAPTIVE_PROPORTION_WINDOW, so we
430 	// can compute our index by taking the entropy buffer's overall
431 	// sample count plus the offset of this observation modulo the
432 	// window size.
433 	uint32_t index = (entropy_data.total_sample_count + offset) & ADAPTIVE_PROPORTION_INDEX_MASK;
434 
435 	if (index == 0) {
436 		reset_test(t, observation);
437 	} else if (t->init_observation == observation) {
438 		return add_observation(t, ADAPTIVE_PROPORTION_BOUND);
439 	}
440 
441 	return health_test_success;
442 }
443 
444 static health_test_result_t
entropy_health_test(uint32_t sample_count,entropy_sample_t * samples,__assert_only uint32_t filter_count,bitmap_t * filter)445 entropy_health_test(uint32_t sample_count, entropy_sample_t *samples, __assert_only uint32_t filter_count, bitmap_t *filter)
446 {
447 	health_test_result_t result = health_test_success;
448 
449 	assert(filter_count >= BITMAP_LEN(sample_count));
450 
451 	for (uint32_t i = 0; i < sample_count; i += 1) {
452 		// We use the filter to determine if a given sample "counts"
453 		// or not. We skip the health tests on those samples that
454 		// failed the filter, since they are not expected to provide
455 		// any entropy.
456 		if (!bitmap_test(filter, i)) {
457 			continue;
458 		}
459 
460 		// We only consider the low bits of each sample, since that is
461 		// where we expect the entropy to be concentrated.
462 		entropy_sample_t observation = samples[i] & 0xff;
463 
464 		if (__improbable(repetition_count_test(observation) == health_test_failure)) {
465 			result = health_test_failure;
466 		}
467 
468 		if (__improbable(adaptive_proportion_test(observation, i) == health_test_failure)) {
469 			result = health_test_failure;
470 		}
471 	}
472 
473 	return result;
474 }
475 
476 int32_t
entropy_provide(size_t * entropy_size,void * entropy,__unused void * arg)477 entropy_provide(size_t *entropy_size, void *entropy, __unused void *arg)
478 {
479 #if (DEVELOPMENT || DEBUG)
480 	if (*entropy_size < SHA256_DIGEST_LENGTH) {
481 		panic("[entropy_provide] recipient entropy buffer is too small");
482 	}
483 #endif
484 
485 	int32_t sample_count = 0;
486 	*entropy_size = 0;
487 
488 	// The first call to this function comes while the corecrypto kext
489 	// is being loaded. We require SHA256 to accumulate entropy
490 	// samples.
491 	if (__improbable(!crypto_init)) {
492 		return sample_count;
493 	}
494 
495 	// There is only one consumer (the kernel PRNG), but they could
496 	// try to consume entropy from different threads. We simply fail
497 	// if a consumption is already in progress.
498 	if (!lck_mtx_try_lock(&entropy_data.mutex)) {
499 		return sample_count;
500 	}
501 
502 	// This only happens on the first call to this function. We cannot
503 	// perform this initialization in entropy_init because the
504 	// corecrypto kext is not loaded yet.
505 	if (__improbable(!entropy_data.sha256_ctx_init)) {
506 		SHA256_Init(&entropy_data.sha256_ctx);
507 		entropy_data.sha256_ctx_init = true;
508 	}
509 
510 	health_test_result_t health_test_result = health_test_success;
511 
512 	// We accumulate entropy from all CPUs.
513 	percpu_foreach(e, entropy_cpu_data) {
514 		// On each CPU, the sample count functions as an index into
515 		// the entropy buffer. All samples before that index are valid
516 		// for consumption.
517 		uint32_t cpu_sample_count = os_atomic_load(&e->sample_count, acquire);
518 
519 		assert(cpu_sample_count <= ENTROPY_MAX_SAMPLE_COUNT);
520 
521 		// We'll calculate how many samples that we would filter out
522 		// and only add that many to the total_sample_count. The bitmap
523 		// is not used during this operation.
524 		uint32_t filtered_sample_count = entropy_filter(cpu_sample_count, e->samples, ENTROPY_MAX_FILTER_COUNT, entropy_data.filter);
525 		assert(filtered_sample_count <= cpu_sample_count);
526 
527 		entropy_filter_total_sample_count += cpu_sample_count;
528 		entropy_filter_accepted_sample_count += filtered_sample_count;
529 		entropy_filter_rejected_sample_count += (cpu_sample_count - filtered_sample_count);
530 
531 		// The health test depends in part on the current state of
532 		// the entropy data, so we test the new sample before
533 		// accumulating it.
534 		health_test_result_t cpu_health_test_result = entropy_health_test(cpu_sample_count, e->samples, ENTROPY_MAX_FILTER_COUNT, entropy_data.filter);
535 		if (__improbable(cpu_health_test_result == health_test_failure)) {
536 			health_test_result = health_test_failure;
537 		}
538 
539 		// We accumulate the samples regardless of whether the test
540 		// failed or a particular sample was filtered. It cannot hurt.
541 		entropy_data.total_sample_count += filtered_sample_count;
542 		SHA256_Update(&entropy_data.sha256_ctx, e->samples, cpu_sample_count * sizeof(e->samples[0]));
543 
544 		// "Drain" the per-CPU buffer by resetting its sample count.
545 		os_atomic_store(&e->sample_count, 0, relaxed);
546 	}
547 
548 	// We expect this never to happen.
549 	//
550 	// But if it does happen, we need to return negative to signal the
551 	// consumer (i.e. the kernel PRNG) that there has been a failure.
552 	if (__improbable(health_test_result == health_test_failure)) {
553 		entropy_health_startup_done = 0;
554 		entropy_data.startup_sample_count = entropy_data.total_sample_count;
555 		entropy_data.read_sample_count = entropy_data.total_sample_count;
556 		sample_count = -1;
557 		goto out;
558 	}
559 
560 	// FIPS requires we pass our startup health tests before providing
561 	// any entropy. This condition is only true during startup and in
562 	// case of reset due to test failure.
563 	if (__improbable((entropy_data.total_sample_count - entropy_data.startup_sample_count) < 1024)) {
564 		goto out;
565 	}
566 
567 	entropy_health_startup_done = 1;
568 
569 	// The count of new samples from the consumer's perspective.
570 	int32_t n = (int32_t)(entropy_data.total_sample_count - entropy_data.read_sample_count);
571 
572 	// Assuming one bit of entropy per sample, we buffer at least 256
573 	// samples before delivering a high-entropy payload. In theory,
574 	// each payload will be a 256-bit seed with full entropy.
575 	if (n < 256) {
576 		goto out;
577 	}
578 
579 	SHA256_Final(entropy, &entropy_data.sha256_ctx);
580 	SHA256_Init(&entropy_data.sha256_ctx);
581 	entropy_data.read_sample_count = entropy_data.total_sample_count;
582 
583 	sample_count = n;
584 	*entropy_size = SHA256_DIGEST_LENGTH;
585 
586 out:
587 	lck_mtx_unlock(&entropy_data.mutex);
588 
589 	return sample_count;
590 }
591