--- /dev/null
+From 5310760af1d4fbea1452bfc77db5f9a680f7ae47 Mon Sep 17 00:00:00 2001
+From: Sishuai Gong <sishuai.system@gmail.com>
+Date: Thu, 10 Aug 2023 15:12:42 -0400
+Subject: ipvs: fix racy memcpy in proc_do_sync_threshold
+
+From: Sishuai Gong <sishuai.system@gmail.com>
+
+commit 5310760af1d4fbea1452bfc77db5f9a680f7ae47 upstream.
+
+When two threads run proc_do_sync_threshold() in parallel,
+data races could happen between the two memcpy():
+
+Thread-1 Thread-2
+memcpy(val, valp, sizeof(val));
+ memcpy(valp, val, sizeof(val));
+
+This race might mess up the (struct ctl_table *) table->data,
+so we add a mutex lock to serialize them.
+
+Fixes: 1da177e4c3f4 ("Linux-2.6.12-rc2")
+Link: https://lore.kernel.org/netdev/B6988E90-0A1E-4B85-BF26-2DAF6D482433@gmail.com/
+Signed-off-by: Sishuai Gong <sishuai.system@gmail.com>
+Acked-by: Simon Horman <horms@kernel.org>
+Acked-by: Julian Anastasov <ja@ssi.bg>
+Signed-off-by: Florian Westphal <fw@strlen.de>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ net/netfilter/ipvs/ip_vs_ctl.c | 4 ++++
+ 1 file changed, 4 insertions(+)
+
+--- a/net/netfilter/ipvs/ip_vs_ctl.c
++++ b/net/netfilter/ipvs/ip_vs_ctl.c
+@@ -1690,6 +1690,7 @@ static int
+ proc_do_sync_threshold(struct ctl_table *table, int write,
+ void __user *buffer, size_t *lenp, loff_t *ppos)
+ {
++ struct netns_ipvs *ipvs = table->extra2;
+ int *valp = table->data;
+ int val[2];
+ int rc;
+@@ -1699,6 +1700,7 @@ proc_do_sync_threshold(struct ctl_table
+ .mode = table->mode,
+ };
+
++ mutex_lock(&ipvs->sync_mutex);
+ memcpy(val, valp, sizeof(val));
+ rc = proc_dointvec(&tmp, write, buffer, lenp, ppos);
+ if (write) {
+@@ -1708,6 +1710,7 @@ proc_do_sync_threshold(struct ctl_table
+ else
+ memcpy(valp, val, sizeof(val));
+ }
++ mutex_unlock(&ipvs->sync_mutex);
+ return rc;
+ }
+
+@@ -3944,6 +3947,7 @@ static int __net_init ip_vs_control_net_
+ ipvs->sysctl_sync_threshold[0] = DEFAULT_SYNC_THRESHOLD;
+ ipvs->sysctl_sync_threshold[1] = DEFAULT_SYNC_PERIOD;
+ tbl[idx].data = &ipvs->sysctl_sync_threshold;
++ tbl[idx].extra2 = ipvs;
+ tbl[idx++].maxlen = sizeof(ipvs->sysctl_sync_threshold);
+ ipvs->sysctl_sync_refresh_period = DEFAULT_SYNC_REFRESH_PERIOD;
+ tbl[idx++].data = &ipvs->sysctl_sync_refresh_period;
--- /dev/null
+From 1b90af292e71b20d03b837d39406acfbdc5d4b2a Mon Sep 17 00:00:00 2001
+From: Junwei Hu <hujunwei4@huawei.com>
+Date: Thu, 1 Aug 2019 00:03:30 +0800
+Subject: ipvs: Improve robustness to the ipvs sysctl
+
+From: Junwei Hu <hujunwei4@huawei.com>
+
+commit 1b90af292e71b20d03b837d39406acfbdc5d4b2a upstream.
+
+The ipvs module parse the user buffer and save it to sysctl,
+then check if the value is valid. invalid value occurs
+over a period of time.
+Here, I add a variable, struct ctl_table tmp, used to read
+the value from the user buffer, and save only when it is valid.
+I delete proc_do_sync_mode and use extra1/2 in table for the
+proc_dointvec_minmax call.
+
+Fixes: f73181c8288f ("ipvs: add support for sync threads")
+Signed-off-by: Junwei Hu <hujunwei4@huawei.com>
+Acked-by: Julian Anastasov <ja@ssi.bg>
+Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
+[Julian: Backport by changing SYSCTL_ZERO/SYSCTL_ONE to zero/one]
+Signed-off-by: Julian Anastasov <ja@ssi.bg>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ net/netfilter/ipvs/ip_vs_ctl.c | 70 +++++++++++++++++++++--------------------
+ 1 file changed, 36 insertions(+), 34 deletions(-)
+
+--- a/net/netfilter/ipvs/ip_vs_ctl.c
++++ b/net/netfilter/ipvs/ip_vs_ctl.c
+@@ -1656,6 +1656,7 @@ static int ip_vs_zero_all(struct netns_i
+ #ifdef CONFIG_SYSCTL
+
+ static int zero;
++static int one = 1;
+ static int three = 3;
+
+ static int
+@@ -1667,12 +1668,18 @@ proc_do_defense_mode(struct ctl_table *t
+ int val = *valp;
+ int rc;
+
+- rc = proc_dointvec(table, write, buffer, lenp, ppos);
++ struct ctl_table tmp = {
++ .data = &val,
++ .maxlen = sizeof(int),
++ .mode = table->mode,
++ };
++
++ rc = proc_dointvec(&tmp, write, buffer, lenp, ppos);
+ if (write && (*valp != val)) {
+- if ((*valp < 0) || (*valp > 3)) {
+- /* Restore the correct value */
+- *valp = val;
++ if (val < 0 || val > 3) {
++ rc = -EINVAL;
+ } else {
++ *valp = val;
+ update_defense_level(ipvs);
+ }
+ }
+@@ -1686,33 +1693,20 @@ proc_do_sync_threshold(struct ctl_table
+ int *valp = table->data;
+ int val[2];
+ int rc;
++ struct ctl_table tmp = {
++ .data = &val,
++ .maxlen = table->maxlen,
++ .mode = table->mode,
++ };
+
+- /* backup the value first */
+ memcpy(val, valp, sizeof(val));
+-
+- rc = proc_dointvec(table, write, buffer, lenp, ppos);
+- if (write && (valp[0] < 0 || valp[1] < 0 ||
+- (valp[0] >= valp[1] && valp[1]))) {
+- /* Restore the correct value */
+- memcpy(valp, val, sizeof(val));
+- }
+- return rc;
+-}
+-
+-static int
+-proc_do_sync_mode(struct ctl_table *table, int write,
+- void __user *buffer, size_t *lenp, loff_t *ppos)
+-{
+- int *valp = table->data;
+- int val = *valp;
+- int rc;
+-
+- rc = proc_dointvec(table, write, buffer, lenp, ppos);
+- if (write && (*valp != val)) {
+- if ((*valp < 0) || (*valp > 1)) {
+- /* Restore the correct value */
+- *valp = val;
+- }
++ rc = proc_dointvec(&tmp, write, buffer, lenp, ppos);
++ if (write) {
++ if (val[0] < 0 || val[1] < 0 ||
++ (val[0] >= val[1] && val[1]))
++ rc = -EINVAL;
++ else
++ memcpy(valp, val, sizeof(val));
+ }
+ return rc;
+ }
+@@ -1725,12 +1719,18 @@ proc_do_sync_ports(struct ctl_table *tab
+ int val = *valp;
+ int rc;
+
+- rc = proc_dointvec(table, write, buffer, lenp, ppos);
++ struct ctl_table tmp = {
++ .data = &val,
++ .maxlen = sizeof(int),
++ .mode = table->mode,
++ };
++
++ rc = proc_dointvec(&tmp, write, buffer, lenp, ppos);
+ if (write && (*valp != val)) {
+- if (*valp < 1 || !is_power_of_2(*valp)) {
+- /* Restore the correct value */
++ if (val < 1 || !is_power_of_2(val))
++ rc = -EINVAL;
++ else
+ *valp = val;
+- }
+ }
+ return rc;
+ }
+@@ -1790,7 +1790,9 @@ static struct ctl_table vs_vars[] = {
+ .procname = "sync_version",
+ .maxlen = sizeof(int),
+ .mode = 0644,
+- .proc_handler = proc_do_sync_mode,
++ .proc_handler = proc_dointvec_minmax,
++ .extra1 = &zero,
++ .extra2 = &one,
+ },
+ {
+ .procname = "sync_ports",