svn commit: r342125 - in head/sys/netinet: . cc

Brooks Davis brooks at FreeBSD.org
Sat Dec 15 15:06:25 UTC 2018


Author: brooks
Date: Sat Dec 15 15:06:22 2018
New Revision: 342125
URL: https://svnweb.freebsd.org/changeset/base/342125

Log:
  Fix bugs in plugable CC algorithm and siftr sysctls.
  
  Use the sysctl_handle_int() handler to write out the old value and read
  the new value into a temporary variable. Use the temporary variable
  for any checks of values rather than using the CAST_PTR_INT() macro on
  req->newptr. The prior usage read directly from userspace memory if the
  sysctl() was called correctly. This is unsafe and doesn't work at all on
  some architectures (at least i386.)
  
  In some cases, the code could also be tricked into reading from kernel
  memory and leaking limited information about the contents or crashing
  the system. This was true for CDG, newreno, and siftr on all platforms
  and true for i386 in all cases. The impact of this bug is largest in
  VIMAGE jails which have been configured to allow writing to these
  sysctls.
  
  Per discussion with the security officer, we will not be issuing an
  advisory for this issue as root access and a non-default config are
  required to be impacted.
  
  Reviewed by:	markj, bz
  Discussed with:	gordon (security officer)
  MFC after:	3 days
  Security:	kernel information leak, local DoS (both require root)
  Differential Revision:	https://reviews.freebsd.org/D18443

Modified:
  head/sys/netinet/cc/cc_cdg.c
  head/sys/netinet/cc/cc_chd.c
  head/sys/netinet/cc/cc_dctcp.c
  head/sys/netinet/cc/cc_hd.c
  head/sys/netinet/cc/cc_newreno.c
  head/sys/netinet/cc/cc_vegas.c
  head/sys/netinet/siftr.c

Modified: head/sys/netinet/cc/cc_cdg.c
==============================================================================
--- head/sys/netinet/cc/cc_cdg.c	Sat Dec 15 14:58:45 2018	(r342124)
+++ head/sys/netinet/cc/cc_cdg.c	Sat Dec 15 15:06:22 2018	(r342125)
@@ -80,8 +80,6 @@ __FBSDID("$FreeBSD$");
 
 #define	CDG_VERSION "0.1"
 
-#define	CAST_PTR_INT(X) (*((int*)(X)))
-
 /* Private delay-gradient induced congestion control signal. */
 #define	CC_CDG_DELAY 0x01000000
 
@@ -358,22 +356,37 @@ cdg_cb_destroy(struct cc_var *ccv)
 static int
 cdg_beta_handler(SYSCTL_HANDLER_ARGS)
 {
+	int error;
+	uint32_t new;
 
-	if (req->newptr != NULL &&
-	    (CAST_PTR_INT(req->newptr) == 0 || CAST_PTR_INT(req->newptr) > 100))
-		return (EINVAL);
+	new = *(uint32_t *)arg1;
+	error = sysctl_handle_int(oidp, &new, 0, req);
+	if (error == 0 && req->newptr != NULL) {
+		if (new == 0 || new > 100)
+			error = EINVAL;
+		else
+			*(uint32_t *)arg1 = new;
+	}
 
-	return (sysctl_handle_int(oidp, arg1, arg2, req));
+	return (error);
 }
 
 static int
 cdg_exp_backoff_scale_handler(SYSCTL_HANDLER_ARGS)
 {
+	int error;
+	uint32_t new;
 
-	if (req->newptr != NULL && CAST_PTR_INT(req->newptr) < 1)
-		return (EINVAL);
+	new = *(uint32_t *)arg1;
+	error = sysctl_handle_int(oidp, &new, 0, req);
+	if (error == 0 && req->newptr != NULL) {
+		if (new < 1)
+			error = EINVAL;
+		else
+			*(uint32_t *)arg1 = new;
+	}
 
-	return (sysctl_handle_int(oidp, arg1, arg2, req));
+	return (error);
 }
 
 static inline uint32_t

Modified: head/sys/netinet/cc/cc_chd.c
==============================================================================
--- head/sys/netinet/cc/cc_chd.c	Sat Dec 15 14:58:45 2018	(r342124)
+++ head/sys/netinet/cc/cc_chd.c	Sat Dec 15 15:06:22 2018	(r342125)
@@ -78,8 +78,6 @@ __FBSDID("$FreeBSD$");
 
 #include <netinet/khelp/h_ertt.h>
 
-#define	CAST_PTR_INT(X)	(*((int*)(X)))
-
 /*
  * Private signal type for rate based congestion signal.
  * See <netinet/cc.h> for appropriate bit-range to use for private signals.
@@ -421,7 +419,7 @@ chd_loss_fair_handler(SYSCTL_HANDLER_ARGS)
 	new = V_chd_loss_fair;
 	error = sysctl_handle_int(oidp, &new, 0, req);
 	if (error == 0 && req->newptr != NULL) {
-		if (CAST_PTR_INT(req->newptr) > 1)
+		if (new > 1)
 			error = EINVAL;
 		else
 			V_chd_loss_fair = new;
@@ -439,8 +437,7 @@ chd_pmax_handler(SYSCTL_HANDLER_ARGS)
 	new = V_chd_pmax;
 	error = sysctl_handle_int(oidp, &new, 0, req);
 	if (error == 0 && req->newptr != NULL) {
-		if (CAST_PTR_INT(req->newptr) == 0 ||
-		    CAST_PTR_INT(req->newptr) > 100)
+		if (new == 0 || new > 100)
 			error = EINVAL;
 		else
 			V_chd_pmax = new;
@@ -458,7 +455,7 @@ chd_qthresh_handler(SYSCTL_HANDLER_ARGS)
 	new = V_chd_qthresh;
 	error = sysctl_handle_int(oidp, &new, 0, req);
 	if (error == 0 && req->newptr != NULL) {
-		if (CAST_PTR_INT(req->newptr) <= V_chd_qmin)
+		if (new <= V_chd_qmin)
 			error = EINVAL;
 		else
 			V_chd_qthresh = new;

Modified: head/sys/netinet/cc/cc_dctcp.c
==============================================================================
--- head/sys/netinet/cc/cc_dctcp.c	Sat Dec 15 14:58:45 2018	(r342124)
+++ head/sys/netinet/cc/cc_dctcp.c	Sat Dec 15 15:06:22 2018	(r342125)
@@ -56,8 +56,6 @@ __FBSDID("$FreeBSD$");
 #include <netinet/cc/cc.h>
 #include <netinet/cc/cc_module.h>
 
-#define	CAST_PTR_INT(X)	(*((int*)(X)))
-
 #define MAX_ALPHA_VALUE 1024
 VNET_DEFINE_STATIC(uint32_t, dctcp_alpha) = 0;
 #define V_dctcp_alpha	    VNET(dctcp_alpha)
@@ -400,7 +398,7 @@ dctcp_alpha_handler(SYSCTL_HANDLER_ARGS)
 	new = V_dctcp_alpha;
 	error = sysctl_handle_int(oidp, &new, 0, req);
 	if (error == 0 && req->newptr != NULL) {
-		if (CAST_PTR_INT(req->newptr) > 1)
+		if (new > 1)
 			error = EINVAL;
 		else {
 			if (new > MAX_ALPHA_VALUE)
@@ -422,7 +420,7 @@ dctcp_shift_g_handler(SYSCTL_HANDLER_ARGS)
 	new = V_dctcp_shift_g;
 	error = sysctl_handle_int(oidp, &new, 0, req);
 	if (error == 0 && req->newptr != NULL) {
-		if (CAST_PTR_INT(req->newptr) > 1)
+		if (new > 1)
 			error = EINVAL;
 		else
 			V_dctcp_shift_g = new;
@@ -440,7 +438,7 @@ dctcp_slowstart_handler(SYSCTL_HANDLER_ARGS)
 	new = V_dctcp_slowstart;
 	error = sysctl_handle_int(oidp, &new, 0, req);
 	if (error == 0 && req->newptr != NULL) {
-		if (CAST_PTR_INT(req->newptr) > 1)
+		if (new > 1)
 			error = EINVAL;
 		else
 			V_dctcp_slowstart = new;

Modified: head/sys/netinet/cc/cc_hd.c
==============================================================================
--- head/sys/netinet/cc/cc_hd.c	Sat Dec 15 14:58:45 2018	(r342124)
+++ head/sys/netinet/cc/cc_hd.c	Sat Dec 15 15:06:22 2018	(r342125)
@@ -79,8 +79,6 @@ __FBSDID("$FreeBSD$");
 
 #include <netinet/khelp/h_ertt.h>
 
-#define	CAST_PTR_INT(X)	(*((int*)(X)))
-
 /* Largest possible number returned by random(). */
 #define	RANDOM_MAX	INT_MAX
 
@@ -188,8 +186,7 @@ hd_pmax_handler(SYSCTL_HANDLER_ARGS)
 	new = V_hd_pmax;
 	error = sysctl_handle_int(oidp, &new, 0, req);
 	if (error == 0 && req->newptr != NULL) {
-		if (CAST_PTR_INT(req->newptr) == 0 ||
-		    CAST_PTR_INT(req->newptr) > 100)
+		if (new == 0 || new > 100)
 			error = EINVAL;
 		else
 			V_hd_pmax = new;
@@ -207,7 +204,7 @@ hd_qmin_handler(SYSCTL_HANDLER_ARGS)
 	new = V_hd_qmin;
 	error = sysctl_handle_int(oidp, &new, 0, req);
 	if (error == 0 && req->newptr != NULL) {
-		if (CAST_PTR_INT(req->newptr) > V_hd_qthresh)
+		if (new > V_hd_qthresh)
 			error = EINVAL;
 		else
 			V_hd_qmin = new;
@@ -225,8 +222,7 @@ hd_qthresh_handler(SYSCTL_HANDLER_ARGS)
 	new = V_hd_qthresh;
 	error = sysctl_handle_int(oidp, &new, 0, req);
 	if (error == 0 && req->newptr != NULL) {
-		if (CAST_PTR_INT(req->newptr) < 1 ||
-		    CAST_PTR_INT(req->newptr) < V_hd_qmin)
+		if (new == 0 || new < V_hd_qmin)
 			error = EINVAL;
 		else
 			V_hd_qthresh = new;

Modified: head/sys/netinet/cc/cc_newreno.c
==============================================================================
--- head/sys/netinet/cc/cc_newreno.c	Sat Dec 15 14:58:45 2018	(r342124)
+++ head/sys/netinet/cc/cc_newreno.c	Sat Dec 15 15:06:22 2018	(r342125)
@@ -79,8 +79,6 @@ __FBSDID("$FreeBSD$");
 static MALLOC_DEFINE(M_NEWRENO, "newreno data",
 	"newreno beta values");
 
-#define	CAST_PTR_INT(X) (*((int*)(X)))
-
 static void	newreno_cb_destroy(struct cc_var *ccv);
 static void	newreno_ack_received(struct cc_var *ccv, uint16_t type);
 static void	newreno_after_idle(struct cc_var *ccv);
@@ -364,15 +362,21 @@ newreno_ctl_output(struct cc_var *ccv, struct sockopt 
 static int
 newreno_beta_handler(SYSCTL_HANDLER_ARGS)
 {
+	int error;
+	uint32_t new;
 
-	if (req->newptr != NULL ) {
+	new = *(uint32_t *)arg1;
+	error = sysctl_handle_int(oidp, &new, 0, req);
+	if (error == 0 && req->newptr != NULL ) {
 		if (arg1 == &VNET_NAME(newreno_beta_ecn) && !V_cc_do_abe)
-			return (EACCES);
-		if (CAST_PTR_INT(req->newptr) <= 0 || CAST_PTR_INT(req->newptr) > 100)
-			return (EINVAL);
+			error = EACCES;
+		else if (new == 0 || new > 100)
+			error = EINVAL;
+		else
+			*(uint32_t *)arg1 = new;
 	}
 
-	return (sysctl_handle_int(oidp, arg1, arg2, req));
+	return (error);
 }
 
 SYSCTL_DECL(_net_inet_tcp_cc_newreno);

Modified: head/sys/netinet/cc/cc_vegas.c
==============================================================================
--- head/sys/netinet/cc/cc_vegas.c	Sat Dec 15 14:58:45 2018	(r342124)
+++ head/sys/netinet/cc/cc_vegas.c	Sat Dec 15 15:06:22 2018	(r342125)
@@ -79,8 +79,6 @@ __FBSDID("$FreeBSD$");
 
 #include <netinet/khelp/h_ertt.h>
 
-#define	CAST_PTR_INT(X)	(*((int*)(X)))
-
 /*
  * Private signal type for rate based congestion signal.
  * See <netinet/cc.h> for appropriate bit-range to use for private signals.
@@ -260,8 +258,7 @@ vegas_alpha_handler(SYSCTL_HANDLER_ARGS)
 	new = V_vegas_alpha;
 	error = sysctl_handle_int(oidp, &new, 0, req);
 	if (error == 0 && req->newptr != NULL) {
-		if (CAST_PTR_INT(req->newptr) < 1 ||
-		    CAST_PTR_INT(req->newptr) > V_vegas_beta)
+		if (new == 0 || new > V_vegas_beta)
 			error = EINVAL;
 		else
 			V_vegas_alpha = new;
@@ -279,8 +276,7 @@ vegas_beta_handler(SYSCTL_HANDLER_ARGS)
 	new = V_vegas_beta;
 	error = sysctl_handle_int(oidp, &new, 0, req);
 	if (error == 0 && req->newptr != NULL) {
-		if (CAST_PTR_INT(req->newptr) < 1 ||
-		    CAST_PTR_INT(req->newptr) < V_vegas_alpha)
+		if (new == 0 || new < V_vegas_alpha)
 			 error = EINVAL;
 		else
 			V_vegas_beta = new;

Modified: head/sys/netinet/siftr.c
==============================================================================
--- head/sys/netinet/siftr.c	Sat Dec 15 14:58:45 2018	(r342124)
+++ head/sys/netinet/siftr.c	Sat Dec 15 15:06:22 2018	(r342125)
@@ -152,8 +152,6 @@ __FBSDID("$FreeBSD$");
 #endif
 
 /* useful macros */
-#define CAST_PTR_INT(X) (*((int*)(X)))
-
 #define UPPER_SHORT(X)	(((X) & 0xFFFF0000) >> 16)
 #define LOWER_SHORT(X)	((X) & 0x0000FFFF)
 
@@ -1442,22 +1440,22 @@ siftr_manage_ops(uint8_t action)
 static int
 siftr_sysctl_enabled_handler(SYSCTL_HANDLER_ARGS)
 {
-	if (req->newptr == NULL)
-		goto skip;
+	int error;
+	uint32_t new;
 
-	/* If the value passed in isn't 0 or 1, return an error. */
-	if (CAST_PTR_INT(req->newptr) != 0 && CAST_PTR_INT(req->newptr) != 1)
-		return (1);
-
-	/* If we are changing state (0 to 1 or 1 to 0). */
-	if (CAST_PTR_INT(req->newptr) != siftr_enabled )
-		if (siftr_manage_ops(CAST_PTR_INT(req->newptr))) {
-			siftr_manage_ops(SIFTR_DISABLE);
-			return (1);
+	new = siftr_enabled;
+	error = sysctl_handle_int(oidp, &new, 0, req);
+	if (error != 0 && req->newptr != NULL) {
+		if (new > 1)
+			return (EINVAL);
+		else if (new != siftr_enabled) {
+			error = siftr_manage_ops(new);
+			if (error != 0)
+				siftr_manage_ops(SIFTR_DISABLE);
 		}
+	}
 
-skip:
-	return (sysctl_handle_int(oidp, arg1, arg2, req));
+	return (error);
 }
 
 


More information about the svn-src-head mailing list