confile: use deindexed network keys

When we are passed a network key like "lxc.net.[i].ipv4.address" we need to make sure that we pass the deindexed key "lxc.net.ipv4.address" to the {get,clr,set} methods otherwise we'll end up in an endless loop. Signed-off-by: 's avatarChristian Brauner <christian.brauner@ubuntu.com>
parent da7a897e
...@@ -3680,72 +3680,88 @@ static int get_config_includefiles(const char *key, char *retv, int inlen, ...@@ -3680,72 +3680,88 @@ static int get_config_includefiles(const char *key, char *retv, int inlen,
return -ENOSYS; return -ENOSYS;
} }
static struct lxc_config_t * static struct lxc_config_t *get_network_config_ops(const char *key,
get_network_config_ops(const char *key, struct lxc_conf *lxc_conf, ssize_t *idx) struct lxc_conf *lxc_conf,
ssize_t *idx,
char **deindexed_key)
{ {
int ret;
unsigned int tmpidx;
size_t numstrlen;
char *copy, *idx_start, *idx_end; char *copy, *idx_start, *idx_end;
struct lxc_config_t *config = NULL; struct lxc_config_t *config = NULL;
/* check that this is a sensible network key */ /* check that this is a sensible network key */
if (strncmp("lxc.net.", key, 8)) if (strncmp("lxc.net.", key, 8)) {
ERROR("Invalid network configuration key \"%s\"", key);
return NULL; return NULL;
}
copy = strdup(key); copy = strdup(key);
if (!copy) if (!copy) {
ERROR("Failed to duplicate string \"%s\"", key);
return NULL; return NULL;
}
/* lxc.net.<n> */ /* lxc.net.<n> */
if (isdigit(*(key + 8))) { if (!isdigit(*(key + 8))) {
int ret; ERROR("Failed to detect digit in string \"%s\"", key + 8);
unsigned int tmpidx; goto on_error;
size_t numstrlen; }
/* beginning of index string */
idx_start = (copy + 7);
*idx_start = '\0';
/* end of index string */
idx_end = strchr((copy + 8), '.');
if (!idx_end)
goto on_error;
*idx_end = '\0';
/* parse current index */
ret = lxc_safe_uint((idx_start + 1), &tmpidx);
if (ret < 0) {
*idx = ret;
goto on_error;
}
/* This, of course is utterly nonsensical on so many levels, but
* better safe than sorry.
* (Checking for INT_MAX here is intentional.)
*/
if (tmpidx == INT_MAX) {
SYSERROR(
"number of configured networks would overflow the "
"counter... what are you doing?");
goto on_error;
}
*idx = tmpidx;
numstrlen = strlen((idx_start + 1)); /* beginning of index string */
idx_start = (copy + 7);
*idx_start = '\0';
/* repair configuration key */ /* end of index string */
*idx_start = '.'; idx_end = strchr((copy + 8), '.');
*idx_end = '.'; if (!idx_end) {
ERROR("Failed to detect \".\" in string \"%s\"", (copy + 8));
goto on_error;
}
*idx_end = '\0';
/* parse current index */
ret = lxc_safe_uint((idx_start + 1), &tmpidx);
if (ret < 0) {
ERROR("Failed to parse usigned integer from string \"%s\": %s",
idx_start + 1, strerror(-ret));
*idx = ret;
goto on_error;
}
memmove(copy + 8, idx_end + 1, strlen(idx_end + 1)); /* This, of course is utterly nonsensical on so many levels, but
copy[strlen(key) - numstrlen + 1] = '\0'; * better safe than sorry.
* (Checking for INT_MAX here is intentional.)
*/
if (tmpidx == INT_MAX) {
SYSERROR("number of configured networks would overflow the "
"counter... what are you doing?");
goto on_error;
} }
*idx = tmpidx;
numstrlen = strlen((idx_start + 1));
/* repair configuration key */
*idx_start = '.';
*idx_end = '.';
memmove(copy + 8, idx_end + 1, strlen(idx_end + 1));
copy[strlen(key) - numstrlen + 1] = '\0';
config = lxc_getconfig(copy); config = lxc_getconfig(copy);
if (!config) if (!config) {
ERROR("unknown network configuration key %s", key); ERROR("unknown network configuration key %s", key);
goto on_error;
}
*deindexed_key = copy;
return config;
on_error: on_error:
free(copy); free(copy);
return config; return NULL;
} }
/* /*
...@@ -3756,22 +3772,33 @@ on_error: ...@@ -3756,22 +3772,33 @@ on_error:
static int set_config_net_nic(const char *key, const char *value, static int set_config_net_nic(const char *key, const char *value,
struct lxc_conf *lxc_conf, void *data) struct lxc_conf *lxc_conf, void *data)
{ {
int ret;
const char *idxstring;
struct lxc_config_t *config; struct lxc_config_t *config;
struct lxc_netdev *netdev; struct lxc_netdev *netdev;
ssize_t idx = -1; ssize_t idx = -1;
char *deindexed_key = NULL;
idxstring = key + 8;
if (!isdigit(*idxstring))
return -1;
if (lxc_config_value_empty(value)) if (lxc_config_value_empty(value))
return clr_config_net_nic(key, lxc_conf, data); return clr_config_net_nic(key, lxc_conf, data);
config = get_network_config_ops(key, lxc_conf, &idx); config = get_network_config_ops(key, lxc_conf, &idx, &deindexed_key);
if (!config || idx < 0) if (!config || idx < 0)
return -1; return -1;
netdev = lxc_get_netdev_by_idx(lxc_conf, (unsigned int)idx, true); netdev = lxc_get_netdev_by_idx(lxc_conf, (unsigned int)idx, true);
if (!netdev) if (!netdev) {
free(deindexed_key);
return -1; return -1;
}
return config->set(key, value, lxc_conf, netdev); ret = config->set(deindexed_key, value, lxc_conf, netdev);
free(deindexed_key);
return ret;
} }
/* /*
...@@ -3782,18 +3809,19 @@ static int set_config_net_nic(const char *key, const char *value, ...@@ -3782,18 +3809,19 @@ static int set_config_net_nic(const char *key, const char *value,
static int clr_config_net_nic(const char *key, struct lxc_conf *lxc_conf, static int clr_config_net_nic(const char *key, struct lxc_conf *lxc_conf,
void *data) void *data)
{ {
int ret;
const char *idxstring; const char *idxstring;
struct lxc_config_t *config; struct lxc_config_t *config;
struct lxc_netdev *netdev; struct lxc_netdev *netdev;
ssize_t idx; ssize_t idx = -1;
char *deindexed_key = NULL;
/* If we get passed "lxc.net.<n>" we clear the whole network. */ idxstring = key + 8;
if (strncmp("lxc.net.", key, 8)) if (!isdigit(*idxstring))
return -1; return -1;
idxstring = key + 8;
/* The left conjunct is pretty self-explanatory. The right conjunct /* The left conjunct is pretty self-explanatory. The right conjunct
* checks whether the two pointers are equal. If they are we now that * checks whether the two pointers are equal. If they are we know that
* this is not a key that is namespaced any further and so we are * this is not a key that is namespaced any further and so we are
* supposed to clear the whole network. * supposed to clear the whole network.
*/ */
...@@ -3808,15 +3836,19 @@ static int clr_config_net_nic(const char *key, struct lxc_conf *lxc_conf, ...@@ -3808,15 +3836,19 @@ static int clr_config_net_nic(const char *key, struct lxc_conf *lxc_conf,
return 0; return 0;
} }
config = get_network_config_ops(key, lxc_conf, &idx); config = get_network_config_ops(key, lxc_conf, &idx, &deindexed_key);
if (!config || idx < 0) if (!config || idx < 0)
return -1; return -1;
netdev = lxc_get_netdev_by_idx(lxc_conf, (unsigned int)idx, false); netdev = lxc_get_netdev_by_idx(lxc_conf, (unsigned int)idx, false);
if (!netdev) if (!netdev) {
free(deindexed_key);
return -1; return -1;
}
return config->clr(key, lxc_conf, netdev); ret = config->clr(deindexed_key, lxc_conf, netdev);
free(deindexed_key);
return ret;
} }
static int clr_config_net_type(const char *key, struct lxc_conf *lxc_conf, static int clr_config_net_type(const char *key, struct lxc_conf *lxc_conf,
...@@ -4099,19 +4131,30 @@ static int clr_config_net_ipv6_address(const char *key, ...@@ -4099,19 +4131,30 @@ static int clr_config_net_ipv6_address(const char *key,
static int get_config_net_nic(const char *key, char *retv, int inlen, static int get_config_net_nic(const char *key, char *retv, int inlen,
struct lxc_conf *c, void *data) struct lxc_conf *c, void *data)
{ {
int ret;
const char *idxstring;
struct lxc_config_t *config; struct lxc_config_t *config;
struct lxc_netdev *netdev; struct lxc_netdev *netdev;
ssize_t idx = -1; ssize_t idx = -1;
char *deindexed_key = NULL;
config = get_network_config_ops(key, c, &idx); idxstring = key + 8;
if (!isdigit(*idxstring))
return -1;
config = get_network_config_ops(key, c, &idx, &deindexed_key);
if (!config || idx < 0) if (!config || idx < 0)
return -1; return -1;
netdev = lxc_get_netdev_by_idx(c, (unsigned int)idx, false); netdev = lxc_get_netdev_by_idx(c, (unsigned int)idx, false);
if (!netdev) if (!netdev) {
free(deindexed_key);
return -1; return -1;
}
return config->get(key, retv, inlen, c, netdev); ret = config->get(deindexed_key, retv, inlen, c, netdev);
free(deindexed_key);
return ret;
} }
static int get_config_net_type(const char *key, char *retv, int inlen, static int get_config_net_type(const char *key, char *retv, int inlen,
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment