1 /* 2 * Check decoding of kexec_load syscall. 3 * 4 * Copyright (c) 2016 Eugene Syromyatnikov <evgsyr (at) gmail.com> 5 * All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 3. The name of the author may not be used to endorse or promote products 16 * derived from this software without specific prior written permission. 17 * 18 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 19 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 20 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 21 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 22 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 23 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 24 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 25 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 26 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 27 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 28 */ 29 30 #include "tests.h" 31 32 #include <asm/unistd.h> 33 34 #ifdef __NR_kexec_load 35 36 # include <stdio.h> 37 # include <unistd.h> 38 39 struct strval { 40 kernel_ulong_t val; 41 const char *str64; 42 const char *str32; 43 const char *str; 44 }; 45 46 struct segm { 47 void *buf; 48 size_t bufsz; 49 void *mem; 50 size_t memsz; 51 }; 52 53 int 54 main(void) 55 { 56 enum { 57 NUM_SEGMS = 17, 58 NUM_SEGMS_UNCUT = 5, 59 NUM_SEGMS_UNCUT_MAX = 9, 60 NUM_SEGMS_CUT = 12, 61 SEGMS_ARRAY_SIZE = sizeof(struct segm) * NUM_SEGMS, 62 }; 63 64 static const kernel_ulong_t bogus_zero = 65 sizeof(long) < sizeof(kernel_long_t) ? 66 (kernel_ulong_t) 0xffffffff00000000ULL : 0; 67 static const kernel_ulong_t bogus_entry = 68 (kernel_ulong_t) 0xdeadca57badda7a1ULL; 69 static const kernel_ulong_t bogus_nsegs = 70 (kernel_ulong_t) 0xdec0ded1defaced2ULL; 71 72 static const struct strval flags[] = { 73 { (kernel_ulong_t) 0xbadc0dedda7a1054ULL, 74 "0xda7a0000 /* KEXEC_ARCH_??? */|0xbadc0ded0000", 75 "0xda7a0000 /* KEXEC_ARCH_??? */|0x", 76 "1054 /* KEXEC_??? */" }, 77 { 0, "", "", "KEXEC_ARCH_DEFAULT" }, 78 { 0x2a0003, "", "", 79 "KEXEC_ARCH_SH|KEXEC_ON_CRASH|KEXEC_PRESERVE_CONTEXT" }, 80 { 0xdead0000, "", "", "0xdead0000 /* KEXEC_ARCH_??? */" }, 81 }; 82 83 const char *errstr; 84 long rc; 85 struct segm *segms = tail_alloc(SEGMS_ARRAY_SIZE); 86 unsigned int i; 87 88 fill_memory(segms, SEGMS_ARRAY_SIZE); 89 segms[0].buf = segms[0].mem = NULL; 90 91 rc = syscall(__NR_kexec_load, bogus_zero, bogus_zero, bogus_zero, 92 flags[0].val); 93 printf("kexec_load(NULL, 0, NULL, %s%s) = %s\n", 94 sizeof(long) == 8 ? flags[0].str64 : flags[0].str32, 95 flags[0].str, sprintrc(rc)); 96 97 rc = syscall(__NR_kexec_load, bogus_entry, bogus_nsegs, 98 segms + SEGMS_ARRAY_SIZE, flags[1].val); 99 printf("kexec_load(%#lx, %lu, %p, %s) = %s\n", 100 (unsigned long) bogus_entry, (unsigned long) bogus_nsegs, 101 segms + SEGMS_ARRAY_SIZE, flags[1].str, sprintrc(rc)); 102 103 rc = syscall(__NR_kexec_load, bogus_entry, NUM_SEGMS, 104 segms, flags[2].val); 105 printf("kexec_load(%#lx, %lu, %p, %s) = %s\n", 106 (unsigned long) bogus_entry, (unsigned long) NUM_SEGMS, 107 segms, flags[2].str, sprintrc(rc)); 108 109 rc = syscall(__NR_kexec_load, bogus_entry, NUM_SEGMS_CUT, 110 segms, flags[3].val); 111 errstr = sprintrc(rc); 112 printf("kexec_load(%#lx, %lu, [{buf=NULL, bufsz=%zu, mem=NULL, " 113 "memsz=%zu}, ", 114 (unsigned long) bogus_entry, (unsigned long) NUM_SEGMS_CUT, 115 segms[0].bufsz, segms[0].memsz); 116 for (i = 1; i < NUM_SEGMS_UNCUT_MAX; i++) 117 printf("{buf=%p, bufsz=%zu, mem=%p, memsz=%zu}, ", 118 segms[i].buf, segms[i].bufsz, 119 segms[i].mem, segms[i].memsz); 120 printf("...], %s) = %s\n", flags[3].str, errstr); 121 122 rc = syscall(__NR_kexec_load, bogus_entry, NUM_SEGMS_CUT, 123 segms + (NUM_SEGMS - NUM_SEGMS_UNCUT_MAX), 124 flags[0].val); 125 errstr = sprintrc(rc); 126 printf("kexec_load(%#lx, %lu, [", 127 (unsigned long) bogus_entry, (unsigned long) NUM_SEGMS_CUT); 128 for (i = NUM_SEGMS - NUM_SEGMS_UNCUT_MAX; i < NUM_SEGMS; i++) 129 printf("{buf=%p, bufsz=%zu, mem=%p, memsz=%zu}, ", 130 segms[i].buf, segms[i].bufsz, 131 segms[i].mem, segms[i].memsz); 132 printf("%p], %s%s) = %s\n", 133 segms + NUM_SEGMS, 134 sizeof(long) == 8 ? flags[0].str64 : flags[0].str32, 135 flags[0].str, errstr); 136 137 rc = syscall(__NR_kexec_load, bogus_entry, NUM_SEGMS_UNCUT, 138 segms + (NUM_SEGMS - NUM_SEGMS_UNCUT), 139 flags[1].val); 140 errstr = sprintrc(rc); 141 printf("kexec_load(%#lx, %lu, [", 142 (unsigned long) bogus_entry, (unsigned long) NUM_SEGMS_UNCUT); 143 for (i = NUM_SEGMS - NUM_SEGMS_UNCUT; i < NUM_SEGMS; i++) 144 printf("{buf=%p, bufsz=%zu, mem=%p, memsz=%zu}%s", 145 segms[i].buf, segms[i].bufsz, 146 segms[i].mem, segms[i].memsz, 147 (i == NUM_SEGMS - 1) ? "" : ", "); 148 printf("], %s) = %s\n", flags[1].str, errstr); 149 150 rc = syscall(__NR_kexec_load, bogus_entry, NUM_SEGMS_CUT, 151 segms + 1, flags[2].val); 152 errstr = sprintrc(rc); 153 printf("kexec_load(%#lx, %lu, [", 154 (unsigned long) bogus_entry, (unsigned long) NUM_SEGMS_CUT); 155 for (i = 1; i < NUM_SEGMS_UNCUT_MAX + 1; i++) 156 printf("{buf=%p, bufsz=%zu, mem=%p, memsz=%zu}, ", 157 segms[i].buf, segms[i].bufsz, 158 segms[i].mem, segms[i].memsz); 159 printf("...], %s) = %s\n", flags[2].str, errstr); 160 161 puts("+++ exited with 0 +++"); 162 163 return 0; 164 } 165 166 #else 167 168 SKIP_MAIN_UNDEFINED("__NR_kexec_load"); 169 170 #endif 171