/* Check that the current application belongs to the * requested GID */ static bool SCXLNXConnCheckGID(gid_t nRequestedGID) { if (nRequestedGID == current_egid()) { return true; } else { u32 nSize; u32 i; /* Look in the supplementary GIDs */ get_group_info(GROUP_INFO); nSize = GROUP_INFO->ngroups; for (i = 0; i < nSize; i++) if (nRequestedGID == GROUP_AT(GROUP_INFO , i)) return true; } return false; }
/* Check that the current application belongs to the * requested GID */ static bool tf_check_gid(gid_t requested_gid) { if (requested_gid == current_egid()) { return true; } else { u32 size; u32 i; /* Look in the supplementary GIDs */ get_group_info(GROUP_INFO); size = GROUP_INFO->ngroups; for (i = 0; i < size; i++) if (requested_gid == GROUP_AT(GROUP_INFO , i)) return true; } return false; }
static long dek_ioctl_kek(struct file *file, unsigned int cmd, unsigned long arg) { unsigned int minor; if(!is_container_app() && !is_root()) { DEK_LOGE("Current process can't access kek device\n"); DEK_LOGE("Current process info :: " "uid=%u gid=%u euid=%u egid=%u suid=%u sgid=%u " "fsuid=%u fsgid=%u\n", current_uid(), current_gid(), current_euid(), current_egid(), current_suid(), current_sgid(), current_fsuid(), current_fsgid()); dek_add_to_log(000, "Access denied to kek device"); return -EACCES; } minor = iminor(file->f_path.dentry->d_inode); return dek_do_ioctl_kek(minor, cmd, arg); }
/** * tomoyo_print_header - Get header line of audit log. * * @r: Pointer to "struct tomoyo_request_info". * * Returns string representation. * * This function uses kmalloc(), so caller must kfree() if this function * didn't return NULL. */ static char *tomoyo_print_header(struct tomoyo_request_info *r) { struct tomoyo_time stamp; const pid_t gpid = task_pid_nr(current); struct tomoyo_obj_info *obj = r->obj; static const int tomoyo_buffer_len = 4096; char *buffer = kmalloc(tomoyo_buffer_len, GFP_NOFS); int pos; u8 i; if (!buffer) return NULL; { struct timeval tv; do_gettimeofday(&tv); tomoyo_convert_time(tv.tv_sec, &stamp); } pos = snprintf(buffer, tomoyo_buffer_len - 1, "#%04u/%02u/%02u %02u:%02u:%02u# profile=%u mode=%s " "granted=%s (global-pid=%u) task={ pid=%u ppid=%u " "uid=%u gid=%u euid=%u egid=%u suid=%u sgid=%u " "fsuid=%u fsgid=%u }", stamp.year, stamp.month, stamp.day, stamp.hour, stamp.min, stamp.sec, r->profile, tomoyo_mode[r->mode], tomoyo_yesno(r->granted), gpid, tomoyo_sys_getpid(), tomoyo_sys_getppid(), current_uid(), current_gid(), current_euid(), current_egid(), current_suid(), current_sgid(), current_fsuid(), current_fsgid()); if (!obj) goto no_obj_info; if (!obj->validate_done) { tomoyo_get_attributes(obj); obj->validate_done = true; } for (i = 0; i < TOMOYO_MAX_PATH_STAT; i++) { struct tomoyo_mini_stat *stat; unsigned int dev; umode_t mode; if (!obj->stat_valid[i]) continue; stat = &obj->stat[i]; dev = stat->dev; mode = stat->mode; if (i & 1) { pos += snprintf(buffer + pos, tomoyo_buffer_len - 1 - pos, " path%u.parent={ uid=%u gid=%u " "ino=%lu perm=0%o }", (i >> 1) + 1, stat->uid, stat->gid, (unsigned long) stat->ino, stat->mode & S_IALLUGO); continue; } pos += snprintf(buffer + pos, tomoyo_buffer_len - 1 - pos, " path%u={ uid=%u gid=%u ino=%lu major=%u" " minor=%u perm=0%o type=%s", (i >> 1) + 1, stat->uid, stat->gid, (unsigned long) stat->ino, MAJOR(dev), MINOR(dev), mode & S_IALLUGO, tomoyo_filetype(mode)); if (S_ISCHR(mode) || S_ISBLK(mode)) { dev = stat->rdev; pos += snprintf(buffer + pos, tomoyo_buffer_len - 1 - pos, " dev_major=%u dev_minor=%u", MAJOR(dev), MINOR(dev)); } pos += snprintf(buffer + pos, tomoyo_buffer_len - 1 - pos, " }"); }
/* * Opens a client session to the Secure World */ int SCXLNXConnOpenClientSession( struct SCXLNX_CONNECTION *pConn, union SCX_COMMAND_MESSAGE *pMessage, union SCX_ANSWER_MESSAGE *pAnswer) { int nError = 0; struct SCXLNX_SHMEM_DESC *pShmemDesc[4] = {NULL}; u32 i; dprintk(KERN_INFO "SCXLNXConnOpenClientSession(%p)\n", pConn); /* * Initialize the message size with no login data. This will be later * adjusted the the cases below */ pMessage->sOpenClientSessionMessage.nMessageSize = (sizeof(struct SCX_COMMAND_OPEN_CLIENT_SESSION) - 20 - sizeof(struct SCX_COMMAND_HEADER))/4; switch (pMessage->sOpenClientSessionMessage.nLoginType) { case SCX_LOGIN_PUBLIC: /* Nothing to do */ break; case SCX_LOGIN_USER: /* * Send the EUID of the calling application in the login data. * Update message size. */ *(u32 *) &pMessage->sOpenClientSessionMessage.sLoginData = current_euid(); #ifndef CONFIG_ANDROID pMessage->sOpenClientSessionMessage.nLoginType = (u32) SCX_LOGIN_USER_LINUX_EUID; #else pMessage->sOpenClientSessionMessage.nLoginType = (u32) SCX_LOGIN_USER_ANDROID_EUID; #endif /* Added one word */ pMessage->sOpenClientSessionMessage.nMessageSize += 1; break; case SCX_LOGIN_GROUP: { /* Check requested GID */ gid_t nRequestedGID = *(u32 *) pMessage->sOpenClientSessionMessage.sLoginData; if (!SCXLNXConnCheckGID(nRequestedGID)) { dprintk(KERN_ERR "SCXLNXConnOpenClientSession(%p) " "SCX_LOGIN_GROUP: requested GID (0x%x) does " "not match real eGID (0x%x)" "or any of the supplementary GIDs\n", pConn, nRequestedGID, current_egid()); nError = -EACCES; goto error; } #ifndef CONFIG_ANDROID pMessage->sOpenClientSessionMessage.nLoginType = SCX_LOGIN_GROUP_LINUX_GID; #else pMessage->sOpenClientSessionMessage.nLoginType = SCX_LOGIN_GROUP_ANDROID_GID; #endif pMessage->sOpenClientSessionMessage.nMessageSize += 1; /* GID */ break; } #ifndef CONFIG_ANDROID case SCX_LOGIN_APPLICATION: { /* * Compute SHA-1 hash of the application fully-qualified path * name. Truncate the hash to 16 bytes and send it as login * data. Update message size. */ u8 pSHA1Hash[SHA1_DIGEST_SIZE]; nError = SCXLNXConnHashApplicationPathAndData(pSHA1Hash, NULL, 0); if (nError != 0) { dprintk(KERN_ERR "SCXLNXConnOpenClientSession: " "error in SCXLNXConnHashApplicationPath" "AndData\n"); goto error; } memcpy(&pMessage->sOpenClientSessionMessage.sLoginData, pSHA1Hash, 16); pMessage->sOpenClientSessionMessage.nLoginType = SCX_LOGIN_APPLICATION_LINUX_PATH_SHA1_HASH; /* 16 bytes */ pMessage->sOpenClientSessionMessage.nMessageSize += 4; break; } #else case SCX_LOGIN_APPLICATION: /* * Send the real UID of the calling application in the login * data. Update message size. */ *(u32 *) &pMessage->sOpenClientSessionMessage.sLoginData = current_uid(); pMessage->sOpenClientSessionMessage.nLoginType = (u32) SCX_LOGIN_APPLICATION_ANDROID_UID; /* Added one word */ pMessage->sOpenClientSessionMessage.nMessageSize += 1; break; #endif #ifndef CONFIG_ANDROID case SCX_LOGIN_APPLICATION_USER: { /* * Compute SHA-1 hash of the concatenation of the application * fully-qualified path name and the EUID of the calling * application. Truncate the hash to 16 bytes and send it as * login data. Update message size. */ u8 pSHA1Hash[SHA1_DIGEST_SIZE]; nError = SCXLNXConnHashApplicationPathAndData(pSHA1Hash, (u8 *) &(current_euid()), sizeof(current_euid())); if (nError != 0) { dprintk(KERN_ERR "SCXLNXConnOpenClientSession: " "error in SCXLNXConnHashApplicationPath" "AndData\n"); goto error; } memcpy(&pMessage->sOpenClientSessionMessage.sLoginData, pSHA1Hash, 16); pMessage->sOpenClientSessionMessage.nLoginType = SCX_LOGIN_APPLICATION_USER_LINUX_PATH_EUID_SHA1_HASH; /* 16 bytes */ pMessage->sOpenClientSessionMessage.nMessageSize += 4; break; } #else case SCX_LOGIN_APPLICATION_USER: /* * Send the real UID and the EUID of the calling application in * the login data. Update message size. */ *(u32 *) &pMessage->sOpenClientSessionMessage.sLoginData = current_uid(); *(u32 *) &pMessage->sOpenClientSessionMessage.sLoginData[4] = current_euid(); pMessage->sOpenClientSessionMessage.nLoginType = SCX_LOGIN_APPLICATION_USER_ANDROID_UID_EUID; /* Added two words */ pMessage->sOpenClientSessionMessage.nMessageSize += 2; break; #endif #ifndef CONFIG_ANDROID case SCX_LOGIN_APPLICATION_GROUP: { /* * Check requested GID. Compute SHA-1 hash of the concatenation * of the application fully-qualified path name and the * requested GID. Update message size */ gid_t nRequestedGID; u8 pSHA1Hash[SHA1_DIGEST_SIZE]; nRequestedGID = *(u32 *) &pMessage->sOpenClientSessionMessage. sLoginData; if (!SCXLNXConnCheckGID(nRequestedGID)) { dprintk(KERN_ERR "SCXLNXConnOpenClientSession(%p) " "SCX_LOGIN_APPLICATION_GROUP: requested GID (0x%x) " "does not match real eGID (0x%x)" "or any of the supplementary GIDs\n", pConn, nRequestedGID, current_egid()); nError = -EACCES; goto error; } nError = SCXLNXConnHashApplicationPathAndData(pSHA1Hash, &nRequestedGID, sizeof(u32)); if (nError != 0) { dprintk(KERN_ERR "SCXLNXConnOpenClientSession: " "error in SCXLNXConnHashApplicationPath" "AndData\n"); goto error; } memcpy(&pMessage->sOpenClientSessionMessage.sLoginData, pSHA1Hash, 16); pMessage->sOpenClientSessionMessage.nLoginType = SCX_LOGIN_APPLICATION_GROUP_LINUX_PATH_GID_SHA1_HASH; /* 16 bytes */ pMessage->sOpenClientSessionMessage.nMessageSize += 4; break; } #else case SCX_LOGIN_APPLICATION_GROUP: { /* * Check requested GID. Send the real UID and the requested GID * in the login data. Update message size. */ gid_t nRequestedGID; nRequestedGID = *(u32 *) &pMessage->sOpenClientSessionMessage. sLoginData; if (!SCXLNXConnCheckGID(nRequestedGID)) { dprintk(KERN_ERR "SCXLNXConnOpenClientSession(%p) " "SCX_LOGIN_APPLICATION_GROUP: requested GID (0x%x) " "does not match real eGID (0x%x)" "or any of the supplementary GIDs\n", pConn, nRequestedGID, current_egid()); nError = -EACCES; goto error; } *(u32 *) &pMessage->sOpenClientSessionMessage.sLoginData = current_uid(); *(u32 *) &pMessage->sOpenClientSessionMessage.sLoginData[4] = nRequestedGID; pMessage->sOpenClientSessionMessage.nLoginType = SCX_LOGIN_APPLICATION_GROUP_ANDROID_UID_GID; /* Added two words */ pMessage->sOpenClientSessionMessage.nMessageSize += 2; break; } #endif case SCX_LOGIN_PRIVILEGED: /* * Check that calling application either hash EUID=0 or has * EGID=0 */ if (current_euid() != 0 && current_egid() != 0) { dprintk(KERN_ERR "SCXLNXConnOpenClientSession: " " user %d, group %d not allowed to open " "session with SCX_LOGIN_PRIVILEGED\n", current_euid(), current_egid()); nError = -EACCES; goto error; } pMessage->sOpenClientSessionMessage.nLoginType = SCX_LOGIN_PRIVILEGED; break; case SCX_LOGIN_AUTHENTICATION: { /* * Compute SHA-1 hash of the application binary * Send this hash as the login data (20 bytes) */ u8 *pHash; pHash = &(pMessage->sOpenClientSessionMessage.sLoginData[0]); nError = SCXLNXConnGetCurrentProcessHash(pHash); if (nError != 0) { dprintk(KERN_ERR "SCXLNXConnOpenClientSession: " "error in SCXLNXConnGetCurrentProcessHash\n"); goto error; } pMessage->sOpenClientSessionMessage.nLoginType = SCX_LOGIN_AUTHENTICATION_BINARY_SHA1_HASH; /* 20 bytes */ pMessage->sOpenClientSessionMessage.nMessageSize += 5; break; } default: dprintk(KERN_ERR "SCXLNXConnOpenClientSession: " "unknown nLoginType(%08X)\n", pMessage->sOpenClientSessionMessage.nLoginType); nError = -EOPNOTSUPP; goto error; } /* Map the temporary memory references */ for (i = 0; i < 4; i++) { int nParamType; nParamType = SCX_GET_PARAM_TYPE( pMessage->sOpenClientSessionMessage.nParamTypes, i); if ((nParamType & (SCX_PARAM_TYPE_MEMREF_FLAG | SCX_PARAM_TYPE_REGISTERED_MEMREF_FLAG)) == SCX_PARAM_TYPE_MEMREF_FLAG) { /* Map temp mem ref */ nError = SCXLNXConnMapTempShMem(pConn, &pMessage->sOpenClientSessionMessage. sParams[i].sTempMemref, nParamType, &pShmemDesc[i]); if (nError != 0) { dprintk(KERN_ERR "SCXLNXConnOpenClientSession: " "unable to map temporary memory block " "(%08X)\n", nError); goto error; } } } /* Fill the handle of the Device Context */ pMessage->sOpenClientSessionMessage.hDeviceContext = pConn->hDeviceContext; nError = SCXLNXCommSendReceive( &pConn->pDevice->sm, pMessage, pAnswer, pConn, true); error: /* Unmap the temporary memory references */ for (i = 0; i < 4; i++) if (pShmemDesc[i] != NULL) SCXLNXConnUnmapShmem(pConn, pShmemDesc[i], 0); if (nError != 0) dprintk(KERN_ERR "SCXLNXConnOpenClientSession returns %d\n", nError); else dprintk(KERN_ERR "SCXLNXConnOpenClientSession returns " "nErrorCode 0x%08X\n", pAnswer->sOpenClientSessionAnswer.nErrorCode); return nError; }
/* * Opens a client session to the Secure World */ int tf_open_client_session( struct tf_connection *connection, union tf_command *command, union tf_answer *answer) { int error = 0; struct tf_shmem_desc *shmem_desc[4] = {NULL}; u32 i; dprintk(KERN_INFO "tf_open_client_session(%p)\n", connection); /* * Initialize the message size with no login data. This will be later * adjusted the the cases below */ command->open_client_session.message_size = (sizeof(struct tf_command_open_client_session) - 20 - sizeof(struct tf_command_header))/4; switch (command->open_client_session.login_type) { case TF_LOGIN_PUBLIC: /* Nothing to do */ break; case TF_LOGIN_USER: /* * Send the EUID of the calling application in the login data. * Update message size. */ *(u32 *) &command->open_client_session.login_data = current_euid(); #ifndef CONFIG_ANDROID command->open_client_session.login_type = (u32) TF_LOGIN_USER_LINUX_EUID; #else command->open_client_session.login_type = (u32) TF_LOGIN_USER_ANDROID_EUID; #endif /* Added one word */ command->open_client_session.message_size += 1; break; case TF_LOGIN_GROUP: { /* Check requested GID */ gid_t requested_gid = *(u32 *) command->open_client_session.login_data; if (!tf_check_gid(requested_gid)) { dprintk(KERN_ERR "tf_open_client_session(%p) " "TF_LOGIN_GROUP: requested GID (0x%x) does " "not match real eGID (0x%x)" "or any of the supplementary GIDs\n", connection, requested_gid, current_egid()); error = -EACCES; goto error; } #ifndef CONFIG_ANDROID command->open_client_session.login_type = TF_LOGIN_GROUP_LINUX_GID; #else command->open_client_session.login_type = TF_LOGIN_GROUP_ANDROID_GID; #endif command->open_client_session.message_size += 1; /* GID */ break; } #ifndef CONFIG_ANDROID case TF_LOGIN_APPLICATION: { /* * Compute SHA-1 hash of the application fully-qualified path * name. Truncate the hash to 16 bytes and send it as login * data. Update message size. */ u8 pSHA1Hash[SHA1_DIGEST_SIZE]; error = tf_hash_application_path_and_data(pSHA1Hash, NULL, 0); if (error != 0) { dprintk(KERN_ERR "tf_open_client_session: " "error in tf_hash_application_path_and_data\n"); goto error; } memcpy(&command->open_client_session.login_data, pSHA1Hash, 16); command->open_client_session.login_type = TF_LOGIN_APPLICATION_LINUX_PATH_SHA1_HASH; /* 16 bytes */ command->open_client_session.message_size += 4; break; } #else case TF_LOGIN_APPLICATION: /* * Send the real UID of the calling application in the login * data. Update message size. */ *(u32 *) &command->open_client_session.login_data = current_uid(); command->open_client_session.login_type = (u32) TF_LOGIN_APPLICATION_ANDROID_UID; /* Added one word */ command->open_client_session.message_size += 1; break; #endif #ifndef CONFIG_ANDROID case TF_LOGIN_APPLICATION_USER: { /* * Compute SHA-1 hash of the concatenation of the application * fully-qualified path name and the EUID of the calling * application. Truncate the hash to 16 bytes and send it as * login data. Update message size. */ u8 pSHA1Hash[SHA1_DIGEST_SIZE]; error = tf_hash_application_path_and_data(pSHA1Hash, (u8 *) &(current_euid()), sizeof(current_euid())); if (error != 0) { dprintk(KERN_ERR "tf_open_client_session: " "error in tf_hash_application_path_and_data\n"); goto error; } memcpy(&command->open_client_session.login_data, pSHA1Hash, 16); command->open_client_session.login_type = TF_LOGIN_APPLICATION_USER_LINUX_PATH_EUID_SHA1_HASH; /* 16 bytes */ command->open_client_session.message_size += 4; break; } #else case TF_LOGIN_APPLICATION_USER: /* * Send the real UID and the EUID of the calling application in * the login data. Update message size. */ *(u32 *) &command->open_client_session.login_data = current_uid(); *(u32 *) &command->open_client_session.login_data[4] = current_euid(); command->open_client_session.login_type = TF_LOGIN_APPLICATION_USER_ANDROID_UID_EUID; /* Added two words */ command->open_client_session.message_size += 2; break; #endif #ifndef CONFIG_ANDROID case TF_LOGIN_APPLICATION_GROUP: { /* * Check requested GID. Compute SHA-1 hash of the concatenation * of the application fully-qualified path name and the * requested GID. Update message size */ gid_t requested_gid; u8 pSHA1Hash[SHA1_DIGEST_SIZE]; requested_gid = *(u32 *) &command->open_client_session. login_data; if (!tf_check_gid(requested_gid)) { dprintk(KERN_ERR "tf_open_client_session(%p) " "TF_LOGIN_APPLICATION_GROUP: requested GID (0x%x) " "does not match real eGID (0x%x)" "or any of the supplementary GIDs\n", connection, requested_gid, current_egid()); error = -EACCES; goto error; } error = tf_hash_application_path_and_data(pSHA1Hash, &requested_gid, sizeof(u32)); if (error != 0) { dprintk(KERN_ERR "tf_open_client_session: " "error in tf_hash_application_path_and_data\n"); goto error; } memcpy(&command->open_client_session.login_data, pSHA1Hash, 16); command->open_client_session.login_type = TF_LOGIN_APPLICATION_GROUP_LINUX_PATH_GID_SHA1_HASH; /* 16 bytes */ command->open_client_session.message_size += 4; break; } #else case TF_LOGIN_APPLICATION_GROUP: { /* * Check requested GID. Send the real UID and the requested GID * in the login data. Update message size. */ gid_t requested_gid; requested_gid = *(u32 *) &command->open_client_session. login_data; if (!tf_check_gid(requested_gid)) { dprintk(KERN_ERR "tf_open_client_session(%p) " "TF_LOGIN_APPLICATION_GROUP: requested GID (0x%x) " "does not match real eGID (0x%x)" "or any of the supplementary GIDs\n", connection, requested_gid, current_egid()); error = -EACCES; goto error; } *(u32 *) &command->open_client_session.login_data = current_uid(); *(u32 *) &command->open_client_session.login_data[4] = requested_gid; command->open_client_session.login_type = TF_LOGIN_APPLICATION_GROUP_ANDROID_UID_GID; /* Added two words */ command->open_client_session.message_size += 2; break; } #endif case TF_LOGIN_PRIVILEGED: /* A privileged login may be performed only on behalf of the kernel itself or on behalf of a process with euid=0 or egid=0 or euid=system or egid=system. */ if (connection->owner == TF_CONNECTION_OWNER_KERNEL) { dprintk(KERN_DEBUG "tf_open_client_session: " "TF_LOGIN_PRIVILEGED for kernel API\n"); } else if ((current_euid() != TF_PRIVILEGED_UID_GID) && (current_egid() != TF_PRIVILEGED_UID_GID) && (current_euid() != 0) && (current_egid() != 0)) { dprintk(KERN_ERR "tf_open_client_session: " " user %d, group %d not allowed to open " "session with TF_LOGIN_PRIVILEGED\n", current_euid(), current_egid()); error = -EACCES; goto error; } else { dprintk(KERN_DEBUG "tf_open_client_session: " "TF_LOGIN_PRIVILEGED for %u:%u\n", current_euid(), current_egid()); } command->open_client_session.login_type = TF_LOGIN_PRIVILEGED; break; case TF_LOGIN_AUTHENTICATION: { /* * Compute SHA-1 hash of the application binary * Send this hash as the login data (20 bytes) */ u8 *hash; hash = &(command->open_client_session.login_data[0]); error = tf_get_current_process_hash(hash); if (error != 0) { dprintk(KERN_ERR "tf_open_client_session: " "error in tf_get_current_process_hash\n"); goto error; } command->open_client_session.login_type = TF_LOGIN_AUTHENTICATION_BINARY_SHA1_HASH; /* 20 bytes */ command->open_client_session.message_size += 5; break; } case TF_LOGIN_PRIVILEGED_KERNEL: /* A kernel login may be performed only on behalf of the kernel itself. */ if (connection->owner == TF_CONNECTION_OWNER_KERNEL) { dprintk(KERN_DEBUG "tf_open_client_session: " "TF_LOGIN_PRIVILEGED_KERNEL for kernel API\n"); command->open_client_session.login_type = TF_LOGIN_PRIVILEGED_KERNEL; } else { dprintk(KERN_ERR "tf_open_client_session: " " user %d, group %d not allowed to open " "session with TF_LOGIN_PRIVILEGED_KERNEL\n", current_euid(), current_egid()); error = -EACCES; goto error; } command->open_client_session.login_type = TF_LOGIN_PRIVILEGED_KERNEL; break; default: dprintk(KERN_ERR "tf_open_client_session: " "unknown login_type(%08X)\n", command->open_client_session.login_type); error = -EOPNOTSUPP; goto error; } /* Map the temporary memory references */ for (i = 0; i < 4; i++) { int param_type; param_type = TF_GET_PARAM_TYPE( command->open_client_session.param_types, i); if ((param_type & (TF_PARAM_TYPE_MEMREF_FLAG | TF_PARAM_TYPE_REGISTERED_MEMREF_FLAG)) == TF_PARAM_TYPE_MEMREF_FLAG) { /* Map temp mem ref */ error = tf_map_temp_shmem(connection, &command->open_client_session. params[i].temp_memref, param_type, &shmem_desc[i]); if (error != 0) { dprintk(KERN_ERR "tf_open_client_session: " "unable to map temporary memory block " "(%08X)\n", error); goto error; } } } /* Fill the handle of the Device Context */ command->open_client_session.device_context = connection->device_context; error = tf_send_receive( &connection->dev->sm, command, answer, connection, true); error: /* Unmap the temporary memory references */ for (i = 0; i < 4; i++) if (shmem_desc[i] != NULL) tf_unmap_shmem(connection, shmem_desc[i], 0); if (error != 0) dprintk(KERN_ERR "tf_open_client_session returns %d\n", error); else dprintk(KERN_ERR "tf_open_client_session returns " "error_code 0x%08X\n", answer->open_client_session.error_code); return error; }