binddynport.c honor ip_local_reserved_ports (RHEL-27005)
Signed-off-by: Steve Dickson <steved@redhat.com> Resolves: RHEL-27005
This commit is contained in:
parent
b1d2c0b914
commit
589b33251d
185
libtirpc-1.1.4-ip_local_reserved_ports.patch
Normal file
185
libtirpc-1.1.4-ip_local_reserved_ports.patch
Normal file
@ -0,0 +1,185 @@
|
||||
From 20148930201b732c5dd1003933dd70543d3e929d Mon Sep 17 00:00:00 2001
|
||||
From: Otto Hollmann <otto.hollmann@suse.com>
|
||||
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 <otto.hollmann@suse.com>
|
||||
Signed-off-by: Steve Dickson <steved@redhat.com>
|
||||
---
|
||||
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 <unistd.h>
|
||||
#include <errno.h>
|
||||
#include <string.h>
|
||||
+#include <syslog.h>
|
||||
|
||||
#include <rpc/rpc.h>
|
||||
|
||||
@@ -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
|
||||
|
@ -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 <steved@redhat.com> 1.1.4-12
|
||||
- binddynport.c honor ip_local_reserved_ports (RHEL-27005)
|
||||
|
||||
* Tue Mar 19 2024 Steve Dickson <steved@redhat.com> 1.1.4-11
|
||||
- rpcb_clnt.c (fixed): Eliminate double frees in delete_cache() (RHEL-11293)
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user