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 (the "License"). 6 * You may not use this file except in compliance with the License. 7 * 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9 * or http://www.opensolaris.org/os/licensing. 10 * See the License for the specific language governing permissions 11 * and limitations under the License. 12 * 13 * When distributing Covered Code, include this CDDL HEADER in each 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15 * If applicable, add the following below this CDDL HEADER, with the 16 * fields enclosed by brackets "[]" replaced with your own identifying 17 * information: Portions Copyright [yyyy] [name of copyright owner] 18 * 19 * CDDL HEADER END 20 */ 21 22 /* 23 * Copyright 2007 Sun Microsystems, Inc. All rights reserved. 24 * Use is subject to license terms. 25 */ 26 27 #pragma ident "%Z%%M% %I% %E% SMI" 28 29 #define ELF_TARGET_ALL /* get definitions of all section flags */ 30 31 #include <sys/types.h> 32 #include <sys/stat.h> 33 #include <fcntl.h> 34 #include <unistd.h> 35 #include <strings.h> 36 #include <stddef.h> 37 #include <stdlib.h> 38 #include <libintl.h> 39 #include <dirent.h> 40 #include <errno.h> 41 #include <libelf.h> 42 #include <gelf.h> 43 #include <sys/mman.h> 44 #include <cryptoutil.h> 45 #include <sha1.h> 46 #include <sys/crypto/elfsign.h> 47 #include <libelfsign.h> 48 49 #ifndef SHA1_DIGEST_LENGTH 50 #define SHA1_DIGEST_LENGTH 20 51 #endif /* SHA1_DIGEST_LENGTH */ 52 53 const char SUNW_ELF_SIGNATURE_ID[] = ELF_SIGNATURE_SECTION; 54 const char OID_sha1WithRSAEncryption[] = "1.2.840.113549.1.1.5"; 55 56 static ELFsign_status_t elfsign_adjustoffsets(ELFsign_t ess, 57 Elf_Scn *scn, uint64_t new_size); 58 static ELFsign_status_t elfsign_verify_esa(ELFsign_t ess, 59 uchar_t *sig, size_t sig_len); 60 static uint32_t elfsign_switch_uint32(uint32_t i); 61 static ELFsign_status_t elfsign_switch(ELFsign_t ess, 62 struct filesignatures *fssp, enum ES_ACTION action); 63 64 struct filesig_extraction { 65 filesig_vers_t fsx_version; 66 char *fsx_format; 67 char fsx_signer_DN[ELFCERT_MAX_DN_LEN]; 68 size_t fsx_signer_DN_len; 69 uchar_t fsx_signature[SIG_MAX_LENGTH]; 70 size_t fsx_sig_len; 71 char fsx_sig_oid[100]; 72 size_t fsx_sig_oid_len; 73 time_t fsx_time; 74 }; 75 76 static char * 77 version_to_str(filesig_vers_t v) 78 { 79 char *ret; 80 81 switch (v) { 82 case FILESIG_VERSION1: 83 ret = "VERSION1"; 84 break; 85 case FILESIG_VERSION2: 86 ret = "VERSION2"; 87 break; 88 case FILESIG_VERSION3: 89 ret = "VERSION3"; 90 break; 91 case FILESIG_VERSION4: 92 ret = "VERSION4"; 93 break; 94 default: 95 ret = "UNKNOWN"; 96 break; 97 } 98 return (ret); 99 } 100 101 /* 102 * Update filesignatures to include the v1/v2 filesig, 103 * composed of signer DN, signature, and OID. 104 */ 105 static struct filesignatures * 106 filesig_insert_dso(struct filesignatures *fssp, 107 filesig_vers_t version, 108 const char *dn, 109 int dn_len, 110 const uchar_t *sig, 111 int sig_len, 112 const char *oid, 113 int oid_len) 114 { 115 struct filesig *fsgp; 116 char *fsdatap; 117 118 if (oid == NULL) { 119 /* 120 * This OID is used for the rsa_md5_sha1 format signature also. 121 * This use is historical, and is hence continued, 122 * despite its lack of technical accuracy. 123 */ 124 oid = OID_sha1WithRSAEncryption; 125 oid_len = strlen(oid); 126 } 127 128 /* 129 * for now, always insert a single-signature signature block 130 */ 131 if (fssp != NULL) 132 free(fssp); 133 fssp = (struct filesignatures *) 134 malloc(filesig_ALIGN(sizeof (struct filesignatures) + 135 dn_len + sig_len + oid_len)); 136 if (fssp == NULL) 137 return (fssp); 138 139 fssp->filesig_cnt = 1; 140 fssp->filesig_pad = 0; /* reserve for future use */ 141 142 fsgp = &fssp->filesig_sig; 143 fsgp->filesig_size = sizeof (struct filesig) + 144 dn_len + sig_len + oid_len; 145 fsgp->filesig_version = version; 146 switch (version) { 147 case FILESIG_VERSION1: 148 case FILESIG_VERSION2: 149 fsgp->filesig_size -= sizeof (struct filesig) - 150 offsetof(struct filesig, filesig_v1_data[0]); 151 fsgp->filesig_v1_dnsize = dn_len; 152 fsgp->filesig_v1_sigsize = sig_len; 153 fsgp->filesig_v1_oidsize = oid_len; 154 fsdatap = &fsgp->filesig_v1_data[0]; 155 break; 156 case FILESIG_VERSION3: 157 case FILESIG_VERSION4: 158 fsgp->filesig_size -= sizeof (struct filesig) - 159 offsetof(struct filesig, filesig_v3_data[0]); 160 fsgp->filesig_v3_time = time(NULL); 161 fsgp->filesig_v3_dnsize = dn_len; 162 fsgp->filesig_v3_sigsize = sig_len; 163 fsgp->filesig_v3_oidsize = oid_len; 164 fsdatap = &fsgp->filesig_v3_data[0]; 165 break; 166 default: 167 cryptodebug("filesig_insert_dso: unknown version: %d", 168 version); 169 free(fssp); 170 return (NULL); 171 } 172 (void) memcpy(fsdatap, dn, dn_len); 173 fsdatap += dn_len; 174 (void) memcpy(fsdatap, (char *)sig, sig_len); 175 fsdatap += sig_len; 176 (void) memcpy(fsdatap, oid, oid_len); 177 fsdatap += oid_len; 178 fsgp = filesig_next(fsgp); 179 (void) memset(fsdatap, 0, (char *)(fsgp) - fsdatap); 180 181 return (fssp); 182 } 183 184 /* 185 * filesig_extract - extract filesig structure to internal form 186 */ 187 static filesig_vers_t 188 filesig_extract(struct filesig *fsgp, struct filesig_extraction *fsxp) 189 { 190 char *fsdp; 191 192 #define filesig_extract_common(cp, field, data_var, len_var, len_limit) { \ 193 len_var = len_limit; \ 194 if (len_var > fsgp->field) \ 195 len_var = fsgp->field; \ 196 (void) memcpy(data_var, cp, len_var); \ 197 cp += fsgp->field; } 198 #define filesig_extract_str(cp, field, data_var, len_var) \ 199 filesig_extract_common(cp, field, data_var, len_var, \ 200 sizeof (data_var) - 1); \ 201 data_var[len_var] = '\0'; 202 #define filesig_extract_opaque(cp, field, data_var, len_var) \ 203 filesig_extract_common(cp, field, data_var, len_var, sizeof (data_var)) 204 205 fsxp->fsx_version = fsgp->filesig_version; 206 cryptodebug("filesig_extract: version=%s", 207 version_to_str(fsxp->fsx_version)); 208 switch (fsxp->fsx_version) { 209 case FILESIG_VERSION1: 210 case FILESIG_VERSION2: 211 /* 212 * extract VERSION1 DN, signature, and OID 213 */ 214 fsdp = fsgp->filesig_v1_data; 215 fsxp->fsx_format = ES_FMT_RSA_MD5_SHA1; 216 fsxp->fsx_time = 0; 217 filesig_extract_str(fsdp, filesig_v1_dnsize, 218 fsxp->fsx_signer_DN, fsxp->fsx_signer_DN_len); 219 filesig_extract_opaque(fsdp, filesig_v1_sigsize, 220 fsxp->fsx_signature, fsxp->fsx_sig_len); 221 filesig_extract_str(fsdp, filesig_v1_oidsize, 222 fsxp->fsx_sig_oid, fsxp->fsx_sig_oid_len); 223 break; 224 case FILESIG_VERSION3: 225 case FILESIG_VERSION4: 226 fsdp = fsgp->filesig_v3_data; 227 fsxp->fsx_format = ES_FMT_RSA_SHA1; 228 fsxp->fsx_time = fsgp->filesig_v3_time; 229 filesig_extract_str(fsdp, filesig_v3_dnsize, 230 fsxp->fsx_signer_DN, fsxp->fsx_signer_DN_len); 231 filesig_extract_opaque(fsdp, filesig_v3_sigsize, 232 fsxp->fsx_signature, fsxp->fsx_sig_len); 233 filesig_extract_str(fsdp, filesig_v3_oidsize, 234 fsxp->fsx_sig_oid, fsxp->fsx_sig_oid_len); 235 break; 236 default: 237 break; 238 } 239 240 return (fsxp->fsx_version); 241 } 242 243 ELFsign_status_t 244 elfsign_begin(const char *filename, enum ES_ACTION action, ELFsign_t *essp) 245 { 246 Elf_Cmd elfcmd; 247 int oflags = 0; 248 short l_type; 249 ELFsign_t ess; 250 struct stat stb; 251 union { 252 char c[2]; 253 short s; 254 } uorder; 255 GElf_Ehdr elfehdr; 256 char *ident; 257 258 switch (action) { 259 case ES_GET: 260 case ES_GET_CRYPTO: 261 cryptodebug("elfsign_begin for get"); 262 elfcmd = ELF_C_READ; 263 oflags = O_RDONLY | O_NOCTTY | O_NDELAY; 264 l_type = F_RDLCK; 265 break; 266 case ES_UPDATE_RSA_MD5_SHA1: 267 case ES_UPDATE_RSA_SHA1: 268 cryptodebug("elfsign_begin for update"); 269 elfcmd = ELF_C_RDWR; 270 oflags = O_RDWR | O_NOCTTY | O_NDELAY; 271 l_type = F_WRLCK; 272 break; 273 default: 274 return (ELFSIGN_UNKNOWN); 275 } 276 277 if ((ess = malloc(sizeof (struct ELFsign_s))) == NULL) { 278 return (ELFSIGN_UNKNOWN); 279 } 280 (void) memset((void *)ess, 0, sizeof (struct ELFsign_s)); 281 282 if (!elfcertlib_init(ess)) { 283 cryptodebug("elfsign_begin: failed initialization"); 284 return (ELFSIGN_UNKNOWN); 285 } 286 287 ess->es_elf = NULL; 288 ess->es_action = action; 289 ess->es_version = FILESIG_UNKNOWN; 290 ess->es_pathname = NULL; 291 ess->es_certpath = NULL; 292 293 if (filename == NULL) { 294 *essp = ess; 295 return (ELFSIGN_SUCCESS); 296 } 297 298 if ((ess->es_fd = open(filename, oflags)) == -1) { 299 elfsign_end(ess); 300 return (ELFSIGN_INVALID_ELFOBJ); 301 } 302 if ((fstat(ess->es_fd, &stb) == -1) || !S_ISREG(stb.st_mode)) { 303 elfsign_end(ess); 304 return (ELFSIGN_INVALID_ELFOBJ); 305 } 306 if ((ess->es_pathname = strdup(filename)) == NULL) { 307 elfsign_end(ess); 308 return (ELFSIGN_UNKNOWN); 309 } 310 /* 311 * The following lock is released in elfsign_end() when we close(2) 312 * the es_fd. This ensures that we aren't trying verify a file 313 * we are currently updating. 314 */ 315 ess->es_flock.l_type = l_type; 316 ess->es_flock.l_whence = SEEK_CUR; 317 ess->es_flock.l_start = 0; 318 ess->es_flock.l_len = 0; 319 if (fcntl(ess->es_fd, F_SETLK, &ess->es_flock) == -1) { 320 cryptodebug("fcntl(F_SETLK) of %s failed with: %s", 321 ess->es_pathname, strerror(errno)); 322 elfsign_end(ess); 323 return (ELFSIGN_UNKNOWN); 324 } 325 326 if (elf_version(EV_CURRENT) == EV_NONE) { 327 elfsign_end(ess); 328 return (ELFSIGN_UNKNOWN); 329 } 330 331 if ((ess->es_elf = elf_begin(ess->es_fd, elfcmd, 332 (Elf *)NULL)) == NULL) { 333 cryptodebug("elf_begin() failed: %s", elf_errmsg(-1)); 334 elfsign_end(ess); 335 return (ELFSIGN_INVALID_ELFOBJ); 336 } 337 338 if (gelf_getehdr(ess->es_elf, &elfehdr) == NULL) { 339 cryptodebug("elf_getehdr() failed: %s", elf_errmsg(-1)); 340 elfsign_end(ess); 341 return (ELFSIGN_INVALID_ELFOBJ); 342 } 343 ess->es_has_phdr = (elfehdr.e_phnum != 0); 344 345 uorder.s = ELFDATA2MSB << 8 | ELFDATA2LSB; 346 ident = elf_getident(ess->es_elf, NULL); 347 if (ident == NULL) { 348 cryptodebug("elf_getident() failed: %s", elf_errmsg(-1)); 349 elfsign_end(ess); 350 return (ELFSIGN_INVALID_ELFOBJ); 351 } 352 ess->es_same_endian = (ident[EI_DATA] == uorder.c[0]); 353 ess->es_ei_class = ident[EI_CLASS]; 354 355 /* 356 * Call elf_getshstrndx to be sure we have a real ELF object 357 * this is required because elf_begin doesn't check that. 358 */ 359 if (elf_getshstrndx(ess->es_elf, &ess->es_shstrndx) == 0) { 360 elfsign_end(ess); 361 cryptodebug("elfsign_begin: elf_getshstrndx failed"); 362 return (ELFSIGN_INVALID_ELFOBJ); 363 } 364 365 /* 366 * Make sure libelf doesn't rearrange section ordering / offsets. 367 */ 368 (void) elf_flagelf(ess->es_elf, ELF_C_SET, ELF_F_LAYOUT); 369 370 *essp = ess; 371 372 return (ELFSIGN_SUCCESS); 373 } 374 375 /* 376 * elfsign_end - cleanup the ELFsign_t 377 * 378 * IN/OUT: ess 379 */ 380 void 381 elfsign_end(ELFsign_t ess) 382 { 383 if (ess == NULL) 384 return; 385 386 if (ess->es_elf != NULL && ES_ACTISUPDATE(ess->es_action)) { 387 if (elf_update(ess->es_elf, ELF_C_WRITE) == -1) { 388 cryptodebug("elf_update() failed: %s", 389 elf_errmsg(-1)); 390 return; 391 } 392 } 393 394 if (ess->es_fd != -1) { 395 (void) close(ess->es_fd); 396 ess->es_fd = -1; 397 } 398 399 if (ess->es_pathname != NULL) { 400 free(ess->es_pathname); 401 ess->es_pathname = NULL; 402 } 403 if (ess->es_certpath != NULL) { 404 free(ess->es_certpath); 405 ess->es_certpath = NULL; 406 } 407 408 if (ess->es_elf != NULL) { 409 (void) elf_end(ess->es_elf); 410 ess->es_elf = NULL; 411 } 412 413 elfcertlib_fini(ess); 414 415 free(ess); 416 } 417 418 /* 419 * set the certificate path 420 */ 421 ELFsign_status_t 422 elfsign_setcertpath(ELFsign_t ess, const char *certpath) 423 { 424 /* 425 * Normally use of access(2) is insecure, here we are only 426 * doing it to help provide early failure and better error 427 * checking, so there is no race condition. 428 */ 429 if (access(certpath, R_OK) != 0) 430 return (ELFSIGN_INVALID_CERTPATH); 431 432 if ((ess->es_certpath = strdup(certpath)) == NULL) 433 return (ELFSIGN_FAILED); 434 435 if (ES_ACTISUPDATE(ess->es_action)) { 436 ELFCert_t cert = NULL; 437 char *subject; 438 439 /* set the version based on the certificate */ 440 if (elfcertlib_getcert(ess, ess->es_certpath, NULL, 441 &cert, ess->es_action)) { 442 if ((subject = elfcertlib_getdn(cert)) != NULL) { 443 if (strstr(subject, ELFSIGN_CRYPTO)) 444 ess->es_version = (ess->es_action == 445 ES_UPDATE_RSA_MD5_SHA1) ? 446 FILESIG_VERSION1 : FILESIG_VERSION3; 447 else 448 ess->es_version = (ess->es_action == 449 ES_UPDATE_RSA_MD5_SHA1) ? 450 FILESIG_VERSION2 : FILESIG_VERSION4; 451 } 452 elfcertlib_releasecert(ess, cert); 453 } 454 if (ess->es_version == FILESIG_UNKNOWN) 455 return (ELFSIGN_FAILED); 456 } 457 return (ELFSIGN_SUCCESS); 458 } 459 460 /* 461 * set the callback context 462 */ 463 void 464 elfsign_setcallbackctx(ELFsign_t ess, void *ctx) 465 { 466 ess->es_callbackctx = ctx; 467 } 468 469 /* 470 * set the signature extraction callback 471 */ 472 void 473 elfsign_setsigvercallback(ELFsign_t ess, 474 void (*cb)(void *, void *, size_t, ELFCert_t)) 475 { 476 ess->es_sigvercallback = cb; 477 } 478 479 /* 480 * elfsign_signatures 481 * 482 * IN: ess, fsspp, action 483 * OUT: fsspp 484 */ 485 ELFsign_status_t 486 elfsign_signatures(ELFsign_t ess, 487 struct filesignatures **fsspp, 488 size_t *fslen, 489 enum ES_ACTION action) 490 { 491 Elf_Scn *scn = NULL, *sig_scn = NULL; 492 GElf_Shdr shdr; 493 Elf_Data *data = NULL; 494 const char *elf_section = SUNW_ELF_SIGNATURE_ID; 495 int fscnt, fssize; 496 struct filesig *fsgp, *fsgpnext; 497 uint64_t sig_offset = 0; 498 499 cryptodebug("elfsign_signature"); 500 if ((ess == NULL) || (fsspp == NULL)) { 501 cryptodebug("invalid arguments"); 502 return (ELFSIGN_UNKNOWN); 503 } 504 505 cryptodebug("elfsign_signature %s for %s", 506 ES_ACTISUPDATE(action) ? "ES_UPDATE" : "ES_GET", elf_section); 507 508 (void) elf_errno(); 509 while ((scn = elf_nextscn(ess->es_elf, scn)) != NULL) { 510 const char *sh_name; 511 /* 512 * Do a string compare to examine each section header 513 * to see if this is the section that needs to be updated. 514 */ 515 if (gelf_getshdr(scn, &shdr) == NULL) { 516 cryptodebug("gelf_getshdr() failed: %s", 517 elf_errmsg(-1)); 518 return (ELFSIGN_FAILED); 519 } 520 sh_name = elf_strptr(ess->es_elf, ess->es_shstrndx, 521 (size_t)shdr.sh_name); 522 if (strcmp(sh_name, elf_section) == 0) { 523 cryptodebug("elfsign_signature: found %s", elf_section); 524 sig_scn = scn; 525 break; 526 } 527 if (shdr.sh_type != SHT_NOBITS && 528 sig_offset < shdr.sh_offset + shdr.sh_size) { 529 sig_offset = shdr.sh_offset + shdr.sh_size; 530 } 531 } 532 if (elf_errmsg(0) != NULL) { 533 cryptodebug("unexpected error: %s", elf_section, 534 elf_errmsg(-1)); 535 return (ELFSIGN_FAILED); 536 } 537 538 if (ES_ACTISUPDATE(action) && (sig_scn == NULL)) { 539 size_t old_size, new_size; 540 char *new_d_buf; 541 542 cryptodebug("elfsign_signature: %s not found - creating", 543 elf_section); 544 545 /* 546 * insert section name in .shstrtab 547 */ 548 if ((scn = elf_getscn(ess->es_elf, ess->es_shstrndx)) == 0) { 549 cryptodebug("elf_getscn() failed: %s", 550 elf_errmsg(-1)); 551 return (ELFSIGN_FAILED); 552 } 553 if (gelf_getshdr(scn, &shdr) == NULL) { 554 cryptodebug("gelf_getshdr() failed: %s", 555 elf_errmsg(-1)); 556 return (ELFSIGN_FAILED); 557 } 558 if ((data = elf_getdata(scn, data)) == NULL) { 559 cryptodebug("elf_getdata() failed: %s", 560 elf_errmsg(-1)); 561 return (ELFSIGN_FAILED); 562 } 563 old_size = data->d_size; 564 if (old_size != shdr.sh_size) { 565 cryptodebug("mismatch between data size %d " 566 "and section size %lld", old_size, shdr.sh_size); 567 return (ELFSIGN_FAILED); 568 } 569 new_size = old_size + strlen(elf_section) + 1; 570 if ((new_d_buf = malloc(new_size)) == NULL) 571 return (ELFSIGN_FAILED); 572 573 (void) memcpy(new_d_buf, data->d_buf, old_size); 574 (void) strlcpy(new_d_buf + old_size, elf_section, 575 new_size - old_size); 576 data->d_buf = new_d_buf; 577 data->d_size = new_size; 578 data->d_align = 1; 579 /* 580 * Add the section name passed in to the end of the file. 581 * Initialize the fields in the Section Header that 582 * libelf will not fill in. 583 */ 584 if ((sig_scn = elf_newscn(ess->es_elf)) == 0) { 585 cryptodebug("elf_newscn() failed: %s", 586 elf_errmsg(-1)); 587 return (ELFSIGN_FAILED); 588 } 589 if (gelf_getshdr(sig_scn, &shdr) == 0) { 590 cryptodebug("gelf_getshdr() failed: %s", 591 elf_errmsg(-1)); 592 return (ELFSIGN_FAILED); 593 } 594 shdr.sh_name = old_size; 595 shdr.sh_type = SHT_SUNW_SIGNATURE; 596 shdr.sh_flags = SHF_EXCLUDE; 597 shdr.sh_addr = 0; 598 shdr.sh_link = 0; 599 shdr.sh_info = 0; 600 shdr.sh_size = 0; 601 shdr.sh_offset = sig_offset; 602 shdr.sh_addralign = 1; 603 604 /* 605 * Flush the changes to the underlying elf32 or elf64 606 * section header. 607 */ 608 if (gelf_update_shdr(sig_scn, &shdr) == 0) { 609 cryptodebug("gelf_update_shdr failed"); 610 return (ELFSIGN_FAILED); 611 } 612 613 if ((data = elf_newdata(sig_scn)) == NULL) { 614 cryptodebug("can't add elf data area for %s: %s", 615 elf_section, elf_errmsg(-1)); 616 return (ELFSIGN_FAILED); 617 } 618 if (elfsign_adjustoffsets(ess, scn, 619 old_size + strlen(elf_section) + 1) != ELFSIGN_SUCCESS) { 620 cryptodebug("can't adjust for new section name %s", 621 elf_section); 622 return (ELFSIGN_FAILED); 623 } 624 } else { 625 if (sig_scn == NULL) { 626 cryptodebug("can't find signature section"); 627 *fsspp = NULL; 628 return (ELFSIGN_NOTSIGNED); 629 } 630 if ((data = elf_getdata(sig_scn, NULL)) == 0) { 631 cryptodebug("can't get section data for %s", 632 elf_section); 633 return (ELFSIGN_FAILED); 634 } 635 } 636 637 if (ES_ACTISUPDATE(action)) { 638 fssize = offsetof(struct filesignatures, _u1); 639 if (*fsspp != NULL) { 640 fsgp = &(*fsspp)->filesig_sig; 641 for (fscnt = 0; fscnt < (*fsspp)->filesig_cnt; 642 fscnt++) { 643 fsgpnext = filesig_next(fsgp); 644 fssize += (char *)(fsgpnext) - (char *)(fsgp); 645 fsgp = fsgpnext; 646 } 647 } 648 if (shdr.sh_addr != 0) { 649 cryptodebug("section %s is part of a loadable segment, " 650 "it cannot be changed.\n", elf_section); 651 return (ELFSIGN_FAILED); 652 } 653 if ((data->d_buf = malloc(fssize)) == NULL) 654 return (ELFSIGN_FAILED); 655 if (*fsspp != NULL) { 656 (void) memcpy(data->d_buf, *fsspp, fssize); 657 (void) elfsign_switch(ess, 658 (struct filesignatures *)data->d_buf, action); 659 } 660 data->d_size = fssize; 661 data->d_align = 1; 662 data->d_type = ELF_T_BYTE; 663 cryptodebug("elfsign_signature: data->d_size = %d", 664 data->d_size); 665 if (elfsign_adjustoffsets(ess, sig_scn, fssize) != 666 ELFSIGN_SUCCESS) { 667 cryptodebug("can't adjust for revised signature " 668 "section contents"); 669 return (ELFSIGN_FAILED); 670 } 671 } else { 672 *fsspp = malloc(data->d_size); 673 if (*fsspp == NULL) 674 return (ELFSIGN_FAILED); 675 (void) memcpy(*fsspp, data->d_buf, data->d_size); 676 if (elfsign_switch(ess, *fsspp, ES_GET) != ELFSIGN_SUCCESS) { 677 free(*fsspp); 678 *fsspp = NULL; 679 return (ELFSIGN_FAILED); 680 } 681 *fslen = data->d_size; 682 } 683 684 return (ELFSIGN_SUCCESS); 685 } 686 687 static ELFsign_status_t 688 elfsign_adjustoffsets(ELFsign_t ess, Elf_Scn *scn, uint64_t new_size) 689 { 690 GElf_Ehdr elfehdr; 691 GElf_Shdr shdr; 692 uint64_t prev_end, scn_offset; 693 char *name; 694 Elf_Scn *scnp; 695 Elf_Data *data; 696 ELFsign_status_t retval = ELFSIGN_FAILED; 697 struct scninfo { 698 struct scninfo *scni_next; 699 Elf_Scn *scni_scn; 700 uint64_t scni_offset; 701 } *scnip = NULL, *tmpscnip, **scnipp; 702 703 /* get the size of the current section */ 704 if (gelf_getshdr(scn, &shdr) == NULL) 705 return (ELFSIGN_FAILED); 706 if (shdr.sh_size == new_size) 707 return (ELFSIGN_SUCCESS); 708 scn_offset = shdr.sh_offset; 709 name = elf_strptr(ess->es_elf, ess->es_shstrndx, 710 (size_t)shdr.sh_name); 711 if (shdr.sh_flags & SHF_ALLOC && ess->es_has_phdr) { 712 cryptodebug("elfsign_adjustoffsets: " 713 "can't move allocated section %s", name ? name : "NULL"); 714 return (ELFSIGN_FAILED); 715 } 716 717 /* resize the desired section */ 718 cryptodebug("elfsign_adjustoffsets: " 719 "resizing %s at 0x%llx from 0x%llx to 0x%llx", 720 name ? name : "NULL", shdr.sh_offset, shdr.sh_size, new_size); 721 shdr.sh_size = new_size; 722 if (gelf_update_shdr(scn, &shdr) == 0) { 723 cryptodebug("gelf_update_shdr failed"); 724 goto bad; 725 } 726 prev_end = shdr.sh_offset + shdr.sh_size; 727 728 /* 729 * find sections whose data follows the changed section 730 * must scan all sections since section data may not 731 * be in same order as section headers 732 */ 733 scnp = elf_getscn(ess->es_elf, 0); /* "seek" to start */ 734 while ((scnp = elf_nextscn(ess->es_elf, scnp)) != NULL) { 735 if (gelf_getshdr(scnp, &shdr) == NULL) 736 goto bad; 737 if (shdr.sh_offset <= scn_offset) 738 continue; 739 name = elf_strptr(ess->es_elf, ess->es_shstrndx, 740 (size_t)shdr.sh_name); 741 if (shdr.sh_flags & SHF_ALLOC && ess->es_has_phdr) { 742 if (shdr.sh_type == SHT_NOBITS) { 743 /* .bss can occasionally overlap .shrtab */ 744 continue; 745 } 746 cryptodebug("elfsign_adjustoffsets: " 747 "can't move allocated section %s", 748 name ? name : "NULL"); 749 goto bad; 750 } 751 /* 752 * force reading of data to memory image 753 */ 754 data = NULL; 755 while ((data = elf_rawdata(scnp, data)) != NULL) 756 ; 757 /* 758 * capture section information 759 * insert into list in order of sh_offset 760 */ 761 cryptodebug("elfsign_adjustoffsets: " 762 "may have to adjust section %s, offset 0x%llx", 763 name ? name : "NULL", shdr.sh_offset); 764 tmpscnip = (struct scninfo *)malloc(sizeof (struct scninfo)); 765 if (tmpscnip == NULL) { 766 cryptodebug("elfsign_adjustoffsets: " 767 "memory allocation failure"); 768 goto bad; 769 } 770 tmpscnip->scni_scn = scnp; 771 tmpscnip->scni_offset = shdr.sh_offset; 772 for (scnipp = &scnip; *scnipp != NULL; 773 scnipp = &(*scnipp)->scni_next) { 774 if ((*scnipp)->scni_offset > tmpscnip->scni_offset) 775 break; 776 } 777 tmpscnip->scni_next = *scnipp; 778 *scnipp = tmpscnip; 779 } 780 781 /* move following sections as necessary */ 782 for (tmpscnip = scnip; tmpscnip != NULL; 783 tmpscnip = tmpscnip->scni_next) { 784 scnp = tmpscnip->scni_scn; 785 if (gelf_getshdr(scnp, &shdr) == NULL) { 786 cryptodebug("elfsign_adjustoffsets: " 787 "elf_getshdr for section %d failed", 788 elf_ndxscn(scnp)); 789 goto bad; 790 } 791 if (shdr.sh_offset >= prev_end) 792 break; 793 prev_end = (prev_end + shdr.sh_addralign - 1) & 794 (-shdr.sh_addralign); 795 name = elf_strptr(ess->es_elf, ess->es_shstrndx, 796 (size_t)shdr.sh_name); 797 cryptodebug("elfsign_adjustoffsets: " 798 "moving %s size 0x%llx from 0x%llx to 0x%llx", 799 name ? name : "NULL", shdr.sh_size, 800 shdr.sh_offset, prev_end); 801 shdr.sh_offset = prev_end; 802 if (gelf_update_shdr(scnp, &shdr) == 0) { 803 cryptodebug("gelf_update_shdr failed"); 804 goto bad; 805 } 806 prev_end = shdr.sh_offset + shdr.sh_size; 807 } 808 809 /* 810 * adjust section header offset in elf header 811 */ 812 if (gelf_getehdr(ess->es_elf, &elfehdr) == NULL) { 813 cryptodebug("elf_getehdr() failed: %s", elf_errmsg(-1)); 814 goto bad; 815 } 816 if (elfehdr.e_shoff < prev_end) { 817 if (ess->es_ei_class == ELFCLASS32) 818 prev_end = (prev_end + ELF32_FSZ_OFF - 1) & 819 (-ELF32_FSZ_OFF); 820 else if (ess->es_ei_class == ELFCLASS64) 821 prev_end = (prev_end + ELF64_FSZ_OFF - 1) & 822 (-ELF64_FSZ_OFF); 823 cryptodebug("elfsign_adjustoffsets: " 824 "move sh_off from 0x%llx to 0x%llx", 825 elfehdr.e_shoff, prev_end); 826 elfehdr.e_shoff = prev_end; 827 if (gelf_update_ehdr(ess->es_elf, &elfehdr) == 0) { 828 cryptodebug("elf_update_ehdr() failed: %s", 829 elf_errmsg(-1)); 830 goto bad; 831 } 832 } 833 834 retval = ELFSIGN_SUCCESS; 835 836 bad: 837 while (scnip != NULL) { 838 tmpscnip = scnip->scni_next; 839 free(scnip); 840 scnip = tmpscnip; 841 } 842 return (retval); 843 } 844 845 struct filesignatures * 846 elfsign_insert_dso(ELFsign_t ess, 847 struct filesignatures *fssp, 848 const char *dn, 849 int dn_len, 850 const uchar_t *sig, 851 int sig_len, 852 const char *oid, 853 int oid_len) 854 { 855 return (filesig_insert_dso(fssp, ess->es_version, dn, dn_len, 856 sig, sig_len, oid, oid_len)); 857 } 858 859 /*ARGSUSED*/ 860 filesig_vers_t 861 elfsign_extract_sig(ELFsign_t ess, 862 struct filesignatures *fssp, 863 uchar_t *sig, 864 size_t *sig_len) 865 { 866 struct filesig_extraction fsx; 867 filesig_vers_t version; 868 869 if (fssp == NULL) 870 return (FILESIG_UNKNOWN); 871 if (fssp->filesig_cnt != 1) 872 return (FILESIG_UNKNOWN); 873 version = filesig_extract(&fssp->filesig_sig, &fsx); 874 switch (version) { 875 case FILESIG_VERSION1: 876 case FILESIG_VERSION2: 877 case FILESIG_VERSION3: 878 case FILESIG_VERSION4: 879 if (*sig_len >= fsx.fsx_sig_len) { 880 (void) memcpy((char *)sig, (char *)fsx.fsx_signature, 881 *sig_len); 882 *sig_len = fsx.fsx_sig_len; 883 } else 884 version = FILESIG_UNKNOWN; 885 break; 886 default: 887 version = FILESIG_UNKNOWN; 888 break; 889 } 890 891 if (ess->es_version == FILESIG_UNKNOWN) { 892 ess->es_version = version; 893 } 894 895 return (version); 896 } 897 898 static ELFsign_status_t 899 elfsign_hash_common(ELFsign_t ess, uchar_t *hash, size_t *hash_len, 900 boolean_t hash_mem_resident) 901 { 902 Elf_Scn *scn = NULL; 903 ELFsign_status_t elfstat; 904 GElf_Shdr shdr; 905 SHA1_CTX ctx; 906 907 /* The buffer must be large enough to hold the hash */ 908 if (*hash_len < SHA1_DIGEST_LENGTH) 909 return (ELFSIGN_FAILED); 910 911 bzero(hash, *hash_len); 912 913 /* Initialize the digest session */ 914 SHA1Init(&ctx); 915 916 scn = elf_getscn(ess->es_elf, 0); /* "seek" to start */ 917 (void) elf_errno(); 918 while ((scn = elf_nextscn(ess->es_elf, scn)) != 0) { 919 char *name = NULL; 920 Elf_Data *data = NULL; 921 922 if (gelf_getshdr(scn, &shdr) == NULL) { 923 elfstat = ELFSIGN_FAILED; 924 goto done; 925 } 926 927 name = elf_strptr(ess->es_elf, ess->es_shstrndx, 928 (size_t)shdr.sh_name); 929 if (name == NULL) 930 name = "NULL"; 931 932 if (!hash_mem_resident && 933 (ess->es_version == FILESIG_VERSION1 || 934 ess->es_version == FILESIG_VERSION3)) { 935 /* 936 * skip the signature section only 937 */ 938 if (shdr.sh_type == SHT_SUNW_SIGNATURE) { 939 cryptodebug("elfsign_hash: skipping %s", name); 940 continue; 941 } 942 } else if (!(shdr.sh_flags & SHF_ALLOC)) { 943 /* 944 * select only memory resident sections 945 */ 946 cryptodebug("elfsign_hash: skipping %s", name); 947 continue; 948 } 949 950 /* 951 * throw this section into the hash 952 * use elf_rawdata for endian-independence 953 * use elf_getdata to get update of .shstrtab 954 */ 955 while ((data = (shdr.sh_type == SHT_STRTAB ? 956 elf_getdata(scn, data) : elf_rawdata(scn, data))) != NULL) { 957 if (data->d_buf == NULL) { 958 cryptodebug("elfsign_hash: %s has NULL data", 959 name); 960 continue; 961 } 962 cryptodebug("elfsign_hash: updating hash " 963 "with %s data size=%d", name, data->d_size); 964 SHA1Update(&ctx, data->d_buf, data->d_size); 965 } 966 } 967 if (elf_errmsg(0) != NULL) { 968 cryptodebug("elfsign_hash: %s", elf_errmsg(-1)); 969 elfstat = ELFSIGN_FAILED; 970 goto done; 971 } 972 973 SHA1Final(hash, &ctx); 974 *hash_len = SHA1_DIGEST_LENGTH; 975 { /* DEBUG START */ 976 const int hashstr_len = (*hash_len) * 2 + 1; 977 char *hashstr = malloc(hashstr_len); 978 979 if (hashstr != NULL) { 980 tohexstr(hash, *hash_len, hashstr, hashstr_len); 981 cryptodebug("hash value is: %s", hashstr); 982 free(hashstr); 983 } 984 } /* DEBUG END */ 985 elfstat = ELFSIGN_SUCCESS; 986 done: 987 return (elfstat); 988 } 989 990 /* 991 * elfsign_hash - return the hash of the ELF sections affecting execution. 992 * 993 * IN: ess, hash_len 994 * OUT: hash, hash_len 995 */ 996 ELFsign_status_t 997 elfsign_hash(ELFsign_t ess, uchar_t *hash, size_t *hash_len) 998 { 999 return (elfsign_hash_common(ess, hash, hash_len, B_FALSE)); 1000 } 1001 1002 /* 1003 * elfsign_hash_mem_resident - return the hash of the ELF sections 1004 * with only memory resident sections. 1005 * 1006 * IN: ess, hash_len 1007 * OUT: hash, hash_len 1008 */ 1009