Annotation of embedaddon/sudo/common/sudo_dso.c, revision 1.1
1.1 ! misho 1: /*
! 2: * Copyright (c) 2010, 2012-2014 Todd C. Miller <Todd.Miller@courtesan.com>
! 3: *
! 4: * Permission to use, copy, modify, and distribute this software for any
! 5: * purpose with or without fee is hereby granted, provided that the above
! 6: * copyright notice and this permission notice appear in all copies.
! 7: *
! 8: * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
! 9: * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
! 10: * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
! 11: * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
! 12: * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
! 13: * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
! 14: * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
! 15: */
! 16:
! 17: #include <config.h>
! 18:
! 19: #include <sys/types.h>
! 20:
! 21: #include <stdio.h>
! 22: #ifdef STDC_HEADERS
! 23: # include <stdlib.h>
! 24: # include <stddef.h>
! 25: #else
! 26: # ifdef HAVE_STDLIB_H
! 27: # include <stdlib.h>
! 28: # endif
! 29: #endif /* STDC_HEADERS */
! 30: #ifdef HAVE_STRING_H
! 31: # include <string.h>
! 32: #endif /* HAVE_STRING_H */
! 33: #ifdef HAVE_STRINGS_H
! 34: # include <strings.h>
! 35: #endif /* HAVE_STRINGS_H */
! 36: #if defined(HAVE_SHL_LOAD)
! 37: # include <dl.h>
! 38: #elif defined(HAVE_DLOPEN)
! 39: # include <dlfcn.h>
! 40: #endif
! 41: #include <errno.h>
! 42:
! 43: #include "sudo_dso.h"
! 44: #include "missing.h"
! 45:
! 46: /*
! 47: * Pointer for statically compiled symbols.
! 48: */
! 49: static struct sudo_preload_table *preload_table;
! 50:
! 51: void
! 52: sudo_dso_preload_table(struct sudo_preload_table *table)
! 53: {
! 54: preload_table = table;
! 55: }
! 56:
! 57: #if defined(HAVE_SHL_LOAD)
! 58:
! 59: # ifndef DYNAMIC_PATH
! 60: # define DYNAMIC_PATH 0
! 61: # endif
! 62:
! 63: void *
! 64: sudo_dso_load(const char *path, int mode)
! 65: {
! 66: struct sudo_preload_table *pt;
! 67: int flags = DYNAMIC_PATH | BIND_VERBOSE;
! 68:
! 69: if (mode == 0)
! 70: mode = SUDO_DSO_LAZY; /* default behavior */
! 71:
! 72: /* Check prelinked symbols first. */
! 73: if (preload_table != NULL) {
! 74: for (pt = preload_table; pt->handle != NULL; pt++) {
! 75: if (pt->path != NULL && strcmp(path, pt->path) == 0)
! 76: return pt->handle;
! 77: }
! 78: }
! 79:
! 80: /* We don't support SUDO_DSO_GLOBAL or SUDO_DSO_LOCAL yet. */
! 81: if (ISSET(mode, SUDO_DSO_LAZY))
! 82: flags |= BIND_DEFERRED;
! 83: if (ISSET(mode, SUDO_DSO_NOW))
! 84: flags |= BIND_IMMEDIATE;
! 85:
! 86: return (void *)shl_load(path, flags, 0L);
! 87: }
! 88:
! 89: int
! 90: sudo_dso_unload(void *handle)
! 91: {
! 92: struct sudo_preload_table *pt;
! 93:
! 94: /* Check prelinked symbols first. */
! 95: if (preload_table != NULL) {
! 96: for (pt = preload_table; pt->handle != NULL; pt++) {
! 97: if (pt->handle == handle)
! 98: return 0;
! 99: }
! 100: }
! 101:
! 102: return shl_unload((shl_t)handle);
! 103: }
! 104:
! 105: void *
! 106: sudo_dso_findsym(void *vhandle, const char *symbol)
! 107: {
! 108: struct sudo_preload_table *pt;
! 109: shl_t handle = vhandle;
! 110: void *value = NULL;
! 111:
! 112: /* Check prelinked symbols first. */
! 113: if (preload_table != NULL) {
! 114: for (pt = preload_table; pt->handle != NULL; pt++) {
! 115: if (pt->handle == handle) {
! 116: struct sudo_preload_symbol *sym;
! 117: for (sym = pt->symbols; sym->name != NULL; sym++) {
! 118: if (strcmp(sym->name, symbol) == 0)
! 119: return sym->addr;
! 120: }
! 121: errno = ENOENT;
! 122: return NULL;
! 123: }
! 124: }
! 125: }
! 126:
! 127: /*
! 128: * Note that the behavior of of SUDO_DSO_NEXT and SUDO_DSO_SELF
! 129: * differs from most implementations when called from
! 130: * a shared library.
! 131: */
! 132: if (vhandle == SUDO_DSO_NEXT) {
! 133: /* Iterate over all shared libs looking for symbol. */
! 134: shl_t myhandle = PROG_HANDLE;
! 135: struct shl_descriptor *desc;
! 136: int idx = 0;
! 137:
! 138: /* Find program's real handle. */
! 139: if (shl_gethandle(PROG_HANDLE, &desc) == 0)
! 140: myhandle = desc->handle;
! 141: while (shl_get(idx++, &desc) == 0) {
! 142: if (desc->handle == myhandle)
! 143: continue;
! 144: if (shl_findsym(&desc->handle, symbol, TYPE_UNDEFINED, &value) == 0)
! 145: break;
! 146: }
! 147: } else {
! 148: if (vhandle == SUDO_DSO_DEFAULT)
! 149: handle = NULL;
! 150: else if (vhandle == SUDO_DSO_SELF)
! 151: handle = PROG_HANDLE;
! 152: (void)shl_findsym(&handle, symbol, TYPE_UNDEFINED, &value);
! 153: }
! 154:
! 155: return value;
! 156: }
! 157:
! 158: char *
! 159: sudo_dso_strerror(void)
! 160: {
! 161: return strerror(errno);
! 162: }
! 163:
! 164: #elif defined(HAVE_DLOPEN)
! 165:
! 166: # ifndef RTLD_GLOBAL
! 167: # define RTLD_GLOBAL 0
! 168: # endif
! 169:
! 170: void *
! 171: sudo_dso_load(const char *path, int mode)
! 172: {
! 173: struct sudo_preload_table *pt;
! 174: int flags = 0;
! 175:
! 176: /* Check prelinked symbols first. */
! 177: if (preload_table != NULL) {
! 178: for (pt = preload_table; pt->handle != NULL; pt++) {
! 179: if (pt->path != NULL && strcmp(path, pt->path) == 0)
! 180: return pt->handle;
! 181: }
! 182: }
! 183:
! 184: /* Map SUDO_DSO_* -> RTLD_* */
! 185: if (ISSET(mode, SUDO_DSO_LAZY))
! 186: flags |= RTLD_LAZY;
! 187: if (ISSET(mode, SUDO_DSO_NOW))
! 188: flags |= RTLD_NOW;
! 189: if (ISSET(mode, SUDO_DSO_GLOBAL))
! 190: flags |= RTLD_GLOBAL;
! 191: if (ISSET(mode, SUDO_DSO_LOCAL))
! 192: flags |= RTLD_LOCAL;
! 193:
! 194: return dlopen(path, flags);
! 195: }
! 196:
! 197: int
! 198: sudo_dso_unload(void *handle)
! 199: {
! 200: struct sudo_preload_table *pt;
! 201:
! 202: /* Check prelinked symbols first. */
! 203: if (preload_table != NULL) {
! 204: for (pt = preload_table; pt->handle != NULL; pt++) {
! 205: if (pt->handle == handle)
! 206: return 0;
! 207: }
! 208: }
! 209:
! 210: return dlclose(handle);
! 211: }
! 212:
! 213: void *
! 214: sudo_dso_findsym(void *handle, const char *symbol)
! 215: {
! 216: struct sudo_preload_table *pt;
! 217:
! 218: /* Check prelinked symbols first. */
! 219: if (preload_table != NULL) {
! 220: for (pt = preload_table; pt->handle != NULL; pt++) {
! 221: if (pt->handle == handle) {
! 222: struct sudo_preload_symbol *sym;
! 223: for (sym = pt->symbols; sym->name != NULL; sym++) {
! 224: if (strcmp(sym->name, symbol) == 0)
! 225: return sym->addr;
! 226: }
! 227: errno = ENOENT;
! 228: return NULL;
! 229: }
! 230: }
! 231: }
! 232:
! 233: /*
! 234: * Not all implementations support the special handles.
! 235: */
! 236: if (handle == SUDO_DSO_NEXT) {
! 237: # ifdef RTLD_NEXT
! 238: handle = RTLD_NEXT;
! 239: # else
! 240: errno = ENOENT;
! 241: return NULL;
! 242: # endif
! 243: } else if (handle == SUDO_DSO_DEFAULT) {
! 244: # ifdef RTLD_DEFAULT
! 245: handle = RTLD_DEFAULT;
! 246: # else
! 247: errno = ENOENT;
! 248: return NULL;
! 249: # endif
! 250: } else if (handle == SUDO_DSO_SELF) {
! 251: # ifdef RTLD_SELF
! 252: handle = RTLD_SELF;
! 253: # else
! 254: errno = ENOENT;
! 255: return NULL;
! 256: # endif
! 257: }
! 258:
! 259: return dlsym(handle, symbol);
! 260: }
! 261:
! 262: char *
! 263: sudo_dso_strerror(void)
! 264: {
! 265: return dlerror();
! 266: }
! 267:
! 268: #else /* !HAVE_SHL_LOAD && !HAVE_DLOPEN */
! 269:
! 270: /*
! 271: * Emulate dlopen() using a static list of symbols compiled into sudo.
! 272: */
! 273: void *
! 274: sudo_dso_load(const char *path, int mode)
! 275: {
! 276: struct sudo_preload_table *pt;
! 277:
! 278: /* Check prelinked symbols first. */
! 279: if (preload_table != NULL) {
! 280: for (pt = preload_table; pt->handle != NULL; pt++) {
! 281: if (pt->path != NULL && strcmp(path, pt->path) == 0)
! 282: return pt->handle;
! 283: }
! 284: }
! 285: return NULL;
! 286: }
! 287:
! 288: int
! 289: sudo_dso_unload(void *handle)
! 290: {
! 291: struct sudo_preload_table *pt;
! 292:
! 293: if (preload_table != NULL) {
! 294: for (pt = preload_table; pt->handle != NULL; pt++) {
! 295: if (pt->handle == handle)
! 296: return 0;
! 297: }
! 298: }
! 299: return -1;
! 300: }
! 301:
! 302: void *
! 303: sudo_dso_findsym(void *handle, const char *symbol)
! 304: {
! 305: struct sudo_preload_table *pt;
! 306:
! 307: if (preload_table != NULL) {
! 308: for (pt = preload_table; pt->handle != NULL; pt++) {
! 309: if (pt->handle == handle) {
! 310: struct sudo_preload_symbol *sym;
! 311: for (sym = pt->symbols; sym->name != NULL; sym++) {
! 312: if (strcmp(sym->name, symbol) == 0)
! 313: return sym->addr;
! 314: }
! 315: }
! 316: }
! 317: }
! 318: errno = ENOENT;
! 319: return NULL;
! 320: }
! 321:
! 322: char *
! 323: sudo_dso_strerror(void)
! 324: {
! 325: return strerror(errno);
! 326: }
! 327: #endif /* !HAVE_SHL_LOAD && !HAVE_DLOPEN */
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>