]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
parse-helpers: allow port 0 for socket bind items
authornetworkException <git@nwex.de>
Thu, 4 Jan 2024 17:45:25 +0000 (18:45 +0100)
committerYu Watanabe <watanabe.yu+github@gmail.com>
Fri, 5 Jan 2024 23:27:14 +0000 (08:27 +0900)
This patch adds a new parameter to parse_ip_port_range, giving callers
the option to allow ranges to have their min be 0 instead of 1.

This is then used by parse_ip_ports_token, intern used by
parse_socket_bind_item to allow port 0 when restricting bind system
calls with SocketBindDeny / SocketBindAllow.

With this, users running server software written using the golang
standard library will be able to effectively sandbox their software,
albeit with a small loss in security protections by allowing the
process to bind on a random port in the
/proc/sys/net/ipv4/ip_local_port_range.

src/basic/parse-util.c
src/basic/parse-util.h
src/network/netdev/vxlan.c
src/network/networkd-routing-policy-rule.c
src/shared/parse-helpers.c
src/test/test-parse-helpers.c

index 0430e33e40df55e22c3773dda826252657430530..5971173915a30506cd671cc83a8f887b925d5c04 100644 (file)
@@ -691,7 +691,7 @@ int parse_ip_port(const char *s, uint16_t *ret) {
         return 0;
 }
 
-int parse_ip_port_range(const char *s, uint16_t *low, uint16_t *high) {
+int parse_ip_port_range(const char *s, uint16_t *low, uint16_t *high, bool allow_zero) {
         unsigned l, h;
         int r;
 
@@ -699,7 +699,10 @@ int parse_ip_port_range(const char *s, uint16_t *low, uint16_t *high) {
         if (r < 0)
                 return r;
 
-        if (l <= 0 || l > 65535 || h <= 0 || h > 65535)
+        if (l > 65535 || h > 65535)
+                return -EINVAL;
+
+        if (!allow_zero && (l == 0 || h == 0))
                 return -EINVAL;
 
         if (h < l)
index 1845f0a876f1aa00ef92aff9eac5b2b13e198d4c..c12988ef2049794b7ac69c095495b34a081ba3a5 100644 (file)
@@ -139,7 +139,7 @@ int parse_fractional_part_u(const char **s, size_t digits, unsigned *res);
 int parse_nice(const char *p, int *ret);
 
 int parse_ip_port(const char *s, uint16_t *ret);
-int parse_ip_port_range(const char *s, uint16_t *low, uint16_t *high);
+int parse_ip_port_range(const char *s, uint16_t *low, uint16_t *high, bool allow_zero);
 
 int parse_ip_prefix_length(const char *s, int *ret);
 
index b11fdbbd0de05741c015da6def203f4c7fc500c4..f333abc6c04f6aba61f052af2cb6f49b90a97a77 100644 (file)
@@ -289,7 +289,7 @@ int config_parse_port_range(
         VxLan *v = ASSERT_PTR(userdata);
         int r;
 
-        r = parse_ip_port_range(rvalue, &v->port_range.low, &v->port_range.high);
+        r = parse_ip_port_range(rvalue, &v->port_range.low, &v->port_range.high, /* allow_zero = */ false);
         if (r < 0)
                 log_syntax(unit, LOG_WARNING, filename, line, r,
                            "Failed to parse VXLAN port range '%s'. Port should be greater than 0 and less than 65535.", rvalue);
index 6324b044983649de1e9679022f73fa6dd4b78944..914e288aeccca924ffac3fc9a2dc957b94cb0d89 100644 (file)
@@ -1408,7 +1408,7 @@ int config_parse_routing_policy_rule_port_range(
         if (r < 0)
                 return log_oom();
 
-        r = parse_ip_port_range(rvalue, &low, &high);
+        r = parse_ip_port_range(rvalue, &low, &high, /* allow_zero = */ false);
         if (r < 0) {
                 log_syntax(unit, LOG_WARNING, filename, line, r, "Failed to parse routing policy rule port range '%s'", rvalue);
                 return 0;
index 9664b9c773bcbc23156fcffe3718fd5ced4aaa24..bad3af8ebf65df9cda10aa5daf8bafbc59a990fd 100644 (file)
@@ -102,6 +102,8 @@ static int parse_ip_ports_token(
                 uint16_t *nr_ports,
                 uint16_t *port_min) {
 
+        int r;
+
         assert(token);
         assert(nr_ports);
         assert(port_min);
@@ -110,7 +112,7 @@ static int parse_ip_ports_token(
                 *nr_ports = *port_min = 0;
         else {
                 uint16_t mn = 0, mx = 0;
-                int r = parse_ip_port_range(token, &mn, &mx);
+                r = parse_ip_port_range(token, &mn, &mx, /* allow_zero = */ true);
                 if (r < 0)
                         return r;
 
@@ -194,6 +196,7 @@ int parse_socket_bind_item(
         *ip_protocol = proto;
         *nr_ports = nr;
         *port_min = mn;
+
         return 0;
 }
 
index 052e2514f43849374fa4b13df21a40a65137a94b..49438713791fd2b39ca435da9cb8b5cfc94da0e5 100644 (file)
@@ -37,6 +37,7 @@ static void test_invalid_item(const char *str) {
 
 TEST(valid_items) {
         test_valid_item("any", AF_UNSPEC, 0, 0, 0);
+        test_valid_item("0-65535", AF_UNSPEC, 0, 0, 0);
         test_valid_item("ipv4", AF_INET, 0, 0, 0);
         test_valid_item("ipv6", AF_INET6, 0, 0, 0);
         test_valid_item("ipv4:any", AF_INET, 0, 0, 0);
@@ -45,6 +46,7 @@ TEST(valid_items) {
         test_valid_item("udp", AF_UNSPEC, IPPROTO_UDP, 0, 0);
         test_valid_item("tcp:any", AF_UNSPEC, IPPROTO_TCP, 0, 0);
         test_valid_item("udp:any", AF_UNSPEC, IPPROTO_UDP, 0, 0);
+        test_valid_item("0", AF_UNSPEC, 0, 1, 0);
         test_valid_item("6666", AF_UNSPEC, 0, 1, 6666);
         test_valid_item("6666-6667", AF_UNSPEC, 0, 2, 6666);
         test_valid_item("65535", AF_UNSPEC, 0, 1, 65535);
@@ -61,6 +63,7 @@ TEST(valid_items) {
         test_valid_item("ipv6:tcp:6666", AF_INET6, IPPROTO_TCP, 1, 6666);
         test_valid_item("ipv6:udp:6666-6667", AF_INET6, IPPROTO_UDP, 2, 6666);
         test_valid_item("ipv6:tcp:any", AF_INET6, IPPROTO_TCP, 0, 0);
+        test_valid_item("ipv6:tcp:0", AF_INET6, IPPROTO_TCP, 1, 0);
 }
 
 TEST(invalid_items) {
@@ -77,9 +80,7 @@ TEST(invalid_items) {
         test_invalid_item("ipv6::");
         test_invalid_item("ipv6:ipv6");
         test_invalid_item("ipv6:icmp");
-        test_invalid_item("ipv6:tcp:0");
         test_invalid_item("65536");
-        test_invalid_item("0-65535");
         test_invalid_item("ipv6:tcp:6666-6665");
         test_invalid_item("ipv6:tcp:6666-100000");
         test_invalid_item("ipv6::6666");