/** * @file rm_policy.c * * @brief * Resource Manager Policy source. * * \par * ============================================================================ * @n (C) Copyright 2012-2013, Texas Instruments, Inc. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the * distribution. * * Neither the name of Texas Instruments Incorporated nor the names of * its contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * * \par */ /* Standard includes */ #include /* RM external API includes */ #include /* RM internal API includes */ #include #include #include #include #include /* RM LIBFDT includes */ #include /* Tree algorithm includes */ #include /* RM OSAL layer */ #include /********************************************************************** *********************** Policy Globals ******************************* **********************************************************************/ /* Character used in Policies to specify all RM instances receive * the defined permissions for a resource node */ const char Rm_policyAllInstances[] = "*"; /********************************************************************** ******************** Local Policy Functions ************************** **********************************************************************/ /* FUNCTION PURPOSE: Returns a pointer to the valid instance tree *********************************************************************** * DESCRIPTION: Returns a pointer to the instance's valid instance * tree based on the instance type */ static Rm_PolicyValidInstTree *policyGetValidInstTree(Rm_Handle rmHandle) { Rm_Inst *rmInst = (Rm_Inst *)rmHandle; Rm_PolicyValidInstTree *tree = NULL; if ((rmInst->instType == Rm_instType_SERVER) || (rmInst->instType == Rm_instType_SHARED_SERVER)) { tree = rmInst->u.server.globalValidInstTree; } else if (rmInst->instType == Rm_instType_CLIENT_DELEGATE) { tree = rmInst->u.cd.cdValidInstTree; } else if (rmInst->instType == Rm_instType_CLIENT) { tree = rmInst->u.client.staticValidInstTree; } return(tree); } /* FUNCTION PURPOSE: Validates the instance names in a permissions string *********************************************************************** * DESCRIPTION: Returns RM_OK if all the instance names in a permissions * string match instance names defined in the valid instance * list. RM_ERROR_PERM_STR_INST_NOT_VALID is returned if * there are any mismatches */ static int32_t policyCheckInstances(Rm_Handle rmHandle, Rm_PolicyPermission *permissionsList) { while (permissionsList) { if (strncmp(permissionsList->instName, Rm_policyAllInstances, RM_NAME_MAX_CHARS) && (!rmPolicyGetValidInstNode(rmHandle, permissionsList->instName))) { return(RM_ERROR_PERM_STR_INST_NOT_VALID); } permissionsList = permissionsList->nextPermission; } return(RM_OK); } /* FUNCTION PURPOSE: Parses a permissions subgroup *********************************************************************** * DESCRIPTION: Returns a linked list of policy permissions defining * which RM instance referenced in the permissions subgroup * get which permissions. Returns NULL if any syntax * errors are encountered during the parsing. The error * is returned via the result pointer parameter. */ static Rm_PolicyPermission *policyParseSubPermission(char *permStrStart, char *permStrEnd, int32_t *result) { Rm_PolicyPermission *startPerm = NULL; Rm_PolicyPermission *newPerm = NULL; Rm_PolicyPermission *prevPerm = NULL; Rm_PolicyPermission *nextPerm = NULL; char *permStrPtr = NULL; char *subgroupStart = NULL; char *subgroupEnd = NULL; uint32_t permStrLen = (uint32_t)(permStrEnd - permStrStart + 1); char instNameTemp[RM_NAME_MAX_CHARS]; uint32_t instNameIndex; int foundInstName; int instNameComplete; int assignmentLeft; int assignmentRight; /* Create a local copy of the sub-permission string */ permStrPtr = Rm_osalMalloc(permStrLen); strncpy(permStrPtr, permStrStart, permStrLen); /* Make sure the last character in the copied sub-permission string is null */ permStrPtr[permStrLen - 1] = '\0'; permStrStart = permStrPtr; permStrEnd = permStrPtr + strlen(permStrPtr); /* Find the beginning and end of the sub-permission instance group */ subgroupStart = strchr(permStrStart, RM_POLICY_PERM_SUBGROUP_START); subgroupEnd = strchr(permStrStart, RM_POLICY_PERM_SUBGROUP_END); if ((!subgroupStart) || (!subgroupEnd) || (subgroupStart > subgroupEnd) || ((subgroupStart != strrchr(permStrStart, RM_POLICY_PERM_SUBGROUP_START)) && (subgroupEnd != strrchr(permStrStart, RM_POLICY_PERM_SUBGROUP_END)))) { /* Free the memory associated with the temp string and return an error if: * a) Could not find the instance group start * b) Could not find the instance group end * c) Subgroup start and end are out of order * d) There is more than one instance subgroup specified in the string. There * should only be one subgroup per sub-permission string */ *result = RM_ERROR_PERM_STR_TOO_MANY_INST_GROUPS; goto parseError; } /* Create a permission entry for each instance specified in the instance group. * Instances names are separated by one or more spaces. */ permStrPtr = subgroupStart + 1; instNameIndex = 0; foundInstName = RM_FALSE; instNameComplete = RM_FALSE; while (permStrPtr <= subgroupEnd) { if ((isspace(*permStrPtr) || (*permStrPtr == RM_POLICY_PERM_SUBGROUP_END)) && foundInstName) { /* First space encountered after copying an instance name. This * terminates the instance name. All other space characters are * ignored. */ instNameTemp[instNameIndex] = '\0'; instNameComplete = RM_TRUE; } else { if (!foundInstName) { /* First non-whitespace character encountered is the start of an * instance name */ foundInstName = RM_TRUE; } /* Copy the character into the temporary instance name string */ instNameTemp[instNameIndex++] = *permStrPtr; } if (instNameComplete) { newPerm = (Rm_PolicyPermission *) Rm_osalMalloc(sizeof(Rm_PolicyPermission)); memset((void *)newPerm, 0, sizeof(Rm_PolicyPermission)); strncpy(newPerm->instName, instNameTemp, RM_NAME_MAX_CHARS); newPerm->nextPermission = NULL; if (prevPerm == NULL) { /* Save the first instance so it can be returned */ startPerm = newPerm; } else { prevPerm->nextPermission = newPerm; } prevPerm = newPerm; instNameComplete = RM_FALSE; instNameIndex = 0; foundInstName = RM_FALSE; } else if (instNameIndex == RM_NAME_MAX_CHARS) { /* Instance name is longer than max length */ *result = RM_ERROR_INST_NAME_IN_ASSIGNMENT_TOO_LONG; goto parseError; } permStrPtr++; } /* Fill in the permissions for each instance name */ /* Look on left of instance group for permission assignments. */ permStrPtr = subgroupStart - 1; assignmentLeft = RM_FALSE; while (permStrPtr >= permStrStart) { if (*permStrPtr == RM_POLICY_PERM_ASSIGNMENT) { if (assignmentLeft) { /* Assignment character has been found more than once. This is a * syntax error. Free the permission list and the temporary string * and return. */ *result = RM_ERROR_PERM_STR_TOO_MANY_ASSIGN_CHARS; goto parseError; } else { assignmentLeft = RM_TRUE; } } else if (!isspace(*permStrPtr)) { if (assignmentLeft) { if ((*permStrPtr == RM_POLICY_PERM_INIT_LOWER) || (*permStrPtr == RM_POLICY_PERM_INIT_UPPER)) { newPerm = startPerm; while (newPerm) { RM_policy_SET_PERM(newPerm->permissionBits, RM_POLICY_PERM_INIT_SHIFT, 1); newPerm = newPerm->nextPermission; } } else if ((*permStrPtr == RM_POLICY_PERM_USE_LOWER) || (*permStrPtr == RM_POLICY_PERM_USE_UPPER)) { newPerm = startPerm; while (newPerm) { RM_policy_SET_PERM(newPerm->permissionBits, RM_POLICY_PERM_USE_SHIFT, 1); newPerm = newPerm->nextPermission; } } else if ((*permStrPtr == RM_POLICY_PERM_EXCLUSIVE_LOWER) || (*permStrPtr == RM_POLICY_PERM_EXCLUSIVE_UPPER)) { newPerm = startPerm; while (newPerm) { RM_policy_SET_PERM(newPerm->permissionBits, RM_POLICY_PERM_EXCLUSIVE_SHIFT, 1); newPerm = newPerm->nextPermission; } } else if ((*permStrPtr == RM_POLICY_PERM_SHARED_LINUX_LOWER) || (*permStrPtr == RM_POLICY_PERM_SHARED_LINUX_UPPER)) { newPerm = startPerm; while (newPerm) { RM_policy_SET_PERM(newPerm->permissionBits, RM_POLICY_PERM_SHARED_LINUX_SHIFT, 1); newPerm = newPerm->nextPermission; } } else { /* Invalid permission character. This is a * syntax error. Free the permission list and the temporary string * and return. */ *result = RM_ERROR_PERM_STR_INVALID_CHAR; goto parseError; } } else { /* Character found without the assignment character being found. This is a * syntax error. Free the permission list and the temporary string * and return. */ *result = RM_ERROR_PERM_CHAR_WITHOUT_ASSIGN_CHAR; goto parseError; } } permStrPtr--; } /* Look on right of instance group for permission assignments. */ permStrPtr = subgroupEnd + 1; assignmentRight = RM_FALSE; while (permStrPtr < permStrEnd) { if (assignmentLeft && (!isspace(*permStrPtr))) { /* There should be nothing but spaces on right if assignment was already found on left */ *result = RM_ERROR_INVALID_PERMS_CHAR_ON_RIGHT; goto parseError; } if (*permStrPtr == RM_POLICY_PERM_ASSIGNMENT) { if (assignmentRight) { /* Assignment character has been found more than once. This is a * syntax error. Free the permission list and the temporary string * and return. */ *result = RM_ERROR_PERM_STR_TOO_MANY_ASSIGN_CHARS; goto parseError; } else { assignmentRight = RM_TRUE; } } else if (!isspace(*permStrPtr)) { if (assignmentRight) { if ((*permStrPtr == RM_POLICY_PERM_INIT_LOWER) || (*permStrPtr == RM_POLICY_PERM_INIT_UPPER)) { newPerm = startPerm; while (newPerm) { RM_policy_SET_PERM(newPerm->permissionBits, RM_POLICY_PERM_INIT_SHIFT, 1); newPerm = newPerm->nextPermission; } } else if ((*permStrPtr == RM_POLICY_PERM_USE_LOWER) || (*permStrPtr == RM_POLICY_PERM_USE_UPPER)) { newPerm = startPerm; while (newPerm) { RM_policy_SET_PERM(newPerm->permissionBits, RM_POLICY_PERM_USE_SHIFT, 1); newPerm = newPerm->nextPermission; } } else if ((*permStrPtr == RM_POLICY_PERM_EXCLUSIVE_LOWER) || (*permStrPtr == RM_POLICY_PERM_EXCLUSIVE_UPPER)) { newPerm = startPerm; while (newPerm) { RM_policy_SET_PERM(newPerm->permissionBits, RM_POLICY_PERM_EXCLUSIVE_SHIFT, 1); newPerm = newPerm->nextPermission; } } else if ((*permStrPtr == RM_POLICY_PERM_SHARED_LINUX_LOWER) || (*permStrPtr == RM_POLICY_PERM_SHARED_LINUX_UPPER)) { newPerm = startPerm; while (newPerm) { RM_policy_SET_PERM(newPerm->permissionBits, RM_POLICY_PERM_SHARED_LINUX_SHIFT, 1); newPerm = newPerm->nextPermission; } } else { /* Invalid permission character. This is a * syntax error. Free the permission list and the temporary string * and return. */ *result = RM_ERROR_PERM_STR_INVALID_CHAR; goto parseError; } } else { /* Character found without the assignment character being found. This is a * syntax error. Free the permission list and the temporary string * and return. */ *result = RM_ERROR_PERM_STR_TOO_MANY_ASSIGN_CHARS; goto parseError; } } permStrPtr++; } Rm_osalFree((void *)permStrStart, sizeof(permStrLen)); *result = RM_OK; return (startPerm); parseError: while (startPerm) { nextPerm = startPerm->nextPermission; Rm_osalFree((void *)startPerm, sizeof(Rm_PolicyPermission)); startPerm = nextPerm; } Rm_osalFree((void *)permStrStart, sizeof(permStrLen)); return(NULL); } /* FUNCTION PURPOSE: Frees a linked list of assignment permissions *********************************************************************** * DESCRIPTION: Frees the memory associated with a linked list of * assignment permissions extracted from a permissions * assignment subgroup in a policy DTB. */ static void policyFreeAssignmentPermissions(Rm_PolicyPermission *permissionList) { Rm_PolicyPermission *nextPerm; while (permissionList) { nextPerm = permissionList->nextPermission; Rm_osalFree((void *)permissionList, sizeof(Rm_PolicyPermission)); permissionList = nextPerm; } } /* FUNCTION PURPOSE: Extracts permissions from a Policy "assignment" *********************************************************************** * DESCRIPTION: Returns a linked list of permissions for a resource node * containing an "assignment" property in the Policy DTB. * Each node in the linked list will contain a valid instance * name along with the permissions assigned to the instance */ static Rm_PolicyPermission *policyGetAssignmentPermissions(Rm_PolicyAssignment *assignment, int32_t *result) { Rm_PolicyPermission *startPerm = NULL; Rm_PolicyPermission *newPerm = NULL; Rm_PolicyPermission *prevPerm = NULL; char *permStrStart = assignment->permissionsList; char *permStrEnd; uint32_t permStrLen = strlen(assignment->permissionsList) + 1; uint32_t i = 0; *result = RM_OK; while(i < permStrLen) { /* Find the first sub-permission specification and parse it. A sub-permission * can be terminated by the termination character or the end of the string. */ if (!(permStrEnd = strchr(permStrStart, RM_POLICY_PERM_TERMINATOR))) { /* Sub-permission termination character not found. The permission string * end is the end of the entire permission string */ permStrEnd = permStrStart + strlen(permStrStart); } newPerm = policyParseSubPermission(permStrStart, permStrEnd, result); if (*result != RM_OK) { /* Delete the permission list that's been created thus far, return * the error and NULL for the permission list */ policyFreeAssignmentPermissions(startPerm); return(NULL); } if (prevPerm == NULL) { startPerm = newPerm; } else { prevPerm->nextPermission = newPerm; } /* Set prevPerm to the last sub-permission returned by the sub-permission parser */ prevPerm = newPerm; while(prevPerm->nextPermission != NULL) { prevPerm = prevPerm->nextPermission; } /* Update the number of characters parsed from the permission list and point to * the start of the next sub-permission */ i += ((uint32_t)(permStrEnd - permStrStart + 1)); permStrStart = permStrEnd + 1; } return(startPerm); } /* FUNCTION PURPOSE: Validates a policy "assignment" string list *********************************************************************** * DESCRIPTION: Returns RM_OK if the specified Policy DTB "assignment" * property specification parses okay and all the RM * instances in the assignment match RM instances in the * valid instances list */ static int32_t policyValidateAssignmentPermissions(Rm_Handle rmHandle, Rm_PolicyAssignment *assignmentList) { Rm_PolicyAssignment *assignment = assignmentList; Rm_PolicyPermission *permissionList; int32_t result; while (assignment) { /* Make sure assignment's permissions parse okay */ permissionList = policyGetAssignmentPermissions(assignment, &result); if (result != RM_OK) { return(result); } if (result = policyCheckInstances(rmHandle, permissionList) != RM_OK) { policyFreeAssignmentPermissions(permissionList); return(result); } policyFreeAssignmentPermissions(permissionList); assignment = assignment->nextAssignment; } return (RM_OK); } /********************************************************************** ************************ Internal Policy APIs ************************ **********************************************************************/ /* FUNCTION PURPOSE: Returns a pointer to the instance policy *********************************************************************** * DESCRIPTION: Returns a pointer to the instance's policy based on * the instance type */ void *rmPolicyGetPolicy(Rm_Handle rmHandle) { Rm_Inst *rmInst = (Rm_Inst *)rmHandle; void *policy = NULL; if ((rmInst->instType == Rm_instType_SERVER) || (rmInst->instType == Rm_instType_SHARED_SERVER)) { policy = rmInst->u.server.globalPolicy; } else if (rmInst->instType == Rm_instType_CLIENT_DELEGATE) { policy = rmInst->u.cd.cdPolicy; } else if (rmInst->instType == Rm_instType_CLIENT) { policy = rmInst->u.client.staticPolicy; } return(policy); } /* FUNCTION PURPOSE: Get a valid instace node from the valid inst tree *********************************************************************** * DESCRIPTION: Returns a valid instance node from the valid instance * tree that matches the specified instName */ Rm_PolicyValidInstNode *rmPolicyGetValidInstNode(Rm_Handle rmHandle, char *instName) { Rm_Inst *rmInst = (Rm_Inst *)rmHandle; Rm_PolicyValidInstTree *treeRoot = policyGetValidInstTree(rmHandle); Rm_PolicyValidInstNode findNode; if (rmInst->instType == Rm_instType_SHARED_SERVER) { rmPolicyValidInstTreeInv(treeRoot); } memset((void *)&findNode, 0, sizeof(Rm_PolicyValidInstNode)); strncpy(findNode.name, instName, RM_NAME_MAX_CHARS); return (RB_FIND(_Rm_PolicyValidInstTree, treeRoot, &findNode)); } /* FUNCTION PURPOSE: Gets the Linux Valid instance node *********************************************************************** * DESCRIPTION: Returns a pointer to the valid instance node in the * valid instance tree that matches the instance name * reserved for resource assigned to the Linux kernel. */ Rm_PolicyValidInstNode *rmPolicyGetLinuxInstNode(Rm_Handle rmHandle) { char linuxName[] = RM_ALLOCATED_TO_LINUX; return (rmPolicyGetValidInstNode(rmHandle, linuxName)); } /* FUNCTION PURPOSE: Validates resource permissions against a Policy DTB *********************************************************************** * DESCRIPTION: Returns TRUE if the instance name has the specified * permissions for the specified resource in the Policy * DTB. Otherwise, returns FALSE. */ int rmPolicyCheckPrivilege(Rm_PolicyCheckCfg *privilegeCfg, int32_t *result) { int32_t propertyOffset; const char *propertyName; int32_t propertyLen; const void *propertyData; Rm_PolicyAssignment *assignment = NULL; Rm_PolicyAssignment *assignmentStart = NULL; Rm_PolicyPermission *permission = NULL; Rm_PolicyPermission *permissionStart = NULL; uint32_t assignmentEnd; uint32_t resourceEnd = privilegeCfg->resourceBase + privilegeCfg->resourceLength - 1; int foundInstance; *result = RM_OK; /* Get the resource's assignments */ propertyOffset = fdt_first_property_offset(privilegeCfg->policyDtb, privilegeCfg->resourceOffset); if (propertyOffset > RM_DTB_UTIL_STARTING_NODE_OFFSET) { while (propertyOffset > RM_DTB_UTIL_STARTING_NODE_OFFSET) { propertyData = fdt_getprop_by_offset(privilegeCfg->policyDtb, propertyOffset, &propertyName, &propertyLen); if (rmDtbUtilPolicyGetPropertyType(propertyName) == Rm_policyPropType_ASSIGNMENTS) { assignment = assignmentStart = rmDtbUtilPolicyExtractAssignments(propertyData, propertyLen); break; } propertyOffset = fdt_next_property_offset(privilegeCfg->policyDtb, propertyOffset); } } if (assignment) { while (assignment) { assignmentEnd = assignment->resourceBase + assignment->resourceLength - 1; foundInstance = RM_FALSE; if (((privilegeCfg->resourceBase >= assignment->resourceBase) && (privilegeCfg->resourceBase <= assignmentEnd)) || ((privilegeCfg->resourceBase < assignment->resourceBase) && (resourceEnd > assignmentEnd)) || ((resourceEnd >= assignment->resourceBase) && (resourceEnd <= assignmentEnd))) { permission = permissionStart = policyGetAssignmentPermissions(assignment, result); while (permission) { if ((strncmp(permission->instName, privilegeCfg->validInstNode->name, RM_NAME_MAX_CHARS) == 0) || (strncmp(permission->instName, Rm_policyAllInstances, RM_NAME_MAX_CHARS) == 0)) { foundInstance = RM_TRUE; /* Check instance's permissions */ if (privilegeCfg->type == Rm_policyCheck_INIT) { if (!RM_policy_GET_PERM(permission->permissionBits, RM_POLICY_PERM_INIT_SHIFT)) { policyFreeAssignmentPermissions(permissionStart); rmDtbUtilPolicyFreeAssignments(assignmentStart); return(RM_FALSE); } } else if (privilegeCfg->type == Rm_policyCheck_USE) { if (!RM_policy_GET_PERM(permission->permissionBits, RM_POLICY_PERM_USE_SHIFT)) { policyFreeAssignmentPermissions(permissionStart); rmDtbUtilPolicyFreeAssignments(assignmentStart); return(RM_FALSE); } } else if (privilegeCfg->type == Rm_policyCheck_EXCLUSIVE) { if (!RM_policy_GET_PERM(permission->permissionBits, RM_POLICY_PERM_EXCLUSIVE_SHIFT)) { policyFreeAssignmentPermissions(permissionStart); rmDtbUtilPolicyFreeAssignments(assignmentStart); return(RM_FALSE); } } else if (privilegeCfg->type == Rm_policyCheck_SHARED_LINUX) { if (!RM_policy_GET_PERM(permission->permissionBits, RM_POLICY_PERM_SHARED_LINUX_SHIFT)) { policyFreeAssignmentPermissions(permissionStart); rmDtbUtilPolicyFreeAssignments(assignmentStart); return(RM_FALSE); } } break; } permission = permission->nextPermission; } policyFreeAssignmentPermissions(permissionStart); if (!foundInstance) { rmDtbUtilPolicyFreeAssignments(assignmentStart); return(RM_FALSE); } } assignment = assignment->nextAssignment; } rmDtbUtilPolicyFreeAssignments(assignmentStart); } else { return(RM_FALSE); } return(RM_TRUE); } /* FUNCTION PURPOSE: Returns resource base value according to the Policy *********************************************************************** * DESCRIPTION: Returns a resource base value based on the resource * ranges assigned to the specified valid instance by the * Policy DTB. */ uint32_t rmPolicyGetResourceBase(void *policyDtb, Rm_PolicyValidInstNode *validInstNode, int32_t resourceOffset, Rm_PolicyCheckType policyCheckType, int32_t *result) { int32_t propertyOffset; const char *propertyName; int32_t propertyLen; const void *propertyData; Rm_PolicyAssignment *assignment = NULL; Rm_PolicyAssignment *assignmentStart = NULL; Rm_PolicyPermission *permission = NULL; Rm_PolicyPermission *permissionStart = NULL; uint32_t resourceBase = 0; *result = RM_OK; propertyOffset = fdt_first_property_offset(policyDtb, resourceOffset); if (propertyOffset > RM_DTB_UTIL_STARTING_NODE_OFFSET) { while (propertyOffset > RM_DTB_UTIL_STARTING_NODE_OFFSET) { propertyData = fdt_getprop_by_offset(policyDtb, propertyOffset, &propertyName, &propertyLen); if (rmDtbUtilPolicyGetPropertyType(propertyName) == Rm_policyPropType_ASSIGNMENTS) { assignment = assignmentStart = rmDtbUtilPolicyExtractAssignments(propertyData, propertyLen); break; } propertyOffset = fdt_next_property_offset(policyDtb, propertyOffset); } } /* Search policy permissions for valid resource base */ while (assignment) { permission = permissionStart = policyGetAssignmentPermissions(assignment, result); while (permission) { if ((strncmp(permission->instName, validInstNode->name, RM_NAME_MAX_CHARS) == 0) || (strncmp(permission->instName, Rm_policyAllInstances, RM_NAME_MAX_CHARS) == 0)) { /* Check instance's permissions */ if ((policyCheckType == Rm_policyCheck_INIT) && RM_policy_GET_PERM(permission->permissionBits, RM_POLICY_PERM_INIT_SHIFT)) { resourceBase = assignment->resourceBase; break; } else if ((policyCheckType == Rm_policyCheck_USE) && RM_policy_GET_PERM(permission->permissionBits, RM_POLICY_PERM_USE_SHIFT)) { resourceBase = assignment->resourceBase; break; } } permission = permission->nextPermission; } policyFreeAssignmentPermissions(permissionStart); if (resourceBase) { break; } else { assignment = assignment->nextAssignment; } } if (assignmentStart) { rmDtbUtilPolicyFreeAssignments(assignmentStart); } return(resourceBase); } /* FUNCTION PURPOSE: Returns resource alignment value according to the Policy *********************************************************************** * DESCRIPTION: Parses the policy DTB to find and return a resource's * alignment. */ uint32_t rmPolicyGetResourceAlignment(void *policyDtb, int32_t resourceOffset) { int32_t propertyOffset; const char *propertyName; int32_t propertyLen; const void *propertyData; Rm_ResourceValue *alignmentList; uint32_t resourceAlignment = 0; propertyOffset = fdt_first_property_offset(policyDtb, resourceOffset); if (propertyOffset > RM_DTB_UTIL_STARTING_NODE_OFFSET) { while (propertyOffset > RM_DTB_UTIL_STARTING_NODE_OFFSET) { propertyData = fdt_getprop_by_offset(policyDtb, propertyOffset, &propertyName, &propertyLen); if (rmDtbUtilPolicyGetPropertyType(propertyName) == Rm_policyPropType_ALLOCATION_ALIGNMENT) { alignmentList = rmDtbUtilPolicyExtractResourceAlignments(propertyData, propertyLen); resourceAlignment = alignmentList->value; rmDtbUtilPolicyFreeResourceAlignments(alignmentList); } propertyOffset = fdt_next_property_offset(policyDtb, propertyOffset); } } return(resourceAlignment); } /* FUNCTION PURPOSE: Returns resource CD allocation size according to the Policy *********************************************************************** * DESCRIPTION: Parses the policy DTB to find and return a resource's * allocation size. */ uint32_t rmPolicyGetResourceCdAllocSize(void *policyDtb, int32_t resourceOffset) { int32_t propertyOffset; const char *propertyName; int32_t propertyLen; const void *propertyData; Rm_ResourceValue *allocSizeList; uint32_t resourceAllocSize = 0; propertyOffset = fdt_first_property_offset(policyDtb, resourceOffset); if (propertyOffset > RM_DTB_UTIL_STARTING_NODE_OFFSET) { while (propertyOffset > RM_DTB_UTIL_STARTING_NODE_OFFSET) { propertyData = fdt_getprop_by_offset(policyDtb, propertyOffset, &propertyName, &propertyLen); if (rmDtbUtilPolicyGetPropertyType(propertyName) == Rm_policyPropType_CD_ALLOCATION_SIZE) { allocSizeList = rmDtbUtilPolicyExtractCdAllocationSizes(propertyData, propertyLen); resourceAllocSize = allocSizeList->value; rmDtbUtilPolicyFreeCdAllocationSizes(allocSizeList); } propertyOffset = fdt_next_property_offset(policyDtb, propertyOffset); } } return(resourceAllocSize); } /* FUNCTION PURPOSE: Get a resource's offset into a Policy *********************************************************************** * DESCRIPTION: Returns the location of the specified resource node * within the specified Policy in the form of an offset * into the DTB. The resourceName and the Policy * node name must match. */ int32_t rmPolicyGetResourceOffset(void *policyDtb, char *resourceName) { int32_t nodeOffset; int32_t depth; const char *nodeName; if (policyDtb) { depth = RM_DTB_UTIL_STARTING_DEPTH; nodeOffset = RM_DTB_UTIL_STARTING_NODE_OFFSET; /* Find node offset for provided resource name */ while ((nodeOffset >= RM_DTB_UTIL_STARTING_NODE_OFFSET) && (depth >= RM_DTB_UTIL_STARTING_DEPTH)) { nodeOffset = fdt_next_node(policyDtb, nodeOffset, &depth); nodeName = fdt_get_name(policyDtb, nodeOffset, NULL); if (strncmp(nodeName, resourceName, RM_NAME_MAX_CHARS) == 0) { break; } } if (depth < RM_DTB_UTIL_STARTING_DEPTH) { /* Resource name not found */ nodeOffset = RM_SERVICE_DENIED_RES_DOES_NOT_EXIST; } } else { nodeOffset = RM_ERROR_INSTANCE_HAS_NO_POLICY; } return(nodeOffset); } /* FUNCTION PURPOSE: Validates a Policy's resource node names *********************************************************************** * DESCRIPTION: Returns RM_OK if all of a Policy's resource node names * match a node name specified in the "valid-instances" * list specified at the top of the Policy. Otherwise, * returns error */ int32_t rmPolicyValidatePolicyResourceNames(Rm_Handle rmHandle) { void *policyDtb = rmPolicyGetPolicy(rmHandle); int32_t nodeOffset; int32_t depth; const char *nodeName; depth = RM_DTB_UTIL_STARTING_DEPTH; nodeOffset = RM_DTB_UTIL_STARTING_NODE_OFFSET; /* Parse DTB, verifying each resource's assignment permissions. * Permissions must have correct syntax and contain valid instance names * according validInstList */ while ((nodeOffset >= RM_DTB_UTIL_STARTING_NODE_OFFSET) && (depth >= RM_DTB_UTIL_STARTING_DEPTH)) { nodeOffset = fdt_next_node(policyDtb, nodeOffset, &depth); nodeName = fdt_get_name(policyDtb, nodeOffset, NULL); if (fdt_first_property_offset(policyDtb, nodeOffset) > RM_DTB_UTIL_STARTING_NODE_OFFSET) { if (rmAllocatorFind(rmHandle, nodeName) == NULL) { /* No allocator tied to resource name */ return(RM_ERROR_UNKNOWN_RESOURCE_IN_POLICY); } } } return(RM_OK); } /* FUNCTION PURPOSE: Validates a Policy DTB *********************************************************************** * DESCRIPTION: Returns RM_OK if the input Policy satisfies the * following conditions: * a) All "assignment" permission string parse okay * b) All RM instance names specified in the permission * strings match an instance name in the valid instance * list * c) All resource node names match a resource allocator */ int32_t rmPolicyValidatePolicy(Rm_Handle rmHandle) { void *policyDtb = rmPolicyGetPolicy(rmHandle); int32_t nodeOffset; int32_t propertyOffset; int32_t depth; const char *propertyName; int32_t propertyLen; const void *propertyData; Rm_PolicyPropType propertyType; Rm_PolicyAssignment *assignmentList; int32_t result; depth = RM_DTB_UTIL_STARTING_DEPTH; nodeOffset = RM_DTB_UTIL_STARTING_NODE_OFFSET; /* Parse DTB, verifying each resource's assignment permissions. * Permissions must have correct syntax and contain valid instance names * according validInstList */ while ((nodeOffset >= RM_DTB_UTIL_STARTING_NODE_OFFSET) && (depth >= RM_DTB_UTIL_STARTING_DEPTH)) { nodeOffset = fdt_next_node(policyDtb, nodeOffset, &depth); propertyOffset = fdt_first_property_offset(policyDtb, nodeOffset); while (propertyOffset > RM_DTB_UTIL_STARTING_NODE_OFFSET) { propertyData = fdt_getprop_by_offset(policyDtb, propertyOffset, &propertyName, &propertyLen); propertyType = rmDtbUtilPolicyGetPropertyType(propertyName); if (propertyType == Rm_policyPropType_ASSIGNMENTS) { assignmentList = rmDtbUtilPolicyExtractAssignments(propertyData, propertyLen); if ((result = policyValidateAssignmentPermissions(rmHandle, assignmentList)) != RM_OK) { rmDtbUtilPolicyFreeAssignments(assignmentList); return(result); } rmDtbUtilPolicyFreeAssignments(assignmentList); } else if (propertyType == Rm_policyPropType_UNKNOWN) { return(RM_ERROR_UNKNOWN_POLICY_RESOURCE_PROPERTY); } propertyOffset = fdt_next_property_offset(policyDtb, propertyOffset); } } return(RM_OK); } /* FUNCTION PURPOSE: Creates the valid instance tree for a RM instance *********************************************************************** * DESCRIPTION: Creates the valid instance tree for a RM instance * that has been provided a global or static policy * The valid instance tree is created from the * "valid-instances" property at the top of the Policy. * The root entry of the valid instance tree is returned. */ Rm_PolicyValidInstTree *rmPolicyCreateValidInstTree(Rm_Handle rmHandle, int addLinux, int32_t *result) { Rm_Inst *rmInst = (Rm_Inst *)rmHandle; void *policyDtb = rmPolicyGetPolicy(rmHandle); int32_t validInstOffset; const char *validInstName = NULL; int32_t validInstLen; const void *validInstData = NULL; Rm_PolicyPropType propertyType; Rm_PolicyValidInst *vInstListStart = NULL; Rm_PolicyValidInst *validInstList = NULL; Rm_PolicyValidInstTree *rootEntry = NULL; Rm_PolicyValidInstNode *newNode = NULL; char linuxName[] = RM_ALLOCATED_TO_LINUX; /* Valid instance list must be first and only property in the root node of * the policyDtb */ validInstOffset = fdt_first_property_offset(policyDtb, RM_DTB_UTIL_STARTING_NODE_OFFSET); if (validInstOffset < -FDT_ERR_NOTFOUND) { *result = validInstOffset; return (NULL); } else if (validInstOffset == -FDT_ERR_NOTFOUND) { *result = RM_ERROR_NO_VALID_INST_IN_POLICY; return (NULL); } validInstData = fdt_getprop_by_offset(policyDtb, validInstOffset, &validInstName, &validInstLen); propertyType = rmDtbUtilPolicyGetPropertyType(validInstName); if (propertyType != Rm_policyPropType_VALID_INSTANCES) { *result = RM_ERROR_NO_VALID_INST_IN_POLICY; return (NULL); } if (!(validInstList = rmDtbUtilPolicyExtractValidInstances(validInstData, validInstLen, result))) { return (NULL); } /* Create the tree */ rootEntry = Rm_osalMalloc(sizeof(Rm_PolicyValidInstTree)); RB_INIT(rootEntry); vInstListStart = validInstList; while (validInstList) { newNode = rmPolicyValidInstNodeNew(validInstList->instName); RB_INSERT(_Rm_PolicyValidInstTree, rootEntry, newNode); validInstList = validInstList->nextValidInst; } rmDtbUtilPolicyFreeValidInstances(vInstListStart); /* Add the Linux kernel node */ if (addLinux) { newNode = rmPolicyValidInstNodeNew(linuxName); RB_INSERT(_Rm_PolicyValidInstTree, rootEntry, newNode); } if (rmInst->instType == Rm_instType_SHARED_SERVER) { /* Writeback the valid instance tree */ rmPolicyValidInstTreeWb(rootEntry); } *result = RM_OK; return (rootEntry); } /* FUNCTION PURPOSE: Deletes a valid instance tree *********************************************************************** * DESCRIPTION: Frees all memory associated with a Policy valid * instance tree. */ void rmPolicyFreeValidInstTree(Rm_Handle rmHandle) { Rm_Inst *rmInst = (Rm_Inst *)rmHandle; Rm_PolicyValidInstTree *treeRoot = policyGetValidInstTree(rmHandle); Rm_PolicyValidInstNode *node; Rm_PolicyValidInstNode *nextNode; if (treeRoot) { if (rmInst->instType == Rm_instType_SHARED_SERVER) { rmPolicyValidInstTreeInv(treeRoot); } for (node = RB_MIN(_Rm_PolicyValidInstTree, treeRoot); node != NULL; node = nextNode) { nextNode = RB_NEXT(_Rm_PolicyValidInstTree, treeRoot, node); RB_REMOVE(_Rm_PolicyValidInstTree, treeRoot, node); rmPolicyValidInstNodeFree(node); } /* Don't need to writeback tree node changes since valid instance will be made * NULL in instance */ if (RB_MIN(_Rm_PolicyValidInstTree, treeRoot) == NULL) { /* No more valid instance nodes in tree */ Rm_osalFree((void *)treeRoot, sizeof(Rm_PolicyValidInstTree)); } if ((rmInst->instType == Rm_instType_SERVER) || (rmInst->instType == Rm_instType_SHARED_SERVER)) { rmInst->u.server.globalValidInstTree = NULL; } else if (rmInst->instType == Rm_instType_CLIENT_DELEGATE) { rmInst->u.cd.cdValidInstTree = NULL; } else if (rmInst->instType == Rm_instType_CLIENT) { rmInst->u.client.staticValidInstTree = NULL; } } }