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