1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License, Version 1.0 only 6 * (the "License"). You may not use this file except in compliance 7 * with the License. 8 * 9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10 * or http://www.opensolaris.org/os/licensing. 11 * See the License for the specific language governing permissions 12 * and limitations under the License. 13 * 14 * When distributing Covered Code, include this CDDL HEADER in each 15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16 * If applicable, add the following below this CDDL HEADER, with the 17 * fields enclosed by brackets "[]" replaced with your own identifying 18 * information: Portions Copyright [yyyy] [name of copyright owner] 19 * 20 * CDDL HEADER END 21 */ 22 /* 23 * Copyright 2005 Sun Microsystems, Inc. All rights reserved. 24 * Use is subject to license terms. 25 */ 26 #pragma ident "%Z%%M% %I% %E% SMI" 27 28 #include "_synonyms.h" 29 30 #include <sys/types.h> 31 #include <sys/mman.h> 32 #include <dirent.h> 33 #include <stdio.h> 34 #include <string.h> 35 #include <limits.h> 36 #include "conv.h" 37 #include "_rtld.h" 38 #include "_audit.h" 39 #include "_elf.h" 40 #include "msg.h" 41 #include "debug.h" 42 43 /* 44 * qsort(3c) comparison function. 45 */ 46 static int 47 compare(const void * fdesc1, const void * fdesc2) 48 { 49 ulong_t hwcap1 = ((Fdesc *)fdesc1)->fd_fmap.fm_hwptr; 50 ulong_t hwcap2 = ((Fdesc *)fdesc2)->fd_fmap.fm_hwptr; 51 52 if (hwcap1 && (hwcap2 == 0)) 53 return (-1); 54 if ((hwcap1 == 0) && hwcap2) 55 return (1); 56 if ((hwcap1 == 0) && (hwcap2 == 0)) 57 return (0); 58 59 if (hwcap1 > hwcap2) 60 return (-1); 61 if (hwcap1 < hwcap2) 62 return (1); 63 return (0); 64 } 65 66 /* 67 * If this object defines a set of hardware capability requirements, insure the 68 * kernal can cope with them. 69 */ 70 int 71 hwcap_check(Rej_desc *rej, Ehdr *ehdr) 72 { 73 Cap *cptr; 74 Phdr *phdr; 75 int cnt; 76 77 /* LINTED */ 78 phdr = (Phdr *)((char *)ehdr + ehdr->e_phoff); 79 for (cnt = 0; cnt < ehdr->e_phnum; cnt++, phdr++) { 80 Lword val; 81 82 if (phdr->p_type != PT_SUNWCAP) 83 continue; 84 85 /* LINTED */ 86 cptr = (Cap *)((char *)ehdr + phdr->p_offset); 87 while (cptr->c_tag != CA_SUNW_NULL) { 88 if (cptr->c_tag == CA_SUNW_HW_1) 89 break; 90 cptr++; 91 } 92 if (cptr->c_tag == CA_SUNW_NULL) 93 break; 94 95 if ((val = (cptr->c_un.c_val & ~hwcap)) != 0) { 96 rej->rej_type = SGS_REJ_HWCAP_1; 97 rej->rej_str = conv_hwcap_1_str(val, M_MACH); 98 return (0); 99 } 100 101 /* 102 * Retain this hardware capabilities pointer for possible later 103 * inspection should this object be processed as a filtee. 104 */ 105 fmap->fm_hwptr = cptr->c_un.c_val; 106 } 107 return (1); 108 } 109 110 static void 111 remove_fdesc(Fdesc * fdp) 112 { 113 #if defined(MAP_ALIGN) 114 if (fdp->fd_fmap.fm_maddr && 115 ((fdp->fd_fmap.fm_mflags & MAP_ALIGN) == 0)) { 116 #else 117 if (fdp->fd_fmap.fm_maddr) { 118 #endif 119 (void) munmap(fdp->fd_fmap.fm_maddr, fdp->fd_fmap.fm_msize); 120 /* 121 * Note, this file descriptor might be duplicating information 122 * from the global fmap descriptor. If so, clean up the global 123 * descriptor to prevent a duplicate (unnecessary) unmap. 124 */ 125 if (fmap->fm_maddr == fdp->fd_fmap.fm_maddr) 126 fmap->fm_maddr = 0; 127 } 128 if (fdp->fd_fd) 129 (void) close(fdp->fd_fd); 130 if (fdp->fd_pname && (fdp->fd_pname != fdp->fd_nname)) 131 free((void *)fdp->fd_pname); 132 if (fdp->fd_nname) 133 free((void *)fdp->fd_nname); 134 } 135 136 /* 137 * When $HWCAP is used to represent dependencies, take the associated directory 138 * and analyze all the files it contains. 139 */ 140 int 141 hwcap_dir(Alist ** fdalpp, Lm_list * lml, const char *name, Rt_map * clmp, 142 uint_t flags, Rej_desc *rej) 143 { 144 char path[PATH_MAX], *dst; 145 const char *src; 146 DIR *dir; 147 struct dirent *dirent; 148 Aliste off; 149 Alist *fdalp = 0; 150 Fdesc *fdp; 151 int error = 0; 152 153 /* 154 * Access the directory in preparation for reading its entries. If 155 * successful, establish the initial pathname. 156 */ 157 if ((dir = opendir(name)) == 0) { 158 Rej_desc _rej = { 0 }; 159 160 _rej.rej_type = SGS_REJ_STR; 161 _rej.rej_name = name; 162 _rej.rej_str = strerror(errno); 163 DBG_CALL(Dbg_file_rejected(&_rej)); 164 rejection_inherit(rej, &_rej, 0); 165 return (0); 166 } 167 168 for (dst = path, src = name; *src; dst++, src++) 169 *dst = *src; 170 *dst++ = '/'; 171 172 /* 173 * Read each entry from the directory and determine whether it is a 174 * valid ELF file. 175 */ 176 while ((dirent = readdir(dir)) != NULL) { 177 const char *file = dirent->d_name; 178 char *_dst; 179 Fdesc fdesc = { 0 }; 180 Rej_desc _rej = { 0 }; 181 182 /* 183 * Ignore "." and ".." entries. 184 */ 185 if ((file[0] == '.') && ((file[1] == '\0') || 186 ((file[1] == '.') && (file[2] == '\0')))) 187 continue; 188 189 /* 190 * Complete the full pathname, and verify its usability. 191 */ 192 for (_dst = dst, src = file, file = dst; *src; _dst++, src++) 193 *_dst = *src; 194 *_dst = '\0'; 195 196 if ((name = strdup(path)) == 0) { 197 error = 1; 198 break; 199 } 200 if ((name = load_trace(lml, name, clmp)) == 0) 201 continue; 202 203 if (find_path(lml, name, clmp, flags, &fdesc, &_rej) == 0) 204 rejection_inherit(rej, &_rej, &fdesc); 205 else { 206 DBG_CALL(Dbg_cap_hw_candidate(name)); 207 208 /* 209 * If this object has already been loaded, obtain the 210 * hardware capabilities for later sorting. Otherwise 211 * we have a new candidate. 212 */ 213 if (fdesc.fd_lmp) 214 fdesc.fd_fmap.fm_hwptr = HWCAP(fdesc.fd_lmp); 215 else 216 fdesc.fd_fmap = *fmap; 217 218 if (alist_append(&fdalp, &fdesc, 219 sizeof (Fdesc), 10) == 0) { 220 remove_fdesc(&fdesc); 221 error = 1; 222 break; 223 } 224 } 225 226 /* 227 * Clear the global file mapping structure so that the mapping 228 * for this file won't be overriden. 229 */ 230 fmap->fm_mflags = MAP_PRIVATE; 231 fmap->fm_maddr = 0; 232 fmap->fm_msize = syspagsz; 233 fmap->fm_hwptr = 0; 234 235 } 236 (void) closedir(dir); 237 238 /* 239 * If no objects have been found, we're done. Also, if an allocation 240 * error occurred while processing any object, remove any objects that 241 * had already been added to the list and return. 242 */ 243 if ((fdalp == 0) || error) { 244 if (fdalp) { 245 for (ALIST_TRAVERSE(fdalp, off, fdp)) 246 remove_fdesc(fdp); 247 free(fdalp); 248 } 249 return (0); 250 } 251 252 /* 253 * Having processed and retained all candidates from this directory, 254 * sort them, based on the precedence of their hardware capabilities. 255 */ 256 qsort(&(fdalp->al_data[0]), ((fdalp->al_next - (sizeof (Alist) - 257 sizeof (void *))) / fdalp->al_size), fdalp->al_size, compare); 258 259 *fdalpp = fdalp; 260 return (1); 261 } 262 263 static Pnode * 264 _hwcap_filtees(Pnode ** pnpp, Aliste nlmco, Rt_map * flmp, const char *ref, 265 const char *dir, int mode, uint_t flags) 266 { 267 Alist *fdalp = 0; 268 Aliste off; 269 Pnode *fpnp = 0, *lpnp, *npnp = (*pnpp)->p_next; 270 Fdesc *fdp; 271 Lm_list *lml = LIST(flmp); 272 int unused = 0; 273 Rej_desc rej = { 0 }; 274 275 if (hwcap_dir(&fdalp, lml, dir, flmp, flags, &rej) == 0) { 276 remove_rej(&rej); 277 return (0); 278 } 279 280 /* 281 * Now complete the mapping of each of the ordered objects, adding 282 * each object to a new Pnode. 283 */ 284 for (ALIST_TRAVERSE(fdalp, off, fdp)) { 285 Rt_map *nlmp; 286 Grp_hdl *ghp; 287 Pnode *pnp; 288 289 if (unused) { 290 /* 291 * Flush out objects remaining. 292 */ 293 remove_fdesc(fdp); 294 continue; 295 } 296 297 /* 298 * Complete mapping the file, obtaining a handle, and continue 299 * to analyze the object, establishing dependencies and 300 * relocating. Remove the file descriptor at this point, as it 301 * is no longer required. 302 */ 303 DBG_CALL(Dbg_file_filtee(NAME(flmp), fdp->fd_nname, 0)); 304 305 nlmp = load_path(lml, nlmco, fdp->fd_nname, flmp, mode, 306 (flags | FLG_RT_HANDLE), &ghp, fdp, &rej); 307 remove_fdesc(fdp); 308 309 if (nlmp == 0) 310 continue; 311 312 /* 313 * Audit the filter/filtee established. A return of 0 314 * indicates the auditor wishes to ignore this filtee. 315 */ 316 if ((lml->lm_tflags | FLAGS1(flmp)) & 317 LML_TFLG_AUD_OBJFILTER) { 318 if (audit_objfilter(flmp, ref, nlmp, 0) == 0) { 319 DBG_CALL(Dbg_file_filtee(0, NAME(nlmp), 1)); 320 (void) dlclose_core(ghp, flmp); 321 continue; 322 } 323 } 324 325 ghp->gh_flags |= GPH_FILTEE; 326 327 /* 328 * Finish processing the objects associated with this request. 329 */ 330 if ((analyze_lmc(lml, nlmco, nlmp) == 0) || 331 (relocate_lmc(lml, nlmco, nlmp) == 0)) { 332 (void) dlclose_core(ghp, flmp); 333 continue; 334 } 335 336 /* 337 * Create a new Pnode to represent this filtee, and substitute 338 * the calling Pnode (which was used to represent the hardware 339 * capability directory). 340 */ 341 if ((pnp = calloc(1, sizeof (Pnode))) == 0) { 342 (void) dlclose_core(ghp, flmp); 343 continue; 344 } 345 if ((pnp->p_name = strdup(NAME(nlmp))) == 0) { 346 (void) dlclose_core(ghp, flmp); 347 free(pnp); 348 continue; 349 } 350 pnp->p_len = strlen(NAME(nlmp)); 351 pnp->p_info = (void *)ghp; 352 pnp->p_next = npnp; 353 354 /* 355 * Finally, if the filtee is part of a link-map control list 356 * that is equivalent, or less, than the filter control list, 357 * create an association between the filter and filtee. This 358 * association provides sufficient information to tear down the 359 * filter and filtee if necessary. 360 */ 361 if ((CNTL(nlmp) <= CNTL(flmp)) && 362 (hdl_add(ghp, flmp, GPD_FILTER) == 0)) { 363 (void) dlclose_core(ghp, flmp); 364 free((void *)pnp->p_name); 365 free(pnp); 366 continue; 367 } 368 369 if (fpnp == 0) { 370 Pnode *opnp = (*pnpp); 371 /* 372 * If this is the first pnode, reuse the original after 373 * freeing any of its pathnames. 374 */ 375 if (opnp->p_name) 376 free((void *)opnp->p_name); 377 if (opnp->p_oname) 378 free((void *)opnp->p_oname); 379 *opnp = *pnp; 380 free((void *)pnp); 381 fpnp = lpnp = opnp; 382 } else { 383 lpnp->p_next = pnp; 384 lpnp = pnp; 385 } 386 387 /* 388 * If this object is marked an end-filtee, we're done. 389 */ 390 if (FLAGS1(nlmp) & FL1_RT_ENDFILTE) 391 unused = 1; 392 } 393 394 free(fdalp); 395 return (fpnp); 396 } 397 398 Pnode * 399 hwcap_filtees(Pnode ** pnpp, Aliste nlmco, Dyninfo * dip, Rt_map * flmp, 400 const char *ref, int mode, uint_t flags) 401 { 402 Pnode *pnp = *pnpp; 403 const char *dir = pnp->p_name; 404 405 DBG_CALL(Dbg_cap_hw_filter(dir, NAME(flmp))); 406 407 if ((pnp = _hwcap_filtees(pnpp, nlmco, flmp, ref, dir, mode, 408 flags)) != 0) 409 return (pnp); 410 411 /* 412 * If no hardware capability filtees have been found, provide suitable 413 * diagnostics and mark the incoming Pnode as unused. 414 */ 415 if ((LIST(flmp)->lm_flags & LML_FLG_TRC_ENABLE) && 416 (dip->di_flags & FLG_DI_AUXFLTR) && (rtld_flags & RT_FL_WARNFLTR)) 417 (void) printf(MSG_INTL(MSG_LDD_HWCAP_NFOUND), dir); 418 419 DBG_CALL(Dbg_cap_hw_filter(dir, 0)); 420 421 pnp = *pnpp; 422 pnp->p_len = 0; 423 return (pnp); 424 } 425 426 /* 427 * Load an individual hardware capabilities object. 428 */ 429 Rt_map * 430 load_hwcap(Lm_list * lml, Aliste lmco, const char *dir, Rt_map * clmp, 431 uint_t mode, uint_t flags, Grp_hdl ** hdl, Rej_desc *rej) 432 { 433 Alist *fdalp = 0; 434 Aliste off; 435 Fdesc *fdp; 436 int found = 0; 437 Rt_map *lmp = 0; 438 439 /* 440 * Obtain the sorted list of hardware capabilites objects available. 441 */ 442 if (hwcap_dir(&fdalp, lml, dir, clmp, flags, rej) == 0) 443 return (0); 444 445 /* 446 * From the list of hardware capability objects, use the first and 447 * discard the rest. 448 */ 449 for (ALIST_TRAVERSE(fdalp, off, fdp)) { 450 if ((found == 0) && ((lmp = load_path(lml, lmco, fdp->fd_nname, 451 clmp, mode, flags, hdl, fdp, rej)) != 0)) 452 found++; 453 454 /* 455 * Remove the used file descriptor and any objects remaining. 456 */ 457 remove_fdesc(fdp); 458 } 459 460 free(fdalp); 461 return (lmp); 462 } 463