18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * This code tests that the current task stack is properly erased (filled 48c2ecf20Sopenharmony_ci * with STACKLEAK_POISON). 58c2ecf20Sopenharmony_ci * 68c2ecf20Sopenharmony_ci * Authors: 78c2ecf20Sopenharmony_ci * Alexander Popov <alex.popov@linux.com> 88c2ecf20Sopenharmony_ci * Tycho Andersen <tycho@tycho.ws> 98c2ecf20Sopenharmony_ci */ 108c2ecf20Sopenharmony_ci 118c2ecf20Sopenharmony_ci#include "lkdtm.h" 128c2ecf20Sopenharmony_ci#include <linux/stackleak.h> 138c2ecf20Sopenharmony_ci 148c2ecf20Sopenharmony_civoid lkdtm_STACKLEAK_ERASING(void) 158c2ecf20Sopenharmony_ci{ 168c2ecf20Sopenharmony_ci unsigned long *sp, left, found, i; 178c2ecf20Sopenharmony_ci const unsigned long check_depth = 188c2ecf20Sopenharmony_ci STACKLEAK_SEARCH_DEPTH / sizeof(unsigned long); 198c2ecf20Sopenharmony_ci bool test_failed = false; 208c2ecf20Sopenharmony_ci 218c2ecf20Sopenharmony_ci /* 228c2ecf20Sopenharmony_ci * For the details about the alignment of the poison values, see 238c2ecf20Sopenharmony_ci * the comment in stackleak_track_stack(). 248c2ecf20Sopenharmony_ci */ 258c2ecf20Sopenharmony_ci sp = PTR_ALIGN(&i, sizeof(unsigned long)); 268c2ecf20Sopenharmony_ci 278c2ecf20Sopenharmony_ci left = ((unsigned long)sp & (THREAD_SIZE - 1)) / sizeof(unsigned long); 288c2ecf20Sopenharmony_ci sp--; 298c2ecf20Sopenharmony_ci 308c2ecf20Sopenharmony_ci /* 318c2ecf20Sopenharmony_ci * One 'long int' at the bottom of the thread stack is reserved 328c2ecf20Sopenharmony_ci * and not poisoned. 338c2ecf20Sopenharmony_ci */ 348c2ecf20Sopenharmony_ci if (left > 1) { 358c2ecf20Sopenharmony_ci left--; 368c2ecf20Sopenharmony_ci } else { 378c2ecf20Sopenharmony_ci pr_err("FAIL: not enough stack space for the test\n"); 388c2ecf20Sopenharmony_ci test_failed = true; 398c2ecf20Sopenharmony_ci goto end; 408c2ecf20Sopenharmony_ci } 418c2ecf20Sopenharmony_ci 428c2ecf20Sopenharmony_ci pr_info("checking unused part of the thread stack (%lu bytes)...\n", 438c2ecf20Sopenharmony_ci left * sizeof(unsigned long)); 448c2ecf20Sopenharmony_ci 458c2ecf20Sopenharmony_ci /* 468c2ecf20Sopenharmony_ci * Search for 'check_depth' poison values in a row (just like 478c2ecf20Sopenharmony_ci * stackleak_erase() does). 488c2ecf20Sopenharmony_ci */ 498c2ecf20Sopenharmony_ci for (i = 0, found = 0; i < left && found <= check_depth; i++) { 508c2ecf20Sopenharmony_ci if (*(sp - i) == STACKLEAK_POISON) 518c2ecf20Sopenharmony_ci found++; 528c2ecf20Sopenharmony_ci else 538c2ecf20Sopenharmony_ci found = 0; 548c2ecf20Sopenharmony_ci } 558c2ecf20Sopenharmony_ci 568c2ecf20Sopenharmony_ci if (found <= check_depth) { 578c2ecf20Sopenharmony_ci pr_err("FAIL: the erased part is not found (checked %lu bytes)\n", 588c2ecf20Sopenharmony_ci i * sizeof(unsigned long)); 598c2ecf20Sopenharmony_ci test_failed = true; 608c2ecf20Sopenharmony_ci goto end; 618c2ecf20Sopenharmony_ci } 628c2ecf20Sopenharmony_ci 638c2ecf20Sopenharmony_ci pr_info("the erased part begins after %lu not poisoned bytes\n", 648c2ecf20Sopenharmony_ci (i - found) * sizeof(unsigned long)); 658c2ecf20Sopenharmony_ci 668c2ecf20Sopenharmony_ci /* The rest of thread stack should be erased */ 678c2ecf20Sopenharmony_ci for (; i < left; i++) { 688c2ecf20Sopenharmony_ci if (*(sp - i) != STACKLEAK_POISON) { 698c2ecf20Sopenharmony_ci pr_err("FAIL: bad value number %lu in the erased part: 0x%lx\n", 708c2ecf20Sopenharmony_ci i, *(sp - i)); 718c2ecf20Sopenharmony_ci test_failed = true; 728c2ecf20Sopenharmony_ci } 738c2ecf20Sopenharmony_ci } 748c2ecf20Sopenharmony_ci 758c2ecf20Sopenharmony_ciend: 768c2ecf20Sopenharmony_ci if (test_failed) { 778c2ecf20Sopenharmony_ci pr_err("FAIL: the thread stack is NOT properly erased\n"); 788c2ecf20Sopenharmony_ci dump_stack(); 798c2ecf20Sopenharmony_ci } else { 808c2ecf20Sopenharmony_ci pr_info("OK: the rest of the thread stack is properly erased\n"); 818c2ecf20Sopenharmony_ci } 828c2ecf20Sopenharmony_ci} 83