Blob Blame History Raw
netlabelctl: add additional validation code to the network address parser

From: Paul Moore <pmoore@redhat.com>

It is possible to use network masks with non-integer values or integer
values greater than the size of the network address, this patch fixes
this.

Signed-off-by: Paul Moore <pmoore@redhat.com>
---
 netlabelctl/main.c |   39 ++++++++++++++++++++++++++++++++++++---
 1 file changed, 36 insertions(+), 3 deletions(-)

diff --git a/netlabelctl/main.c b/netlabelctl/main.c
index 4479bbf..6c4ab7f 100644
--- a/netlabelctl/main.c
+++ b/netlabelctl/main.c
@@ -210,7 +210,30 @@ void nlctl_addr_print(const struct nlbl_netaddr *addr)
 }
 
 /**
- * Add a domain mapping to NetLabel
+ * Parse an unsigned interger number
+ * @param str the number string
+ * @param num pointer to number to return
+ *
+ * Parse an unsigned integer number string and returns the value in @num.
+ * Returns zero on success, negative values on failure.
+ *
+ */
+static int _nlctl_num_parse(char *str, uint32_t *num)
+{
+	char *spot = str;
+
+	while (*spot != '\0') {
+		if (*spot < '0' || *spot > '9')
+			return -EINVAL;
+		spot++;
+	}
+
+	*num = atoi(str);
+	return 0;
+}
+
+/**
+ * Parse a network address/mask pair
  * @param addr_str the IP address/mask in string format
  * @param addr the IP address/mask in native NetLabel format
  *
@@ -240,7 +263,12 @@ int nlctl_addr_parse(char *addr_str, struct nlbl_netaddr *addr)
 	ret_val = inet_pton(AF_INET, addr_str, &addr->addr.v4);
 	if (ret_val > 0) {
 		addr->type = AF_INET;
-		iter_a = (mask ? atoi(mask) : 32);
+		if (mask != NULL) {
+			ret_val = _nlctl_num_parse(mask, &iter_a);
+			if (ret_val < 0 || iter_a > 32)
+				return -EINVAL;
+		} else
+			iter_a = 32;
 		for (; iter_a > 0; iter_a--) {
 			addr->mask.v4.s_addr >>= 1;
 			addr->mask.v4.s_addr |= 0x80000000;
@@ -253,7 +281,12 @@ int nlctl_addr_parse(char *addr_str, struct nlbl_netaddr *addr)
 	ret_val = inet_pton(AF_INET6, addr_str, &addr->addr.v6);
 	if (ret_val > 0) {
 		addr->type = AF_INET6;
-		iter_a = (mask ? atoi(mask) : 128);
+		if (mask != NULL) {
+			ret_val = _nlctl_num_parse(mask, &iter_a);
+			if (ret_val < 0 || iter_a > 128)
+				return -EINVAL;
+		} else
+			iter_a = 128;
 		for (iter_b = 0; iter_a > 0 && iter_b < 4; iter_b++) {
 			for (; iter_a > 0 &&
 			       addr->mask.v6.s6_addr32[iter_b] < 0xffffffff;