bsdload.c (5435B)
1/* 2 * Load BSD executables. 3 * 4 * This program is free software; you can redistribute it and/or modify 5 * it under the terms of the GNU General Public License as published by 6 * the Free Software Foundation; either version 2 of the License, or 7 * (at your option) any later version. 8 * 9 * This program is distributed in the hope that it will be useful, 10 * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 * GNU General Public License for more details. 13 * 14 * You should have received a copy of the GNU General Public License 15 * along with this program; if not, see <http://www.gnu.org/licenses/>. 16 */ 17 18#include "qemu/osdep.h" 19 20#include "qemu.h" 21 22/* ??? This should really be somewhere else. */ 23abi_long memcpy_to_target(abi_ulong dest, const void *src, 24 unsigned long len) 25{ 26 void *host_ptr; 27 28 host_ptr = lock_user(VERIFY_WRITE, dest, len, 0); 29 if (!host_ptr) { 30 return -TARGET_EFAULT; 31 } 32 memcpy(host_ptr, src, len); 33 unlock_user(host_ptr, dest, 1); 34 return 0; 35} 36 37static int count(char **vec) 38{ 39 int i; 40 41 for (i = 0; *vec; i++) { 42 vec++; 43 } 44 45 return i; 46} 47 48static int prepare_binprm(struct bsd_binprm *bprm) 49{ 50 struct stat st; 51 int mode; 52 int retval; 53 54 if (fstat(bprm->fd, &st) < 0) { 55 return -errno; 56 } 57 58 mode = st.st_mode; 59 if (!S_ISREG(mode)) { /* Must be regular file */ 60 return -EACCES; 61 } 62 if (!(mode & 0111)) { /* Must have at least one execute bit set */ 63 return -EACCES; 64 } 65 66 bprm->e_uid = geteuid(); 67 bprm->e_gid = getegid(); 68 69 /* Set-uid? */ 70 if (mode & S_ISUID) { 71 bprm->e_uid = st.st_uid; 72 } 73 74 /* Set-gid? */ 75 /* 76 * If setgid is set but no group execute bit then this 77 * is a candidate for mandatory locking, not a setgid 78 * executable. 79 */ 80 if ((mode & (S_ISGID | S_IXGRP)) == (S_ISGID | S_IXGRP)) { 81 bprm->e_gid = st.st_gid; 82 } 83 84 memset(bprm->buf, 0, sizeof(bprm->buf)); 85 retval = lseek(bprm->fd, 0L, SEEK_SET); 86 if (retval >= 0) { 87 retval = read(bprm->fd, bprm->buf, 128); 88 } 89 if (retval < 0) { 90 perror("prepare_binprm"); 91 exit(-1); 92 } else { 93 return retval; 94 } 95} 96 97/* Construct the envp and argv tables on the target stack. */ 98abi_ulong loader_build_argptr(int envc, int argc, abi_ulong sp, 99 abi_ulong stringp) 100{ 101 int n = sizeof(abi_ulong); 102 abi_ulong envp; 103 abi_ulong argv; 104 105 sp -= (envc + 1) * n; 106 envp = sp; 107 sp -= (argc + 1) * n; 108 argv = sp; 109 sp -= n; 110 /* FIXME - handle put_user() failures */ 111 put_user_ual(argc, sp); 112 113 while (argc-- > 0) { 114 /* FIXME - handle put_user() failures */ 115 put_user_ual(stringp, argv); 116 argv += n; 117 stringp += target_strlen(stringp) + 1; 118 } 119 /* FIXME - handle put_user() failures */ 120 put_user_ual(0, argv); 121 while (envc-- > 0) { 122 /* FIXME - handle put_user() failures */ 123 put_user_ual(stringp, envp); 124 envp += n; 125 stringp += target_strlen(stringp) + 1; 126 } 127 /* FIXME - handle put_user() failures */ 128 put_user_ual(0, envp); 129 130 return sp; 131} 132 133static bool is_there(const char *candidate) 134{ 135 struct stat fin; 136 137 /* XXX work around access(2) false positives for superuser */ 138 if (access(candidate, X_OK) == 0 && stat(candidate, &fin) == 0 && 139 S_ISREG(fin.st_mode) && (getuid() != 0 || 140 (fin.st_mode & (S_IXUSR | S_IXGRP | S_IXOTH)) != 0)) { 141 return true; 142 } 143 144 return false; 145} 146 147int loader_exec(const char *filename, char **argv, char **envp, 148 struct target_pt_regs *regs, struct image_info *infop, 149 struct bsd_binprm *bprm) 150{ 151 char *path, fullpath[PATH_MAX]; 152 int retval, i; 153 154 bprm->p = TARGET_PAGE_SIZE * MAX_ARG_PAGES; 155 for (i = 0; i < MAX_ARG_PAGES; i++) { /* clear page-table */ 156 bprm->page[i] = NULL; 157 } 158 159 if (strchr(filename, '/') != NULL) { 160 path = realpath(filename, fullpath); 161 if (path == NULL) { 162 /* Failed to resolve. */ 163 return -1; 164 } 165 if (!is_there(path)) { 166 return -1; 167 } 168 } else { 169 path = g_find_program_in_path(filename); 170 if (path == NULL) { 171 return -1; 172 } 173 } 174 175 retval = open(path, O_RDONLY); 176 if (retval < 0) { 177 g_free(path); 178 return retval; 179 } 180 181 bprm->fullpath = path; 182 bprm->fd = retval; 183 bprm->filename = (char *)filename; 184 bprm->argc = count(argv); 185 bprm->argv = argv; 186 bprm->envc = count(envp); 187 bprm->envp = envp; 188 189 retval = prepare_binprm(bprm); 190 191 if (retval >= 0) { 192 if (bprm->buf[0] == 0x7f 193 && bprm->buf[1] == 'E' 194 && bprm->buf[2] == 'L' 195 && bprm->buf[3] == 'F') { 196 retval = load_elf_binary(bprm, regs, infop); 197 } else { 198 fprintf(stderr, "Unknown binary format\n"); 199 return -1; 200 } 201 } 202 203 if (retval >= 0) { 204 /* success. Initialize important registers */ 205 do_init_thread(regs, infop); 206 return retval; 207 } 208 209 /* Something went wrong, return the inode and free the argument pages*/ 210 for (i = 0 ; i < MAX_ARG_PAGES ; i++) { 211 g_free(bprm->page[i]); 212 } 213 return retval; 214}