github.com/rkt/rkt@v1.30.1-0.20200224141603-171c416fac02/stage1/diagnostic/diagnostic-util.c (about) 1 // Copyright 2014-2016 The rkt Authors 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 #define _GNU_SOURCE 16 #include <errno.h> 17 #include <fcntl.h> 18 #include <grp.h> 19 #include <inttypes.h> 20 #include <limits.h> 21 #include <stdint.h> 22 #include <sys/mman.h> 23 #include <sys/stat.h> 24 #include <sys/types.h> 25 #include <unistd.h> 26 27 #include "diagnostic-util.h" 28 #include "elf.h" 29 30 31 static void map_file(const char *path, int prot, int flags, struct stat *st, void **map) 32 { 33 int fd; 34 35 pexit_if((fd = open(path, O_RDONLY)) == -1, 36 "Unable to open \"%s\"", path); 37 pexit_if(fstat(fd, st) == -1, 38 "Cannot stat \"%s\"", path); 39 exit_if(!S_ISREG(st->st_mode), "\"%s\" is not a regular file", path); 40 pexit_if(!(*map = mmap(NULL, st->st_size, prot, flags, fd, 0)), 41 "Mmap of \"%s\" failed", path); 42 pexit_if(close(fd) == -1, 43 "Close of %i [%s] failed", fd, path); 44 } 45 46 void diag(const char *exe) 47 { 48 static const uint8_t elf[] = {0x7f, 'E', 'L', 'F'}; 49 static const uint8_t shebang[] = {'#','!'}; 50 static int diag_depth; 51 struct stat st; 52 const uint8_t *mm; 53 const char *itrp = NULL; 54 55 map_file(exe, PROT_READ, MAP_SHARED, &st, (void **)&mm); 56 exit_if(!((S_IXUSR|S_IXGRP|S_IXOTH) & st.st_mode), 57 "\"%s\" is not executable", exe) 58 59 if(st.st_size >= sizeof(shebang) && 60 !memcmp(mm, shebang, sizeof(shebang))) { 61 const uint8_t *nl; 62 int maxlen = MIN(PATH_MAX, st.st_size - sizeof(shebang)); 63 /* TODO(vc): EOF-terminated shebang lines are technically possible */ 64 exit_if(!(nl = memchr(&mm[sizeof(shebang)], '\n', maxlen)), 65 "Shebang line too long"); 66 pexit_if(!(itrp = strndup((char *)&mm[sizeof(shebang)], (nl - mm) - 2)), 67 "Failed to dup interpreter path"); 68 } else if(st.st_size >= sizeof(elf) && 69 !memcmp(mm, elf, sizeof(elf))) { 70 uint64_t (*lget)(const uint8_t *) = NULL; 71 uint32_t (*iget)(const uint8_t *) = NULL; 72 uint16_t (*sget)(const uint8_t *) = NULL; 73 const void *phoff = NULL, *phesz = NULL, *phecnt = NULL; 74 const uint8_t *ph = NULL; 75 int i, phreloff, phrelsz; 76 77 exit_if(mm[ELF_VERSION] != 1, 78 "Unsupported ELF version: %hhx", mm[ELF_VERSION]); 79 80 /* determine which accessors to use and where */ 81 if(mm[ELF_BITS] == ELF_BITS_32) { 82 if(mm[ELF_ENDIAN] == ELF_ENDIAN_LITL) { 83 lget = le32_lget; 84 sget = le_sget; 85 iget = le_iget; 86 } else if(mm[ELF_ENDIAN] == ELF_ENDIAN_BIG) { 87 lget = be32_lget; 88 sget = be_sget; 89 iget = be_iget; 90 } 91 phoff = &mm[ELF32_PHT_OFF]; 92 phesz = &mm[ELF32_PHTE_SIZE]; 93 phecnt = &mm[ELF32_PHTE_CNT]; 94 phreloff = ELF32_PHE_OFF; 95 phrelsz = ELF32_PHE_SIZE; 96 } else if(mm[ELF_BITS] == ELF_BITS_64) { 97 if(mm[ELF_ENDIAN] == ELF_ENDIAN_LITL) { 98 lget = le64_lget; 99 sget = le_sget; 100 iget = le_iget; 101 } else if(mm[ELF_ENDIAN] == ELF_ENDIAN_BIG) { 102 lget = be64_lget; 103 sget = be_sget; 104 iget = be_iget; 105 } 106 phoff = &mm[ELF64_PHT_OFF]; 107 phesz = &mm[ELF64_PHTE_SIZE]; 108 phecnt = &mm[ELF64_PHTE_CNT]; 109 phreloff = ELF64_PHE_OFF; 110 phrelsz = ELF64_PHE_SIZE; 111 } 112 113 exit_if(!lget, "Unsupported ELF format"); 114 115 if(!phoff) /* program header may be absent, don't make it an error */ 116 return; 117 118 /* TODO(vc): sanity checks on values before using them */ 119 for(ph = &mm[lget(phoff)], i = 0; i < sget(phecnt); i++, ph += sget(phesz)) { 120 if(iget(ph) == ELF_PT_INTERP) { 121 itrp = strndup((char *)&mm[lget(&ph[phreloff])], lget(&ph[phrelsz])); 122 break; 123 } 124 } 125 } else { 126 exit_if(1, "Unsupported file type"); 127 } 128 129 exit_if(!itrp, "Unable to determine interpreter for \"%s\"", exe); 130 exit_if(*itrp != '/', "Path must be absolute: \"%s\"", itrp); 131 exit_if(++diag_depth > MAX_DIAG_DEPTH, 132 "Excessive interpreter recursion, giving up"); 133 diag(itrp); 134 }