diff --git a/libtirpc-1.1.4-ip_local_reserved_ports.patch b/libtirpc-1.1.4-ip_local_reserved_ports.patch new file mode 100644 index 0000000..5b41f39 --- /dev/null +++ b/libtirpc-1.1.4-ip_local_reserved_ports.patch @@ -0,0 +1,185 @@ +From 20148930201b732c5dd1003933dd70543d3e929d Mon Sep 17 00:00:00 2001 +From: Otto Hollmann +Date: Sat, 7 Oct 2023 03:48:22 -0400 +Subject: [PATCH] binddynport.c honor ip_local_reserved_ports + +Read reserved ports from /proc/sys/net/ipv4/ip_local_reserved_ports, +store them into bit-wise array and before binding to random port check +if port is not reserved. + +Currently, there is no way how to reserve ports so then will not be +used by rpcbind. + +Random ports are opened by rpcbind because of rmtcalls. There is +compile-time flag for disabling them, but in some cases we can not +simply disable them. + +One solution would be run time option --enable-rmtcalls as already +discussed, but it was rejected. So if we want to keep rmtcalls enabled +and also be able to reserve some ports, there is no other way than +filtering available ports. The easiest and clearest way seems to be +just respect kernel list of ip_reserved_ports. + +Unfortunately there is one known disadvantage/side effect - it affects +probability of ports which are right after reserved ones. The bigger +reserved block is, the higher is probability of selecting following +unreserved port. But if there is no reserved port, impact of this patch +is minimal/none. + +Signed-off-by: Otto Hollmann +Signed-off-by: Steve Dickson +--- + src/binddynport.c | 108 ++++++++++++++++++++++++++++++++++++++++++---- + 1 file changed, 100 insertions(+), 8 deletions(-) + +diff --git a/src/binddynport.c b/src/binddynport.c +index 062629a..c2e9a20 100644 +--- a/src/binddynport.c ++++ b/src/binddynport.c +@@ -37,6 +37,7 @@ + #include + #include + #include ++#include + + #include + +@@ -56,6 +57,84 @@ enum { + NPORTS = ENDPORT - LOWPORT + 1, + }; + ++/* ++ * This function decodes information about given port from provided array and ++ * return if port is reserved or not. ++ * ++ * @reserved_ports an array of size at least "NPORTS / (8*sizeof(char)) + 1". ++ * @port port number within range LOWPORT and ENDPORT ++ * ++ * Returns 0 if port is not reserved, non-negative if port is reserved. ++ */ ++static int is_reserved(char *reserved_ports, int port) { ++ port -= LOWPORT; ++ if (port < 0 || port >= NPORTS) ++ return 0; ++ return reserved_ports[port/(8*sizeof(char))] & 1<<(port%(8*sizeof(char))); ++} ++ ++/* ++ * This function encodes information about given *reserved* port into provided ++ * array. Don't call this function for ports which are not reserved. ++ * ++ * @reserved_ports an array of size at least "NPORTS / (8*sizeof(char)) + 1". ++ * @port port number within range LOWPORT and ENDPORT ++ * ++ */ ++static void set_reserved(char *reserved_ports, int port) { ++ port -= LOWPORT; ++ if (port < 0 || port >= NPORTS) ++ return; ++ reserved_ports[port/(8*sizeof(char))] |= 1<<(port%(8*sizeof(char))); ++} ++ ++/* ++ * Parse local reserved ports obtained from ++ * /proc/sys/net/ipv4/ip_local_reserved_ports into bit array. ++ * ++ * @reserved_ports a zeroed array of size at least ++ * "NPORTS / (8*sizeof(char)) + 1". Will be used for bit-wise encoding of ++ * reserved ports. ++ * ++ * On each call, reserved ports are read from /proc and bit-wise stored into ++ * provided array ++ * ++ * Returns 0 on success, -1 on failure. ++ */ ++ ++static int parse_reserved_ports(char *reserved_ports) { ++ int from=0, to; ++ char delimiter = ','; ++ int res; ++ FILE * file_ptr = fopen("/proc/sys/net/ipv4/ip_local_reserved_ports","r"); ++ if (file_ptr == NULL) { ++ (void) syslog(LOG_ERR, ++ "Unable to open open /proc/sys/net/ipv4/ip_local_reserved_ports."); ++ return -1; ++ } ++ do { ++ if ((res = fscanf(file_ptr, "%d", &to)) != 1) { ++ if (res == EOF) break; ++ goto err; ++ } ++ if (delimiter != '-') { ++ from = to; ++ } ++ for (int i = from; i <= to; ++i) { ++ set_reserved(reserved_ports, i); ++ } ++ } while ((res = fscanf(file_ptr, "%c", &delimiter)) == 1); ++ if (res != EOF) ++ goto err; ++ fclose(file_ptr); ++ return 0; ++err: ++ (void) syslog(LOG_ERR, ++ "An error occurred while parsing ip_local_reserved_ports."); ++ fclose(file_ptr); ++ return -1; ++} ++ + /* + * Bind a socket to a dynamically-assigned IP port. + * +@@ -81,7 +160,8 @@ int __binddynport(int fd) + in_port_t port, *portp; + struct sockaddr *sap; + socklen_t salen; +- int i, res; ++ int i, res, array_size; ++ char *reserved_ports = NULL; + + if (__rpc_sockisbound(fd)) + return 0; +@@ -119,21 +199,33 @@ int __binddynport(int fd) + gettimeofday(&tv, NULL); + seed = tv.tv_usec * getpid(); + } ++ array_size = NPORTS / (8*sizeof(char)) + 1; ++ reserved_ports = malloc(array_size); ++ if (!reserved_ports) { ++ goto out; ++ } ++ memset(reserved_ports, 0, array_size); ++ if (parse_reserved_ports(reserved_ports) < 0) ++ goto out; ++ + port = (rand_r(&seed) % NPORTS) + LOWPORT; + for (i = 0; i < NPORTS; ++i) { +- *portp = htons(port++); +- res = bind(fd, sap, salen); +- if (res >= 0) { +- res = 0; +- break; ++ *portp = htons(port); ++ if (!is_reserved(reserved_ports, port++)) { ++ res = bind(fd, sap, salen); ++ if (res >= 0) { ++ res = 0; ++ break; ++ } ++ if (errno != EADDRINUSE) ++ break; + } +- if (errno != EADDRINUSE) +- break; + if (port > ENDPORT) + port = LOWPORT; + } + + out: ++ free(reserved_ports); + mutex_unlock(&port_lock); + return res; + } +-- +2.40.1 + diff --git a/libtirpc.spec b/libtirpc.spec index 70ee635..c7ce28c 100644 --- a/libtirpc.spec +++ b/libtirpc.spec @@ -2,7 +2,7 @@ Name: libtirpc Version: 1.1.4 -Release: 11%{?dist} +Release: 12%{?dist} Summary: Transport Independent RPC Library Group: System Environment/Libraries License: SISSL and BSD @@ -53,6 +53,7 @@ Patch009: libtirpc-1.1.4-multithr-cleanup.patch Patch010: libtirpc-1.1.4-null-ptrs-not-reused.patch Patch011: libtirpc-1.1.4-double-free.patch Patch012: libtirpc-1.1.4-null-ptrs-not-reused-fixed.patch +Patch013: libtirpc-1.1.4-ip_local_reserved_ports.patch BuildRequires: automake, autoconf, libtool, pkgconfig BuildRequires: krb5-devel @@ -173,6 +174,9 @@ mv %{buildroot}%{_mandir}/man3 %{buildroot}%{_mandir}/man3t %{_mandir}/*/* %changelog +* Fri Apr 26 2024 Steve Dickson 1.1.4-12 +- binddynport.c honor ip_local_reserved_ports (RHEL-27005) + * Tue Mar 19 2024 Steve Dickson 1.1.4-11 - rpcb_clnt.c (fixed): Eliminate double frees in delete_cache() (RHEL-11293)