[lxc-devel] [lxc/master] network parser fixes

brauner on Github lxc-bot at linuxcontainers.org
Sun Jul 30 19:47:02 UTC 2017


A non-text attachment was scrubbed...
Name: not available
Type: text/x-mailbox
Size: 581 bytes
Desc: not available
URL: <http://lists.linuxcontainers.org/pipermail/lxc-devel/attachments/20170730/4bcd9671/attachment.bin>
-------------- next part --------------
From 31ee747baa110d3cea080005f773c786edacb3b1 Mon Sep 17 00:00:00 2001
From: Christian Brauner <christian.brauner at ubuntu.com>
Date: Sun, 30 Jul 2017 21:42:40 +0200
Subject: [PATCH 1/2] 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: Christian Brauner <christian.brauner at ubuntu.com>
---
 src/lxc/confile.c | 161 ++++++++++++++++++++++++++++++++++--------------------
 1 file changed, 102 insertions(+), 59 deletions(-)

diff --git a/src/lxc/confile.c b/src/lxc/confile.c
index 55917e8c4..858341952 100644
--- a/src/lxc/confile.c
+++ b/src/lxc/confile.c
@@ -3680,72 +3680,88 @@ static int get_config_includefiles(const char *key, char *retv, int inlen,
 	return -ENOSYS;
 }
 
-static struct lxc_config_t *
-get_network_config_ops(const char *key, struct lxc_conf *lxc_conf, ssize_t *idx)
+static struct lxc_config_t *get_network_config_ops(const char *key,
+						   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;
 	struct lxc_config_t *config = NULL;
 
 	/* 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;
+	}
 
 	copy = strdup(key);
-	if (!copy)
+	if (!copy) {
+		ERROR("Failed to duplicate string \"%s\"", key);
 		return NULL;
+	}
 
 	/* lxc.net.<n> */
-	if (isdigit(*(key + 8))) {
-		int ret;
-		unsigned int tmpidx;
-		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;
+	if (!isdigit(*(key + 8))) {
+		ERROR("Failed to detect digit in string \"%s\"", key + 8);
+		goto on_error;
+	}
 
-		numstrlen = strlen((idx_start + 1));
+	/* beginning of index string */
+	idx_start = (copy + 7);
+	*idx_start = '\0';
 
-		/* repair configuration key */
-		*idx_start = '.';
-		*idx_end = '.';
+	/* end of index string */
+	idx_end = strchr((copy + 8), '.');
+	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));
-		copy[strlen(key) - numstrlen + 1] = '\0';
+	/* 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));
+
+	/* 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);
-	if (!config)
+	if (!config) {
 		ERROR("unknown network configuration key %s", key);
+		goto on_error;
+	}
+
+	*deindexed_key = copy;
+	return config;
 
 on_error:
 	free(copy);
-	return config;
+	return NULL;
 }
 
 /*
@@ -3756,22 +3772,33 @@ get_network_config_ops(const char *key, struct lxc_conf *lxc_conf, ssize_t *idx)
 static int set_config_net_nic(const char *key, const char *value,
 			      struct lxc_conf *lxc_conf, void *data)
 {
+	int ret;
+	const char *idxstring;
 	struct lxc_config_t *config;
 	struct lxc_netdev *netdev;
 	ssize_t idx = -1;
+	char *deindexed_key = NULL;
+
+	idxstring = key + 8;
+	if (!isdigit(*idxstring))
+		return -1;
 
 	if (lxc_config_value_empty(value))
 		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)
 		return -1;
 
 	netdev = lxc_get_netdev_by_idx(lxc_conf, (unsigned int)idx, true);
-	if (!netdev)
+	if (!netdev) {
+		free(deindexed_key);
 		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,
 static int clr_config_net_nic(const char *key, struct lxc_conf *lxc_conf,
 			      void *data)
 {
+	int ret;
 	const char *idxstring;
 	struct lxc_config_t *config;
 	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. */
-	if (strncmp("lxc.net.", key, 8))
+	idxstring = key + 8;
+	if (!isdigit(*idxstring))
 		return -1;
 
-	idxstring = key + 8;
 	/* 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
 	 * supposed to clear the whole network.
 	 */
@@ -3808,15 +3836,19 @@ static int clr_config_net_nic(const char *key, struct lxc_conf *lxc_conf,
 		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)
 		return -1;
 
 	netdev = lxc_get_netdev_by_idx(lxc_conf, (unsigned int)idx, false);
-	if (!netdev)
+	if (!netdev) {
+		free(deindexed_key);
 		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,
@@ -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,
 			      struct lxc_conf *c, void *data)
 {
+	int ret;
+	const char *idxstring;
 	struct lxc_config_t *config;
 	struct lxc_netdev *netdev;
 	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)
 		return -1;
 
 	netdev = lxc_get_netdev_by_idx(c, (unsigned int)idx, false);
-	if (!netdev)
+	if (!netdev) {
+		free(deindexed_key);
 		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,

From 4222a9f44b57af51d140350160877a807eea96a6 Mon Sep 17 00:00:00 2001
From: Christian Brauner <christian.brauner at ubuntu.com>
Date: Sun, 30 Jul 2017 21:45:36 +0200
Subject: [PATCH 2/2] lxccontainer: clear whole indexed networks

Signed-off-by: Christian Brauner <christian.brauner at ubuntu.com>
---
 src/lxc/lxccontainer.c | 46 ++++++++++++++++++++++++++++++++++------------
 1 file changed, 34 insertions(+), 12 deletions(-)

diff --git a/src/lxc/lxccontainer.c b/src/lxc/lxccontainer.c
index fa04becb6..eba65a44a 100644
--- a/src/lxc/lxccontainer.c
+++ b/src/lxc/lxccontainer.c
@@ -50,6 +50,7 @@
 #include "commands_utils.h"
 #include "confile.h"
 #include "confile_legacy.h"
+#include "confile_utils.h"
 #include "console.h"
 #include "criu.h"
 #include "log.h"
@@ -1839,18 +1840,30 @@ static bool lxcapi_createl(struct lxc_container *c, const char *t,
 
 static void do_clear_unexp_config_line(struct lxc_conf *conf, const char *key)
 {
-	if (strcmp(key, "lxc.cgroup") == 0)
-		clear_unexp_config_line(conf, key, true);
-	else if (strcmp(key, "lxc.network") == 0)
-		clear_unexp_config_line(conf, key, true);
-	else if (strcmp(key, "lxc.net") == 0)
-		clear_unexp_config_line(conf, key, true);
-	else if (strcmp(key, "lxc.hook") == 0)
-		clear_unexp_config_line(conf, key, true);
-	else
-		clear_unexp_config_line(conf, key, false);
-	if (!do_append_unexp_config_line(conf, key, ""))
-		WARN("Error clearing configuration for %s", key);
+	if (!strcmp(key, "lxc.cgroup"))
+		return clear_unexp_config_line(conf, key, true);
+
+	if (!strcmp(key, "lxc.network"))
+		return clear_unexp_config_line(conf, key, true);
+
+	if (!strcmp(key, "lxc.net"))
+		return clear_unexp_config_line(conf, key, true);
+
+	/* Clear a network with a specific index. */
+	if (!strncmp(key, "lxc.net.", 8)) {
+		int ret;
+		const char *idx;
+
+		idx = key + 8;
+		ret = lxc_safe_uint(idx, &(unsigned int){0});
+		if (!ret)
+			return clear_unexp_config_line(conf, key, true);
+	}
+
+	if (!strcmp(key, "lxc.hook"))
+		return clear_unexp_config_line(conf, key, true);
+
+	return clear_unexp_config_line(conf, key, false);
 }
 
 static bool do_lxcapi_clear_config_item(struct lxc_container *c,
@@ -2656,13 +2669,22 @@ static bool set_config_item_locked(struct lxc_container *c, const char *key, con
 
 	if (!c->lxc_conf)
 		c->lxc_conf = lxc_conf_init();
+
 	if (!c->lxc_conf)
 		return false;
+
 	config = lxc_getconfig(key);
 	if (!config)
 		return false;
+
 	if (config->set(key, v, c->lxc_conf, NULL) != 0)
 		return false;
+
+	if (lxc_config_value_empty(v)) {
+		do_clear_unexp_config_line(c->lxc_conf, key);
+		return true;
+	}
+
 	return do_append_unexp_config_line(c->lxc_conf, key, v);
 }
 


More information about the lxc-devel mailing list