1 /* Code for loading Linux executables. Mostly linux kernel code. */ 2 3 #include "qemu/osdep.h" 4 #include "qemu.h" 5 #include "user-internals.h" 6 #include "user-mmap.h" 7 #include "loader.h" 8 #include "qapi/error.h" 9 10 #define NGROUPS 32 11 12 /* ??? This should really be somewhere else. */ 13 abi_long memcpy_to_target(abi_ulong dest, const void *src, unsigned long len) 14 { 15 void *host_ptr; 16 17 host_ptr = lock_user(VERIFY_WRITE, dest, len, 0); 18 if (!host_ptr) { 19 return -TARGET_EFAULT; 20 } 21 memcpy(host_ptr, src, len); 22 unlock_user(host_ptr, dest, 1); 23 return 0; 24 } 25 26 static int count(char **vec) 27 { 28 int i; 29 30 for (i = 0; *vec; i++) { 31 vec++; 32 } 33 return i; 34 } 35 36 static int prepare_binprm(struct linux_binprm *bprm) 37 { 38 struct stat st; 39 int mode; 40 int retval; 41 42 if (fstat(bprm->src.fd, &st) < 0) { 43 return -errno; 44 } 45 46 mode = st.st_mode; 47 if (!S_ISREG(mode)) { /* Must be regular file */ 48 return -EACCES; 49 } 50 if (!(mode & 0111)) { /* Must have at least one execute bit set */ 51 return -EACCES; 52 } 53 54 bprm->e_uid = geteuid(); 55 bprm->e_gid = getegid(); 56 57 /* Set-uid? */ 58 if (mode & S_ISUID) { 59 bprm->e_uid = st.st_uid; 60 } 61 62 /* Set-gid? */ 63 /* 64 * If setgid is set but no group execute bit then this 65 * is a candidate for mandatory locking, not a setgid 66 * executable. 67 */ 68 if ((mode & (S_ISGID | S_IXGRP)) == (S_ISGID | S_IXGRP)) { 69 bprm->e_gid = st.st_gid; 70 } 71 72 retval = read(bprm->src.fd, bprm->buf, BPRM_BUF_SIZE); 73 if (retval < 0) { 74 perror("prepare_binprm"); 75 exit(-1); 76 } 77 if (retval < BPRM_BUF_SIZE) { 78 /* Make sure the rest of the loader won't read garbage. */ 79 memset(bprm->buf + retval, 0, BPRM_BUF_SIZE - retval); 80 } 81 82 bprm->src.cache = bprm->buf; 83 bprm->src.cache_size = retval; 84 85 return retval; 86 } 87 88 /* Construct the envp and argv tables on the target stack. */ 89 abi_ulong loader_build_argptr(int envc, int argc, abi_ulong sp, 90 abi_ulong stringp, int push_ptr) 91 { 92 TaskState *ts = get_task_state(thread_cpu); 93 int n = sizeof(abi_ulong); 94 abi_ulong envp; 95 abi_ulong argv; 96 97 sp -= (envc + 1) * n; 98 envp = sp; 99 sp -= (argc + 1) * n; 100 argv = sp; 101 ts->info->envp = envp; 102 ts->info->envc = envc; 103 ts->info->argv = argv; 104 ts->info->argc = argc; 105 106 if (push_ptr) { 107 /* FIXME - handle put_user() failures */ 108 sp -= n; 109 put_user_ual(envp, sp); 110 sp -= n; 111 put_user_ual(argv, sp); 112 } 113 114 sp -= n; 115 /* FIXME - handle put_user() failures */ 116 put_user_ual(argc, sp); 117 118 ts->info->arg_strings = stringp; 119 while (argc-- > 0) { 120 /* FIXME - handle put_user() failures */ 121 put_user_ual(stringp, argv); 122 argv += n; 123 stringp += target_strlen(stringp) + 1; 124 } 125 /* FIXME - handle put_user() failures */ 126 put_user_ual(0, argv); 127 128 ts->info->env_strings = stringp; 129 while (envc-- > 0) { 130 /* FIXME - handle put_user() failures */ 131 put_user_ual(stringp, envp); 132 envp += n; 133 stringp += target_strlen(stringp) + 1; 134 } 135 /* FIXME - handle put_user() failures */ 136 put_user_ual(0, envp); 137 138 return sp; 139 } 140 141 int loader_exec(int fdexec, const char *filename, char **argv, char **envp, 142 struct image_info *infop, struct linux_binprm *bprm) 143 { 144 int retval; 145 146 bprm->src.fd = fdexec; 147 bprm->filename = (char *)filename; 148 bprm->argc = count(argv); 149 bprm->argv = argv; 150 bprm->envc = count(envp); 151 bprm->envp = envp; 152 153 retval = prepare_binprm(bprm); 154 155 if (retval < 4) { 156 return -ENOEXEC; 157 } 158 if (bprm->buf[0] == 0x7f 159 && bprm->buf[1] == 'E' 160 && bprm->buf[2] == 'L' 161 && bprm->buf[3] == 'F') { 162 retval = load_elf_binary(bprm, infop); 163 #if defined(TARGET_HAS_BFLT) 164 } else if (bprm->buf[0] == 'b' 165 && bprm->buf[1] == 'F' 166 && bprm->buf[2] == 'L' 167 && bprm->buf[3] == 'T') { 168 retval = load_flt_binary(bprm, infop); 169 #endif 170 } else { 171 return -ENOEXEC; 172 } 173 if (retval < 0) { 174 return retval; 175 } 176 177 /* Success. */ 178 return 0; 179 } 180 181 bool imgsrc_read(void *dst, off_t offset, size_t len, 182 const ImageSource *img, Error **errp) 183 { 184 ssize_t ret; 185 186 if (offset + len <= img->cache_size) { 187 memcpy(dst, img->cache + offset, len); 188 return true; 189 } 190 191 if (img->fd < 0) { 192 error_setg(errp, "read past end of buffer"); 193 return false; 194 } 195 196 ret = pread(img->fd, dst, len, offset); 197 if (ret == len) { 198 return true; 199 } 200 if (ret < 0) { 201 error_setg_errno(errp, errno, "Error reading file header"); 202 } else { 203 error_setg(errp, "Incomplete read of file header"); 204 } 205 return false; 206 } 207 208 void *imgsrc_read_alloc(off_t offset, size_t len, 209 const ImageSource *img, Error **errp) 210 { 211 void *alloc = g_malloc(len); 212 bool ok = imgsrc_read(alloc, offset, len, img, errp); 213 214 if (!ok) { 215 g_free(alloc); 216 alloc = NULL; 217 } 218 return alloc; 219 } 220 221 abi_long imgsrc_mmap(abi_ulong start, abi_ulong len, int prot, 222 int flags, const ImageSource *src, abi_ulong offset) 223 { 224 const int prot_write = PROT_READ | PROT_WRITE; 225 abi_long ret; 226 void *haddr; 227 228 assert(flags == (MAP_PRIVATE | MAP_FIXED)); 229 230 if (src->fd >= 0) { 231 return target_mmap(start, len, prot, flags, src->fd, offset); 232 } 233 234 /* 235 * This case is for the vdso; we don't expect bad images. 236 * The mmap may extend beyond the end of the image, especially 237 * to the end of the page. Zero fill. 238 */ 239 assert(offset < src->cache_size); 240 241 ret = target_mmap(start, len, prot_write, flags | MAP_ANON, -1, 0); 242 if (ret == -1) { 243 return ret; 244 } 245 246 haddr = lock_user(VERIFY_WRITE, start, len, 0); 247 assert(haddr != NULL); 248 if (offset + len <= src->cache_size) { 249 memcpy(haddr, src->cache + offset, len); 250 } else { 251 size_t rest = src->cache_size - offset; 252 memcpy(haddr, src->cache + offset, rest); 253 memset(haddr + rest, 0, len - rest); 254 } 255 unlock_user(haddr, start, len); 256 257 if (prot != prot_write) { 258 target_mprotect(start, len, prot); 259 } 260 261 return ret; 262 } 263