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 */
41typedef void (*PG_init_t) (void);
42typedef void (*PG_fini_t) (void);
43
44/* hashtable entry for rendezvous variables */
45typedef 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
55typedef 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
67static DynamicFileList *file_list = NULL;
68static 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
77char *Dynamic_library_path;
78
79static void *internal_load_library(const char *libname);
80static void incompatible_module_error(const char *libname,
81 const Pg_magic_struct *module_magic_data) pg_attribute_noreturn();
82static void internal_unload_library(const char *libname);
83static bool file_exists(const char *name);
84static char *expand_dynamic_library_name(const char *name);
85static void check_restricted_library_name(const char *name);
86static char *substitute_libpath_macro(const char *name);
87static char *find_in_dynamic_libpath(const char *basename);
88
89/* Magic structure that module needs to match to be accepted */
90static 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 */
106PGFunction
107load_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 */
145void
146load_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 */
170PGFunction
171lookup_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 */
183static void *
184internal_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 */
305static void
306incompatible_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 */
408static void
409internal_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
462static bool
463file_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 */
494static char *
495expand_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 */
549static void
550check_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 */
564static char *
565substitute_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 */
595static char *
596find_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 */
679void **
680find_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 */
718Size
719EstimateLibraryStateSpace(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 */
735void
736SerializeLibraryState(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 */
757void
758RestoreLibraryState(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