Пример #1
0
//--------------------------------------------------------------------------
// returns true-lowcnd was false, resumed the application
// nb: recursive calls to this function are not handled in any special way!
bool debmod_t::handle_lowcnd(lowcnd_t *lc, debug_event_t *event, int elc_flags)
{
  if ( (debugger_flags & DBG_FLAG_CAN_CONT_BPT) == 0 )
  {
    // difficult case: we have to reset pc, remove the bpt, single step, and resume the app
    QASSERT(616, !handling_lowcnds.has(lc->ea));
    handling_lowcnds.push_back(lc->ea);

    int code;
    if ( (elc_flags & ELC_KEEP_EIP) == 0 )
    {
      regval_t rv;
      rv._set_int(lc->ea);
      code = dbg_write_register(event->tid, pc_idx, &rv);
      if ( code <= 0 )
      {
        handling_lowcnds.del(lc->ea);
        return false;
      }
    }

    code = dbg_freeze_threads_except(event->tid);
    if ( code > 0 )
    {
      int bptlen = lc->type == BPT_SOFT ? lc->orgbytes.size() : lc->size;
      code = dbg_del_bpt(lc->type, lc->ea, lc->orgbytes.begin(), bptlen);
      if ( code > 0 )
      {
        code = dbg_perform_single_step(event, lc->cmd);
        if ( code <= 0 )
          dmsg("%a: failed to single step\n", event->ea); // may happen

        if ( dbg_add_bpt(lc->type, lc->ea, bptlen) <= 0 )
        {
          // if this fails, it may be because the breakpoint is invalid
          // at this time so we should notify IDA it isn't available
          // any more
          code = 0;
          dwarning("%a: could not restore deleted bpt\n", lc->ea); // odd
        }
      }
      if ( dbg_thaw_threads_except(event->tid) <= 0 )
      {
        dwarning("%d: could not resume suspended threads\n", event->tid); // odd
        code = 0;
      }
    }
    handling_lowcnds.del(lc->ea);
    if ( code <= 0 || event->eid != STEP )
      return false; // did not resume
  }
  if ( (elc_flags & ELC_KEEP_SUSP) != 0 )
    return true;
  return dbg_continue_after_event(event) > 0;
}
Пример #2
0
static uint64_t
_adjustPartitionSize( const char*  description,
                      uint64_t     imageBytes,
                      uint64_t     defaultBytes,
                      int          inAndroidBuild )
{
    char      temp[64];
    unsigned  imageMB;
    unsigned  defaultMB;

    if (imageBytes <= defaultBytes)
        return defaultBytes;

    imageMB   = convertBytesToMB(imageBytes);
    defaultMB = convertBytesToMB(defaultBytes);

    if (imageMB > defaultMB) {
        snprintf(temp, sizeof temp, "(%d MB > %d MB)", imageMB, defaultMB);
    } else {
        snprintf(temp, sizeof temp, "(%lld bytes > %lld bytes)", imageBytes, defaultBytes);
    }

    if (inAndroidBuild) {
        dwarning("%s partition size adjusted to match image file %s\n", description, temp);
    }

    return convertMBToBytes(imageMB);
}
Пример #3
0
void
auserConfig_save( AUserConfig*  uconfig )
{
    IniFile*   ini;
    char       temp[256];

    if (uconfig->changed == 0) {
        D("User-config was not changed.");
        return;
    }

    bufprint(temp, temp+sizeof(temp),
             "%s = %d\n"
             "%s = %d\n"
             "%s = %lld\n",
             KEY_WINDOW_X, uconfig->windowX,
             KEY_WINDOW_Y, uconfig->windowY,
             KEY_UUID,     uconfig->uuid );

    DD("Generated user-config file:\n%s", temp);

    ini = iniFile_newFromMemory(temp, uconfig->iniPath);
    if (ini == NULL) {
        D("Weird: can't create user-config iniFile?");
        return;
    }
    if (iniFile_saveToFile(ini, uconfig->iniPath) < 0) {
        dwarning("could not save user configuration: %s: %s",
                 uconfig->iniPath, strerror(errno));
    } else {
        D("User configuration saved to %s", uconfig->iniPath);
    }
    iniFile_free(ini);
}
Пример #4
0
void
android_adb_service_init(void)
{
static int _inited = 0;

    if (!adb_server_is_initialized()) {
        return;
    }

    if (!_inited) {
        /* Register main ADB service. */
        QemudService*  serv = qemud_service_register(SERVICE_NAME, 0, NULL,
                                                     _adb_service_connect,
                                                     NULL, NULL);
        if (serv == NULL) {
            derror("%s: Could not register '%s' service",
                   __FUNCTION__, SERVICE_NAME);
            return;
        }
        D("%s: Registered '%s' qemud service", __FUNCTION__, SERVICE_NAME);

        /* Register debugging ADB service. */
        serv = qemud_service_register(DEBUG_SERVICE_NAME, 0, NULL,
                                      _adb_debug_service_connect, NULL, NULL);
        if (serv != NULL) {
            DD("Registered '%s' qemud service", DEBUG_SERVICE_NAME);
        } else {
            dwarning("%s: Could not register '%s' service",
                   __FUNCTION__, DEBUG_SERVICE_NAME);
        }
    }
}
Пример #5
0
//--------------------------------------------------------------------------
// returns true-lowcnd was false, resumed the application
// nb: recursive calls to this function are not handled in any special way!
bool debmod_t::handle_lowcnd(lowcnd_t *lc, debug_event_t *event)
{
  if ( (debugger_flags & DBG_FLAG_CAN_CONT_BPT) == 0 )
  {
    // difficult case: we have to reset pc, remove the bpt, single step, and resume the app
    handling_lowcnd = true;

    regval_t rv;
    rv._set_int(lc->ea);
    int code = dbg_write_register(event->tid, pc_idx, &rv);
    if ( code <= 0 )
    {
      handling_lowcnd = false;
      return false;
    }

    code = dbg_freeze_threads_except(event->tid);
    if ( code > 0 )
    {
      code = dbg_del_bpt(lc->type, lc->ea, lc->orgbytes.begin(), lc->orgbytes.size());
      if ( code > 0 )
      {
        code = dbg_perform_single_step(event, lc->cmd);
        if ( code <= 0 )
          dmsg("%a: failed to single step\n", event->ea); // may happen

        if ( dbg_add_bpt(lc->type, lc->ea, lc->orgbytes.size()) <= 0 )
        {
          code = 0;
          dwarning("%a: could not restore deleted bpt\n", lc->cmd.ea); // odd
        }
      }
      if ( dbg_thaw_threads_except(event->tid) <= 0 )
      {
        dwarning("%d: could not resume suspended threads\n", event->tid); // odd
        code = 0;
      }
    }
    handling_lowcnd = false;
    if ( code <= 0 || event->eid != STEP )
      return false; // did not resume
  }
  return dbg_continue_after_event(event);
}
/* Prints the warning string corresponding to the error code returned by
 * boot_propery_add2().
 */
static void
boot_property_raise_warning( int ret, const char*  name, int  namelen,
                             const char*  value, int  valuelen )
{
    switch (ret) {
    case -1:
        dwarning("boot property name too long: '%.*s'",
                    namelen, name);
        break;
    case -2:
        dwarning("boot property value too long: '%.*s'",
                    valuelen, value);
        break;
    case -3:
        dwarning("boot property name contains invalid chars: %.*s",
                    namelen, name);
        break;
    }
}
//--------------------------------------------------------------------------
// return the address of all names exported by a DLL in 'ni'
// if 'exported_name' is given, only the address of this exported name will be returned in 'ni'
bool win32_debmod_t::get_dll_exports(
  const images_t &dlls,
  ea_t imagebase,
  name_info_t &ni,
  const char *exported_name)
{
  char prefix[MAXSTR];
  images_t::const_iterator p = dlls.find(imagebase);
  if ( p == dlls.end() )
  {
    dwarning("get_dll_exports: can't find dll name for imagebase %a", imagebase);
    return false;
  }
  const char *dllname = p->second.name.c_str();

  linput_t *li = open_linput(dllname, false);
  if ( li == NULL )
  {
    // sysWOW64: ntdll32.dll does not exist but there is a file called ntdll.dll
    if ( stricmp(qbasename(dllname), "ntdll32.dll") != 0 )
      return false;
    qstrncpy(prefix, dllname, sizeof(prefix));
    char *fname = qbasename(prefix);
    qstrncpy(fname, "ntdll.dll", sizeof(prefix)-(fname-prefix));
    dllname = prefix;
    li = open_linput(dllname, false);
    if ( li == NULL )
      return false;
  }

  // prepare nice name prefix for exported functions names
  qstrncpy(prefix, qbasename(dllname), sizeof(prefix));
  char *ptr = strrchr(prefix, '.');
  if ( ptr != NULL )
    *ptr = '\0';
  qstrlwr(prefix);

  bool ok = get_dll_exports_from_file(prefix, li, imagebase, ni, exported_name);
  close_linput(li);
  return ok;
}
Пример #8
0
char*  avdInfo_getSdCardPath( AvdInfo* i )
{
    const char* imageName = _imageFileNames[ AVD_IMAGE_SDCARD ];
    char*       path;

    /* Special case, the config.ini can have a SDCARD_PATH entry
     * that gives the full path to the SD Card.
     */
    if (i->configIni != NULL) {
        path = iniFile_getString(i->configIni, SDCARD_PATH, NULL);
        if (path != NULL) {
            if (path_exists(path))
                return path;

            dwarning("Ignoring invalid SDCard path: %s", path);
            AFREE(path);
        }
    }

    /* Otherwise, simply look into the content directory */
    return _avdInfo_getContentFilePath(i, imageName);
}
void
boot_property_parse_option( const char*  param )
{
    char* q = strchr(param,'=');
    const char* name;
    const char* value;
    int   namelen, valuelen, ret;

    if (q == NULL) {
        dwarning("boot property missing (=) separator: %s", param);
        return;
    }

    name    = param;
    namelen = q - param;

    value    = q+1;
    valuelen = strlen(name) - (namelen+1);

    ret = boot_property_add2(name, namelen, value, valuelen);
    if (ret < 0) {
        boot_property_raise_warning(ret, name, namelen, value, valuelen);
    }
}
Пример #10
0
void
parse_nand_limits(char*  limits)
{
    int      pid = -1, signal = -1;
    int64_t  reads = 0, writes = 0;
    char*    item = limits;

    /* parse over comma-separated items */
    while (item && *item) {
        char*  next = strchr(item, ',');
        char*  end;

        if (next == NULL) {
            next = item + strlen(item);
        } else {
            *next++ = 0;
        }

        if ( !memcmp(item, "pid=", 4) ) {
            pid = strtol(item+4, &end, 10);
            if (end == NULL || *end) {
                derror( "bad parameter, expecting pid=<number>, got '%s'",
                        item );
                exit(1);
            }
            if (pid <= 0) {
                derror( "bad parameter: process identifier must be > 0" );
                exit(1);
            }
        }
        else if ( !memcmp(item, "signal=", 7) ) {
            signal = strtol(item+7,&end, 10);
            if (end == NULL || *end) {
                derror( "bad parameter: expecting signal=<number>, got '%s'",
                        item );
                exit(1);
            }
            if (signal <= 0) {
                derror( "bad parameter: signal number must be > 0" );
                exit(1);
            }
        }
        else if ( !memcmp(item, "reads=", 6) ) {
            reads = parse_nand_rw_limit(item+6);
        }
        else if ( !memcmp(item, "writes=", 7) ) {
            writes = parse_nand_rw_limit(item+7);
        }
        else {
            derror( "bad parameter '%s' (see -help-nand-limits)", item );
            exit(1);
        }
        item = next;
    }
    if (pid < 0) {
        derror( "bad paramater: missing pid=<number>" );
        exit(1);
    }
    else if (signal < 0) {
        derror( "bad parameter: missing signal=<number>" );
        exit(1);
    }
    else if (reads == 0 && writes == 0) {
        dwarning( "no read or write limit specified. ignoring -nand-limits" );
    } else {
        nand_threshold*  t;

        t  = &android_nand_read_threshold;
        t->pid     = pid;
        t->signal  = signal;
        t->counter = 0;
        t->limit   = reads;

        t  = &android_nand_write_threshold;
        t->pid     = pid;
        t->signal  = signal;
        t->counter = 0;
        t->limit   = writes;
    }
}
Пример #11
0
/* Create a new AUserConfig object from a given AvdInfo */
AUserConfig*
auserConfig_new( AvdInfo*  info )
{
    AUserConfig*  uc;
    char          inAndroidBuild = avdInfo_inAndroidBuild(info);
    char          needUUID = 1;
    char          temp[PATH_MAX], *p=temp, *end=p+sizeof(temp);
    char*         parentPath;
    IniFile*      ini = NULL;

    ANEW0(uc);

    /* If we are in the Android build system, store the configuration
     * in ~/.android/emulator-user.ini. otherwise, store it in the file
     * emulator-user.ini in the AVD's content directory.
     */
    if (inAndroidBuild) {
        p = bufprint_config_file(temp, end, USER_CONFIG_FILE);
    } else {
        p = bufprint(temp, end, "%s/%s", avdInfo_getContentPath(info), 
                     USER_CONFIG_FILE);
    }

    /* handle the unexpected */
    if (p >= end) {
        /* Hmmm, something is weird, let's use a temporary file instead */
        p = bufprint_temp_file(temp, end, USER_CONFIG_FILE);
        if (p >= end) {
            derror("Weird: Cannot create temporary user-config file?");
            exit(2);
        }
        dwarning("Weird: Content path too long, using temporary user-config.");
    }

    uc->iniPath = ASTRDUP(temp);
    DD("looking user-config in: %s", uc->iniPath);


    /* ensure that the parent directory exists */
    parentPath = path_parent(uc->iniPath, 1);
    if (parentPath == NULL) {
        derror("Weird: Can't find parent of user-config file: %s",
               uc->iniPath);
        exit(2);
    }

    if (!path_exists(parentPath)) {
        if (!inAndroidBuild) {
            derror("Weird: No content path for this AVD: %s", parentPath);
            exit(2);
        }
        DD("creating missing directory: %s", parentPath);
        if (path_mkdir_if_needed(parentPath, 0755) < 0) {
            derror("Using empty user-config, can't create %s: %s",
                   parentPath, strerror(errno));
            exit(2);
        }
    }

    if (path_exists(uc->iniPath)) {
        DD("reading user-config file");
        ini = iniFile_newFromFile(uc->iniPath);
        if (ini == NULL) {
            dwarning("Can't read user-config file: %s\nUsing default values",
                     uc->iniPath);
        }
    }

    if (ini != NULL) {
        uc->windowX = iniFile_getInteger(ini, KEY_WINDOW_X, DEFAULT_X);
        DD("    found %s = %d", KEY_WINDOW_X, uc->windowX);

        uc->windowY = iniFile_getInteger(ini, KEY_WINDOW_Y, DEFAULT_Y);
        DD("    found %s = %d", KEY_WINDOW_Y, uc->windowY);

        if (iniFile_getValue(ini, KEY_UUID) != NULL) {
            uc->uuid = (uint64_t) iniFile_getInt64(ini, KEY_UUID, 0LL);
            needUUID = 0;
            DD("    found %s = %lld", KEY_UUID, uc->uuid);
        }

        iniFile_free(ini);
    }
    else {
        uc->windowX = DEFAULT_X;
        uc->windowY = DEFAULT_Y;
        uc->changed = 1;
    }

    /* Generate a 64-bit UUID if necessary. We simply take the
     * current time, which avoids any privacy-related value.
     */
    if (needUUID) {
        struct timeval  tm;

        gettimeofday( &tm, NULL );
        uc->uuid    = (uint64_t)tm.tv_sec*1000 + tm.tv_usec/1000;
        uc->changed = 1;
        DD("    Generated UUID = %lld", uc->uuid);
    }

    return uc;
}
//--------------------------------------------------------------------------
// Read/write a model specific register using the driver provided by WinDbg.
// The following requirements are imposed by this code:
//      - debugger module should be run with admin privileges
//      - System must be loaded with /debug switch (use bcdedit.exe to turn it on)
//      - Windbg local kernel debugging should be used at least once
// This code is based on a sample kindly provided by Alex Ionescu.
int win32_debmod_t::kldbgdrv_access_msr(SYSDBG_MSR *msr, bool write)
{
  NTSTATUS code;
  IO_STATUS_BLOCK IoStatusBlock;
  if ( DriverHandle == NULL )
  {
    //
    // Acquire 'load driver' privilege
    //
    BOOLEAN Old;
    code = RtlAdjustPrivilege(SE_LOAD_DRIVER_PRIVILEGE, TRUE, FALSE, &Old);
    if ( FAILED(code) )
    {
      dwarning("AUTOHIDE NONE\n"
               "Failed to acquire 'load driver' privilege, please run as admin!\n"
               "Error: %s\n", winerr(code));
      return code;
    }

    //
    // And need this for the driver to accept our commands
    // Additionally, system must be booted in /DEBUG mode
    //
    code = RtlAdjustPrivilege(SE_DEBUG_PRIVILEGE, TRUE, FALSE, &Old);
    if ( FAILED(code) )
    {
      dwarning("AUTOHIDE NONE\n"
               "Failed to acquire 'debug' privilege, is system booted in /debug mode?\n"
               "Error: %s\n", winerr(code));
      return code;
    }

    //
    // Now load the driver
    //
    code = NtLoadDriver(&DriverPath);
    if ( FAILED(code) && code != STATUS_IMAGE_ALREADY_LOADED )
    {
      dwarning("AUTOHIDE NONE\n"
               "Failed to load 'kldbgdrv', please use local kernel debugging at least once!\n"
               "Error: %s\n", winerr(code));
      return code;
    }

    //
    // Open a handle to it
    //
    OBJECT_ATTRIBUTES ObjectAttributes;
    InitializeObjectAttributes(&ObjectAttributes, &DriverName, OBJ_CASE_INSENSITIVE, NULL, NULL);
    code = NtCreateFile(&DriverHandle,
                        GENERIC_READ | GENERIC_WRITE,
                        &ObjectAttributes,
                        &IoStatusBlock,
                        NULL,
                        FILE_ATTRIBUTE_NORMAL,
                        0,
                        FILE_CREATE,
                        FILE_NON_DIRECTORY_FILE,
                        NULL,
                        0);
    if ( FAILED(code) )
    {
      dwarning("AUTOHIDE NONE\n"
               "Failed to open 'kldbgdrv'\n"
               "Error: %s\n", winerr(code));
      return code;
    }
  }

  //
  // Package the input parameters into the private structure
  //
  KLDD_DATA_DEBUG_CONTROL KldDebugCommand;
  KldDebugCommand.Command = write ? SysDbgWriteMsr : SysDbgReadMsr;
  KldDebugCommand.InputBuffer = msr;
  KldDebugCommand.InputBufferLength = sizeof(*msr);

  //
  // Send the request -- output isn't packaged, just specify directly the buffer
  //
  code = NtDeviceIoControlFile(DriverHandle,
                               NULL,
                               NULL,
                               NULL,
                               &IoStatusBlock,
                               KLDD_CODE_DEBUG_CONTROL,
                               &KldDebugCommand,
                               sizeof(KldDebugCommand),
                               msr,
                               sizeof(*msr));
  if ( FAILED(code) )
  {
    dwarning("AUTOHIDE NONE\n"
             "Failed to access model specific register, is system booted in /debug mode?\n"
             "Error: %s\n", winerr(code));
    return code;
  }

  // all ok!
  return code;
}
//--------------------------------------------------------------------------
bool win32_debmod_t::create_process(
    const char *path,
    const char *args,
    const char *startdir,
    bool is_gui,
    PROCESS_INFORMATION *ProcessInformation)
{
#ifndef __X64__
  linput_t *li = open_linput(path, false);
  if ( li == NULL )
    return false;

  pe_loader_t pl;
  pl.read_header(li, true);
  close_linput(li);
  if ( pl.pe.is_pe_plus() )
  {
    static const char server_name[] = "win64_remotex64.exe";
#ifdef __EA64__
    if ( askyn_c(1, "AUTOHIDE REGISTRY\nHIDECANCEL\nDebugging 64-bit applications is only possible with the %s server. Launch it now?", server_name) == 1 ) do
    {
      // Switch to the remote win32 debugger
      if ( !load_debugger("win32_stub", true))
      {
        warning("Failed to switch to the remote windows debugger!");
        break;
      }

      // Form the server path
      char server_exe[QMAXPATH];
      qmakepath(server_exe, sizeof(server_exe), idadir(NULL), server_name, NULL);

      // Try to launch the server
      STARTUPINFO si = {sizeof(si)};
      PROCESS_INFORMATION pi;
      if ( !::CreateProcess(server_exe, NULL, NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi) )
      {
        warning("Failed to run the 64-bit remote server!");
        break;
      }

      // Set the remote debugging options: localhost
      set_remote_debugger("localhost", "", -1);

      // Notify the user
      info("Debugging server has been started, please try debugging the program again.");
    } while ( false );
#else
    dwarning("AUTOHIDE NONE\n"
      "Please use %s remote server to debug 64-bit applications", server_name);
#endif // __EA64__
    SetLastError(ERROR_NOT_SUPPORTED);
    return false;
  }
#endif // __X64__

  // Empty directory means our directory
  if ( startdir != NULL && startdir[0] == '\0' )
    startdir = NULL;

  // Args passed as empty string?
  if ( args != NULL && args[0] == '\0' )
    args = NULL;

  launch_process_params_t lpp;
  lpp.flags |= LP_TRACE | LP_PATH_WITH_ARGS;
  if ( !is_gui )
    lpp.flags |= LP_NEW_CONSOLE;
  lpp.path = path;
  lpp.args = args;
  lpp.startdir = startdir;
  lpp.info = ProcessInformation;

  qstring errbuf;
  if ( launch_process(lpp, &errbuf) == NULL )
  {
    dwarning("AUTOHIDE NONE\n%s", errbuf.c_str());
    return false;
  }
  return true;
}
Пример #14
0
int crypto_run(struct fcrypt *fcr, struct kernel_crypt_op *kcop)
{
	struct csession *ses_ptr;
	struct crypt_op *cop = &kcop->cop;
	int ret;

	if (unlikely(cop->op != COP_ENCRYPT && cop->op != COP_DECRYPT)) {
		ddebug(1, "invalid operation op=%u", cop->op);
		return -EINVAL;
	}

	/* this also enters ses_ptr->sem */
	ses_ptr = crypto_get_session_by_sid(fcr, cop->ses);
	if (unlikely(!ses_ptr)) {
		derr(1, "invalid session ID=0x%08X", cop->ses);
		return -EINVAL;
	}

	if (ses_ptr->hdata.init != 0 && (cop->flags == 0 || cop->flags & COP_FLAG_RESET)) {
		ret = cryptodev_hash_reset(&ses_ptr->hdata);
		if (unlikely(ret)) {
			derr(1, "error in cryptodev_hash_reset()");
			goto out_unlock;
		}
	}

	if (ses_ptr->cdata.init != 0) {
		int blocksize = ses_ptr->cdata.blocksize;

		if (unlikely(cop->len % blocksize)) {
			derr(1, "data size (%u) isn't a multiple of block size (%u)",
				cop->len, blocksize);
			ret = -EINVAL;
			goto out_unlock;
		}

		cryptodev_cipher_set_iv(&ses_ptr->cdata, kcop->iv,
				min(ses_ptr->cdata.ivsize, kcop->ivlen));
	}

	if (likely(cop->len)) {
		if (cop->flags & COP_FLAG_NO_ZC) {
			if (unlikely(ses_ptr->alignmask && !IS_ALIGNED((unsigned long)cop->src, ses_ptr->alignmask))) {
				dwarning(2, "source address %p is not %d byte aligned - disabling zero copy",
						cop->src, ses_ptr->alignmask + 1);
				cop->flags &= ~COP_FLAG_NO_ZC;
			}

			if (unlikely(ses_ptr->alignmask && !IS_ALIGNED((unsigned long)cop->dst, ses_ptr->alignmask))) {
				dwarning(2, "destination address %p is not %d byte aligned - disabling zero copy",
						cop->dst, ses_ptr->alignmask + 1);
				cop->flags &= ~COP_FLAG_NO_ZC;
			}
		}

		if (cop->flags & COP_FLAG_NO_ZC)
			ret = __crypto_run_std(ses_ptr, &kcop->cop);
		else
			ret = __crypto_run_zc(ses_ptr, kcop);
		if (unlikely(ret))
			goto out_unlock;
	}

	if (ses_ptr->cdata.init != 0) {
		cryptodev_cipher_get_iv(&ses_ptr->cdata, kcop->iv,
				min(ses_ptr->cdata.ivsize, kcop->ivlen));
	}

	if (ses_ptr->hdata.init != 0 &&
		((cop->flags & COP_FLAG_FINAL) ||
		   (!(cop->flags & COP_FLAG_UPDATE) || cop->len == 0))) {

		ret = cryptodev_hash_final(&ses_ptr->hdata, kcop->hash_output);
		if (unlikely(ret)) {
			derr(0, "CryptoAPI failure: %d", ret);
			goto out_unlock;
		}
		kcop->digestsize = ses_ptr->hdata.digestsize;
	}

	if (ses_ptr->rdata.init != 0 && cop->len > 0) {
		kcop->rng_output = kmalloc(cop->len, GFP_KERNEL);
		if (unlikely(!kcop->rng_output)) {
			derr(0, "Not enough space to store %d random bytes.", cop->len);
			ret = -ENOMEM;
			goto out_unlock;
		}

		ret = cryptodev_rng_get_bytes(&ses_ptr->rdata, kcop->rng_output, cop->len);
		// some RNGs return 0 for success, while
		// some return the number of bytes generated
		if (unlikely(ret != 0 && ret != cop->len)) {
			derr(0, "RNG failure: %d", ret);
			kfree(kcop->rng_output); kcop->rng_output = NULL;
			goto out_unlock;
		}

		ret = 0;
		kcop->rnglen = cop->len;
	}

out_unlock:
	crypto_put_session(ses_ptr);
	return ret;
}