1 /* Code for loading BSD executables. Mostly linux kernel code. */ 2 3 #include "qemu/osdep.h" 4 5 #include "qemu.h" 6 7 #define TARGET_NGROUPS 32 8 9 /* ??? This should really be somewhere else. */ 10 abi_long memcpy_to_target(abi_ulong dest, const void *src, 11 unsigned long len) 12 { 13 void *host_ptr; 14 15 host_ptr = lock_user(VERIFY_WRITE, dest, len, 0); 16 if (!host_ptr) 17 return -TARGET_EFAULT; 18 memcpy(host_ptr, src, len); 19 unlock_user(host_ptr, dest, 1); 20 return 0; 21 } 22 23 static int in_group_p(gid_t g) 24 { 25 /* return TRUE if we're in the specified group, FALSE otherwise */ 26 int ngroup; 27 int i; 28 gid_t grouplist[TARGET_NGROUPS]; 29 30 ngroup = getgroups(TARGET_NGROUPS, grouplist); 31 for(i = 0; i < ngroup; i++) { 32 if(grouplist[i] == g) { 33 return 1; 34 } 35 } 36 return 0; 37 } 38 39 static int count(char ** vec) 40 { 41 int i; 42 43 for(i = 0; *vec; i++) { 44 vec++; 45 } 46 47 return(i); 48 } 49 50 static int prepare_binprm(struct linux_binprm *bprm) 51 { 52 struct stat st; 53 int mode; 54 int retval, id_change; 55 56 if(fstat(bprm->fd, &st) < 0) { 57 return(-errno); 58 } 59 60 mode = st.st_mode; 61 if(!S_ISREG(mode)) { /* Must be regular file */ 62 return(-EACCES); 63 } 64 if(!(mode & 0111)) { /* Must have at least one execute bit set */ 65 return(-EACCES); 66 } 67 68 bprm->e_uid = geteuid(); 69 bprm->e_gid = getegid(); 70 id_change = 0; 71 72 /* Set-uid? */ 73 if(mode & S_ISUID) { 74 bprm->e_uid = st.st_uid; 75 if(bprm->e_uid != geteuid()) { 76 id_change = 1; 77 } 78 } 79 80 /* Set-gid? */ 81 /* 82 * If setgid is set but no group execute bit then this 83 * is a candidate for mandatory locking, not a setgid 84 * executable. 85 */ 86 if ((mode & (S_ISGID | S_IXGRP)) == (S_ISGID | S_IXGRP)) { 87 bprm->e_gid = st.st_gid; 88 if (!in_group_p(bprm->e_gid)) { 89 id_change = 1; 90 } 91 } 92 93 memset(bprm->buf, 0, sizeof(bprm->buf)); 94 retval = lseek(bprm->fd, 0L, SEEK_SET); 95 if(retval >= 0) { 96 retval = read(bprm->fd, bprm->buf, 128); 97 } 98 if(retval < 0) { 99 perror("prepare_binprm"); 100 exit(-1); 101 /* return(-errno); */ 102 } 103 else { 104 return(retval); 105 } 106 } 107 108 /* Construct the envp and argv tables on the target stack. */ 109 abi_ulong loader_build_argptr(int envc, int argc, abi_ulong sp, 110 abi_ulong stringp, int push_ptr) 111 { 112 int n = sizeof(abi_ulong); 113 abi_ulong envp; 114 abi_ulong argv; 115 116 sp -= (envc + 1) * n; 117 envp = sp; 118 sp -= (argc + 1) * n; 119 argv = sp; 120 if (push_ptr) { 121 /* FIXME - handle put_user() failures */ 122 sp -= n; 123 put_user_ual(envp, sp); 124 sp -= n; 125 put_user_ual(argv, sp); 126 } 127 sp -= n; 128 /* FIXME - handle put_user() failures */ 129 put_user_ual(argc, sp); 130 131 while (argc-- > 0) { 132 /* FIXME - handle put_user() failures */ 133 put_user_ual(stringp, argv); 134 argv += n; 135 stringp += target_strlen(stringp) + 1; 136 } 137 /* FIXME - handle put_user() failures */ 138 put_user_ual(0, argv); 139 while (envc-- > 0) { 140 /* FIXME - handle put_user() failures */ 141 put_user_ual(stringp, envp); 142 envp += n; 143 stringp += target_strlen(stringp) + 1; 144 } 145 /* FIXME - handle put_user() failures */ 146 put_user_ual(0, envp); 147 148 return sp; 149 } 150 151 int loader_exec(const char * filename, char ** argv, char ** envp, 152 struct target_pt_regs * regs, struct image_info *infop) 153 { 154 struct linux_binprm bprm; 155 int retval; 156 int i; 157 158 bprm.p = TARGET_PAGE_SIZE*MAX_ARG_PAGES-sizeof(unsigned int); 159 for (i=0 ; i<MAX_ARG_PAGES ; i++) /* clear page-table */ 160 bprm.page[i] = NULL; 161 retval = open(filename, O_RDONLY); 162 if (retval < 0) 163 return retval; 164 bprm.fd = retval; 165 bprm.filename = (char *)filename; 166 bprm.argc = count(argv); 167 bprm.argv = argv; 168 bprm.envc = count(envp); 169 bprm.envp = envp; 170 171 retval = prepare_binprm(&bprm); 172 173 if(retval>=0) { 174 if (bprm.buf[0] == 0x7f 175 && bprm.buf[1] == 'E' 176 && bprm.buf[2] == 'L' 177 && bprm.buf[3] == 'F') { 178 retval = load_elf_binary(&bprm,regs,infop); 179 } else { 180 fprintf(stderr, "Unknown binary format\n"); 181 return -1; 182 } 183 } 184 185 if(retval>=0) { 186 /* success. Initialize important registers */ 187 do_init_thread(regs, infop); 188 return retval; 189 } 190 191 /* Something went wrong, return the inode and free the argument pages*/ 192 for (i=0 ; i<MAX_ARG_PAGES ; i++) { 193 g_free(bprm.page[i]); 194 } 195 return(retval); 196 } 197