Print this page
smatch clean rtld
Split |
Close |
Expand all |
Collapse all |
--- old/usr/src/cmd/sgs/rtld/common/cap.c
+++ new/usr/src/cmd/sgs/rtld/common/cap.c
1 1 /*
2 2 * CDDL HEADER START
3 3 *
4 4 * The contents of this file are subject to the terms of the
5 5 * Common Development and Distribution License (the "License").
6 6 * You may not use this file except in compliance with the License.
7 7 *
8 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 9 * or http://www.opensolaris.org/os/licensing.
10 10 * See the License for the specific language governing permissions
11 11 * and limitations under the License.
12 12 *
13 13 * When distributing Covered Code, include this CDDL HEADER in each
14 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 15 * If applicable, add the following below this CDDL HEADER, with the
16 16 * fields enclosed by brackets "[]" replaced with your own identifying
17 17 * information: Portions Copyright [yyyy] [name of copyright owner]
18 18 *
19 19 * CDDL HEADER END
20 20 */
21 21
22 22 /*
23 23 * Copyright (c) 2004, 2010, Oracle and/or its affiliates. All rights reserved.
24 24 */
25 25
26 26 #include <sys/types.h>
27 27 #include <sys/mman.h>
28 28 #include <dirent.h>
29 29 #include <stdio.h>
30 30 #include <stdlib.h>
31 31 #include <string.h>
32 32 #include <limits.h>
33 33 #include <debug.h>
34 34 #include <conv.h>
35 35 #include <elfcap.h>
36 36 #include "_rtld.h"
37 37 #include "_elf.h"
38 38 #include "_audit.h"
39 39 #include "msg.h"
40 40
41 41 /*
42 42 * qsort(3c) capability comparison function.
43 43 */
44 44 static int
45 45 compare(const void *vp_a, const void *vp_b)
46 46 {
47 47 Fdesc *fdp_a = (Fdesc *)vp_a, *fdp_b = (Fdesc *)vp_b;
48 48 char *strcap_a, *strcap_b;
49 49 Xword hwcap_a, hwcap_b;
50 50
51 51 /*
52 52 * First, investigate any platform capability.
53 53 */
54 54 strcap_a = fdp_a->fd_scapset.sc_plat;
55 55 strcap_b = fdp_b->fd_scapset.sc_plat;
56 56
57 57 if (strcap_a && (strcap_b == NULL))
58 58 return (-1);
59 59 if (strcap_b && (strcap_a == NULL))
60 60 return (1);
61 61
62 62 /*
63 63 * Second, investigate any machine capability.
64 64 */
65 65 strcap_a = fdp_a->fd_scapset.sc_mach;
66 66 strcap_b = fdp_b->fd_scapset.sc_mach;
67 67
68 68 if (strcap_a && (strcap_b == NULL))
69 69 return (-1);
70 70 if (strcap_b && (strcap_a == NULL))
71 71 return (1);
72 72
73 73 /*
74 74 * Third, investigate any CA_SUNW_HW_2 hardware capabilities.
75 75 */
76 76 hwcap_a = fdp_a->fd_scapset.sc_hw_2;
77 77 hwcap_b = fdp_b->fd_scapset.sc_hw_2;
78 78
79 79 if (hwcap_a > hwcap_b)
80 80 return (-1);
81 81 if (hwcap_a < hwcap_b)
82 82 return (1);
83 83
84 84 /*
85 85 * Finally, investigate any CA_SUNW_HW_1 hardware capabilities.
86 86 */
87 87 hwcap_a = fdp_a->fd_scapset.sc_hw_1;
88 88 hwcap_b = fdp_b->fd_scapset.sc_hw_1;
89 89
90 90 if (hwcap_a > hwcap_b)
91 91 return (-1);
92 92 if (hwcap_a < hwcap_b)
93 93 return (1);
94 94
95 95 /*
96 96 * Normally, a capabilities directory contains one or more capabilities
97 97 * files, each with different capabilities. The role of ld.so.1 is to
98 98 * select the best candidate from these variants. However, we've come
99 99 * across cases where files containing the same capabilities have been
100 100 * placed in the same capabilities directory. As we can't tell which
101 101 * file is the best, we select neither, and diagnose this suspicious
102 102 * scenario.
103 103 */
104 104 DBG_CALL(Dbg_cap_identical(fdp_a->fd_lml, fdp_a->fd_nname,
105 105 fdp_b->fd_nname));
106 106
107 107 fdp_a->fd_flags |= FLG_FD_IGNORE;
108 108 fdp_b->fd_flags |= FLG_FD_IGNORE;
109 109
110 110 return (0);
111 111 }
112 112
113 113 /*
114 114 * Determine whether HWCAP1 capabilities value is supported.
115 115 */
116 116 int
117 117 hwcap1_check(Syscapset *scapset, Xword val, Rej_desc *rej)
118 118 {
119 119 Xword mval;
120 120
121 121 /*
122 122 * Ensure that the kernel can cope with the required capabilities.
123 123 */
124 124 if ((rtld_flags2 & RT_FL2_HWCAP) &&
125 125 ((mval = (val & ~scapset->sc_hw_1)) != 0)) {
126 126 if (rej) {
127 127 static Conv_cap_val_hw1_buf_t cap_buf;
128 128
129 129 rej->rej_type = SGS_REJ_HWCAP_1;
130 130 rej->rej_str = conv_cap_val_hw1(mval,
131 131 M_MACH, 0, &cap_buf);
132 132 }
133 133 return (0);
134 134 }
135 135 return (1);
136 136 }
137 137
138 138 /*
139 139 * Determine whether HWCAP2 capabilities value is supported.
140 140 */
141 141 int
142 142 hwcap2_check(Syscapset *scapset, Xword val, Rej_desc *rej)
143 143 {
144 144 Xword mval;
145 145
146 146 /*
147 147 * Ensure that the kernel can cope with the required capabilities.
148 148 */
149 149 if ((mval = (val & ~scapset->sc_hw_2)) != 0) {
150 150 if (rej) {
151 151 static Conv_cap_val_hw2_buf_t cap_buf;
152 152
153 153 rej->rej_type = SGS_REJ_HWCAP_2;
154 154 rej->rej_str = conv_cap_val_hw2(mval,
155 155 M_MACH, 0, &cap_buf);
156 156 }
157 157 return (0);
158 158 }
159 159 return (1);
160 160 }
161 161
162 162 /*
163 163 * Process any software capabilities.
164 164 */
165 165 /* ARGSUSED0 */
166 166 int
167 167 sfcap1_check(Syscapset *scapset, Xword val, Rej_desc *rej)
168 168 {
169 169 #if defined(_ELF64)
170 170 /*
171 171 * A 64-bit executable that started the process can be restricted to a
172 172 * 32-bit address space. A 64-bit dependency that is restricted to a
173 173 * 32-bit address space can not be loaded unless the executable has
174 174 * established this requirement.
175 175 */
176 176 if ((val & SF1_SUNW_ADDR32) && ((rtld_flags2 & RT_FL2_ADDR32) == 0)) {
177 177 if (rej) {
178 178 static Conv_cap_val_sf1_buf_t cap_buf;
179 179
180 180 rej->rej_type = SGS_REJ_SFCAP_1;
181 181 rej->rej_str = conv_cap_val_sf1(SF1_SUNW_ADDR32,
182 182 M_MACH, 0, &cap_buf);
183 183 }
184 184 return (0);
185 185 }
186 186 #endif
187 187 return (1);
188 188 }
189 189
190 190 /*
191 191 * Process any platform capability.
192 192 */
193 193 int
194 194 platcap_check(Syscapset *scapset, const char *str, Rej_desc *rej)
195 195 {
196 196 /*
197 197 * If the platform name hasn't been set, try and obtain it.
198 198 */
199 199 if ((scapset->sc_plat == NULL) &&
200 200 (scapset->sc_platsz == 0))
201 201 platform_name(scapset);
202 202
203 203 if ((scapset->sc_plat == NULL) ||
204 204 (str && strcmp(scapset->sc_plat, str))) {
205 205 if (rej) {
206 206 /*
207 207 * Note, the platform name points to a string within an
208 208 * objects string table, and if that object can't be
209 209 * loaded, it will be unloaded and thus invalidate the
210 210 * string. Duplicate the string here for rejection
211 211 * message inheritance.
212 212 */
213 213 rej->rej_type = SGS_REJ_PLATCAP;
214 214 rej->rej_str = stravl_insert(str, 0, 0, 0);
215 215 }
216 216 return (0);
217 217 }
218 218 return (1);
219 219 }
220 220
221 221 /*
222 222 * Process any machine capability.
223 223 */
224 224 int
225 225 machcap_check(Syscapset *scapset, const char *str, Rej_desc *rej)
226 226 {
227 227 /*
228 228 * If the machine name hasn't been set, try and obtain it.
229 229 */
230 230 if ((scapset->sc_mach == NULL) &&
231 231 (scapset->sc_machsz == 0))
232 232 machine_name(scapset);
233 233
234 234 if ((scapset->sc_mach == NULL) ||
235 235 (str && strcmp(scapset->sc_mach, str))) {
236 236 if (rej) {
237 237 /*
238 238 * Note, the machine name points to a string within an
239 239 * objects string table, and if that object can't be
240 240 * loaded, it will be unloaded and thus invalidate the
241 241 * string. Duplicate the string here for rejection
242 242 * message inheritance.
243 243 */
244 244 rej->rej_type = SGS_REJ_MACHCAP;
245 245 rej->rej_str = stravl_insert(str, 0, 0, 0);
246 246 }
247 247 return (0);
248 248 }
249 249 return (1);
250 250 }
251 251
252 252 /*
253 253 * Generic front-end to capabilities validation.
254 254 */
255 255 static int
256 256 cap_check(Cap *cptr, char *strs, int alt, Fdesc *fdp, Rej_desc *rej)
257 257 {
258 258 Syscapset *scapset;
259 259 int totplat, ivlplat, totmach, ivlmach;
260 260
261 261 /*
262 262 * If the caller has no capabilities, then the object is valid.
263 263 */
264 264 if (cptr == NULL)
265 265 return (1);
266 266
267 267 if (alt)
268 268 scapset = alt_scapset;
269 269 else
270 270 scapset = org_scapset;
271 271
272 272 totplat = ivlplat = totmach = ivlmach = 0;
273 273
274 274 while (cptr->c_tag != CA_SUNW_NULL) {
275 275 Xword val = cptr->c_un.c_val;
276 276 char *str;
277 277
278 278 switch (cptr->c_tag) {
279 279 case CA_SUNW_HW_1:
280 280 /*
281 281 * Remove any historic values that should not be
282 282 * involved with any validation.
283 283 */
284 284 val &= ~AV_HW1_IGNORE;
285 285
286 286 if (hwcap1_check(scapset, val, rej) == 0)
287 287 return (0);
288 288 if (fdp)
289 289 fdp->fd_scapset.sc_hw_1 = val;
290 290 break;
291 291 case CA_SUNW_SF_1:
292 292 if (sfcap1_check(scapset, val, rej) == 0)
293 293 return (0);
294 294 if (fdp)
295 295 fdp->fd_scapset.sc_sf_1 = val;
296 296 break;
297 297 case CA_SUNW_HW_2:
298 298 if (hwcap2_check(scapset, val, rej) == 0)
299 299 return (0);
300 300 if (fdp)
301 301 fdp->fd_scapset.sc_hw_2 = val;
302 302 break;
303 303 case CA_SUNW_PLAT:
304 304 /*
305 305 * A capabilities group can define multiple platform
306 306 * names that are appropriate. Only if all the names
307 307 * are deemed invalid is the group determined
308 308 * inappropriate.
309 309 */
310 310 if (totplat == ivlplat) {
311 311 totplat++;
312 312
313 313 str = strs + val;
314 314
315 315 if (platcap_check(scapset, str, rej) == 0)
316 316 ivlplat++;
317 317 else if (fdp)
318 318 fdp->fd_scapset.sc_plat = str;
319 319 }
320 320 break;
321 321 case CA_SUNW_MACH:
322 322 /*
323 323 * A capabilities group can define multiple machine
324 324 * names that are appropriate. Only if all the names
325 325 * are deemed invalid is the group determined
326 326 * inappropriate.
327 327 */
328 328 if (totmach == ivlmach) {
329 329 totmach++;
330 330
331 331 str = strs + val;
332 332
333 333 if (machcap_check(scapset, str, rej) == 0)
334 334 ivlmach++;
335 335 else if (fdp)
336 336 fdp->fd_scapset.sc_mach = str;
337 337 }
338 338 break;
339 339 case CA_SUNW_ID:
340 340 /*
341 341 * Capabilities identifiers provide for diagnostics,
342 342 * but are not attributes that must be compared with
343 343 * the system. They are ignored.
344 344 */
345 345 break;
346 346 default:
347 347 rej->rej_type = SGS_REJ_UNKCAP;
348 348 rej->rej_info = cptr->c_tag;
349 349 return (0);
350 350 }
351 351 cptr++;
352 352 }
353 353
354 354 /*
355 355 * If any platform names, or machine names were found, and all were
356 356 * invalid, indicate that the object is inappropriate.
357 357 */
358 358 if ((totplat && (totplat == ivlplat)) ||
359 359 (totmach && (totmach == ivlmach)))
360 360 return (0);
361 361
362 362 return (1);
363 363 }
364 364
365 365 #define HWAVL_RECORDED(n) pnavl_recorded(&capavl, n, NULL, NULL)
366 366
367 367 /*
368 368 * Determine whether a link-map should use alternative system capabilities.
369 369 */
370 370 static void
371 371 cap_check_lmp_init(Rt_map *lmp)
372 372 {
373 373 int alt = 0;
374 374
375 375 /*
376 376 * If an alternative set of system capabilities have been established,
377 377 * and only specific files should use these alternative system
378 378 * capabilities, determine whether this file is one of those specified.
379 379 */
380 380 if (capavl) {
381 381 const char *file;
382 382
383 383 /*
384 384 * The simplest way to reference a file is to use its file name
385 385 * (soname), however try all of the names that this file is
386 386 * known by.
387 387 */
388 388 if ((file = strrchr(NAME(lmp), '/')) != NULL)
389 389 file++;
390 390 else
391 391 file = NULL;
392 392
393 393 if ((file && (HWAVL_RECORDED(file) != 0)) ||
394 394 (HWAVL_RECORDED(NAME(lmp)) != 0) ||
395 395 ((PATHNAME(lmp) != NAME(lmp)) &&
396 396 (HWAVL_RECORDED(PATHNAME(lmp)) != 0)))
397 397 alt = 1;
398 398
399 399 if (alt == 0) {
400 400 Aliste idx;
401 401 const char *cp;
402 402
403 403 for (APLIST_TRAVERSE(ALIAS(lmp), idx, cp)) {
404 404 if ((alt = HWAVL_RECORDED(cp)) != 0)
405 405 break;
406 406 }
407 407 }
408 408 }
409 409
410 410 /*
411 411 * Indicate if this link-map should use alternative system capabilities,
412 412 * and that the alternative system capabilities check has been carried
413 413 * out.
414 414 */
415 415 if ((org_scapset != alt_scapset) && ((capavl == NULL) || alt))
416 416 FLAGS1(lmp) |= FL1_RT_ALTCAP;
417 417 FLAGS1(lmp) |= FL1_RT_ALTCHECK;
418 418 }
419 419
420 420 /*
421 421 * Validate the capabilities requirements of a link-map.
422 422 *
423 423 * This routine is called for main, where a link-map is constructed from the
424 424 * mappings returned from exec(), and for any symbol capabilities comparisons.
425 425 */
426 426 int
427 427 cap_check_lmp(Rt_map *lmp, Rej_desc *rej)
428 428 {
429 429 if ((FLAGS1(lmp) & FL1_RT_ALTCHECK) == 0)
430 430 cap_check_lmp_init(lmp);
431 431
432 432 return (cap_check(CAP(lmp), STRTAB(lmp),
433 433 (FLAGS1(lmp) & FL1_RT_ALTCAP), NULL, rej));
434 434 }
435 435
436 436 /*
437 437 * Validate the capabilities requirements of a file under inspection.
438 438 * This file is still under the early stages of loading, and has no link-map
439 439 * yet. The file must have an object capabilities definition (PT_SUNWCAP), to
440 440 * have gotten us here. The logic here is the same as cap_check_lmp().
441 441 */
442 442 int
443 443 cap_check_fdesc(Fdesc *fdp, Cap *cptr, char *strs, Rej_desc *rej)
444 444 {
445 445 int alt = 0;
446 446
447 447 /*
448 448 * If an alternative set of system capabilities have been established,
449 449 * and only specific files should use these alternative system
450 450 * capabilities, determine whether this file is one of those specified.
451 451 */
452 452 if (capavl) {
453 453 const char *file;
454 454
455 455 /*
456 456 * The simplest way to reference a file is to use its file name
457 457 * (soname), however try all of the names that this file is
458 458 * known by.
459 459 */
460 460 if (fdp->fd_oname &&
461 461 ((file = strrchr(fdp->fd_oname, '/')) != NULL))
462 462 file++;
463 463 else
464 464 file = NULL;
465 465
466 466 if ((file && (HWAVL_RECORDED(file) != 0)) ||
467 467 (fdp->fd_oname && (HWAVL_RECORDED(fdp->fd_oname) != 0)) ||
468 468 (fdp->fd_nname && (HWAVL_RECORDED(fdp->fd_nname) != 0)) ||
469 469 (fdp->fd_pname && (fdp->fd_pname != fdp->fd_nname) &&
470 470 (HWAVL_RECORDED(fdp->fd_pname) != 0)))
471 471 alt = 1;
472 472 }
473 473
474 474 /*
475 475 * Indicate if this file descriptor should use alternative system
476 476 * capabilities, and that the alternative system capabilities check has
477 477 * been carried out.
478 478 */
479 479 if ((org_scapset != alt_scapset) && ((capavl == NULL) || alt))
480 480 fdp->fd_flags |= FLG_FD_ALTCAP;
481 481 fdp->fd_flags |= FLG_FD_ALTCHECK;
482 482
483 483 /*
484 484 * Verify that the required capabilities are supported by the reference.
485 485 */
486 486 return (cap_check(cptr, strs, (fdp->fd_flags & FLG_FD_ALTCAP),
487 487 fdp, rej));
488 488 }
489 489
490 490 /*
491 491 * Free a file descriptor list. As part of building this list, the original
492 492 * names for each capabilities candidate were duplicated for use in later
493 493 * diagnostics. These names need to be freed.
494 494 */
495 495 void
496 496 free_fd(Alist *fdalp)
497 497 {
498 498 if (fdalp) {
499 499 Aliste idx;
500 500 Fdesc *fdp;
501 501
502 502 for (ALIST_TRAVERSE(fdalp, idx, fdp)) {
503 503 if (fdp->fd_oname)
504 504 free((void *)fdp->fd_oname);
505 505 }
506 506 free(fdalp);
507 507 }
508 508 }
509 509
510 510 /*
511 511 * When $CAPABILITY (or $HWCAP) is used to represent dependencies, take the
512 512 * associated directory and analyze all the files it contains.
513 513 */
514 514 static int
515 515 cap_dir(Alist **fdalpp, Lm_list *lml, const char *dname, Rt_map *clmp,
516 516 uint_t flags, Rej_desc *rej, int *in_nfavl)
517 517 {
518 518 char path[PATH_MAX], *dst;
519 519 const char *src;
520 520 DIR *dir;
521 521 struct dirent *dirent;
522 522 Alist *fdalp = NULL;
523 523 Aliste idx;
524 524 Fdesc *fdp;
525 525 int error = 0;
526 526
527 527 /*
528 528 * Access the directory in preparation for reading its entries. If
529 529 * successful, establish the initial pathname.
530 530 */
531 531 if ((dir = opendir(dname)) == NULL) {
532 532 Rej_desc _rej = { 0 };
533 533
534 534 _rej.rej_type = SGS_REJ_STR;
535 535 _rej.rej_name = dname;
536 536 _rej.rej_str = strerror(errno);
537 537 DBG_CALL(Dbg_file_rejected(lml, &_rej, M_MACH));
538 538 rejection_inherit(rej, &_rej);
539 539 return (0);
540 540 }
541 541
542 542 for (dst = path, src = dname; *src; dst++, src++)
543 543 *dst = *src;
544 544 *dst++ = '/';
545 545
546 546 /*
547 547 * Read each entry from the directory and determine whether it is a
548 548 * valid ELF file.
549 549 */
550 550 while ((dirent = readdir(dir)) != NULL) {
551 551 const char *file = dirent->d_name;
552 552 char *_dst;
553 553 Fdesc fd = { 0 };
554 554 Rej_desc _rej = { 0 };
555 555 Pdesc pd = { 0 };
556 556
557 557 /*
558 558 * Ignore "." and ".." entries.
559 559 */
560 560 if ((file[0] == '.') && ((file[1] == '\0') ||
561 561 ((file[1] == '.') && (file[2] == '\0'))))
562 562 continue;
563 563
564 564 /*
565 565 * Complete the full pathname.
566 566 */
567 567 for (_dst = dst, src = file, file = dst; *src; _dst++, src++)
568 568 *_dst = *src;
569 569 *_dst = '\0';
570 570
571 571 /*
572 572 * Trace the inspection of this file, and determine any
573 573 * auditor substitution.
574 574 */
575 575 pd.pd_pname = path;
576 576 pd.pd_flags = PD_FLG_PNSLASH;
577 577
578 578 if (load_trace(lml, &pd, clmp, &fd) == NULL)
579 579 continue;
580 580
581 581 /*
582 582 * Note, all directory entries are processed by find_path(),
583 583 * even entries that are directories themselves. This single
584 584 * point for control keeps the number of stat()'s down, and
585 585 * provides a single point for error diagnostics.
586 586 */
587 587 if (find_path(lml, clmp, flags, &fd, &_rej, in_nfavl) == 0) {
588 588 rejection_inherit(rej, &_rej);
589 589 continue;
590 590 }
591 591
592 592 DBG_CALL(Dbg_cap_candidate(lml, fd.fd_nname));
593 593
594 594 /*
595 595 * If this object has already been loaded, save the capabilities
596 596 * for later sorting. Otherwise we have a new candidate.
597 597 */
598 598 if (fd.fd_lmp)
599 599 fd.fd_scapset = CAPSET(fd.fd_lmp);
600 600 fd.fd_lml = lml;
601 601
602 602 /*
603 603 * Duplicate the original name, as this may be required for
604 604 * later diagnostics. Keep a copy of the file descriptor for
605 605 * analysis once all capabilities candidates have been
606 606 * determined.
607 607 */
608 608 if (((fd.fd_oname = strdup(fd.fd_oname)) == NULL) ||
609 609 (alist_append(&fdalp, &fd, sizeof (Fdesc),
610 610 AL_CNT_CAP) == NULL)) {
611 611 error = 1;
612 612 break;
613 613 }
614 614 }
615 615 (void) closedir(dir);
616 616
617 617 /*
618 618 * If no objects have been found, we're done. Also, if an allocation
619 619 * error occurred while processing any object, remove any objects that
620 620 * had already been added to the list and return.
621 621 */
622 622 if ((fdalp == NULL) || error) {
623 623 if (fdalp)
624 624 free_fd(fdalp);
625 625 return (0);
626 626 }
627 627
628 628 /*
629 629 * Having processed and retained all candidates from this directory,
630 630 * sort them, based on the precedence of their hardware capabilities.
631 631 */
632 632 qsort(fdalp->al_data, fdalp->al_nitems, fdalp->al_size, compare);
633 633
634 634 /*
635 635 * If any objects were found to have the same capabilities, then these
636 636 * objects must be rejected, as we can't tell which object is more
637 637 * appropriate.
638 638 */
639 639 for (ALIST_TRAVERSE(fdalp, idx, fdp)) {
640 640 if (fdp->fd_flags & FLG_FD_IGNORE)
641 641 alist_delete(fdalp, &idx);
642 642 }
643 643
644 644 if (fdalp->al_nitems == 0) {
645 645 free_fd(fdalp);
646 646 return (0);
647 647 }
648 648
649 649 *fdalpp = fdalp;
650 650 return (1);
651 651 }
652 652
653 653 int
654 654 cap_filtees(Alist **alpp, Aliste oidx, const char *dir, Aliste nlmco,
655 655 Rt_map *flmp, Rt_map *clmp, const char *ref, int mode, uint_t flags,
656 656 int *in_nfavl)
657 657 {
658 658 Alist *fdalp = NULL;
659 659 Aliste idx;
660 660 Fdesc *fdp;
661 661 Lm_list *lml = LIST(flmp);
662 662 int unused = 0;
663 663 Rej_desc rej = { 0 };
664 664
665 665 if (cap_dir(&fdalp, lml, dir, flmp, flags, &rej, in_nfavl) == 0)
666 666 return (0);
667 667
668 668 /*
669 669 * Now complete the mapping of each of the ordered objects, adding
670 670 * each object to a new pathname descriptor.
671 671 */
672 672 for (ALIST_TRAVERSE(fdalp, idx, fdp)) {
673 673 Rt_map *nlmp;
674 674 Grp_hdl *ghp = NULL;
675 675 Pdesc *pdp;
676 676 int audit = 0;
677 677
678 678 if (unused)
679 679 continue;
680 680
681 681 /*
682 682 * Complete mapping the file, obtaining a handle, and continue
683 683 * to analyze the object, establishing dependencies and
684 684 * relocating. Remove the file descriptor at this point, as it
685 685 * is no longer required.
686 686 */
687 687 DBG_CALL(Dbg_file_filtee(lml, NAME(flmp), fdp->fd_nname, 0));
688 688
689 689 nlmp = load_path(lml, nlmco, flmp, mode,
690 690 (flags | FLG_RT_PUBHDL), &ghp, fdp, &rej, in_nfavl);
691 691 if (nlmp == NULL)
692 692 continue;
693 693
694 694 /*
695 695 * Create a new pathname descriptor to represent this filtee,
696 696 * and insert this descriptor in the Alist following the
697 697 * hardware descriptor that seeded this processing.
698 698 */
699 699 if ((pdp = alist_insert(alpp, 0, sizeof (Pdesc),
700 700 AL_CNT_FILTEES, ++oidx)) == NULL) {
701 701 if (ghp)
702 702 remove_lmc(lml, flmp, nlmco, NAME(nlmp));
703 703 return (0);
704 704 }
705 705
706 706 pdp->pd_pname = NAME(nlmp);
707 707 pdp->pd_plen = strlen(NAME(nlmp));
708 708
709 709 /*
710 710 * Establish the filter handle to prevent any recursion.
711 711 */
712 712 if (nlmp && ghp) {
713 713 ghp->gh_flags |= GPH_FILTEE;
714 714 pdp->pd_info = (void *)ghp;
715 715 }
716 716
717 717 /*
718 718 * Audit the filter/filtee established. A return of 0
719 719 * indicates the auditor wishes to ignore this filtee.
720 720 */
721 721 if (nlmp && (lml->lm_tflags | FLAGS1(flmp)) &
722 722 LML_TFLG_AUD_OBJFILTER) {
723 723 if (audit_objfilter(flmp, ref, nlmp, 0) == 0) {
724 724 audit = 1;
725 725 nlmp = NULL;
726 726 }
727 727 }
728 728
729 729 /*
730 730 * Finish processing the objects associated with this request.
731 731 */
732 732 if (nlmp && ghp && (((nlmp = analyze_lmc(lml, nlmco, nlmp,
733 733 clmp, in_nfavl)) == NULL) ||
734 734 (relocate_lmc(lml, nlmco, flmp, nlmp, in_nfavl) == 0)))
735 735 nlmp = NULL;
736 736
737 737 /*
738 738 * If the filtee has been successfully processed, then create
739 739 * an association between the filter and the filtee. This
740 740 * association provides sufficient information to tear down the
741 741 * filter and filtee if necessary.
742 742 */
743 743 DBG_CALL(Dbg_file_hdl_title(DBG_HDL_ADD));
744 744 if (nlmp && ghp &&
745 745 (hdl_add(ghp, flmp, GPD_FILTER, NULL) == NULL))
746 746 nlmp = NULL;
747 747
748 748 /*
749 749 * If this object is marked an end-filtee, we're done.
750 750 */
751 751 if (nlmp && ghp && (FLAGS1(nlmp) & FL1_RT_ENDFILTE))
752 752 unused = 1;
753 753
754 754 /*
755 755 * If this filtee loading has failed, generate a diagnostic.
756 756 * Null out the path name descriptor entry, and continue the
757 757 * search.
758 758 */
759 759 if (nlmp == NULL) {
760 760 DBG_CALL(Dbg_file_filtee(lml, 0, pdp->pd_pname, audit));
761 761
762 762 /*
763 763 * If attempting to load this filtee required a new
764 764 * link-map control list to which this request has
765 765 * added objects, then remove all the objects that
766 766 * have been associated to this request.
767 767 */
768 768 if (nlmco != ALIST_OFF_DATA)
769 769 remove_lmc(lml, flmp, nlmco, pdp->pd_pname);
770 770
771 771 pdp->pd_plen = 0;
772 772 pdp->pd_info = NULL;
773 773 }
774 774 }
775 775
776 776 free_fd(fdalp);
777 777 return (1);
778 778 }
779 779
780 780 /*
781 781 * Load an individual capabilities object.
782 782 */
783 783 Rt_map *
784 784 load_cap(Lm_list *lml, Aliste lmco, const char *dir, Rt_map *clmp,
785 785 uint_t mode, uint_t flags, Grp_hdl **hdl, Rej_desc *rej, int *in_nfavl)
786 786 {
787 787 Alist *fdalp = NULL;
788 788 Aliste idx;
789 789 Fdesc *fdp;
790 790 int found = 0;
791 791 Rt_map *lmp = NULL;
792 792
793 793 /*
794 794 * Obtain the sorted list of hardware capabilities objects available.
795 795 */
796 796 if (cap_dir(&fdalp, lml, dir, clmp, flags, rej, in_nfavl) == 0)
797 797 return (NULL);
798 798
799 799 /*
800 800 * From the list of hardware capability objects, use the first and
801 801 * discard the rest.
802 802 */
803 803 for (ALIST_TRAVERSE(fdalp, idx, fdp)) {
804 804 Fdesc fd = *fdp;
805 805
806 806 if ((found == 0) && ((lmp = load_path(lml, lmco, clmp, mode,
807 807 flags, hdl, &fd, rej, in_nfavl)) != NULL))
808 808 found++;
809 809 }
810 810
811 811 free_fd(fdalp);
812 812 return (lmp);
813 813 }
814 814
815 815 /*
816 816 * Use a case insensitive string match when looking up capability mask
817 817 * values by name, and omit the AV_ prefix.
818 818 */
819 819 #define ELFCAP_STYLE ELFCAP_STYLE_LC | ELFCAP_STYLE_F_ICMP
820 820
821 821 /*
822 822 * To aid in the development and testing of capabilities, an alternative system
823 823 * capabilities group can be specified. This alternative set is initialized
824 824 * from the system capabilities that are normally used to validate all object
825 825 * loading. However, the user can disable, enable or override flags within
826 826 * this alternative set, and thus affect object loading.
827 827 *
828 828 * This technique is usually combined with defining the family of objects
829 829 * that should be compared against this alternative set. Without defining the
830 830 * family of objects, all objects loaded by ld.so.1 are validated against the
831 831 * alternative set. This can prevent the loading of critical system objects
832 832 * like libc, and thus prevent process execution.
833 833 */
834 834 typedef enum {
835 835 CAP_OVERRIDE = 0, /* override existing capabilities */
836 836 CAP_ENABLE = 1, /* enable capabilities */
837 837 CAP_DISABLE = 2 /* disable capabilities */
838 838 } cap_mode;
839 839
840 840 static struct {
841 841 elfcap_mask_t cs_val[3]; /* value settings, and indicator for */
842 842 int cs_set[3]; /* OVERRIDE, ENABLE and DISABLE */
843 843 elfcap_mask_t *cs_aval; /* alternative variable for final */
844 844 /* update */
845 845 } cap_settings[3] = {
846 846 { { 0, 0, 0 }, { 0, 0, 0 }, NULL }, /* CA_SUNW_HW_1 */
847 847 { { 0, 0, 0 }, { 0, 0, 0 }, NULL }, /* CA_SUNW_SF_1 */
848 848 { { 0, 0, 0 }, { 0, 0, 0 }, NULL } /* CA_SUNW_HW_2 */
849 849 };
850 850
851 851 static int
852 852 cap_modify(Xword tag, const char *str)
853 853 {
854 854 char *caps, *ptr, *next;
855 855 cap_mode mode = CAP_OVERRIDE;
856 856 Xword ndx;
857 857
858 858 if ((caps = strdup(str)) == NULL)
859 859 return (0);
860 860
861 861 for (ptr = strtok_r(caps, MSG_ORIG(MSG_CAP_DELIMIT), &next);
862 862 ptr != NULL;
863 863 ptr = strtok_r(NULL, MSG_ORIG(MSG_CAP_DELIMIT), &next)) {
864 864 Xword val = 0;
865 865
866 866 /*
867 867 * Determine whether this token should be enabled (+),
868 868 * disabled (-), or override any existing settings.
869 869 */
870 870 if (*ptr == '+') {
871 871 mode = CAP_ENABLE;
872 872 ptr++;
873 873 } else if (*ptr == '-') {
874 874 mode = CAP_DISABLE;
875 875 ptr++;
876 876 }
877 877
878 878 /*
879 879 * Process the capabilities as directed by the calling tag.
880 880 */
881 881 switch (tag) {
882 882 case CA_SUNW_HW_1:
883 883 /*
884 884 * Determine whether the capabilities string matches
885 885 * a known hardware capability mask. Note, the caller
886 886 * indicates that these are hardware capabilities by
887 887 * passing in the CA_SUNW_HW_1 tag. However, the
888 888 * tokens could be CA_SUNW_HW_1 or CA_SUNW_HW_2.
889 889 */
890 890 if ((val = (Xword)elfcap_hw2_from_str(ELFCAP_STYLE,
891 891 ptr, M_MACH)) != 0) {
892 892 ndx = CA_SUNW_HW_2;
893 893 break;
894 894 }
895 895 if ((val = (Xword)elfcap_hw1_from_str(ELFCAP_STYLE,
896 896 ptr, M_MACH)) != 0)
897 897 ndx = CA_SUNW_HW_1;
898 898 break;
899 899 case CA_SUNW_SF_1:
900 900 /*
901 901 * Determine whether the capabilities string matches a
902 902 * known software capability mask. Note, the callers
903 903 * indication of what capabilities to process are
904 904 * triggered by a tag of CA_SUNW_SF_1, but the tokens
905 905 * processed could be CA_SUNW_SF_1, CA_SUNW_SF_2, etc.
906 906 */
907 907 if ((val = (Xword)elfcap_sf1_from_str(ELFCAP_STYLE,
908 908 ptr, M_MACH)) != 0)
909 909 ndx = CA_SUNW_SF_1;
910 910 break;
911 911 }
912 912
913 913 /*
914 914 * If a capabilities token has not been matched, interpret the
915 915 * string as a number. To provide for setting the various
916 916 * families (CA_SUNW_HW_1, CA_SUNW_HW_2), the number can be
917 917 * prefixed with the (bracketed) family index.
918 918 *
919 919 * LD_HWCAP=[1]0x40 sets CA_SUNW_HW_1 with 0x40
920 920 * LD_HWCAP=[2]0x80 sets CA_SUNW_HW_2 with 0x80
921 921 *
922 922 * Invalid indexes are ignored.
923 923 */
924 924 if (val == 0) {
925 925 char *end;
926 926
927 927 if ((*ptr == '[') && (*(ptr + 2) == ']')) {
928 928 if (*(ptr + 1) == '1') {
929 929 ndx = tag;
930 930 ptr += 3;
931 931 } else if (*(ptr + 1) == '2') {
932 932 if (tag == CA_SUNW_HW_1) {
933 933 ndx = CA_SUNW_HW_2;
934 934 ptr += 3;
935 935 } else {
936 936 /* invalid index */
937 937 continue;
938 938 }
939 939 } else {
940 940 /* invalid index */
941 941 continue;
942 942 }
943 943 } else
944 944 ndx = tag;
945 945
946 946 errno = 0;
947 947 if (((val = strtol(ptr, &end, 16)) == 0) && errno)
948 948 continue;
949 949
950 950 /*
951 951 * If the value wasn't an entirely valid hexadecimal
952 952 * integer, assume it was intended as a capability
953 953 * name and skip it.
954 954 */
955 955 if (*end != '\0') {
956 956 eprintf(NULL, ERR_WARNING,
957 957 MSG_INTL(MSG_CAP_IGN_UNKCAP), ptr);
958 958 continue;
959 959 }
960 960 }
961 961
962 962 cap_settings[ndx - 1].cs_val[mode] |= val;
963 963 cap_settings[ndx - 1].cs_set[mode]++;
964 964
965 965 }
966 966
967 967 /*
968 968 * If the "override" token was supplied, set the alternative
969 969 * system capabilities, then enable or disable others.
970 970 */
971 971 for (ndx = 0; ndx < CA_SUNW_HW_2; ndx++) {
972 972 if (cap_settings[ndx].cs_set[CAP_OVERRIDE])
973 973 *(cap_settings[ndx].cs_aval) =
974 974 cap_settings[ndx].cs_val[CAP_OVERRIDE];
975 975 if (cap_settings[ndx].cs_set[CAP_ENABLE])
976 976 *(cap_settings[ndx].cs_aval) |=
977 977 cap_settings[ndx].cs_val[CAP_ENABLE];
978 978 if (cap_settings[ndx].cs_set[CAP_DISABLE])
979 979 *(cap_settings[ndx].cs_aval) &=
980 980 ~cap_settings[ndx].cs_val[CAP_DISABLE];
981 981 }
982 982 free(caps);
983 983 return (1);
984 984 }
985 985 #undef ELFCAP_STYLE
986 986
987 987 /*
988 988 * Create an AVL tree of objects that are to be validated against an alternative
989 989 * system capabilities value.
990 990 */
991 991 static int
992 992 cap_files(const char *str)
993 993 {
994 994 char *caps, *name, *next;
995 995
996 996 if ((caps = strdup(str)) == NULL)
997 997 return (0);
998 998
999 999 for (name = strtok_r(caps, MSG_ORIG(MSG_CAP_DELIMIT), &next);
1000 1000 name != NULL;
1001 1001 name = strtok_r(NULL, MSG_ORIG(MSG_CAP_DELIMIT), &next)) {
↓ open down ↓ |
1001 lines elided |
↑ open up ↑ |
1002 1002 avl_index_t where;
1003 1003 PathNode *pnp;
1004 1004 uint_t hash = sgs_str_hash(name);
1005 1005
1006 1006 /*
1007 1007 * Determine whether this pathname has already been recorded.
1008 1008 */
1009 1009 if (pnavl_recorded(&capavl, name, hash, &where))
1010 1010 continue;
1011 1011
1012 - if ((pnp = calloc(sizeof (PathNode), 1)) != NULL) {
1012 + if ((pnp = calloc(1, sizeof (PathNode))) != NULL) {
1013 1013 pnp->pn_name = name;
1014 1014 pnp->pn_hash = hash;
1015 1015 avl_insert(capavl, pnp, where);
1016 1016 }
1017 1017 }
1018 1018
1019 1019 return (1);
1020 1020 }
1021 1021
1022 1022 /*
1023 1023 * Set alternative system capabilities. A user can establish alternative system
1024 1024 * capabilities from the environment, or from a configuration file. This
1025 1025 * routine is called in each instance. Environment variables only set the
1026 1026 * replaceable (rpl) variables. Configuration files can set both replaceable
1027 1027 * (rpl) and permanent (prm) variables.
1028 1028 */
1029 1029 int
1030 1030 cap_alternative(void)
1031 1031 {
1032 1032 /*
1033 1033 * If no capabilities have been set, we're done.
1034 1034 */
1035 1035 if ((rpl_hwcap == NULL) && (rpl_sfcap == NULL) &&
1036 1036 (rpl_machcap == NULL) && (rpl_platcap == NULL) &&
1037 1037 (prm_hwcap == NULL) && (prm_sfcap == NULL) &&
1038 1038 (prm_machcap == NULL) && (prm_platcap == NULL))
1039 1039 return (1);
1040 1040
1041 1041 /*
1042 1042 * If the user has requested to modify any capabilities, establish a
1043 1043 * unique set from the present system capabilities.
1044 1044 */
1045 1045 if ((alt_scapset = malloc(sizeof (Syscapset))) == NULL)
1046 1046 return (0);
1047 1047 *alt_scapset = *org_scapset;
1048 1048
1049 1049 cap_settings[CA_SUNW_HW_1 - 1].cs_aval = &alt_scapset->sc_hw_1;
1050 1050 cap_settings[CA_SUNW_SF_1 - 1].cs_aval = &alt_scapset->sc_sf_1;
1051 1051 cap_settings[CA_SUNW_HW_2 - 1].cs_aval = &alt_scapset->sc_hw_2;
1052 1052
1053 1053 /*
1054 1054 * Process any replaceable variables.
1055 1055 */
1056 1056 if (rpl_hwcap && (cap_modify(CA_SUNW_HW_1, rpl_hwcap) == 0))
1057 1057 return (0);
1058 1058 if (rpl_sfcap && (cap_modify(CA_SUNW_SF_1, rpl_sfcap) == 0))
1059 1059 return (0);
1060 1060
1061 1061 if (rpl_platcap) {
1062 1062 alt_scapset->sc_plat = (char *)rpl_platcap;
1063 1063 alt_scapset->sc_platsz = strlen(rpl_platcap);
1064 1064 }
1065 1065 if (rpl_machcap) {
1066 1066 alt_scapset->sc_mach = (char *)rpl_machcap;
1067 1067 alt_scapset->sc_machsz = strlen(rpl_machcap);
1068 1068 }
1069 1069
1070 1070 if (rpl_cap_files && (cap_files(rpl_cap_files) == 0))
1071 1071 return (0);
1072 1072
1073 1073 /*
1074 1074 * Process any permanent variables.
1075 1075 */
1076 1076 if (prm_hwcap && (cap_modify(CA_SUNW_HW_1, prm_hwcap) == 0))
1077 1077 return (0);
1078 1078 if (prm_sfcap && (cap_modify(CA_SUNW_SF_1, prm_sfcap) == 0))
1079 1079 return (0);
1080 1080
1081 1081 if (prm_platcap) {
1082 1082 alt_scapset->sc_plat = (char *)prm_platcap;
1083 1083 alt_scapset->sc_platsz = strlen(prm_platcap);
1084 1084 }
1085 1085 if (prm_machcap) {
1086 1086 alt_scapset->sc_mach = (char *)prm_machcap;
1087 1087 alt_scapset->sc_machsz = strlen(prm_machcap);
1088 1088 }
1089 1089
1090 1090 if (prm_cap_files && (cap_files(prm_cap_files) == 0))
1091 1091 return (0);
1092 1092
1093 1093 /*
1094 1094 * Reset the replaceable variables. If this is the environment variable
1095 1095 * processing, these variables are now available for configuration file
1096 1096 * initialization.
1097 1097 */
1098 1098 rpl_hwcap = rpl_sfcap = rpl_machcap = rpl_platcap =
1099 1099 rpl_cap_files = NULL;
1100 1100
1101 1101 return (1);
1102 1102 }
1103 1103
1104 1104 /*
1105 1105 * Take the index from a Capinfo entry and determine the associated capabilities
1106 1106 * set. Verify that the capabilities are available for this system.
1107 1107 */
1108 1108 static int
1109 1109 sym_cap_check(Cap *cptr, uint_t cndx, Syscapset *bestcapset, Rt_map *lmp,
1110 1110 const char *name, uint_t ndx)
1111 1111 {
1112 1112 Syscapset *scapset;
1113 1113 int totplat, ivlplat, totmach, ivlmach, capfail = 0;
1114 1114
1115 1115 /*
1116 1116 * Determine whether this file requires validation against alternative
1117 1117 * system capabilities.
1118 1118 */
1119 1119 if ((FLAGS1(lmp) & FL1_RT_ALTCHECK) == 0)
1120 1120 cap_check_lmp_init(lmp);
1121 1121
1122 1122 if (FLAGS1(lmp) & FL1_RT_ALTCAP)
1123 1123 scapset = alt_scapset;
1124 1124 else
1125 1125 scapset = org_scapset;
1126 1126
1127 1127 totplat = ivlplat = totmach = ivlmach = 0;
1128 1128
1129 1129 /*
1130 1130 * A capabilities index points to a capabilities group that can consist
1131 1131 * of one or more capabilities, terminated with a CA_SUNW_NULL entry.
1132 1132 */
1133 1133 for (cptr += cndx; cptr->c_tag != CA_SUNW_NULL; cptr++) {
1134 1134 Xword val = cptr->c_un.c_val;
1135 1135 char *str;
1136 1136
1137 1137 switch (cptr->c_tag) {
1138 1138 case CA_SUNW_HW_1:
1139 1139 /*
1140 1140 * Remove any historic values that should not be
1141 1141 * involved with any validation.
1142 1142 */
1143 1143 val &= ~AV_HW1_IGNORE;
1144 1144
1145 1145 bestcapset->sc_hw_1 = val;
1146 1146 DBG_CALL(Dbg_syms_cap_lookup(lmp, DBG_CAP_HW_1,
1147 1147 name, ndx, M_MACH, bestcapset));
1148 1148
1149 1149 if (hwcap1_check(scapset, val, NULL) == 0)
1150 1150 capfail++;
1151 1151 break;
1152 1152 case CA_SUNW_SF_1:
1153 1153 bestcapset->sc_sf_1 = val;
1154 1154 DBG_CALL(Dbg_syms_cap_lookup(lmp, DBG_CAP_SF_1,
1155 1155 name, ndx, M_MACH, bestcapset));
1156 1156
1157 1157 if (sfcap1_check(scapset, val, NULL) == 0)
1158 1158 capfail++;
1159 1159 break;
1160 1160 case CA_SUNW_HW_2:
1161 1161 bestcapset->sc_hw_2 = val;
1162 1162 DBG_CALL(Dbg_syms_cap_lookup(lmp, DBG_CAP_HW_2,
1163 1163 name, ndx, M_MACH, bestcapset));
1164 1164
1165 1165 if (hwcap2_check(scapset, val, NULL) == 0)
1166 1166 capfail++;
1167 1167 break;
1168 1168 case CA_SUNW_PLAT:
1169 1169 /*
1170 1170 * A capabilities set can define multiple platform names
1171 1171 * that are appropriate. Only if all the names are
1172 1172 * deemed invalid is the group determined inappropriate.
1173 1173 */
1174 1174 if (totplat == ivlplat) {
1175 1175 totplat++;
1176 1176
1177 1177 str = STRTAB(lmp) + val;
1178 1178 bestcapset->sc_plat = str;
1179 1179
1180 1180 DBG_CALL(Dbg_syms_cap_lookup(lmp, DBG_CAP_PLAT,
1181 1181 name, ndx, M_MACH, bestcapset));
1182 1182
1183 1183 if (platcap_check(scapset, str, NULL) == 0)
1184 1184 ivlplat++;
1185 1185 }
1186 1186 break;
1187 1187 case CA_SUNW_MACH:
1188 1188 /*
1189 1189 * A capabilities set can define multiple machine names
1190 1190 * that are appropriate. Only if all the names are
1191 1191 * deemed invalid is the group determined inappropriate.
1192 1192 */
1193 1193 if (totmach == ivlmach) {
1194 1194 totmach++;
1195 1195
1196 1196 str = STRTAB(lmp) + val;
1197 1197 bestcapset->sc_mach = str;
1198 1198
1199 1199 DBG_CALL(Dbg_syms_cap_lookup(lmp, DBG_CAP_MACH,
1200 1200 name, ndx, M_MACH, bestcapset));
1201 1201
1202 1202 if (machcap_check(scapset, str, NULL) == 0)
1203 1203 ivlmach++;
1204 1204 }
1205 1205 break;
1206 1206 default:
1207 1207 break;
1208 1208 }
1209 1209 }
1210 1210
1211 1211 /*
1212 1212 * If any platform definitions, or machine definitions were found, and
1213 1213 * all were invalid, indicate that the object is inappropriate.
1214 1214 */
1215 1215 if (capfail || (totplat && (totplat == ivlplat)) ||
1216 1216 (totmach && (totmach == ivlmach))) {
1217 1217 DBG_CALL(Dbg_syms_cap_lookup(lmp, DBG_CAP_REJECTED, name, ndx,
1218 1218 M_MACH, NULL));
1219 1219 return (0);
1220 1220 }
1221 1221
1222 1222 DBG_CALL(Dbg_syms_cap_lookup(lmp, DBG_CAP_CANDIDATE, name, ndx,
1223 1223 M_MACH, NULL));
1224 1224 return (1);
1225 1225 }
1226 1226
1227 1227 /*
1228 1228 * Determine whether a symbols capabilities are more significant than any that
1229 1229 * have already been validated. The precedence of capabilities are:
1230 1230 *
1231 1231 * PLATCAP -> MACHCAP -> HWCAP_2 -> HWCAP_1
1232 1232 *
1233 1233 *
1234 1234 * Presently we make no comparisons of software capabilities. However, should
1235 1235 * this symbol capability have required the SF1_SUNW_ADDR32 attribute, then
1236 1236 * this would have been validated as appropriate or not.
1237 1237 *
1238 1238 * bestcapset is the presently available 'best' capabilities group, and
1239 1239 * symcapset is the present capabilities group under investigation. Return 0
1240 1240 * if the bestcapset should remain in affect, or 1 if the symcapset is better.
1241 1241 */
1242 1242 inline static int
1243 1243 is_sym_the_best(Syscapset *bestcapset, Syscapset *symcapset)
1244 1244 {
1245 1245 /*
1246 1246 * Check any platform capability. If the new symbol isn't associated
1247 1247 * with a CA_SUNW_PLAT capability, and the best symbol is, then retain
1248 1248 * the best capabilities group. If the new symbol is associated with a
1249 1249 * CA_SUNW_PLAT capability, and the best symbol isn't, then the new
1250 1250 * symbol needs to be taken.
1251 1251 */
1252 1252 if (bestcapset->sc_plat && (symcapset->sc_plat == NULL))
1253 1253 return (0);
1254 1254
1255 1255 if ((bestcapset->sc_plat == NULL) && symcapset->sc_plat)
1256 1256 return (1);
1257 1257
1258 1258 /*
1259 1259 * Check any machine name capability. If the new symbol isn't
1260 1260 * associated with a CA_SUNW_MACH capability, and the best symbol is,
1261 1261 * then retain the best capabilities group. If the new symbol is
1262 1262 * associated with a CA_SUNW_MACH capability, and the best symbol isn't,
1263 1263 * then the new symbol needs to be taken.
1264 1264 */
1265 1265 if (bestcapset->sc_mach && (symcapset->sc_mach == NULL))
1266 1266 return (0);
1267 1267
1268 1268 if ((bestcapset->sc_mach == NULL) && symcapset->sc_mach)
1269 1269 return (1);
1270 1270
1271 1271 /*
1272 1272 * Check the hardware capabilities. If the best symbols CA_SUNW_HW_2
1273 1273 * capabilities are greater than the new symbols capabilities, then
1274 1274 * retain the best capabilities group. If the new symbols CA_SUNW_HW_2
1275 1275 * capabilities are greater than the best symbol, then the new symbol
1276 1276 * needs to be taken.
1277 1277 */
1278 1278 if (bestcapset->sc_hw_2 > symcapset->sc_hw_2)
1279 1279 return (0);
1280 1280
1281 1281 if (bestcapset->sc_hw_2 < symcapset->sc_hw_2)
1282 1282 return (1);
1283 1283
1284 1284 /*
1285 1285 * Check the remaining hardware capabilities. If the best symbols
1286 1286 * CA_SUNW_HW_1 capabilities are greater than the new symbols
1287 1287 * capabilities, then retain the best capabilities group. If the new
1288 1288 * symbols CA_SUNW_HW_1 capabilities are greater than the best symbol,
1289 1289 * then the new symbol needs to be taken.
1290 1290 */
1291 1291 if (bestcapset->sc_hw_1 > symcapset->sc_hw_1)
1292 1292 return (0);
1293 1293
1294 1294 if (bestcapset->sc_hw_1 < symcapset->sc_hw_1)
1295 1295 return (1);
1296 1296
1297 1297 /*
1298 1298 * Both capabilities are the same. Retain the best on a first-come
1299 1299 * first-served basis.
1300 1300 */
1301 1301 return (0);
1302 1302 }
1303 1303
1304 1304 /*
1305 1305 * Initiate symbol capabilities processing. If an initial symbol lookup
1306 1306 * results in binding to a symbol that has an associated SUNW_capinfo entry,
1307 1307 * we arrive here.
1308 1308 *
1309 1309 * The standard model is that this initial symbol is the lead capabilities
1310 1310 * symbol (defined as CAPINFO_SUNW_GLOB) of a capabilities family. This lead
1311 1311 * symbol's SUNW_capinfo information points to the SUNW_capchain entry that
1312 1312 * provides the family symbol indexes. We traverse this chain, looking at
1313 1313 * each family member, to discover the best capabilities instance. This
1314 1314 * instance name and symbol information is returned to establish the final
1315 1315 * symbol binding.
1316 1316 *
1317 1317 * If the symbol that got us here is not CAPINFO_SUNW_GLOB, then we've bound
1318 1318 * directly to a capabilities symbol which must be verified. This is not the
1319 1319 * model created by ld(1) using -z symbolcap, but might be created directly
1320 1320 * within a relocatable object by the compilation system.
1321 1321 */
1322 1322 int
1323 1323 cap_match(Sresult *srp, uint_t symndx, Sym *symtabptr, char *strtabptr)
1324 1324 {
1325 1325 Rt_map *ilmp = srp->sr_dmap;
1326 1326 Sym *bsym = NULL;
1327 1327 const char *bname;
1328 1328 Syscapset bestcapset = { 0 };
1329 1329 Cap *cap;
1330 1330 Capchain *capchain;
1331 1331 uchar_t grpndx;
1332 1332 uint_t ochainndx, nchainndx, bndx;
1333 1333
1334 1334 cap = CAP(ilmp);
1335 1335 capchain = CAPCHAIN(ilmp);
1336 1336
1337 1337 grpndx = (uchar_t)ELF_C_GROUP(CAPINFO(ilmp)[symndx]);
1338 1338
1339 1339 /*
1340 1340 * If this symbols capability group is not a lead symbol, then simply
1341 1341 * verify the symbol.
1342 1342 */
1343 1343 if (grpndx != CAPINFO_SUNW_GLOB) {
1344 1344 Syscapset symcapset = { 0 };
1345 1345
1346 1346 return (sym_cap_check(cap, grpndx, &symcapset, ilmp,
1347 1347 srp->sr_name, symndx));
1348 1348 }
1349 1349
1350 1350 /*
1351 1351 * If there is no capabilities chain, return the lead symbol.
1352 1352 */
1353 1353 if (capchain == NULL)
1354 1354 return (1);
1355 1355
1356 1356 ochainndx = (uint_t)ELF_C_SYM(CAPINFO(ilmp)[symndx]);
1357 1357
1358 1358 /*
1359 1359 * If there is only one member for this family, take it. Once a family
1360 1360 * has been processed, the best family instance is written to the head
1361 1361 * of the chain followed by a null entry. This caching ensures that the
1362 1362 * same family comparison doesn't have to be undertaken more than once.
1363 1363 */
1364 1364 if (capchain[ochainndx] && (capchain[ochainndx + 1] == 0)) {
1365 1365 Sym *fsym = symtabptr + capchain[ochainndx];
1366 1366 const char *fname = strtabptr + fsym->st_name;
1367 1367
1368 1368 DBG_CALL(Dbg_syms_cap_lookup(ilmp, DBG_CAP_USED, fname,
1369 1369 capchain[ochainndx], M_MACH, NULL));
1370 1370
1371 1371 srp->sr_sym = fsym;
1372 1372 srp->sr_name = fname;
1373 1373 return (1);
1374 1374 }
1375 1375
1376 1376 /*
1377 1377 * As this symbol is the lead symbol of a capabilities family, it is
1378 1378 * considered the generic member, and therefore forms the basic
1379 1379 * fall-back for the capabilities family.
1380 1380 */
1381 1381 DBG_CALL(Dbg_syms_cap_lookup(ilmp, DBG_CAP_DEFAULT, srp->sr_name,
1382 1382 symndx, M_MACH, NULL));
1383 1383 bsym = srp->sr_sym;
1384 1384 bname = srp->sr_name;
1385 1385 bndx = symndx;
1386 1386
1387 1387 /*
1388 1388 * Traverse the capabilities chain analyzing each family member.
1389 1389 */
1390 1390 for (nchainndx = ochainndx + 1, symndx = capchain[nchainndx]; symndx;
1391 1391 nchainndx++, symndx = capchain[nchainndx]) {
1392 1392 Sym *nsym = symtabptr + symndx;
1393 1393 const char *nname = strtabptr + nsym->st_name;
1394 1394 Syscapset symcapset = { 0 };
1395 1395
1396 1396 if ((grpndx =
1397 1397 (uchar_t)ELF_C_GROUP(CAPINFO(ilmp)[symndx])) == 0)
1398 1398 continue;
1399 1399
1400 1400 if (sym_cap_check(cap, grpndx, &symcapset, ilmp,
1401 1401 nname, symndx) == 0)
1402 1402 continue;
1403 1403
1404 1404 /*
1405 1405 * Determine whether a symbol's capabilities are more
1406 1406 * significant than any that have already been validated.
1407 1407 */
1408 1408 if (is_sym_the_best(&bestcapset, &symcapset)) {
1409 1409 bestcapset = symcapset;
1410 1410 bsym = nsym;
1411 1411 bname = nname;
1412 1412 bndx = symndx;
1413 1413 }
1414 1414 }
1415 1415
1416 1416 DBG_CALL(Dbg_syms_cap_lookup(ilmp, DBG_CAP_USED, bname, bndx,
1417 1417 M_MACH, NULL));
1418 1418
1419 1419 /*
1420 1420 * Having found the best symbol, cache the results by overriding the
1421 1421 * first element of the associated chain.
1422 1422 */
1423 1423 capchain[ochainndx] = bndx;
1424 1424 capchain[ochainndx + 1] = 0;
1425 1425
1426 1426 /*
1427 1427 * Update the symbol result information for return to the user.
1428 1428 */
1429 1429 srp->sr_sym = bsym;
1430 1430 srp->sr_name = bname;
1431 1431 return (1);
1432 1432 }
↓ open down ↓ |
410 lines elided |
↑ open up ↑ |
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX