forked from ros2/rcutils
-
Notifications
You must be signed in to change notification settings - Fork 10
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
* Release micro-ROS Foxy (#8) * micro-ROS changes over dashing Feature/add security directory (#1) * Added security directory * Updated security directory Feature/avoid filesystem and allocation (#2) * Included RCUTILS_NO_FILESYSTEM and RCUTILS_AVOID_DYNAMIC_ALLOCATION * Added no filesystem options * Default allocators write access * Avoid dynamic allocation and no filesytem on error handling * Typo * New flags for filesystem and avoid dynamic * Error handling template * New allocator approach Add test_security_directory test from rcl. (#3) Merge pull request #4 from micro-ROS/feature/zephyr_fixes Feature/zephyr fixes CMake refactor (#5) Update approach (#6) * Update approach * Remove target_compile_definitions and refactor flags install * Added RCUTILS_NO_FILESYSTEM on new functions * Added RCUTILS_NO_FILESYSTEM on new functions Co-authored-by: Pablo Garrido <pablogs9@gmail.com> * Initial changes * Add hashing and lock pool * Updates Co-authored-by: Jose Antonio Moral <joseantoniomoralparras@gmail.com>
- Loading branch information
Showing
5 changed files
with
592 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,92 @@ | ||
// Copyright 2020 Proyectos y Sistemas de Mantenimiento SL (eProsima). | ||
// | ||
// Licensed under the Apache License, Version 2.0 (the "License"); | ||
// you may not use this file except in compliance with the License. | ||
// You may obtain a copy of the License at | ||
// | ||
// http://www.apache.org/licenses/LICENSE-2.0 | ||
// | ||
// Unless required by applicable law or agreed to in writing, software | ||
// distributed under the License is distributed on an "AS IS" BASIS, | ||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
// See the License for the specific language governing permissions and | ||
// limitations under the License. | ||
|
||
#ifdef __cplusplus | ||
extern "C" | ||
{ | ||
#endif | ||
|
||
#include <stdint.h> | ||
#include <stdbool.h> | ||
|
||
#define FLAGS_LEN 23 | ||
|
||
static bool * get_memory_lock(void *address) | ||
{ | ||
static bool memory_locks[FLAGS_LEN] = { 0 }; | ||
uintptr_t a = (uintptr_t)(address); | ||
|
||
// Public domain hash function taken from http://burtleburtle.net/bob/hash/integer.html | ||
a = (a ^ 61) ^ (a >> 16); | ||
a = a + (a << 3); | ||
a = a ^ (a >> 4); | ||
a = a * 0x27d4eb2d; | ||
a = a ^ (a >> 15); | ||
|
||
a = a % FLAGS_LEN; | ||
return memory_locks + a; | ||
} | ||
|
||
void lock_memory(uint64_t *address){ | ||
bool * memory_lock = get_memory_lock(address); | ||
|
||
while (__atomic_test_and_set(memory_lock, __ATOMIC_ACQUIRE) == 1); | ||
} | ||
|
||
void unlock_memory(uint64_t *address){ | ||
bool * memory_lock = get_memory_lock(address); | ||
|
||
__atomic_clear(memory_lock, __ATOMIC_RELEASE); | ||
} | ||
|
||
uint64_t __atomic_load_8(uint64_t *mem, int model) { | ||
(void) model; | ||
|
||
lock_memory(mem); | ||
uint64_t ret = *mem; | ||
unlock_memory(mem); | ||
return ret; | ||
} | ||
|
||
void __atomic_store_8(uint64_t *mem, uint64_t val, int model) { | ||
(void) model; | ||
|
||
lock_memory(mem); | ||
*mem = val; | ||
unlock_memory(mem); | ||
} | ||
|
||
uint64_t __atomic_exchange_8(uint64_t *mem, uint64_t val, int model) { | ||
(void) model; | ||
|
||
lock_memory(mem); | ||
uint64_t ret = *mem; | ||
*mem = val; | ||
unlock_memory(mem); | ||
return ret; | ||
} | ||
|
||
uint64_t __atomic_fetch_add_8(uint64_t *mem, uint64_t val, int model) { | ||
(void) model; | ||
|
||
lock_memory(mem); | ||
uint64_t ret = *mem; | ||
*mem += val; | ||
unlock_memory(mem); | ||
return ret; | ||
} | ||
|
||
#ifdef __cplusplus | ||
} | ||
#endif |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,278 @@ | ||
// Copyright 2018 Open Source Robotics Foundation, Inc. | ||
// | ||
// Licensed under the Apache License, Version 2.0 (the "License"); | ||
// you may not use this file except in compliance with the License. | ||
// You may obtain a copy of the License at | ||
// | ||
// http://www.apache.org/licenses/LICENSE-2.0 | ||
// | ||
// Unless required by applicable law or agreed to in writing, software | ||
// distributed under the License is distributed on an "AS IS" BASIS, | ||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
// See the License for the specific language governing permissions and | ||
// limitations under the License. | ||
|
||
#include "rcutils/security_directory.h" | ||
|
||
#include "rcutils/error_handling.h" | ||
#include "rcutils/filesystem.h" | ||
#include "rcutils/get_env.h" | ||
#include "rcutils/format_string.h" | ||
|
||
#ifdef __clang__ | ||
# pragma clang diagnostic push | ||
# pragma clang diagnostic ignored "-Wembedded-directive" | ||
#endif | ||
|
||
#ifndef RCUTILS_NO_FILESYSTEM | ||
#include "tinydir/tinydir.h" | ||
#endif | ||
|
||
#ifdef __clang__ | ||
# pragma clang diagnostic pop | ||
#endif | ||
|
||
/** | ||
* A security lookup function takes in the node's name, namespace, a security root directory and an allocator; | ||
* It returns the relevant information required to load the security credentials, | ||
* which is currently a path to a directory on the filesystem containing DDS Security permission files. | ||
*/ | ||
typedef char * (* security_lookup_fn_t) ( | ||
const char * node_name, | ||
const char * node_namespace, | ||
const char * ros_secure_root_env, | ||
const rcutils_allocator_t * allocator | ||
); | ||
|
||
char * exact_match_lookup( | ||
const char * node_name, | ||
const char * node_namespace, | ||
const char * ros_secure_root_env, | ||
const rcutils_allocator_t * allocator | ||
); | ||
|
||
char * prefix_match_lookup( | ||
const char * node_name, | ||
const char * node_namespace, | ||
const char * ros_secure_root_env, | ||
const rcutils_allocator_t * allocator | ||
); | ||
|
||
security_lookup_fn_t g_security_lookup_fns[] = { | ||
NULL, | ||
exact_match_lookup, | ||
prefix_match_lookup, | ||
}; | ||
|
||
typedef enum ros_security_lookup_type_e | ||
{ | ||
ROS_SECURITY_LOOKUP_NODE_OVERRIDE = 0, | ||
ROS_SECURITY_LOOKUP_MATCH_EXACT = 1, | ||
ROS_SECURITY_LOOKUP_MATCH_PREFIX = 2, | ||
} ros_security_lookup_type_t; | ||
|
||
char * g_security_lookup_type_strings[] = { | ||
"NODE_OVERRIDE", | ||
"MATCH_EXACT", | ||
"MATCH_PREFIX" | ||
}; | ||
|
||
/// Return the directory whose name most closely matches node_name (longest-prefix match), | ||
/// scanning under base_dir. | ||
/** | ||
* By using a prefix match, a node named e.g. "my_node_123" will be able to load and use the | ||
* directory "my_node" if no better match exists. | ||
* \param[in] base_dir | ||
* \param[in] node_name | ||
* \param[out] matched_name must be a valid memory address allocated with at least | ||
* _TINYDIR_FILENAME_MAX characters. | ||
* \return true if a match was found | ||
*/ | ||
static bool get_best_matching_directory( | ||
const char * base_dir, | ||
const char * node_name, | ||
char * matched_name) | ||
{ | ||
#ifdef RCUTILS_NO_FILESYSTEM | ||
RCUTILS_SET_ERROR_MSG("not available filesystem"); | ||
return false; | ||
#else | ||
size_t max_match_length = 0; | ||
tinydir_dir dir; | ||
if (NULL == base_dir || NULL == node_name || NULL == matched_name) { | ||
return false; | ||
} | ||
if (-1 == tinydir_open(&dir, base_dir)) { | ||
return false; | ||
} | ||
while (dir.has_next) { | ||
tinydir_file file; | ||
if (-1 == tinydir_readfile(&dir, &file)) { | ||
goto cleanup; | ||
} | ||
if (file.is_dir) { | ||
size_t matched_name_length = strnlen(file.name, sizeof(file.name) - 1); | ||
if (0 == | ||
strncmp(file.name, node_name, | ||
matched_name_length) && matched_name_length > max_match_length) | ||
{ | ||
max_match_length = matched_name_length; | ||
memcpy(matched_name, file.name, max_match_length); | ||
} | ||
} | ||
if (-1 == tinydir_next(&dir)) { | ||
goto cleanup; | ||
} | ||
} | ||
cleanup: | ||
tinydir_close(&dir); | ||
return max_match_length > 0; | ||
#endif // _RCUTILS_NO_FILESYSTEM | ||
} | ||
|
||
char * exact_match_lookup( | ||
const char * node_name, | ||
const char * node_namespace, | ||
const char * ros_secure_root_env, | ||
const rcutils_allocator_t * allocator) | ||
{ | ||
// Perform an exact match for the node's name in directory <root dir>/<namespace>. | ||
char * node_secure_root = NULL; | ||
// "/" case when root namespace is explicitly passed in | ||
if (1 == strlen(node_namespace)) { | ||
node_secure_root = rcutils_join_path(ros_secure_root_env, node_name, *allocator); | ||
} else { | ||
char * node_fqn = NULL; | ||
char * node_root_path = NULL; | ||
// Combine node namespace with node name | ||
// TODO(ros2team): remove the hard-coded value of the root namespace | ||
node_fqn = rcutils_format_string(*allocator, "%s%s%s", node_namespace, "/", node_name); | ||
// Get native path, ignore the leading forward slash | ||
// TODO(ros2team): remove the hard-coded length, use the length of the root namespace instead | ||
node_root_path = rcutils_to_native_path(node_fqn + 1, *allocator); | ||
node_secure_root = rcutils_join_path(ros_secure_root_env, node_root_path, *allocator); | ||
allocator->deallocate(node_fqn, allocator->state); | ||
allocator->deallocate(node_root_path, allocator->state); | ||
} | ||
return node_secure_root; | ||
} | ||
|
||
char * prefix_match_lookup( | ||
const char * node_name, | ||
const char * node_namespace, | ||
const char * ros_secure_root_env, | ||
const rcutils_allocator_t * allocator) | ||
{ | ||
#ifdef RCUTILS_NO_FILESYSTEM | ||
RCUTILS_SET_ERROR_MSG("not available filesystem"); | ||
return false; | ||
#else | ||
// Perform longest prefix match for the node's name in directory <root dir>/<namespace>. | ||
char * node_secure_root = NULL; | ||
char matched_dir[_TINYDIR_FILENAME_MAX] = {0}; | ||
char * base_lookup_dir = NULL; | ||
if (strlen(node_namespace) == 1) { | ||
base_lookup_dir = (char *) ros_secure_root_env; | ||
} else { | ||
// TODO(ros2team): remove the hard-coded length, use the length of the root namespace instead. | ||
base_lookup_dir = rcutils_join_path(ros_secure_root_env, node_namespace + 1, *allocator); | ||
} | ||
if (get_best_matching_directory(base_lookup_dir, node_name, matched_dir)) { | ||
node_secure_root = rcutils_join_path(base_lookup_dir, matched_dir, *allocator); | ||
} | ||
if (base_lookup_dir != ros_secure_root_env && NULL != base_lookup_dir) { | ||
allocator->deallocate(base_lookup_dir, allocator->state); | ||
} | ||
return node_secure_root; | ||
#endif // _RCUTILS_NO_FILESYSTEM | ||
} | ||
|
||
char * rcutils_get_secure_root( | ||
const char * node_name, | ||
const char * node_namespace, | ||
const rcutils_allocator_t * allocator) | ||
{ | ||
bool ros_secure_node_override = true; | ||
|
||
// find out if either of the configuration environment variables are set | ||
const char * env_buf = NULL; | ||
if (NULL == node_name) { | ||
return NULL; | ||
} | ||
if (rcutils_get_env(ROS_SECURITY_NODE_DIRECTORY_VAR_NAME, &env_buf)) { | ||
return NULL; | ||
} | ||
if (!env_buf) { | ||
return NULL; | ||
} | ||
size_t ros_secure_root_size = strlen(env_buf); | ||
if (!ros_secure_root_size) { | ||
// check root directory if node directory environment variable is empty | ||
if (rcutils_get_env(ROS_SECURITY_ROOT_DIRECTORY_VAR_NAME, &env_buf)) { | ||
return NULL; | ||
} | ||
if (!env_buf) { | ||
return NULL; | ||
} | ||
ros_secure_root_size = strlen(env_buf); | ||
if (!ros_secure_root_size) { | ||
return NULL; // environment variable was empty | ||
} else { | ||
ros_secure_node_override = false; | ||
} | ||
} | ||
|
||
// found a usable environment variable, copy into our memory before overwriting with next lookup | ||
char * ros_secure_root_env = | ||
(char *)allocator->allocate(ros_secure_root_size + 1, allocator->state); | ||
memcpy(ros_secure_root_env, env_buf, ros_secure_root_size + 1); | ||
// TODO(ros2team): This make an assumption on the value and length of the root namespace. | ||
// This should likely come from another (rcl/rmw?) function for reuse. | ||
// If the namespace is the root namespace ("/"), the secure root is just the node name. | ||
|
||
char * lookup_strategy = NULL; | ||
char * node_secure_root = NULL; | ||
if (ros_secure_node_override) { | ||
node_secure_root = (char *)allocator->allocate(ros_secure_root_size + 1, allocator->state); | ||
memcpy(node_secure_root, ros_secure_root_env, ros_secure_root_size + 1); | ||
lookup_strategy = g_security_lookup_type_strings[ROS_SECURITY_LOOKUP_NODE_OVERRIDE]; | ||
|
||
} else { | ||
// Check which lookup method to use and invoke the relevant function. | ||
const char * ros_security_lookup_type = NULL; | ||
if (rcutils_get_env(ROS_SECURITY_LOOKUP_TYPE_VAR_NAME, &ros_security_lookup_type)) { | ||
allocator->deallocate(ros_secure_root_env, allocator->state); | ||
return NULL; | ||
} | ||
if (0 == strcmp(ros_security_lookup_type, | ||
g_security_lookup_type_strings[ROS_SECURITY_LOOKUP_MATCH_PREFIX])) | ||
{ | ||
node_secure_root = g_security_lookup_fns[ROS_SECURITY_LOOKUP_MATCH_PREFIX] | ||
(node_name, node_namespace, ros_secure_root_env, allocator); | ||
lookup_strategy = g_security_lookup_type_strings[ROS_SECURITY_LOOKUP_MATCH_PREFIX]; | ||
} else { /* Default is MATCH_EXACT */ | ||
node_secure_root = g_security_lookup_fns[ROS_SECURITY_LOOKUP_MATCH_EXACT] | ||
(node_name, node_namespace, ros_secure_root_env, allocator); | ||
lookup_strategy = g_security_lookup_type_strings[ROS_SECURITY_LOOKUP_MATCH_EXACT]; | ||
} | ||
} | ||
|
||
if (NULL == node_secure_root || !rcutils_is_directory(node_secure_root)) { | ||
// Check node_secure_root is not NULL before checking directory | ||
if (NULL == node_secure_root) { | ||
RCUTILS_SET_ERROR_MSG_WITH_FORMAT_STRING( | ||
"SECURITY ERROR: unable to find a folder matching the node name in %s%s." | ||
"Lookup strategy: %s", | ||
ros_secure_root_env, node_namespace, lookup_strategy); | ||
} else { | ||
RCUTILS_SET_ERROR_MSG_WITH_FORMAT_STRING( | ||
"SECURITY ERROR: directory %s does not exist. Lookup strategy: %s", | ||
node_secure_root, lookup_strategy); | ||
} | ||
allocator->deallocate(ros_secure_root_env, allocator->state); | ||
allocator->deallocate(node_secure_root, allocator->state); | ||
return NULL; | ||
} | ||
allocator->deallocate(ros_secure_root_env, allocator->state); | ||
return node_secure_root; | ||
} |
Empty file.
Oops, something went wrong.