mirror of
https://github.com/opnsense/src.git
synced 2026-06-08 16:22:46 -04:00
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
This commit is contained in:
parent
3c3e1b0a98
commit
855acb84ca
7 changed files with 57 additions and 55 deletions
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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 *sopt, void *buf)
|
|||
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);
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
||||
|
|
|
|||
Loading…
Reference in a new issue