1 /*------------------------------------------------------------------------- 2 * 3 * dfmgr.c 4 * Dynamic function manager code. 5 * 6 * Portions Copyright (c) 1996-2019, PostgreSQL Global Development Group 7 * Portions Copyright (c) 1994, Regents of the University of California 8 * 9 * 10 * IDENTIFICATION 11 * src/backend/utils/fmgr/dfmgr.c 12 * 13 *------------------------------------------------------------------------- 14 */ 15 #include "postgres.h" 16 17 #include <sys/stat.h> 18 19 #ifdef HAVE_DLOPEN 20 #include <dlfcn.h> 21 22 /* 23 * On macOS, <dlfcn.h> insists on including <stdbool.h>. If we're not 24 * using stdbool, undef bool to undo the damage. 25 */ 26 #ifndef USE_STDBOOL 27 #ifdef bool 28 #undef bool 29 #endif 30 #endif 31 #endif /* HAVE_DLOPEN */ 32 33 #include "fmgr.h" 34 #include "lib/stringinfo.h" 35 #include "miscadmin.h" 36 #include "storage/shmem.h" 37 #include "utils/hsearch.h" 38 39 40 /* signatures for PostgreSQL-specific library init/fini functions */ 41 typedef void (*PG_init_t) (void); 42 typedef void (*PG_fini_t) (void); 43 44 /* hashtable entry for rendezvous variables */ 45 typedef struct 46 { 47 char varName[NAMEDATALEN]; /* hash key (must be first) */ 48 void *varValue; 49 } rendezvousHashEntry; 50 51 /* 52 * List of dynamically loaded files (kept in malloc'd memory). 53 */ 54 55 typedef struct df_files 56 { 57 struct df_files *next; /* List link */ 58 dev_t device; /* Device file is on */ 59 #ifndef WIN32 /* ensures we never again depend on this under 60 * win32 */ 61 ino_t inode; /* Inode number of file */ 62 #endif 63 void *handle; /* a handle for pg_dl* functions */ 64 char filename[FLEXIBLE_ARRAY_MEMBER]; /* Full pathname of file */ 65 } DynamicFileList; 66 67 static DynamicFileList *file_list = NULL; 68 static DynamicFileList *file_tail = NULL; 69 70 /* stat() call under Win32 returns an st_ino field, but it has no meaning */ 71 #ifndef WIN32 72 #define SAME_INODE(A,B) ((A).st_ino == (B).inode && (A).st_dev == (B).device) 73 #else 74 #define SAME_INODE(A,B) false 75 #endif 76 77 char *Dynamic_library_path; 78 79 static void *internal_load_library(const char *libname); 80 static void incompatible_module_error(const char *libname, 81 const Pg_magic_struct *module_magic_data) pg_attribute_noreturn(); 82 static void internal_unload_library(const char *libname); 83 static bool file_exists(const char *name); 84 static char *expand_dynamic_library_name(const char *name); 85 static void check_restricted_library_name(const char *name); 86 static char *substitute_libpath_macro(const char *name); 87 static char *find_in_dynamic_libpath(const char *basename); 88 89 /* Magic structure that module needs to match to be accepted */ 90 static const Pg_magic_struct magic_data = PG_MODULE_MAGIC_DATA; 91 92 93 /* 94 * Load the specified dynamic-link library file, and look for a function 95 * named funcname in it. 96 * 97 * If the function is not found, we raise an error if signalNotFound is true, 98 * else return (PGFunction) NULL. Note that errors in loading the library 99 * will provoke ereport() regardless of signalNotFound. 100 * 101 * If filehandle is not NULL, then *filehandle will be set to a handle 102 * identifying the library file. The filehandle can be used with 103 * lookup_external_function to lookup additional functions in the same file 104 * at less cost than repeating load_external_function. 105 */ 106 PGFunction 107 load_external_function(const char *filename, const char *funcname, 108 bool signalNotFound, void **filehandle) 109 { 110 char *fullname; 111 void *lib_handle; 112 PGFunction retval; 113 114 /* Expand the possibly-abbreviated filename to an exact path name */ 115 fullname = expand_dynamic_library_name(filename); 116 117 /* Load the shared library, unless we already did */ 118 lib_handle = internal_load_library(fullname); 119 120 /* Return handle if caller wants it */ 121 if (filehandle) 122 *filehandle = lib_handle; 123 124 /* Look up the function within the library. */ 125 retval = (PGFunction) dlsym(lib_handle, funcname); 126 127 if (retval == NULL && signalNotFound) 128 ereport(ERROR, 129 (errcode(ERRCODE_UNDEFINED_FUNCTION), 130 errmsg("could not find function \"%s\" in file \"%s\"", 131 funcname, fullname))); 132 133 pfree(fullname); 134 return retval; 135 } 136 137 /* 138 * This function loads a shlib file without looking up any particular 139 * function in it. If the same shlib has previously been loaded, 140 * unload and reload it. 141 * 142 * When 'restricted' is true, only libraries in the presumed-secure 143 * directory $libdir/plugins may be referenced. 144 */ 145 void 146 load_file(const char *filename, bool restricted) 147 { 148 char *fullname; 149 150 /* Apply security restriction if requested */ 151 if (restricted) 152 check_restricted_library_name(filename); 153 154 /* Expand the possibly-abbreviated filename to an exact path name */ 155 fullname = expand_dynamic_library_name(filename); 156 157 /* Unload the library if currently loaded */ 158 internal_unload_library(fullname); 159 160 /* Load the shared library */ 161 (void) internal_load_library(fullname); 162 163 pfree(fullname); 164 } 165 166 /* 167 * Lookup a function whose library file is already loaded. 168 * Return (PGFunction) NULL if not found. 169 */ 170 PGFunction 171 lookup_external_function(void *filehandle, const char *funcname) 172 { 173 return (PGFunction) dlsym(filehandle, funcname); 174 } 175 176 177 /* 178 * Load the specified dynamic-link library file, unless it already is 179 * loaded. Return the pg_dl* handle for the file. 180 * 181 * Note: libname is expected to be an exact name for the library file. 182 */ 183 static void * 184 internal_load_library(const char *libname) 185 { 186 DynamicFileList *file_scanner; 187 PGModuleMagicFunction magic_func; 188 char *load_error; 189 struct stat stat_buf; 190 PG_init_t PG_init; 191 192 /* 193 * Scan the list of loaded FILES to see if the file has been loaded. 194 */ 195 for (file_scanner = file_list; 196 file_scanner != NULL && 197 strcmp(libname, file_scanner->filename) != 0; 198 file_scanner = file_scanner->next) 199 ; 200 201 if (file_scanner == NULL) 202 { 203 /* 204 * Check for same files - different paths (ie, symlink or link) 205 */ 206 if (stat(libname, &stat_buf) == -1) 207 ereport(ERROR, 208 (errcode_for_file_access(), 209 errmsg("could not access file \"%s\": %m", 210 libname))); 211 212 for (file_scanner = file_list; 213 file_scanner != NULL && 214 !SAME_INODE(stat_buf, *file_scanner); 215 file_scanner = file_scanner->next) 216 ; 217 } 218 219 if (file_scanner == NULL) 220 { 221 /* 222 * File not loaded yet. 223 */ 224 file_scanner = (DynamicFileList *) 225 malloc(offsetof(DynamicFileList, filename) + strlen(libname) + 1); 226 if (file_scanner == NULL) 227 ereport(ERROR, 228 (errcode(ERRCODE_OUT_OF_MEMORY), 229 errmsg("out of memory"))); 230 231 MemSet(file_scanner, 0, offsetof(DynamicFileList, filename)); 232 strcpy(file_scanner->filename, libname); 233 file_scanner->device = stat_buf.st_dev; 234 #ifndef WIN32 235 file_scanner->inode = stat_buf.st_ino; 236 #endif 237 file_scanner->next = NULL; 238 239 file_scanner->handle = dlopen(file_scanner->filename, RTLD_NOW | RTLD_GLOBAL); 240 if (file_scanner->handle == NULL) 241 { 242 load_error = dlerror(); 243 free((char *) file_scanner); 244 /* errcode_for_file_access might not be appropriate here? */ 245 ereport(ERROR, 246 (errcode_for_file_access(), 247 errmsg("could not load library \"%s\": %s", 248 libname, load_error))); 249 } 250 251 /* Check the magic function to determine compatibility */ 252 magic_func = (PGModuleMagicFunction) 253 dlsym(file_scanner->handle, PG_MAGIC_FUNCTION_NAME_STRING); 254 if (magic_func) 255 { 256 const Pg_magic_struct *magic_data_ptr = (*magic_func) (); 257 258 if (magic_data_ptr->len != magic_data.len || 259 memcmp(magic_data_ptr, &magic_data, magic_data.len) != 0) 260 { 261 /* copy data block before unlinking library */ 262 Pg_magic_struct module_magic_data = *magic_data_ptr; 263 264 /* try to close library */ 265 dlclose(file_scanner->handle); 266 free((char *) file_scanner); 267 268 /* issue suitable complaint */ 269 incompatible_module_error(libname, &module_magic_data); 270 } 271 } 272 else 273 { 274 /* try to close library */ 275 dlclose(file_scanner->handle); 276 free((char *) file_scanner); 277 /* complain */ 278 ereport(ERROR, 279 (errmsg("incompatible library \"%s\": missing magic block", 280 libname), 281 errhint("Extension libraries are required to use the PG_MODULE_MAGIC macro."))); 282 } 283 284 /* 285 * If the library has a _PG_init() function, call it. 286 */ 287 PG_init = (PG_init_t) dlsym(file_scanner->handle, "_PG_init"); 288 if (PG_init) 289 (*PG_init) (); 290 291 /* OK to link it into list */ 292 if (file_list == NULL) 293 file_list = file_scanner; 294 else 295 file_tail->next = file_scanner; 296 file_tail = file_scanner; 297 } 298 299 return file_scanner->handle; 300 } 301 302 /* 303 * Report a suitable error for an incompatible magic block. 304 */ 305 static void 306 incompatible_module_error(const char *libname, 307 const Pg_magic_struct *module_magic_data) 308 { 309 StringInfoData details; 310 311 /* 312 * If the version doesn't match, just report that, because the rest of the 313 * block might not even have the fields we expect. 314 */ 315 if (magic_data.version != module_magic_data->version) 316 { 317 char library_version[32]; 318 319 if (module_magic_data->version >= 1000) 320 snprintf(library_version, sizeof(library_version), "%d", 321 module_magic_data->version / 100); 322 else 323 snprintf(library_version, sizeof(library_version), "%d.%d", 324 module_magic_data->version / 100, 325 module_magic_data->version % 100); 326 ereport(ERROR, 327 (errmsg("incompatible library \"%s\": version mismatch", 328 libname), 329 errdetail("Server is version %d, library is version %s.", 330 magic_data.version / 100, library_version))); 331 } 332 333 /* 334 * Otherwise, spell out which fields don't agree. 335 * 336 * XXX this code has to be adjusted any time the set of fields in a magic 337 * block change! 338 */ 339 initStringInfo(&details); 340 341 if (module_magic_data->funcmaxargs != magic_data.funcmaxargs) 342 { 343 if (details.len) 344 appendStringInfoChar(&details, '\n'); 345 appendStringInfo(&details, 346 _("Server has FUNC_MAX_ARGS = %d, library has %d."), 347 magic_data.funcmaxargs, 348 module_magic_data->funcmaxargs); 349 } 350 if (module_magic_data->indexmaxkeys != magic_data.indexmaxkeys) 351 { 352 if (details.len) 353 appendStringInfoChar(&details, '\n'); 354 appendStringInfo(&details, 355 _("Server has INDEX_MAX_KEYS = %d, library has %d."), 356 magic_data.indexmaxkeys, 357 module_magic_data->indexmaxkeys); 358 } 359 if (module_magic_data->namedatalen != magic_data.namedatalen) 360 { 361 if (details.len) 362 appendStringInfoChar(&details, '\n'); 363 appendStringInfo(&details, 364 _("Server has NAMEDATALEN = %d, library has %d."), 365 magic_data.namedatalen, 366 module_magic_data->namedatalen); 367 } 368 if (module_magic_data->float4byval != magic_data.float4byval) 369 { 370 if (details.len) 371 appendStringInfoChar(&details, '\n'); 372 appendStringInfo(&details, 373 _("Server has FLOAT4PASSBYVAL = %s, library has %s."), 374 magic_data.float4byval ? "true" : "false", 375 module_magic_data->float4byval ? "true" : "false"); 376 } 377 if (module_magic_data->float8byval != magic_data.float8byval) 378 { 379 if (details.len) 380 appendStringInfoChar(&details, '\n'); 381 appendStringInfo(&details, 382 _("Server has FLOAT8PASSBYVAL = %s, library has %s."), 383 magic_data.float8byval ? "true" : "false", 384 module_magic_data->float8byval ? "true" : "false"); 385 } 386 387 if (details.len == 0) 388 appendStringInfoString(&details, 389 _("Magic block has unexpected length or padding difference.")); 390 391 ereport(ERROR, 392 (errmsg("incompatible library \"%s\": magic block mismatch", 393 libname), 394 errdetail_internal("%s", details.data))); 395 } 396 397 /* 398 * Unload the specified dynamic-link library file, if it is loaded. 399 * 400 * Note: libname is expected to be an exact name for the library file. 401 * 402 * XXX for the moment, this is disabled, resulting in LOAD of an already-loaded 403 * library always being a no-op. We might re-enable it someday if we can 404 * convince ourselves we have safe protocols for un-hooking from hook function 405 * pointers, releasing custom GUC variables, and perhaps other things that 406 * are definitely unsafe currently. 407 */ 408 static void 409 internal_unload_library(const char *libname) 410 { 411 #ifdef NOT_USED 412 DynamicFileList *file_scanner, 413 *prv, 414 *nxt; 415 struct stat stat_buf; 416 PG_fini_t PG_fini; 417 418 /* 419 * We need to do stat() in order to determine whether this is the same 420 * file as a previously loaded file; it's also handy so as to give a good 421 * error message if bogus file name given. 422 */ 423 if (stat(libname, &stat_buf) == -1) 424 ereport(ERROR, 425 (errcode_for_file_access(), 426 errmsg("could not access file \"%s\": %m", libname))); 427 428 /* 429 * We have to zap all entries in the list that match on either filename or 430 * inode, else internal_load_library() will still think it's present. 431 */ 432 prv = NULL; 433 for (file_scanner = file_list; file_scanner != NULL; file_scanner = nxt) 434 { 435 nxt = file_scanner->next; 436 if (strcmp(libname, file_scanner->filename) == 0 || 437 SAME_INODE(stat_buf, *file_scanner)) 438 { 439 if (prv) 440 prv->next = nxt; 441 else 442 file_list = nxt; 443 444 /* 445 * If the library has a _PG_fini() function, call it. 446 */ 447 PG_fini = (PG_fini_t) dlsym(file_scanner->handle, "_PG_fini"); 448 if (PG_fini) 449 (*PG_fini) (); 450 451 clear_external_function_hash(file_scanner->handle); 452 dlclose(file_scanner->handle); 453 free((char *) file_scanner); 454 /* prv does not change */ 455 } 456 else 457 prv = file_scanner; 458 } 459 #endif /* NOT_USED */ 460 } 461 462 static bool 463 file_exists(const char *name) 464 { 465 struct stat st; 466 467 AssertArg(name != NULL); 468 469 if (stat(name, &st) == 0) 470 return S_ISDIR(st.st_mode) ? false : true; 471 else if (!(errno == ENOENT || errno == ENOTDIR || errno == EACCES)) 472 ereport(ERROR, 473 (errcode_for_file_access(), 474 errmsg("could not access file \"%s\": %m", name))); 475 476 return false; 477 } 478 479 480 /* Example format: ".so" */ 481 #ifndef DLSUFFIX 482 #error "DLSUFFIX must be defined to compile this file." 483 #endif 484 485 /* 486 * If name contains a slash, check if the file exists, if so return 487 * the name. Else (no slash) try to expand using search path (see 488 * find_in_dynamic_libpath below); if that works, return the fully 489 * expanded file name. If the previous failed, append DLSUFFIX and 490 * try again. If all fails, just return the original name. 491 * 492 * The result will always be freshly palloc'd. 493 */ 494 static char * 495 expand_dynamic_library_name(const char *name) 496 { 497 bool have_slash; 498 char *new; 499 char *full; 500 501 AssertArg(name); 502 503 have_slash = (first_dir_separator(name) != NULL); 504 505 if (!have_slash) 506 { 507 full = find_in_dynamic_libpath(name); 508 if (full) 509 return full; 510 } 511 else 512 { 513 full = substitute_libpath_macro(name); 514 if (file_exists(full)) 515 return full; 516 pfree(full); 517 } 518 519 new = psprintf("%s%s", name, DLSUFFIX); 520 521 if (!have_slash) 522 { 523 full = find_in_dynamic_libpath(new); 524 pfree(new); 525 if (full) 526 return full; 527 } 528 else 529 { 530 full = substitute_libpath_macro(new); 531 pfree(new); 532 if (file_exists(full)) 533 return full; 534 pfree(full); 535 } 536 537 /* 538 * If we can't find the file, just return the string as-is. The ensuing 539 * load attempt will fail and report a suitable message. 540 */ 541 return pstrdup(name); 542 } 543 544 /* 545 * Check a restricted library name. It must begin with "$libdir/plugins/" 546 * and there must not be any directory separators after that (this is 547 * sufficient to prevent ".." style attacks). 548 */ 549 static void 550 check_restricted_library_name(const char *name) 551 { 552 if (strncmp(name, "$libdir/plugins/", 16) != 0 || 553 first_dir_separator(name + 16) != NULL) 554 ereport(ERROR, 555 (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE), 556 errmsg("access to library \"%s\" is not allowed", 557 name))); 558 } 559 560 /* 561 * Substitute for any macros appearing in the given string. 562 * Result is always freshly palloc'd. 563 */ 564 static char * 565 substitute_libpath_macro(const char *name) 566 { 567 const char *sep_ptr; 568 569 AssertArg(name != NULL); 570 571 /* Currently, we only recognize $libdir at the start of the string */ 572 if (name[0] != '$') 573 return pstrdup(name); 574 575 if ((sep_ptr = first_dir_separator(name)) == NULL) 576 sep_ptr = name + strlen(name); 577 578 if (strlen("$libdir") != sep_ptr - name || 579 strncmp(name, "$libdir", strlen("$libdir")) != 0) 580 ereport(ERROR, 581 (errcode(ERRCODE_INVALID_NAME), 582 errmsg("invalid macro name in dynamic library path: %s", 583 name))); 584 585 return psprintf("%s%s", pkglib_path, sep_ptr); 586 } 587 588 589 /* 590 * Search for a file called 'basename' in the colon-separated search 591 * path Dynamic_library_path. If the file is found, the full file name 592 * is returned in freshly palloc'd memory. If the file is not found, 593 * return NULL. 594 */ 595 static char * 596 find_in_dynamic_libpath(const char *basename) 597 { 598 const char *p; 599 size_t baselen; 600 601 AssertArg(basename != NULL); 602 AssertArg(first_dir_separator(basename) == NULL); 603 AssertState(Dynamic_library_path != NULL); 604 605 p = Dynamic_library_path; 606 if (strlen(p) == 0) 607 return NULL; 608 609 baselen = strlen(basename); 610 611 for (;;) 612 { 613 size_t len; 614 char *piece; 615 char *mangled; 616 char *full; 617 618 piece = first_path_var_separator(p); 619 if (piece == p) 620 ereport(ERROR, 621 (errcode(ERRCODE_INVALID_NAME), 622 errmsg("zero-length component in parameter \"dynamic_library_path\""))); 623 624 if (piece == NULL) 625 len = strlen(p); 626 else 627 len = piece - p; 628 629 piece = palloc(len + 1); 630 strlcpy(piece, p, len + 1); 631 632 mangled = substitute_libpath_macro(piece); 633 pfree(piece); 634 635 canonicalize_path(mangled); 636 637 /* only absolute paths */ 638 if (!is_absolute_path(mangled)) 639 ereport(ERROR, 640 (errcode(ERRCODE_INVALID_NAME), 641 errmsg("component in parameter \"dynamic_library_path\" is not an absolute path"))); 642 643 full = palloc(strlen(mangled) + 1 + baselen + 1); 644 sprintf(full, "%s/%s", mangled, basename); 645 pfree(mangled); 646 647 elog(DEBUG3, "find_in_dynamic_libpath: trying \"%s\"", full); 648 649 if (file_exists(full)) 650 return full; 651 652 pfree(full); 653 654 if (p[len] == '\0') 655 break; 656 else 657 p += len + 1; 658 } 659 660 return NULL; 661 } 662 663 664 /* 665 * Find (or create) a rendezvous variable that one dynamically 666 * loaded library can use to meet up with another. 667 * 668 * On the first call of this function for a particular varName, 669 * a "rendezvous variable" is created with the given name. 670 * The value of the variable is a void pointer (initially set to NULL). 671 * Subsequent calls with the same varName just return the address of 672 * the existing variable. Once created, a rendezvous variable lasts 673 * for the life of the process. 674 * 675 * Dynamically loaded libraries can use rendezvous variables 676 * to find each other and share information: they just need to agree 677 * on the variable name and the data it will point to. 678 */ 679 void ** 680 find_rendezvous_variable(const char *varName) 681 { 682 static HTAB *rendezvousHash = NULL; 683 684 rendezvousHashEntry *hentry; 685 bool found; 686 687 /* Create a hashtable if we haven't already done so in this process */ 688 if (rendezvousHash == NULL) 689 { 690 HASHCTL ctl; 691 692 MemSet(&ctl, 0, sizeof(ctl)); 693 ctl.keysize = NAMEDATALEN; 694 ctl.entrysize = sizeof(rendezvousHashEntry); 695 rendezvousHash = hash_create("Rendezvous variable hash", 696 16, 697 &ctl, 698 HASH_ELEM); 699 } 700 701 /* Find or create the hashtable entry for this varName */ 702 hentry = (rendezvousHashEntry *) hash_search(rendezvousHash, 703 varName, 704 HASH_ENTER, 705 &found); 706 707 /* Initialize to NULL if first time */ 708 if (!found) 709 hentry->varValue = NULL; 710 711 return &hentry->varValue; 712 } 713 714 /* 715 * Estimate the amount of space needed to serialize the list of libraries 716 * we have loaded. 717 */ 718 Size 719 EstimateLibraryStateSpace(void) 720 { 721 DynamicFileList *file_scanner; 722 Size size = 1; 723 724 for (file_scanner = file_list; 725 file_scanner != NULL; 726 file_scanner = file_scanner->next) 727 size = add_size(size, strlen(file_scanner->filename) + 1); 728 729 return size; 730 } 731 732 /* 733 * Serialize the list of libraries we have loaded to a chunk of memory. 734 */ 735 void 736 SerializeLibraryState(Size maxsize, char *start_address) 737 { 738 DynamicFileList *file_scanner; 739 740 for (file_scanner = file_list; 741 file_scanner != NULL; 742 file_scanner = file_scanner->next) 743 { 744 Size len; 745 746 len = strlcpy(start_address, file_scanner->filename, maxsize) + 1; 747 Assert(len < maxsize); 748 maxsize -= len; 749 start_address += len; 750 } 751 start_address[0] = '\0'; 752 } 753 754 /* 755 * Load every library the serializing backend had loaded. 756 */ 757 void 758 RestoreLibraryState(char *start_address) 759 { 760 while (*start_address != '\0') 761 { 762 internal_load_library(start_address); 763 start_address += strlen(start_address) + 1; 764 } 765 } 766