Reject path which isn't by-id link
Check if path passed to core adding or cache starting is by-id link otherwise do not allow to use it except it is exported object's path. Do not resolve device's by-id path during core addition or cache starting. Signed-off-by: Slawomir Jankowski <slawomir.jankowski@intel.com>
This commit is contained in:
parent
4799a2e788
commit
10e5e017c1
225
casadm/cas_lib.c
225
casadm/cas_lib.c
@ -36,6 +36,9 @@
|
|||||||
#include "safeclib/safe_lib.h"
|
#include "safeclib/safe_lib.h"
|
||||||
#include <cas_ioctl_codes.h>
|
#include <cas_ioctl_codes.h>
|
||||||
#include "psort.h"
|
#include "psort.h"
|
||||||
|
#include <libgen.h>
|
||||||
|
#include <regex.h>
|
||||||
|
|
||||||
#define PRINT_STAT(x) header->cmd_input.cache_stats.x
|
#define PRINT_STAT(x) header->cmd_input.cache_stats.x
|
||||||
|
|
||||||
#define CORE_ADD_MAX_TIMEOUT 30
|
#define CORE_ADD_MAX_TIMEOUT 30
|
||||||
@ -547,6 +550,42 @@ void print_slow_atomic_cache_start_info(const char *device_path)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Save to dest an absolute device file path of src.
|
||||||
|
* Return number of characters copied to dest if succeed, negative value if failed.
|
||||||
|
*/
|
||||||
|
static int get_abs_path(char* dest, size_t dest_len, const char* src, size_t src_len)
|
||||||
|
{
|
||||||
|
int path_len = -FAILURE;
|
||||||
|
char *dir_name, *dev_name;
|
||||||
|
char *dev = strndup(src, src_len); // strdup creates hidden malloc
|
||||||
|
if (!dev) // basename/dirname may modify the source and
|
||||||
|
goto dev_err; // segfault when called with a static string
|
||||||
|
|
||||||
|
char *dir = strndup(src, src_len);
|
||||||
|
if (!dir)
|
||||||
|
goto dir_err;
|
||||||
|
|
||||||
|
dir_name = realpath(dirname(dir), NULL); // realpath creates hidden malloc
|
||||||
|
if (!dir_name)
|
||||||
|
goto dir_name_err;
|
||||||
|
|
||||||
|
dev_name = basename(dev);
|
||||||
|
if (!dev_name)
|
||||||
|
goto dev_name_err;
|
||||||
|
|
||||||
|
path_len = snprintf(dest, dest_len, "%s/%s", dir_name, dev_name);
|
||||||
|
|
||||||
|
dev_name_err:
|
||||||
|
free(dir_name);
|
||||||
|
dir_name_err:
|
||||||
|
free(dir);
|
||||||
|
dir_err:
|
||||||
|
free(dev);
|
||||||
|
dev_err:
|
||||||
|
return path_len;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief get special device file path (/dev/sdX) for disk.
|
* @brief get special device file path (/dev/sdX) for disk.
|
||||||
*/
|
*/
|
||||||
@ -565,8 +604,64 @@ int get_dev_path(const char* disk, char* buf, size_t num)
|
|||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
int get_core_info(int fd, int cache_id, int core_id, struct kcas_core_info *info)
|
/* Indicate whether given path should be passed without check */
|
||||||
|
static bool is_dev_link_whitelisted(const char* path)
|
||||||
{
|
{
|
||||||
|
regex_t regex;
|
||||||
|
int result;
|
||||||
|
static const char* const whitelist[] = {"/dev/cas[0-9]\\+-[0-9]\\+$"};
|
||||||
|
static const unsigned count = ARRAY_SIZE(whitelist);
|
||||||
|
size_t i;
|
||||||
|
|
||||||
|
for (i = 0; i < count; i++) {
|
||||||
|
result = regcomp(®ex, whitelist[i], REG_NOSUB);
|
||||||
|
if (result)
|
||||||
|
return FAILURE;
|
||||||
|
|
||||||
|
result = regexec(®ex, path, 0, NULL, 0);
|
||||||
|
regfree(®ex);
|
||||||
|
if (!result) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int _is_by_id_path(const char* dev_path)
|
||||||
|
{
|
||||||
|
static const char dev_by_id_dir[] = "/dev/disk/by-id";
|
||||||
|
|
||||||
|
return (!strncmp(dev_path, dev_by_id_dir,
|
||||||
|
strnlen_s(dev_by_id_dir, sizeof(dev_by_id_dir))));
|
||||||
|
}
|
||||||
|
|
||||||
|
int set_device_path(char *dest_path, size_t dest_len, const char *src_path, size_t src_len)
|
||||||
|
{
|
||||||
|
char abs_dev_path[MAX_STR_LEN];
|
||||||
|
int result;
|
||||||
|
|
||||||
|
/* save given path as absolute path in temporary variable */
|
||||||
|
if (get_abs_path(abs_dev_path, sizeof(abs_dev_path), src_path, src_len) < 0)
|
||||||
|
return FAILURE;
|
||||||
|
|
||||||
|
/* check if given dev_path is whitelisted and then pass it as path or not */
|
||||||
|
if (is_dev_link_whitelisted(abs_dev_path)){
|
||||||
|
result = strncpy_s(dest_path, dest_len, abs_dev_path,
|
||||||
|
strnlen_s(abs_dev_path, sizeof(abs_dev_path)));
|
||||||
|
return result ?: SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (_is_by_id_path(abs_dev_path)) {
|
||||||
|
result = strncpy_s(dest_path, dest_len, abs_dev_path,
|
||||||
|
strnlen_s(abs_dev_path, sizeof(abs_dev_path)));
|
||||||
|
if (!result)
|
||||||
|
return SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
return FAILURE;
|
||||||
|
}
|
||||||
|
|
||||||
memset(info, 0, sizeof(*info));
|
memset(info, 0, sizeof(*info));
|
||||||
info->cache_id = cache_id;
|
info->cache_id = cache_id;
|
||||||
info->core_id = core_id;
|
info->core_id = core_id;
|
||||||
@ -713,8 +808,11 @@ struct cache_device *get_cache_device(const struct kcas_cache_info *info)
|
|||||||
cache->expected_core_count = info->info.core_count;
|
cache->expected_core_count = info->info.core_count;
|
||||||
cache->id = cache_id;
|
cache->id = cache_id;
|
||||||
cache->state = info->info.state;
|
cache->state = info->info.state;
|
||||||
strncpy_s(cache->device, sizeof(cache->device), info->cache_path_name,
|
if (set_device_path(cache->device, sizeof(cache->device), info->cache_path_name,
|
||||||
strnlen_s(info->cache_path_name, sizeof(info->cache_path_name)));
|
sizeof(info->cache_path_name)) != SUCCESS) {
|
||||||
|
free(cache);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
cache->mode = info->info.cache_mode;
|
cache->mode = info->info.cache_mode;
|
||||||
cache->dirty = info->info.dirty;
|
cache->dirty = info->info.dirty;
|
||||||
cache->flushed = info->info.flushed;
|
cache->flushed = info->info.flushed;
|
||||||
@ -928,11 +1026,13 @@ int start_cache(uint16_t cache_id, unsigned int cache_init,
|
|||||||
|
|
||||||
cmd.cache_id = cache_id;
|
cmd.cache_id = cache_id;
|
||||||
cmd.init_cache = cache_init;
|
cmd.init_cache = cache_init;
|
||||||
strncpy_s(cmd.cache_path_name,
|
if (set_device_path(cmd.cache_path_name, sizeof(cmd.cache_path_name),
|
||||||
sizeof(cmd.cache_path_name),
|
cache_device, MAX_STR_LEN) != SUCCESS) {
|
||||||
cache_device,
|
cas_printf(LOG_ERR, "Please use correct by-id path to the device "
|
||||||
strnlen_s(cache_device,
|
"%s.\n", cache_device);
|
||||||
sizeof(cmd.cache_path_name)));
|
close(fd);
|
||||||
|
return FAILURE;
|
||||||
|
}
|
||||||
cmd.caching_mode = cache_mode;
|
cmd.caching_mode = cache_mode;
|
||||||
cmd.eviction_policy = eviction_policy_type;
|
cmd.eviction_policy = eviction_policy_type;
|
||||||
cmd.line_size = line_size;
|
cmd.line_size = line_size;
|
||||||
@ -1619,103 +1719,6 @@ int illegal_recursive_core(unsigned int cache_id, const char *core_device, int c
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Indicate whether given entry in /dev/disk/by-id should be ignored -
|
|
||||||
we ignore software created links like 'lvm-' since these can point to
|
|
||||||
both CAS exported object and core device depending on initialization order.
|
|
||||||
*/
|
|
||||||
static bool dev_link_blacklisted(const char* entry)
|
|
||||||
{
|
|
||||||
static const char* const prefix_blacklist[] = {"lvm", "md-name"};
|
|
||||||
static const unsigned count = ARRAY_SIZE(prefix_blacklist);
|
|
||||||
const char* curr;
|
|
||||||
unsigned i;
|
|
||||||
|
|
||||||
for (i = 0; i < count; i++) {
|
|
||||||
curr = prefix_blacklist[i];
|
|
||||||
if (!strncmp(entry, curr, strnlen_s(curr, MAX_STR_LEN)))
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* get device link starting with /dev/disk/by-id */
|
|
||||||
static int get_dev_link(const char* disk, char* buf, size_t num)
|
|
||||||
{
|
|
||||||
static const char dev_by_id_dir[] = "/dev/disk/by-id";
|
|
||||||
int err;
|
|
||||||
struct dirent *entry;
|
|
||||||
DIR* dir;
|
|
||||||
char disk_dev[MAX_STR_LEN]; /* input disk device file */
|
|
||||||
char dev_by_id[MAX_STR_LEN]; /* current device path by id */
|
|
||||||
char curr_dev[MAX_STR_LEN]; /* current device file - compared against disk_dev[] */
|
|
||||||
int n;
|
|
||||||
|
|
||||||
dir = opendir(dev_by_id_dir);
|
|
||||||
if (!dir) {
|
|
||||||
/* no disk available by id? */
|
|
||||||
cas_printf(LOG_WARNING, "Unable to open disk alias directory.\n");
|
|
||||||
return FAILURE;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (get_dev_path(disk, disk_dev, sizeof(disk_dev))) {
|
|
||||||
err = FAILURE;
|
|
||||||
goto close_dir;
|
|
||||||
}
|
|
||||||
|
|
||||||
err = FAILURE;
|
|
||||||
while (err != SUCCESS && (entry = readdir(dir))) {
|
|
||||||
/* check if link is blacklisted */
|
|
||||||
if (dev_link_blacklisted(entry->d_name))
|
|
||||||
continue;
|
|
||||||
|
|
||||||
/* construct device-by-id path for current device */
|
|
||||||
n = snprintf(dev_by_id, sizeof(dev_by_id), "%s/%s",
|
|
||||||
dev_by_id_dir, entry->d_name);
|
|
||||||
if (n < 0 || n >= sizeof(dev_by_id)) {
|
|
||||||
cas_printf(LOG_WARNING,
|
|
||||||
"Error constructing disk device by-link path.\n");
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
/* get device path for current device */
|
|
||||||
if (get_dev_path(dev_by_id, curr_dev, sizeof(curr_dev))) {
|
|
||||||
/* it's normal to have stale links in /dev/ - no log */
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
/* compare current device path against disk device path */
|
|
||||||
if (!strncmp(disk_dev, curr_dev, sizeof(curr_dev))) {
|
|
||||||
if (n >= num) {
|
|
||||||
cas_printf(LOG_WARNING, "Buffer to short to store device link.\n");
|
|
||||||
} else {
|
|
||||||
strncpy_s(buf, num, dev_by_id, sizeof(dev_by_id));
|
|
||||||
err = SUCCESS;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
close_dir:
|
|
||||||
closedir(dir);
|
|
||||||
|
|
||||||
return err;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int set_core_path(char *path, const char *core_device, size_t len)
|
|
||||||
{
|
|
||||||
/* attempt to get disk device path by id */
|
|
||||||
if (get_dev_link(core_device, path, len) == SUCCESS)
|
|
||||||
return SUCCESS;
|
|
||||||
|
|
||||||
/* .. if this failed, try to get standard /dev/sd* path */
|
|
||||||
if (get_dev_path(core_device, path, len) == SUCCESS)
|
|
||||||
return SUCCESS;
|
|
||||||
|
|
||||||
/* if everything else failed - fall back to user-provided path */
|
|
||||||
if (!strncpy_s(path, len, core_device, strnlen_s(core_device, MAX_STR_LEN)))
|
|
||||||
return SUCCESS;
|
|
||||||
|
|
||||||
return FAILURE;
|
|
||||||
}
|
|
||||||
|
|
||||||
int add_core(unsigned int cache_id, unsigned int core_id, const char *core_device,
|
int add_core(unsigned int cache_id, unsigned int core_id, const char *core_device,
|
||||||
int try_add, int update_path)
|
int try_add, int update_path)
|
||||||
{
|
{
|
||||||
@ -1745,7 +1748,8 @@ int add_core(unsigned int cache_id, unsigned int core_id, const char *core_devic
|
|||||||
}
|
}
|
||||||
|
|
||||||
memset(&cmd, 0, sizeof(cmd));
|
memset(&cmd, 0, sizeof(cmd));
|
||||||
if (set_core_path(cmd.core_path_name, core_device, MAX_STR_LEN) != SUCCESS) {
|
if (set_device_path(cmd.core_path_name, sizeof(cmd.core_path_name),
|
||||||
|
core_device, MAX_STR_LEN) != SUCCESS) {
|
||||||
cas_printf(LOG_ERR, "Failed to copy core path\n");
|
cas_printf(LOG_ERR, "Failed to copy core path\n");
|
||||||
return FAILURE;
|
return FAILURE;
|
||||||
}
|
}
|
||||||
@ -1893,7 +1897,8 @@ int core_pool_remove(const char *core_device)
|
|||||||
if (fd == -1)
|
if (fd == -1)
|
||||||
return FAILURE;
|
return FAILURE;
|
||||||
|
|
||||||
if (set_core_path(cmd.core_path_name, core_device, MAX_STR_LEN) != SUCCESS) {
|
if (set_device_path(cmd.core_path_name, sizeof(cmd.core_path_name),
|
||||||
|
core_device, MAX_STR_LEN) != SUCCESS) {
|
||||||
cas_printf(LOG_ERR, "Failed to copy core path\n");
|
cas_printf(LOG_ERR, "Failed to copy core path\n");
|
||||||
close(fd);
|
close(fd);
|
||||||
return FAILURE;
|
return FAILURE;
|
||||||
@ -2786,8 +2791,10 @@ int _check_cache_device(const char *device_path,
|
|||||||
{
|
{
|
||||||
int result, fd;
|
int result, fd;
|
||||||
|
|
||||||
strncpy_s(cmd_info->path_name, sizeof(cmd_info->path_name), device_path,
|
if (set_device_path(cmd_info->path_name, sizeof(cmd_info->path_name),
|
||||||
strnlen_s(device_path, sizeof(cmd_info->path_name)));
|
device_path, MAX_STR_LEN) != SUCCESS) {
|
||||||
|
return FAILURE;
|
||||||
|
}
|
||||||
|
|
||||||
fd = open_ctrl_device();
|
fd = open_ctrl_device();
|
||||||
if (fd == -1)
|
if (fd == -1)
|
||||||
|
@ -298,6 +298,17 @@ void print_err(int error_code);
|
|||||||
*/
|
*/
|
||||||
int get_dev_path(const char* disk, char* buf, size_t num);
|
int get_dev_path(const char* disk, char* buf, size_t num);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief make sure device link is unique and write sanitized version to \a dest_path
|
||||||
|
*
|
||||||
|
* @param[in] src_path link to device
|
||||||
|
* @param[in] src_len length of \a src_path
|
||||||
|
* @param[in] dest_len max length of \a dest_path
|
||||||
|
* @param[out] dest_path sanitized absolute path
|
||||||
|
* @return 0 on success, nonzero on failure
|
||||||
|
*/
|
||||||
|
int set_device_path(char *dest_path, size_t dest_len, const char *src_path, size_t src_len);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief convert string to int
|
* @brief convert string to int
|
||||||
*/
|
*/
|
||||||
|
Loading…
Reference in New Issue
Block a user