Пример #1
0
// Usage:
//
// dlsym $RTLD_DEFAULT "errno"
//
static int get_symbol_address(WORD_LIST *list)
{
    int opt;
    void *handle;
    void *symbol;
    char *resultname;
    char retval[256];

    resultname = "DLRETVAL";

    reset_internal_getopt();

    // $ dlcall [-n name]
    while ((opt = internal_getopt(list, "n:")) != -1) {
        switch (opt) {
            case 'n':
                resultname = list_optarg;
                break;
            default:
                builtin_usage();
                return EX_USAGE;
        }
    }

    // Skip past any options.
    if ((list = loptend) == NULL || list->next == NULL) {
        builtin_usage();
        return EX_USAGE;
    }

    if (check_parse_ulong(list->word->word, (void *) &handle) == 0) {
        builtin_warning("handle %s %p is not well-formed", list->word->word, handle);
        return EX_USAGE;
    }

    if (!(symbol = dlsym(handle, list->next->word->word))) {
        builtin_warning("failed to resolve symbol %s, %s", list->next->word->word, dlerror());
        return EXECUTION_FAILURE;
    }

    snprintf(retval, sizeof retval, "pointer:%p", symbol);
    
    fprintf(stderr, "%s\n", retval);
    
    bind_variable(resultname, retval, 0);

    return EXECUTION_SUCCESS;
}
Пример #2
0
static int close_dynamic_library(WORD_LIST *list)
{
    void *handle;

    if (!list) {
        builtin_usage();
        return EX_USAGE;
    }

    while (list) {
        if (!check_parse_ulong(list->word->word, (long *) &handle)) {
            builtin_warning("could not parse handle identifier %s", list->word->word);
        } else {
            if (dlclose(handle) != 0) {
                builtin_warning("dlclose set an error for %s, %s", list->word->word, dlerror());
            }
        }

        list = list->next;
    }

    return 0;
}
Пример #3
0
bool decode_primitive_type(const char *parameter, void **value, ffi_type **type)
{
    const char *prefix;

    prefix  = NULL;
    *value  = NULL;
    *type   = NULL;

    // If a colon exists, then everything before it is a type
    if (strchr(parameter, ':')) {
        // Extract the two components.
        prefix    = strndupa(parameter, strchr(parameter, ':') - parameter);
        parameter = strchr(parameter, ':') + 1;
    } else {
        intmax_t n;
        char *string;

        // No type was specified, so there are only two possibilities,
        // If this is a legal number, then it's an int. Otherwise, this is a
        // string.
        if (check_parse_long(parameter, &n)) {
            *type   = &ffi_type_sint;
            *value  = malloc(ffi_type_sint.size);

            memcpy(*value, &n, ffi_type_sint.size);
            return true;
        }

        // This must be a string.
        *type   = &ffi_type_pointer;
        *value  = malloc(ffi_type_pointer.size);
        string  = strdup(parameter);

        memcpy(*value, &string, ffi_type_pointer.size);
        return true;
    }

    if (decode_type_prefix(prefix, parameter, type, value, NULL) != true) {
        builtin_warning("parameter decoding failed");
        return false;
    }

    return true;
}
Пример #4
0
// Return the value of the single rtld flag specified.
static uint32_t rtld_flags_decode(const char *flag) {
    intmax_t result;

    // Enumerate through all flags to find the one specified, this is
    // suboptimal but there are only 32 possible flags.
    for (uint32_t i = 0; i < 31; i++) {
        if (strcmp(rtld_flags_encode(1 << i), flag) == 0) {
            return 1 << i;
        }
    }

    // Perhaps it was specified numerically?
    if (check_parse_ulong(flag, &result)) {
        return result;
    }

    builtin_warning("invalid or unrecognised rtld flag ignored: %s", flag);

    return 0;
}
Пример #5
0
// Usage:
//
// dlcall $RTLD_DEFAULT "printf" "hello %s %u %c" $USER 123 int:10
//
static int call_foreign_function(WORD_LIST *list)
{
    unsigned nargs;
    int opt;
    ffi_cif cif;
    ffi_type **argtypes;
    ffi_type *rettype;
    void **values;
    void *handle;
    void *func;
    char *prefix;
    char *format;
    char *resultname;

    nargs       = 0;
    argtypes    = NULL;
    values      = NULL;
    format      = NULL;
    prefix      = NULL;
    rettype     = &ffi_type_void;
    resultname  = "DLRETVAL";

    reset_internal_getopt();

    // $ dlcall [-a abi] [-r type] [-n name]
    while ((opt = internal_getopt(list, "a:r:n:")) != -1) {
        switch (opt) {
            case 'a':
                builtin_warning("FIXME: only abi %u is currently supported", FFI_DEFAULT_ABI);
                return 1;
                break;
            case 'r':
                if (decode_type_prefix(prefix = list_optarg, NULL, &rettype, NULL, &format) != true) {
                    builtin_warning("failed to parse return type");
                    return 1;
                }
                break;
            case 'n':
                resultname = list_optarg;
                break;
            default:
                builtin_usage();
                return 1;
        }
    }

    // Skip past any options.
    if ((list = loptend) == NULL || list->next == NULL) {
        builtin_usage();
        return 1;
    }

    if (check_parse_ulong(list->word->word, (void *) &handle) == 0) {
        builtin_warning("handle %s %p is not well-formed", list->word->word, handle);
        return 1;
    }

    if (!(func = dlsym(handle, list->next->word->word))) {
        builtin_warning("failed to resolve symbol %s, %s", list->next->word->word, dlerror());
        return 1;
    }

    // Skip to optional parameters
    list = list->next->next;

    while (list) {
        argtypes = realloc(argtypes, (nargs + 1) * sizeof(ffi_type *));
        values   = realloc(values, (nargs + 1) * sizeof(void *));

        if (decode_primitive_type(list->word->word, &values[nargs], &argtypes[nargs]) != true) {
            builtin_error("failed to decode type from parameter %s", list->word->word);
            goto error;
        }

        nargs++;
        list = list->next;
    }

    if (ffi_prep_cif(&cif, FFI_DEFAULT_ABI, nargs, rettype, argtypes) == FFI_OK) {
        char *retval;
        void *rc = alloca(rettype->size);

        // Do the call.
        ffi_call(&cif, func, rc, values);

        // Print the result.
        if (format) {
            switch (rettype->size) {
                case  1: asprintf(&retval, format, *(uint8_t  *) rc); break;
                case  2: asprintf(&retval, format, *(uint16_t *) rc); break;
                case  4: asprintf(&retval, format, *(uint32_t *) rc, *(float *) rc); break;
                case  8: asprintf(&retval, format, *(uint64_t *) rc, *(double *) rc); break;
                case 16: asprintf(&retval, format, *(long double *) rc); break;
                default:
                    builtin_error("cannot handle size %lu", rettype->size);
                    abort();
            }

            fprintf(stderr, "%s\n", retval);
            bind_variable(resultname, retval, 0);
            free(retval);
        }
    }

    for (unsigned i = 0; i < nargs; i++)
        free(values[i]);
    free(values);
    free(argtypes);
    return 0;

  error:
    for (unsigned i = 0; i < nargs; i++)
        free(values[i]);
    free(values);
    free(argtypes);
    return 1;
}
Пример #6
0
bool decode_type_prefix(const char *prefix, const char *value, ffi_type **type, void **result, char **pformat)
{
    static struct {
        char     *prefix;
        ffi_type *type;
        char     *sformat;
        char     *pformat;
    } types[] = {
        { "uint8", &ffi_type_uint8, "%" SCNu8, "uint8:%" PRIu8 },
        { "int8", &ffi_type_sint8, "%" SCNd8, "int8:%" PRId8 },
        { "uint16", &ffi_type_uint16, "%" SCNu16, "uint16:%" PRIu16 },
        { "int16", &ffi_type_sint16, "%" SCNd16, "int16:%" PRId16 },
        { "uint32", &ffi_type_uint32, "%" SCNu32, "uint32:%" PRIu32 },
        { "int32", &ffi_type_sint32, "%" SCNd32, "int32:%" PRId32 },
        { "uint64", &ffi_type_uint64, "%" SCNu64, "uint64:%" PRIu64 },
        { "int64", &ffi_type_sint64, "%" SCNd64, "int64:%" PRId64 },
        { "float", &ffi_type_float, "%f", "float:%f" },
        { "double", &ffi_type_double, "%lf", "double:%lf" },
        { "char", &ffi_type_schar, "%c", "char:%c" },
        { "uchar", &ffi_type_uchar, "%c", "uchar:%c" },
        { "ushort", &ffi_type_ushort, "%hu", "ushort:%hu" },
        { "short", &ffi_type_sshort, "%hd", "short:%hd", },
        { "unsigned", &ffi_type_uint, "%u", "unsigned:%u" },
        { "int", &ffi_type_sint, "%d", "int:%d" },
        { "ulong", &ffi_type_ulong, "%lu", "ulong:%lu" },
        { "long", &ffi_type_slong, "%ld", "long:%ld" },
        { "longdouble", &ffi_type_longdouble, "%llg", "longdouble:%llg" },
        { "pointer", &ffi_type_pointer, "%p", "pointer:%p" },
        { "string", &ffi_type_pointer, "%ms", "string:%s" },
        { "void", &ffi_type_void, "", "" },
        { NULL },
    };

    for (int i = 0; types[i].prefix; i++) {
        if (strcmp(types[i].prefix, prefix) == 0) {
            // Prefix matched type, return information user requested.
            if (type) {
                *type = types[i].type;
            }

            if (pformat) {
                *pformat = types[i].pformat;
            }

            // Caller wants us to decode it, lets go ahead.
            if (result) {
                *result = malloc(types[i].type->size);

                if (sscanf(value, types[i].sformat, *result) != 1) {
                    builtin_warning("failed to parse %s as a %s", value, prefix);
                    free(*result);
                    return false;
                }
            }
            return true;
        }
    }

    builtin_warning("unrecognised type prefix %s", prefix);
    return false;
}
Пример #7
0
// Usage:
//
// dlcall "printf" "hello %s %u %c" $USER 123 int:10
//
static int call_foreign_function(WORD_LIST *list)
{
    unsigned nargs;
    unsigned i;
    int opt;
    ffi_cif cif;
    ffi_type **argtypes;
    ffi_type *rettype;
    void **values;
    void *handle;
    void *func;
    char *prefix;
    char *format;
    char *resultname;

    nargs       = 0;
    argtypes    = NULL;
    values      = NULL;
    format      = NULL;
    prefix      = NULL;
    rettype     = &ffi_type_void;
    resultname  = "DLRETVAL";
    handle      = RTLD_DEFAULT;

    reset_internal_getopt();

    // $ dlcall [-a abi] [-r type] [-n name] [-h handle] symbol args...
    while ((opt = internal_getopt(list, "h:a:r:n:")) != -1) {
        switch (opt) {
            case 'a':
                builtin_warning("FIXME: only abi %u is currently supported", FFI_DEFAULT_ABI);
                return 1;
                break;
            case 'r':
                if (decode_type_prefix(prefix = list_optarg, NULL, &rettype, NULL, &format) != true) {
                    builtin_warning("failed to parse return type");
                    return 1;
                }
                break;
            case 'n':
                resultname = list_optarg;
                break;
            case 'h':
                if (check_parse_ulong(list_optarg, (void *) &handle) == 0) {
                    builtin_warning("handle %s %p is not well-formed", list_optarg, handle);
                    return EXECUTION_FAILURE;
                }
                break;
            default:
                builtin_usage();
                return EX_USAGE;
        }
    }

    // Skip past any options.
    if ((list = loptend) == NULL) {
        builtin_usage();
        return EX_USAGE;
    }

    if (!(func = dlsym(handle, list->word->word))) {
        builtin_warning("failed to resolve symbol %s, %s", list->word->word, dlerror());
        return 1;
    }

    // Skip to optional parameters
    list = list->next;

    while (list) {
        argtypes = realloc(argtypes, (nargs + 1) * sizeof(ffi_type *));
        values   = realloc(values, (nargs + 1) * sizeof(void *));

        if (decode_primitive_type(list->word->word, &values[nargs], &argtypes[nargs]) != true) {
            builtin_error("failed to decode type from parameter %s", list->word->word);
            goto error;
        }

        nargs++;
        list = list->next;
    }

    if (ffi_prep_cif(&cif, FFI_DEFAULT_ABI, nargs, rettype, argtypes) == FFI_OK) {
        char *retval;
        void *rc = alloca(rettype->size);

        // Do the call.
        ffi_call(&cif, func, rc, values);

        // Decode the result.
        if (format) {
            retval = encode_primitive_type(format, rettype, rc);

            // If this is an interactive shell, print the output.
            if (interactive_shell) {
                fprintf(stderr, "%s\n", retval);
            }

            // Save the result to the requested location.
            bind_variable(resultname, retval, 0);

            // Bash maintains it's own copy of this string, so we can throw it away.
            free(retval);
        }
    }

    for (i = 0; i < nargs; i++)
        free(values[i]);
    free(values);
    free(argtypes);
    return 0;

  error:
    for (i = 0; i < nargs; i++)
        free(values[i]);
    free(values);
    free(argtypes);
    return 1;
}
Пример #8
0
// Usage:
//
// dlsym $RTLD_DEFAULT "errno"
//
static int get_symbol_address(WORD_LIST *list)
{
    int opt;
    void *handle;
    void *symbol;
    char *resultname;
    char *format;
    char *retval;
    ffi_type *rettype;

    handle = RTLD_DEFAULT;
    resultname = "DLRETVAL";
    rettype = NULL;

    reset_internal_getopt();

    // $ dlsym [-n name] [-h handle] symbol
    while ((opt = internal_getopt(list, "d:h:n:")) != -1) {
        switch (opt) {
            case 'd':
                if (decode_type_prefix(list_optarg, NULL, &rettype, NULL, &format) != true) {
                    builtin_warning("failed to parse dereference type");
                    return 1;
                }
                break;
            case 'n':
                resultname = list_optarg;
                break;
            case 'h':
                if (check_parse_ulong(list_optarg, (void *) &handle) == 0) {
                    builtin_warning("handle %s %p is not well-formed", list_optarg, handle);
                    return EXECUTION_FAILURE;
                }
                break;
            default:
                builtin_usage();
                return EX_USAGE;
        }
    }

    // Skip past any options.
    if ((list = loptend) == NULL) {
        builtin_usage();
        return EX_USAGE;
    }

    if (!(symbol = dlsym(handle, list->word->word))) {
        builtin_warning("failed to resolve symbol %s, %s", list->word->word, dlerror());
        return EXECUTION_FAILURE;
    }

    if (rettype == NULL) {
        asprintf(&retval, "pointer:%p", symbol);
    } else {
        retval = encode_primitive_type(format, rettype, symbol);
    }


    if (interactive_shell) {
        fprintf(stderr, "%s\n", retval);
    }

    bind_variable(resultname, retval, 0);

    free(retval);

    return EXECUTION_SUCCESS;
}
Пример #9
0
// Usage:
//
//  dlopen [-N] [-t] [-d] [-g] [-n] [library] [RTLD_NODELETE|RTLD_GLOBAL|...] [...]
//
static int open_dynamic_library(WORD_LIST *list)
{
    char varname[1024];
    char value[1024];
    uint32_t flags;
    void *handle;
    int opt;

    reset_internal_getopt();

    flags   = RTLD_LAZY | RTLD_GLOBAL;
    handle  = NULL;

    // Options can either be specified as bash-like flags, or as a list. The
    // bash-like flags look like this:
    //
    // $ dlopen -tg libc.so
    //
    while ((opt = internal_getopt(list, "lNtdgn")) != -1) {
        switch (opt) {
                // RTLD_LAZY and RTLD_NOW are mutually exclusive.
            case 'l':
                flags = (flags & ~RTLD_NOW) | RTLD_LAZY;
                break;
            case 'N':
                flags = (flags & ~RTLD_LAZY) | RTLD_NOW;
                break;
            case 't':
                flags |= RTLD_NOLOAD;
                break;
            case 'd':
#ifdef RTLD_DEEPBIND
                flags |= RTLD_DEEPBIND;
#else
                builtin_warning("RTLD_DEEPBIND is not supported on this platform");
#endif

                break;
            case 'g':
                flags &= ~RTLD_GLOBAL;
                break;
            case 'n':
                flags |= RTLD_NODELETE;
                break;
            default:
                builtin_usage();
                return EX_USAGE;
        }
    }

    // Skip past any options.
    if ((list = loptend) == NULL) {
        builtin_usage();
        return 1;
    }

    // Check and decode parameters, which can be specified as strings.
    //
    // $ dlopen libc.so RTLD_LAZY RTLD_NODELETE
    //
    // or, as an integer
    //
    // $ dlopen libc.so 0x10101
    //
    if (list->next) {
        WORD_LIST *flaglist = list->next;

        // Caller wants more control over flags, so reset and decode the flags
        // specified.
        for (flags = 0; flaglist; flaglist = flaglist->next) {
            flags |= rtld_flags_decode(flaglist->word->word);
        }
    }

    // Now list->word is the library name.
    if (!(handle = dlopen(list->word->word, flags))) {
        builtin_error("dlopen(\"%s\", %#x) failed, %s", list->word->word, flags, dlerror());
        return 1;
    }

    // Print the handle.
    if (interactive_shell) {
        printf("%p\n", handle);
    }

    snprintf(varname, sizeof varname, "DLHANDLES[\"%s\"]", basename(list->word->word));
    snprintf(value, sizeof value, "%p", handle);

    // Make the handle available programmatically.
    if (assign_array_element(varname, value, AV_USEIND) == NULL) {
        builtin_error("failed to append element to $DLHANDLES array");
        dlclose(handle);
        return 1;
    }

    return 0;
}
Пример #10
0
static int generate_native_callback(WORD_LIST *list)
{
    int nargs;
    void *callback;
    ffi_cif *cif;
    ffi_closure *closure;
    ffi_type **argtypes;
    ffi_type *rettype;
    char **proto;
    char *resultname = "DLRETVAL";
    char opt;
    reset_internal_getopt();

    // $ dlcall [-a abi] [-r type] [-n name]
    while ((opt = internal_getopt(list, "a:r:n:")) != -1) {
        switch (opt) {
            case 'n':
                resultname = list_optarg;
                break;
            default:
                builtin_usage();
                return EX_USAGE;
        }
    }

    // Skip past any options.
    if ((list = loptend) == NULL || !list->next) {
        builtin_usage();
        return EX_USAGE;
    }

    closure     = ffi_closure_alloc(sizeof(ffi_closure), &callback);
    cif         = malloc(sizeof(ffi_cif));
    argtypes    = NULL;
    proto       = malloc(sizeof(char *));
    proto[0]    = strdup(list->word->word);
    nargs       = 0;
    list        = list->next;

    // Second parameter must be the return type
    if (decode_type_prefix(list->word->word,
                           NULL,
                           &rettype,
                           NULL,
                           NULL) != true) {
        builtin_warning("couldnt parse the return type %s", list->word->word);
        return EXECUTION_FAILURE;
    }

    // Skip past return type
    list = list->next;

    while (list) {
        argtypes        = realloc(argtypes, (nargs + 1) * sizeof(ffi_type *));
        proto           = realloc(proto, (nargs + 1 + 1) * sizeof(char *));

        if (decode_type_prefix(list->word->word, NULL, &argtypes[nargs], NULL, &proto[nargs+1]) != true) {
            builtin_error("failed to decode type from parameter %s", list->word->word);
            goto error;
        }

        list = list->next;
        nargs++;
    }

    if (ffi_prep_cif(cif, FFI_DEFAULT_ABI, nargs, rettype, argtypes) == FFI_OK) {
        // Initialize the closure.
        if (ffi_prep_closure_loc(closure, cif, execute_bash_trampoline, proto, callback) == FFI_OK) {
            char retval[1024];
            snprintf(retval, sizeof retval, "pointer:%p", callback);
            fprintf(stderr, "%s\n", retval);
            bind_variable(resultname, retval, 0);
        }
    }

    //free(argtypes);
    return 0;

  error:
    //free(argtypes);
    return 1;
}