forked from rpms/kernel
		
	Sync patches with OL 4.18.0-477.21.1.el8_8
This commit is contained in:
		
							parent
							
								
									d4136628be
								
							
						
					
					
						commit
						ab8c284acb
					
				| @ -0,0 +1,77 @@ | |||||||
|  | From b19a194712d8f25e80d53803ccd0176f619b3fbc Mon Sep 17 00:00:00 2001 | ||||||
|  | From: Luiz Augusto von Dentz <luiz.von.dentz@intel.com> | ||||||
|  | Date: Tue, 8 Aug 2023 10:38:26 +0000 | ||||||
|  | Subject: [PATCH 1/7] Bluetooth: L2CAP: Fix accepting connection request for | ||||||
|  |  invalid SPSM | ||||||
|  | 
 | ||||||
|  | commit 711f8c3fb3db61897080468586b970c87c61d9e4 upstream | ||||||
|  | Author: Luiz Augusto von Dentz <luiz.von.dentz@intel.com> | ||||||
|  | Date:   Mon Oct 31 16:10:32 2022 -0700 | ||||||
|  | 
 | ||||||
|  |     Bluetooth: L2CAP: Fix accepting connection request for invalid SPSM | ||||||
|  | 
 | ||||||
|  |     The Bluetooth spec states that the valid range for SPSM is from | ||||||
|  |     0x0001-0x00ff so it is invalid to accept values outside of this range: | ||||||
|  | 
 | ||||||
|  |       BLUETOOTH CORE SPECIFICATION Version 5.3 | Vol 3, Part A | ||||||
|  |       page 1059: | ||||||
|  |       Table 4.15: L2CAP_LE_CREDIT_BASED_CONNECTION_REQ SPSM ranges | ||||||
|  | 
 | ||||||
|  |     CVE: CVE-2022-42896 | ||||||
|  |     CC: stable@vger.kernel.org | ||||||
|  |     Reported-by: Tamás Koczka <poprdi@google.com> | ||||||
|  |     Signed-off-by: Luiz Augusto von Dentz <luiz.von.dentz@intel.com> | ||||||
|  |     Reviewed-by: Tedd Ho-Jeong An <tedd.an@intel.com> | ||||||
|  | 
 | ||||||
|  | Signed-off-by: Nagappan Ramasamy Palaniappan <nagappan.ramasamy.palaniappan@oracle.com> | ||||||
|  | Reviewed-by: Laurence Rochfort <laurence.rochfort@oracle.com> | ||||||
|  | ---
 | ||||||
|  |  net/bluetooth/l2cap_core.c | 25 +++++++++++++++++++++++++ | ||||||
|  |  1 file changed, 25 insertions(+) | ||||||
|  | 
 | ||||||
|  | diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c
 | ||||||
|  | index 86ecd4ad4..4fed6d24a 100644
 | ||||||
|  | --- a/net/bluetooth/l2cap_core.c
 | ||||||
|  | +++ b/net/bluetooth/l2cap_core.c
 | ||||||
|  | @@ -5771,6 +5771,19 @@ static int l2cap_le_connect_req(struct l2cap_conn *conn,
 | ||||||
|  |  	BT_DBG("psm 0x%2.2x scid 0x%4.4x mtu %u mps %u", __le16_to_cpu(psm), | ||||||
|  |  	       scid, mtu, mps); | ||||||
|  |   | ||||||
|  | +	/* BLUETOOTH CORE SPECIFICATION Version 5.3 | Vol 3, Part A
 | ||||||
|  | +	 * page 1059:
 | ||||||
|  | +	 *
 | ||||||
|  | +	 * Valid range: 0x0001-0x00ff
 | ||||||
|  | +	 *
 | ||||||
|  | +	 * Table 4.15: L2CAP_LE_CREDIT_BASED_CONNECTION_REQ SPSM ranges
 | ||||||
|  | +	 */
 | ||||||
|  | +	if (!psm || __le16_to_cpu(psm) > L2CAP_PSM_LE_DYN_END) {
 | ||||||
|  | +		result = L2CAP_CR_LE_BAD_PSM;
 | ||||||
|  | +		chan = NULL;
 | ||||||
|  | +		goto response;
 | ||||||
|  | +	}
 | ||||||
|  | +
 | ||||||
|  |  	/* Check if we have socket listening on psm */ | ||||||
|  |  	pchan = l2cap_global_chan_by_psm(BT_LISTEN, psm, &conn->hcon->src, | ||||||
|  |  					 &conn->hcon->dst, LE_LINK); | ||||||
|  | @@ -5958,6 +5971,18 @@ static inline int l2cap_ecred_conn_req(struct l2cap_conn *conn,
 | ||||||
|  |   | ||||||
|  |  	psm  = req->psm; | ||||||
|  |   | ||||||
|  | +	/* BLUETOOTH CORE SPECIFICATION Version 5.3 | Vol 3, Part A
 | ||||||
|  | +	 * page 1059:
 | ||||||
|  | +	 *
 | ||||||
|  | +	 * Valid range: 0x0001-0x00ff
 | ||||||
|  | +	 *
 | ||||||
|  | +	 * Table 4.15: L2CAP_LE_CREDIT_BASED_CONNECTION_REQ SPSM ranges
 | ||||||
|  | +	 */
 | ||||||
|  | +	if (!psm || __le16_to_cpu(psm) > L2CAP_PSM_LE_DYN_END) {
 | ||||||
|  | +		result = L2CAP_CR_LE_BAD_PSM;
 | ||||||
|  | +		goto response;
 | ||||||
|  | +	}
 | ||||||
|  | +
 | ||||||
|  |  	BT_DBG("psm 0x%2.2x mtu %u mps %u", __le16_to_cpu(psm), mtu, mps); | ||||||
|  |   | ||||||
|  |  	memset(&pdu, 0, sizeof(pdu)); | ||||||
|  | -- 
 | ||||||
|  | 2.31.1 | ||||||
|  | 
 | ||||||
| @ -0,0 +1,113 @@ | |||||||
|  | From a11b8451e966830bb9aeaf27a9464fe0ab59907d Mon Sep 17 00:00:00 2001 | ||||||
|  | From: Jamal Hadi Salim <jhs@mojatatu.com> | ||||||
|  | Date: Tue, 8 Aug 2023 10:46:07 +0000 | ||||||
|  | Subject: [PATCH 2/7] net/sched: tcindex: update imperfect hash filters | ||||||
|  |  respecting rcu | ||||||
|  | 
 | ||||||
|  | commit ee059170b1f7e94e55fa6cadee544e176a6e59c2 upstream | ||||||
|  | Author: Pedro Tammela <pctammela@mojatatu.com> | ||||||
|  | Date:   Thu Feb 9 11:37:39 2023 -0300 | ||||||
|  | 
 | ||||||
|  |     net/sched: tcindex: update imperfect hash filters respecting rcu | ||||||
|  | 
 | ||||||
|  |     The imperfect hash area can be updated while packets are traversing, | ||||||
|  |     which will cause a use-after-free when 'tcf_exts_exec()' is called | ||||||
|  |     with the destroyed tcf_ext. | ||||||
|  | 
 | ||||||
|  |     CPU 0:               CPU 1: | ||||||
|  |     tcindex_set_parms    tcindex_classify | ||||||
|  |     tcindex_lookup | ||||||
|  |                          tcindex_lookup | ||||||
|  |     tcf_exts_change | ||||||
|  |                          tcf_exts_exec [UAF] | ||||||
|  | 
 | ||||||
|  |     Stop operating on the shared area directly, by using a local copy, | ||||||
|  |     and update the filter with 'rcu_replace_pointer()'. Delete the old | ||||||
|  |     filter version only after a rcu grace period elapsed. | ||||||
|  | 
 | ||||||
|  |     Fixes: 9b0d4446b569 ("net: sched: avoid atomic swap in tcf_exts_change") | ||||||
|  |     Reported-by: valis <sec@valis.email> | ||||||
|  |     Suggested-by: valis <sec@valis.email> | ||||||
|  |     Signed-off-by: Jamal Hadi Salim <jhs@mojatatu.com> | ||||||
|  |     Signed-off-by: Pedro Tammela <pctammela@mojatatu.com> | ||||||
|  |     Link: https://lore.kernel.org/r/20230209143739.279867-1-pctammela@mojatatu.com | ||||||
|  |     Signed-off-by: Jakub Kicinski <kuba@kernel.org> | ||||||
|  | 
 | ||||||
|  | CVE: CVE-2023-1281 | ||||||
|  | Signed-off-by: Nagappan Ramasamy Palaniappan <nagappan.ramasamy.palaniappan@oracle.com> | ||||||
|  | Reviewed-by: Reviewed-by: Venkat Venkatsubra <venkat.x.venkatsubra@oracle.com> | ||||||
|  | Reviewed-by: Laurence Rochfort <laurence.rochfort@oracle.com> | ||||||
|  | ---
 | ||||||
|  |  net/sched/cls_tcindex.c | 34 ++++++++++++++++++++++++++++++---- | ||||||
|  |  1 file changed, 30 insertions(+), 4 deletions(-) | ||||||
|  | 
 | ||||||
|  | diff --git a/net/sched/cls_tcindex.c b/net/sched/cls_tcindex.c
 | ||||||
|  | index df229a808..83042a101 100644
 | ||||||
|  | --- a/net/sched/cls_tcindex.c
 | ||||||
|  | +++ b/net/sched/cls_tcindex.c
 | ||||||
|  | @@ -11,6 +11,7 @@
 | ||||||
|  |  #include <linux/errno.h> | ||||||
|  |  #include <linux/slab.h> | ||||||
|  |  #include <linux/refcount.h> | ||||||
|  | +#include <linux/rcupdate.h>
 | ||||||
|  |  #include <net/act_api.h> | ||||||
|  |  #include <net/netlink.h> | ||||||
|  |  #include <net/pkt_cls.h> | ||||||
|  | @@ -337,6 +338,7 @@ tcindex_set_parms(struct net *net, struct tcf_proto *tp, unsigned long base,
 | ||||||
|  |  	struct tcf_result cr = {}; | ||||||
|  |  	int err, balloc = 0; | ||||||
|  |  	struct tcf_exts e; | ||||||
|  | +	bool update_h = false;
 | ||||||
|  |   | ||||||
|  |  	err = tcf_exts_init(&e, net, TCA_TCINDEX_ACT, TCA_TCINDEX_POLICE); | ||||||
|  |  	if (err < 0) | ||||||
|  | @@ -454,10 +456,13 @@ tcindex_set_parms(struct net *net, struct tcf_proto *tp, unsigned long base,
 | ||||||
|  |  		} | ||||||
|  |  	} | ||||||
|  |   | ||||||
|  | -	if (cp->perfect)
 | ||||||
|  | +	if (cp->perfect) {
 | ||||||
|  |  		r = cp->perfect + handle; | ||||||
|  | -	else
 | ||||||
|  | -		r = tcindex_lookup(cp, handle) ? : &new_filter_result;
 | ||||||
|  | +	} else {
 | ||||||
|  | +		/* imperfect area is updated in-place using rcu */
 | ||||||
|  | +		update_h = !!tcindex_lookup(cp, handle);
 | ||||||
|  | +		r = &new_filter_result;
 | ||||||
|  | +	}
 | ||||||
|  |   | ||||||
|  |  	if (r == &new_filter_result) { | ||||||
|  |  		f = kzalloc(sizeof(*f), GFP_KERNEL); | ||||||
|  | @@ -491,7 +496,28 @@ tcindex_set_parms(struct net *net, struct tcf_proto *tp, unsigned long base,
 | ||||||
|  |   | ||||||
|  |  	rcu_assign_pointer(tp->root, cp); | ||||||
|  |   | ||||||
|  | -	if (r == &new_filter_result) {
 | ||||||
|  | +	if (update_h) {
 | ||||||
|  | +		struct tcindex_filter __rcu **fp;
 | ||||||
|  | +		struct tcindex_filter *cf;
 | ||||||
|  | +
 | ||||||
|  | +		f->result.res = r->res;
 | ||||||
|  | +		tcf_exts_change(&f->result.exts, &r->exts);
 | ||||||
|  | +
 | ||||||
|  | +		/* imperfect area bucket */
 | ||||||
|  | +		fp = cp->h + (handle % cp->hash);
 | ||||||
|  | +
 | ||||||
|  | +		/* lookup the filter, guaranteed to exist */
 | ||||||
|  | +		for (cf = rcu_dereference_bh_rtnl(*fp); cf;
 | ||||||
|  | +		     fp = &cf->next, cf = rcu_dereference_bh_rtnl(*fp))
 | ||||||
|  | +			if (cf->key == handle)
 | ||||||
|  | +				break;
 | ||||||
|  | +
 | ||||||
|  | +		f->next = cf->next;
 | ||||||
|  | +
 | ||||||
|  | +		cf = rcu_replace_pointer(*fp, f, 1);
 | ||||||
|  | +		tcf_exts_get_net(&cf->result.exts);
 | ||||||
|  | +		tcf_queue_work(&cf->rwork, tcindex_destroy_fexts_work);
 | ||||||
|  | +	} else if (r == &new_filter_result) {
 | ||||||
|  |  		struct tcindex_filter *nfp; | ||||||
|  |  		struct tcindex_filter __rcu **fp; | ||||||
|  |   | ||||||
|  | -- 
 | ||||||
|  | 2.31.1 | ||||||
|  | 
 | ||||||
| @ -0,0 +1,87 @@ | |||||||
|  | From ad24994e22b545703a710ae7928a160970ff72db Mon Sep 17 00:00:00 2001 | ||||||
|  | From: Jamal Hadi Salim <jhs@mojatatu.com> | ||||||
|  | Date: Tue, 8 Aug 2023 11:07:16 +0000 | ||||||
|  | Subject: [PATCH 3/7] net/sched: tcindex: search key must be 16 bits | ||||||
|  | 
 | ||||||
|  | commit 42018a322bd453e38b3ffee294982243e50a484f upstream | ||||||
|  | Author: Pedro Tammela <pctammela@mojatatu.com> | ||||||
|  | Date:   Mon Feb 13 22:47:29 2023 -0300 | ||||||
|  | 
 | ||||||
|  |     net/sched: tcindex: search key must be 16 bits | ||||||
|  | 
 | ||||||
|  |     Syzkaller found an issue where a handle greater than 16 bits would trigger | ||||||
|  |     a null-ptr-deref in the imperfect hash area update. | ||||||
|  | 
 | ||||||
|  |     general protection fault, probably for non-canonical address | ||||||
|  |     0xdffffc0000000015: 0000 [#1] PREEMPT SMP KASAN | ||||||
|  |     KASAN: null-ptr-deref in range [0x00000000000000a8-0x00000000000000af] | ||||||
|  |     CPU: 0 PID: 5070 Comm: syz-executor456 Not tainted | ||||||
|  |     6.2.0-rc7-syzkaller-00112-gc68f345b7c42 #0 | ||||||
|  |     Hardware name: Google Google Compute Engine/Google Compute Engine, | ||||||
|  |     BIOS Google 01/21/2023 | ||||||
|  |     RIP: 0010:tcindex_set_parms+0x1a6a/0x2990 net/sched/cls_tcindex.c:509 | ||||||
|  |     Code: 01 e9 e9 fe ff ff 4c 8b bd 28 fe ff ff e8 0e 57 7d f9 48 8d bb | ||||||
|  |     a8 00 00 00 48 b8 00 00 00 00 00 fc ff df 48 89 fa 48 c1 ea 03 <80> 3c | ||||||
|  |     02 00 0f 85 94 0c 00 00 48 8b 85 f8 fd ff ff 48 8b 9b a8 00 | ||||||
|  |     RSP: 0018:ffffc90003d3ef88 EFLAGS: 00010202 | ||||||
|  |     RAX: dffffc0000000000 RBX: 0000000000000000 RCX: 0000000000000000 | ||||||
|  |     RDX: 0000000000000015 RSI: ffffffff8803a102 RDI: 00000000000000a8 | ||||||
|  |     RBP: ffffc90003d3f1d8 R08: 0000000000000001 R09: 0000000000000000 | ||||||
|  |     R10: 0000000000000001 R11: 0000000000000000 R12: ffff88801e2b10a8 | ||||||
|  |     R13: dffffc0000000000 R14: 0000000000030000 R15: ffff888017b3be00 | ||||||
|  |     FS: 00005555569af300(0000) GS:ffff8880b9800000(0000) knlGS:0000000000000000 | ||||||
|  |     CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033 | ||||||
|  |     CR2: 000056041c6d2000 CR3: 000000002bfca000 CR4: 00000000003506f0 | ||||||
|  |     DR0: 0000000000000000 DR1: 0000000000000000 DR2: 0000000000000000 | ||||||
|  |     DR3: 0000000000000000 DR6: 00000000fffe0ff0 DR7: 0000000000000400 | ||||||
|  |     Call Trace: | ||||||
|  |     <TASK> | ||||||
|  |     tcindex_change+0x1ea/0x320 net/sched/cls_tcindex.c:572 | ||||||
|  |     tc_new_tfilter+0x96e/0x2220 net/sched/cls_api.c:2155 | ||||||
|  |     rtnetlink_rcv_msg+0x959/0xca0 net/core/rtnetlink.c:6132 | ||||||
|  |     netlink_rcv_skb+0x165/0x440 net/netlink/af_netlink.c:2574 | ||||||
|  |     netlink_unicast_kernel net/netlink/af_netlink.c:1339 [inline] | ||||||
|  |     netlink_unicast+0x547/0x7f0 net/netlink/af_netlink.c:1365 | ||||||
|  |     netlink_sendmsg+0x91b/0xe10 net/netlink/af_netlink.c:1942 | ||||||
|  |     sock_sendmsg_nosec net/socket.c:714 [inline] | ||||||
|  |     sock_sendmsg+0xd3/0x120 net/socket.c:734 | ||||||
|  |     ____sys_sendmsg+0x334/0x8c0 net/socket.c:2476 | ||||||
|  |     ___sys_sendmsg+0x110/0x1b0 net/socket.c:2530 | ||||||
|  |     __sys_sendmmsg+0x18f/0x460 net/socket.c:2616 | ||||||
|  |     __do_sys_sendmmsg net/socket.c:2645 [inline] | ||||||
|  |     __se_sys_sendmmsg net/socket.c:2642 [inline] | ||||||
|  |     __x64_sys_sendmmsg+0x9d/0x100 net/socket.c:2642 | ||||||
|  |     do_syscall_x64 arch/x86/entry/common.c:50 [inline] | ||||||
|  |     do_syscall_64+0x39/0xb0 arch/x86/entry/common.c:80 | ||||||
|  | 
 | ||||||
|  |     Fixes: ee059170b1f7 ("net/sched: tcindex: update imperfect hash filters respecting rcu") | ||||||
|  |     Signed-off-by: Jamal Hadi Salim <jhs@mojatatu.com> | ||||||
|  |     Signed-off-by: Pedro Tammela <pctammela@mojatatu.com> | ||||||
|  |     Reported-by: syzbot <syzkaller@googlegroups.com> | ||||||
|  |     Reviewed-by: Eric Dumazet <edumazet@google.com> | ||||||
|  |     Signed-off-by: David S. Miller <davem@davemloft.net> | ||||||
|  | 
 | ||||||
|  | CVE: CVE-2023-1281 | ||||||
|  | Signed-off-by: Nagappan Ramasamy Palaniappan <nagappan.ramasamy.palaniappan@oracle.com> | ||||||
|  | Reviewed-by: Reviewed-by: Venkat Venkatsubra <venkat.x.venkatsubra@oracle.com> | ||||||
|  | Reviewed-by: Laurence Rochfort <laurence.rochfort@oracle.com> | ||||||
|  | ---
 | ||||||
|  |  net/sched/cls_tcindex.c | 2 +- | ||||||
|  |  1 file changed, 1 insertion(+), 1 deletion(-) | ||||||
|  | 
 | ||||||
|  | diff --git a/net/sched/cls_tcindex.c b/net/sched/cls_tcindex.c
 | ||||||
|  | index 83042a101..a021ba685 100644
 | ||||||
|  | --- a/net/sched/cls_tcindex.c
 | ||||||
|  | +++ b/net/sched/cls_tcindex.c
 | ||||||
|  | @@ -509,7 +509,7 @@ tcindex_set_parms(struct net *net, struct tcf_proto *tp, unsigned long base,
 | ||||||
|  |  		/* lookup the filter, guaranteed to exist */ | ||||||
|  |  		for (cf = rcu_dereference_bh_rtnl(*fp); cf; | ||||||
|  |  		     fp = &cf->next, cf = rcu_dereference_bh_rtnl(*fp)) | ||||||
|  | -			if (cf->key == handle)
 | ||||||
|  | +			if (cf->key == (u16)handle)
 | ||||||
|  |  				break; | ||||||
|  |   | ||||||
|  |  		f->next = cf->next; | ||||||
|  | -- 
 | ||||||
|  | 2.31.1 | ||||||
|  | 
 | ||||||
							
								
								
									
										836
									
								
								SOURCES/1005-net-sched-Retire-tcindex-classifier.patch
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										836
									
								
								SOURCES/1005-net-sched-Retire-tcindex-classifier.patch
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,836 @@ | |||||||
|  | From 4670364a13fccc328386157d820f6ff68619187c Mon Sep 17 00:00:00 2001 | ||||||
|  | From: Jamal Hadi Salim <jhs@mojatatu.com> | ||||||
|  | Date: Tue, 8 Aug 2023 18:26:13 +0000 | ||||||
|  | Subject: [PATCH 4/7] net/sched: Retire tcindex classifier | ||||||
|  | 
 | ||||||
|  | commit 8c710f75256bb3cf05ac7b1672c82b92c43f3d28 upstream | ||||||
|  | 
 | ||||||
|  | The tcindex classifier has served us well for about a quarter of a century | ||||||
|  | but has not been getting much TLC due to lack of known users. Most recently | ||||||
|  | it has become easy prey to syzkaller. For this reason, we are retiring it. | ||||||
|  | 
 | ||||||
|  | Signed-off-by: Jamal Hadi Salim <jhs@mojatatu.com> | ||||||
|  | Acked-by: Jiri Pirko <jiri@nvidia.com> | ||||||
|  | Signed-off-by: Paolo Abeni <pabeni@redhat.com> | ||||||
|  | 
 | ||||||
|  | Conflicts: | ||||||
|  | 	include/net/tc_wrapper.h | ||||||
|  | 	tools/testing/selftests/tc-testing/tc-tests/filters/tcindex.json | ||||||
|  | 
 | ||||||
|  | CVE: CVE-2023-1829 | ||||||
|  | Signed-off-by: Mridula Shastry <mridula.c.shastry@oracle.com> | ||||||
|  | Reviewed-by: Reviewed-by: Venkat Venkatsubra <venkat.x.venkatsubra@oracle.com> | ||||||
|  | Reviewed-by: Laurence Rochfort <laurence.rochfort@oracle.com> | ||||||
|  | ---
 | ||||||
|  |  net/sched/Kconfig       |  11 - | ||||||
|  |  net/sched/Makefile      |   1 - | ||||||
|  |  net/sched/cls_tcindex.c | 763 ---------------------------------------- | ||||||
|  |  3 files changed, 775 deletions(-) | ||||||
|  |  delete mode 100644 net/sched/cls_tcindex.c | ||||||
|  | 
 | ||||||
|  | diff --git a/net/sched/Kconfig b/net/sched/Kconfig
 | ||||||
|  | index afe1d506e..882446fce 100644
 | ||||||
|  | --- a/net/sched/Kconfig
 | ||||||
|  | +++ b/net/sched/Kconfig
 | ||||||
|  | @@ -502,17 +502,6 @@ config NET_CLS_BASIC
 | ||||||
|  |  	  To compile this code as a module, choose M here: the | ||||||
|  |  	  module will be called cls_basic. | ||||||
|  |   | ||||||
|  | -config NET_CLS_TCINDEX
 | ||||||
|  | -	tristate "Traffic-Control Index (TCINDEX)"
 | ||||||
|  | -	select NET_CLS
 | ||||||
|  | -	help
 | ||||||
|  | -	  Say Y here if you want to be able to classify packets based on
 | ||||||
|  | -	  traffic control indices. You will want this feature if you want
 | ||||||
|  | -	  to implement Differentiated Services together with DSMARK.
 | ||||||
|  | -
 | ||||||
|  | -	  To compile this code as a module, choose M here: the
 | ||||||
|  | -	  module will be called cls_tcindex.
 | ||||||
|  | -
 | ||||||
|  |  config NET_CLS_ROUTE4 | ||||||
|  |  	tristate "Routing decision (ROUTE)" | ||||||
|  |  	depends on INET | ||||||
|  | diff --git a/net/sched/Makefile b/net/sched/Makefile
 | ||||||
|  | index dd14ef413..b7dbac5c5 100644
 | ||||||
|  | --- a/net/sched/Makefile
 | ||||||
|  | +++ b/net/sched/Makefile
 | ||||||
|  | @@ -70,7 +70,6 @@ obj-$(CONFIG_NET_CLS_U32)	+= cls_u32.o
 | ||||||
|  |  obj-$(CONFIG_NET_CLS_ROUTE4)	+= cls_route.o | ||||||
|  |  obj-$(CONFIG_NET_CLS_FW)	+= cls_fw.o | ||||||
|  |  obj-$(CONFIG_NET_CLS_RSVP)	+= cls_rsvp.o | ||||||
|  | -obj-$(CONFIG_NET_CLS_TCINDEX)	+= cls_tcindex.o
 | ||||||
|  |  obj-$(CONFIG_NET_CLS_RSVP6)	+= cls_rsvp6.o | ||||||
|  |  obj-$(CONFIG_NET_CLS_BASIC)	+= cls_basic.o | ||||||
|  |  obj-$(CONFIG_NET_CLS_FLOW)	+= cls_flow.o | ||||||
|  | diff --git a/net/sched/cls_tcindex.c b/net/sched/cls_tcindex.c
 | ||||||
|  | deleted file mode 100644 | ||||||
|  | index a021ba685..000000000
 | ||||||
|  | --- a/net/sched/cls_tcindex.c
 | ||||||
|  | +++ /dev/null
 | ||||||
|  | @@ -1,763 +0,0 @@
 | ||||||
|  | -/*
 | ||||||
|  | - * net/sched/cls_tcindex.c	Packet classifier for skb->tc_index
 | ||||||
|  | - *
 | ||||||
|  | - * Written 1998,1999 by Werner Almesberger, EPFL ICA
 | ||||||
|  | - */
 | ||||||
|  | -
 | ||||||
|  | -#include <linux/module.h>
 | ||||||
|  | -#include <linux/types.h>
 | ||||||
|  | -#include <linux/kernel.h>
 | ||||||
|  | -#include <linux/skbuff.h>
 | ||||||
|  | -#include <linux/errno.h>
 | ||||||
|  | -#include <linux/slab.h>
 | ||||||
|  | -#include <linux/refcount.h>
 | ||||||
|  | -#include <linux/rcupdate.h>
 | ||||||
|  | -#include <net/act_api.h>
 | ||||||
|  | -#include <net/netlink.h>
 | ||||||
|  | -#include <net/pkt_cls.h>
 | ||||||
|  | -#include <net/sch_generic.h>
 | ||||||
|  | -
 | ||||||
|  | -/*
 | ||||||
|  | - * Passing parameters to the root seems to be done more awkwardly than really
 | ||||||
|  | - * necessary. At least, u32 doesn't seem to use such dirty hacks. To be
 | ||||||
|  | - * verified. FIXME.
 | ||||||
|  | - */
 | ||||||
|  | -
 | ||||||
|  | -#define PERFECT_HASH_THRESHOLD	64	/* use perfect hash if not bigger */
 | ||||||
|  | -#define DEFAULT_HASH_SIZE	64	/* optimized for diffserv */
 | ||||||
|  | -
 | ||||||
|  | -
 | ||||||
|  | -struct tcindex_data;
 | ||||||
|  | -
 | ||||||
|  | -struct tcindex_filter_result {
 | ||||||
|  | -	struct tcf_exts		exts;
 | ||||||
|  | -	struct tcf_result	res;
 | ||||||
|  | -	struct tcindex_data	*p;
 | ||||||
|  | -	struct rcu_work		rwork;
 | ||||||
|  | -};
 | ||||||
|  | -
 | ||||||
|  | -struct tcindex_filter {
 | ||||||
|  | -	u16 key;
 | ||||||
|  | -	struct tcindex_filter_result result;
 | ||||||
|  | -	struct tcindex_filter __rcu *next;
 | ||||||
|  | -	struct rcu_work rwork;
 | ||||||
|  | -};
 | ||||||
|  | -
 | ||||||
|  | -
 | ||||||
|  | -struct tcindex_data {
 | ||||||
|  | -	struct tcindex_filter_result *perfect; /* perfect hash; NULL if none */
 | ||||||
|  | -	struct tcindex_filter __rcu **h; /* imperfect hash; */
 | ||||||
|  | -	struct tcf_proto *tp;
 | ||||||
|  | -	u16 mask;		/* AND key with mask */
 | ||||||
|  | -	u32 shift;		/* shift ANDed key to the right */
 | ||||||
|  | -	u32 hash;		/* hash table size; 0 if undefined */
 | ||||||
|  | -	u32 alloc_hash;		/* allocated size */
 | ||||||
|  | -	u32 fall_through;	/* 0: only classify if explicit match */
 | ||||||
|  | -	refcount_t refcnt;	/* a temporary refcnt for perfect hash */
 | ||||||
|  | -	struct rcu_work rwork;
 | ||||||
|  | -};
 | ||||||
|  | -
 | ||||||
|  | -static inline int tcindex_filter_is_set(struct tcindex_filter_result *r)
 | ||||||
|  | -{
 | ||||||
|  | -	return tcf_exts_has_actions(&r->exts) || r->res.classid;
 | ||||||
|  | -}
 | ||||||
|  | -
 | ||||||
|  | -static void tcindex_data_get(struct tcindex_data *p)
 | ||||||
|  | -{
 | ||||||
|  | -	refcount_inc(&p->refcnt);
 | ||||||
|  | -}
 | ||||||
|  | -
 | ||||||
|  | -static void tcindex_data_put(struct tcindex_data *p)
 | ||||||
|  | -{
 | ||||||
|  | -	if (refcount_dec_and_test(&p->refcnt)) {
 | ||||||
|  | -		kfree(p->perfect);
 | ||||||
|  | -		kfree(p->h);
 | ||||||
|  | -		kfree(p);
 | ||||||
|  | -	}
 | ||||||
|  | -}
 | ||||||
|  | -
 | ||||||
|  | -static struct tcindex_filter_result *tcindex_lookup(struct tcindex_data *p,
 | ||||||
|  | -						    u16 key)
 | ||||||
|  | -{
 | ||||||
|  | -	if (p->perfect) {
 | ||||||
|  | -		struct tcindex_filter_result *f = p->perfect + key;
 | ||||||
|  | -
 | ||||||
|  | -		return tcindex_filter_is_set(f) ? f : NULL;
 | ||||||
|  | -	} else if (p->h) {
 | ||||||
|  | -		struct tcindex_filter __rcu **fp;
 | ||||||
|  | -		struct tcindex_filter *f;
 | ||||||
|  | -
 | ||||||
|  | -		fp = &p->h[key % p->hash];
 | ||||||
|  | -		for (f = rcu_dereference_bh_rtnl(*fp);
 | ||||||
|  | -		     f;
 | ||||||
|  | -		     fp = &f->next, f = rcu_dereference_bh_rtnl(*fp))
 | ||||||
|  | -			if (f->key == key)
 | ||||||
|  | -				return &f->result;
 | ||||||
|  | -	}
 | ||||||
|  | -
 | ||||||
|  | -	return NULL;
 | ||||||
|  | -}
 | ||||||
|  | -
 | ||||||
|  | -
 | ||||||
|  | -static int tcindex_classify(struct sk_buff *skb, const struct tcf_proto *tp,
 | ||||||
|  | -			    struct tcf_result *res)
 | ||||||
|  | -{
 | ||||||
|  | -	struct tcindex_data *p = rcu_dereference_bh(tp->root);
 | ||||||
|  | -	struct tcindex_filter_result *f;
 | ||||||
|  | -	int key = (skb->tc_index & p->mask) >> p->shift;
 | ||||||
|  | -
 | ||||||
|  | -	pr_debug("tcindex_classify(skb %p,tp %p,res %p),p %p\n",
 | ||||||
|  | -		 skb, tp, res, p);
 | ||||||
|  | -
 | ||||||
|  | -	f = tcindex_lookup(p, key);
 | ||||||
|  | -	if (!f) {
 | ||||||
|  | -		struct Qdisc *q = tcf_block_q(tp->chain->block);
 | ||||||
|  | -
 | ||||||
|  | -		if (!p->fall_through)
 | ||||||
|  | -			return -1;
 | ||||||
|  | -		res->classid = TC_H_MAKE(TC_H_MAJ(q->handle), key);
 | ||||||
|  | -		res->class = 0;
 | ||||||
|  | -		pr_debug("alg 0x%x\n", res->classid);
 | ||||||
|  | -		return 0;
 | ||||||
|  | -	}
 | ||||||
|  | -	*res = f->res;
 | ||||||
|  | -	pr_debug("map 0x%x\n", res->classid);
 | ||||||
|  | -
 | ||||||
|  | -	return tcf_exts_exec(skb, &f->exts, res);
 | ||||||
|  | -}
 | ||||||
|  | -
 | ||||||
|  | -
 | ||||||
|  | -static void *tcindex_get(struct tcf_proto *tp, u32 handle)
 | ||||||
|  | -{
 | ||||||
|  | -	struct tcindex_data *p = rtnl_dereference(tp->root);
 | ||||||
|  | -	struct tcindex_filter_result *r;
 | ||||||
|  | -
 | ||||||
|  | -	pr_debug("tcindex_get(tp %p,handle 0x%08x)\n", tp, handle);
 | ||||||
|  | -	if (p->perfect && handle >= p->alloc_hash)
 | ||||||
|  | -		return NULL;
 | ||||||
|  | -	r = tcindex_lookup(p, handle);
 | ||||||
|  | -	return r && tcindex_filter_is_set(r) ? r : NULL;
 | ||||||
|  | -}
 | ||||||
|  | -
 | ||||||
|  | -static int tcindex_init(struct tcf_proto *tp)
 | ||||||
|  | -{
 | ||||||
|  | -	struct tcindex_data *p;
 | ||||||
|  | -
 | ||||||
|  | -	pr_debug("tcindex_init(tp %p)\n", tp);
 | ||||||
|  | -	p = kzalloc(sizeof(struct tcindex_data), GFP_KERNEL);
 | ||||||
|  | -	if (!p)
 | ||||||
|  | -		return -ENOMEM;
 | ||||||
|  | -
 | ||||||
|  | -	p->mask = 0xffff;
 | ||||||
|  | -	p->hash = DEFAULT_HASH_SIZE;
 | ||||||
|  | -	p->fall_through = 1;
 | ||||||
|  | -	refcount_set(&p->refcnt, 1); /* Paired with tcindex_destroy_work() */
 | ||||||
|  | -
 | ||||||
|  | -	rcu_assign_pointer(tp->root, p);
 | ||||||
|  | -	return 0;
 | ||||||
|  | -}
 | ||||||
|  | -
 | ||||||
|  | -static void __tcindex_destroy_rexts(struct tcindex_filter_result *r)
 | ||||||
|  | -{
 | ||||||
|  | -	tcf_exts_destroy(&r->exts);
 | ||||||
|  | -	tcf_exts_put_net(&r->exts);
 | ||||||
|  | -	tcindex_data_put(r->p);
 | ||||||
|  | -}
 | ||||||
|  | -
 | ||||||
|  | -static void tcindex_destroy_rexts_work(struct work_struct *work)
 | ||||||
|  | -{
 | ||||||
|  | -	struct tcindex_filter_result *r;
 | ||||||
|  | -
 | ||||||
|  | -	r = container_of(to_rcu_work(work),
 | ||||||
|  | -			 struct tcindex_filter_result,
 | ||||||
|  | -			 rwork);
 | ||||||
|  | -	rtnl_lock();
 | ||||||
|  | -	__tcindex_destroy_rexts(r);
 | ||||||
|  | -	rtnl_unlock();
 | ||||||
|  | -}
 | ||||||
|  | -
 | ||||||
|  | -static void __tcindex_destroy_fexts(struct tcindex_filter *f)
 | ||||||
|  | -{
 | ||||||
|  | -	tcf_exts_destroy(&f->result.exts);
 | ||||||
|  | -	tcf_exts_put_net(&f->result.exts);
 | ||||||
|  | -	kfree(f);
 | ||||||
|  | -}
 | ||||||
|  | -
 | ||||||
|  | -static void tcindex_destroy_fexts_work(struct work_struct *work)
 | ||||||
|  | -{
 | ||||||
|  | -	struct tcindex_filter *f = container_of(to_rcu_work(work),
 | ||||||
|  | -						struct tcindex_filter,
 | ||||||
|  | -						rwork);
 | ||||||
|  | -
 | ||||||
|  | -	rtnl_lock();
 | ||||||
|  | -	__tcindex_destroy_fexts(f);
 | ||||||
|  | -	rtnl_unlock();
 | ||||||
|  | -}
 | ||||||
|  | -
 | ||||||
|  | -static int tcindex_delete(struct tcf_proto *tp, void *arg, bool *last,
 | ||||||
|  | -			  bool rtnl_held, struct netlink_ext_ack *extack)
 | ||||||
|  | -{
 | ||||||
|  | -	struct tcindex_data *p = rtnl_dereference(tp->root);
 | ||||||
|  | -	struct tcindex_filter_result *r = arg;
 | ||||||
|  | -	struct tcindex_filter __rcu **walk;
 | ||||||
|  | -	struct tcindex_filter *f = NULL;
 | ||||||
|  | -
 | ||||||
|  | -	pr_debug("tcindex_delete(tp %p,arg %p),p %p\n", tp, arg, p);
 | ||||||
|  | -	if (p->perfect) {
 | ||||||
|  | -		if (!r->res.class)
 | ||||||
|  | -			return -ENOENT;
 | ||||||
|  | -	} else {
 | ||||||
|  | -		int i;
 | ||||||
|  | -
 | ||||||
|  | -		for (i = 0; i < p->hash; i++) {
 | ||||||
|  | -			walk = p->h + i;
 | ||||||
|  | -			for (f = rtnl_dereference(*walk); f;
 | ||||||
|  | -			     walk = &f->next, f = rtnl_dereference(*walk)) {
 | ||||||
|  | -				if (&f->result == r)
 | ||||||
|  | -					goto found;
 | ||||||
|  | -			}
 | ||||||
|  | -		}
 | ||||||
|  | -		return -ENOENT;
 | ||||||
|  | -
 | ||||||
|  | -found:
 | ||||||
|  | -		rcu_assign_pointer(*walk, rtnl_dereference(f->next));
 | ||||||
|  | -	}
 | ||||||
|  | -	tcf_unbind_filter(tp, &r->res);
 | ||||||
|  | -	/* all classifiers are required to call tcf_exts_destroy() after rcu
 | ||||||
|  | -	 * grace period, since converted-to-rcu actions are relying on that
 | ||||||
|  | -	 * in cleanup() callback
 | ||||||
|  | -	 */
 | ||||||
|  | -	if (f) {
 | ||||||
|  | -		if (tcf_exts_get_net(&f->result.exts))
 | ||||||
|  | -			tcf_queue_work(&f->rwork, tcindex_destroy_fexts_work);
 | ||||||
|  | -		else
 | ||||||
|  | -			__tcindex_destroy_fexts(f);
 | ||||||
|  | -	} else {
 | ||||||
|  | -		tcindex_data_get(p);
 | ||||||
|  | -
 | ||||||
|  | -		if (tcf_exts_get_net(&r->exts))
 | ||||||
|  | -			tcf_queue_work(&r->rwork, tcindex_destroy_rexts_work);
 | ||||||
|  | -		else
 | ||||||
|  | -			__tcindex_destroy_rexts(r);
 | ||||||
|  | -	}
 | ||||||
|  | -
 | ||||||
|  | -	*last = false;
 | ||||||
|  | -	return 0;
 | ||||||
|  | -}
 | ||||||
|  | -
 | ||||||
|  | -static void tcindex_destroy_work(struct work_struct *work)
 | ||||||
|  | -{
 | ||||||
|  | -	struct tcindex_data *p = container_of(to_rcu_work(work),
 | ||||||
|  | -					      struct tcindex_data,
 | ||||||
|  | -					      rwork);
 | ||||||
|  | -
 | ||||||
|  | -	tcindex_data_put(p);
 | ||||||
|  | -}
 | ||||||
|  | -
 | ||||||
|  | -static inline int
 | ||||||
|  | -valid_perfect_hash(struct tcindex_data *p)
 | ||||||
|  | -{
 | ||||||
|  | -	return  p->hash > (p->mask >> p->shift);
 | ||||||
|  | -}
 | ||||||
|  | -
 | ||||||
|  | -static const struct nla_policy tcindex_policy[TCA_TCINDEX_MAX + 1] = {
 | ||||||
|  | -	[TCA_TCINDEX_HASH]		= { .type = NLA_U32 },
 | ||||||
|  | -	[TCA_TCINDEX_MASK]		= { .type = NLA_U16 },
 | ||||||
|  | -	[TCA_TCINDEX_SHIFT]		= { .type = NLA_U32 },
 | ||||||
|  | -	[TCA_TCINDEX_FALL_THROUGH]	= { .type = NLA_U32 },
 | ||||||
|  | -	[TCA_TCINDEX_CLASSID]		= { .type = NLA_U32 },
 | ||||||
|  | -};
 | ||||||
|  | -
 | ||||||
|  | -static int tcindex_filter_result_init(struct tcindex_filter_result *r,
 | ||||||
|  | -				      struct tcindex_data *p,
 | ||||||
|  | -				      struct net *net)
 | ||||||
|  | -{
 | ||||||
|  | -	memset(r, 0, sizeof(*r));
 | ||||||
|  | -	r->p = p;
 | ||||||
|  | -	return tcf_exts_init(&r->exts, net, TCA_TCINDEX_ACT,
 | ||||||
|  | -			     TCA_TCINDEX_POLICE);
 | ||||||
|  | -}
 | ||||||
|  | -
 | ||||||
|  | -static void tcindex_free_perfect_hash(struct tcindex_data *cp);
 | ||||||
|  | -
 | ||||||
|  | -static void tcindex_partial_destroy_work(struct work_struct *work)
 | ||||||
|  | -{
 | ||||||
|  | -	struct tcindex_data *p = container_of(to_rcu_work(work),
 | ||||||
|  | -					      struct tcindex_data,
 | ||||||
|  | -					      rwork);
 | ||||||
|  | -
 | ||||||
|  | -	rtnl_lock();
 | ||||||
|  | -	if (p->perfect)
 | ||||||
|  | -		tcindex_free_perfect_hash(p);
 | ||||||
|  | -	kfree(p);
 | ||||||
|  | -	rtnl_unlock();
 | ||||||
|  | -}
 | ||||||
|  | -
 | ||||||
|  | -static void tcindex_free_perfect_hash(struct tcindex_data *cp)
 | ||||||
|  | -{
 | ||||||
|  | -	int i;
 | ||||||
|  | -
 | ||||||
|  | -	for (i = 0; i < cp->hash; i++)
 | ||||||
|  | -		tcf_exts_destroy(&cp->perfect[i].exts);
 | ||||||
|  | -	kfree(cp->perfect);
 | ||||||
|  | -}
 | ||||||
|  | -
 | ||||||
|  | -static int tcindex_alloc_perfect_hash(struct net *net, struct tcindex_data *cp)
 | ||||||
|  | -{
 | ||||||
|  | -	int i, err = 0;
 | ||||||
|  | -
 | ||||||
|  | -	cp->perfect = kcalloc(cp->hash, sizeof(struct tcindex_filter_result),
 | ||||||
|  | -			      GFP_KERNEL | __GFP_NOWARN);
 | ||||||
|  | -	if (!cp->perfect)
 | ||||||
|  | -		return -ENOMEM;
 | ||||||
|  | -
 | ||||||
|  | -	for (i = 0; i < cp->hash; i++) {
 | ||||||
|  | -		err = tcf_exts_init(&cp->perfect[i].exts, net,
 | ||||||
|  | -				    TCA_TCINDEX_ACT, TCA_TCINDEX_POLICE);
 | ||||||
|  | -		if (err < 0)
 | ||||||
|  | -			goto errout;
 | ||||||
|  | -		cp->perfect[i].p = cp;
 | ||||||
|  | -	}
 | ||||||
|  | -
 | ||||||
|  | -	return 0;
 | ||||||
|  | -
 | ||||||
|  | -errout:
 | ||||||
|  | -	tcindex_free_perfect_hash(cp);
 | ||||||
|  | -	return err;
 | ||||||
|  | -}
 | ||||||
|  | -
 | ||||||
|  | -static int
 | ||||||
|  | -tcindex_set_parms(struct net *net, struct tcf_proto *tp, unsigned long base,
 | ||||||
|  | -		  u32 handle, struct tcindex_data *p,
 | ||||||
|  | -		  struct tcindex_filter_result *r, struct nlattr **tb,
 | ||||||
|  | -		  struct nlattr *est, u32 flags, struct netlink_ext_ack *extack)
 | ||||||
|  | -{
 | ||||||
|  | -	struct tcindex_filter_result new_filter_result, *old_r = r;
 | ||||||
|  | -	struct tcindex_data *cp = NULL, *oldp;
 | ||||||
|  | -	struct tcindex_filter *f = NULL; /* make gcc behave */
 | ||||||
|  | -	struct tcf_result cr = {};
 | ||||||
|  | -	int err, balloc = 0;
 | ||||||
|  | -	struct tcf_exts e;
 | ||||||
|  | -	bool update_h = false;
 | ||||||
|  | -
 | ||||||
|  | -	err = tcf_exts_init(&e, net, TCA_TCINDEX_ACT, TCA_TCINDEX_POLICE);
 | ||||||
|  | -	if (err < 0)
 | ||||||
|  | -		return err;
 | ||||||
|  | -	err = tcf_exts_validate(net, tp, tb, est, &e, flags, extack);
 | ||||||
|  | -	if (err < 0)
 | ||||||
|  | -		goto errout;
 | ||||||
|  | -
 | ||||||
|  | -	err = -ENOMEM;
 | ||||||
|  | -	/* tcindex_data attributes must look atomic to classifier/lookup so
 | ||||||
|  | -	 * allocate new tcindex data and RCU assign it onto root. Keeping
 | ||||||
|  | -	 * perfect hash and hash pointers from old data.
 | ||||||
|  | -	 */
 | ||||||
|  | -	cp = kzalloc(sizeof(*cp), GFP_KERNEL);
 | ||||||
|  | -	if (!cp)
 | ||||||
|  | -		goto errout;
 | ||||||
|  | -
 | ||||||
|  | -	cp->mask = p->mask;
 | ||||||
|  | -	cp->shift = p->shift;
 | ||||||
|  | -	cp->hash = p->hash;
 | ||||||
|  | -	cp->alloc_hash = p->alloc_hash;
 | ||||||
|  | -	cp->fall_through = p->fall_through;
 | ||||||
|  | -	cp->tp = tp;
 | ||||||
|  | -	refcount_set(&cp->refcnt, 1); /* Paired with tcindex_destroy_work() */
 | ||||||
|  | -
 | ||||||
|  | -	if (tb[TCA_TCINDEX_HASH])
 | ||||||
|  | -		cp->hash = nla_get_u32(tb[TCA_TCINDEX_HASH]);
 | ||||||
|  | -
 | ||||||
|  | -	if (tb[TCA_TCINDEX_MASK])
 | ||||||
|  | -		cp->mask = nla_get_u16(tb[TCA_TCINDEX_MASK]);
 | ||||||
|  | -
 | ||||||
|  | -	if (tb[TCA_TCINDEX_SHIFT]) {
 | ||||||
|  | -		cp->shift = nla_get_u32(tb[TCA_TCINDEX_SHIFT]);
 | ||||||
|  | -		if (cp->shift > 16) {
 | ||||||
|  | -			err = -EINVAL;
 | ||||||
|  | -			goto errout;
 | ||||||
|  | -		}
 | ||||||
|  | -	}
 | ||||||
|  | -	if (!cp->hash) {
 | ||||||
|  | -		/* Hash not specified, use perfect hash if the upper limit
 | ||||||
|  | -		 * of the hashing index is below the threshold.
 | ||||||
|  | -		 */
 | ||||||
|  | -		if ((cp->mask >> cp->shift) < PERFECT_HASH_THRESHOLD)
 | ||||||
|  | -			cp->hash = (cp->mask >> cp->shift) + 1;
 | ||||||
|  | -		else
 | ||||||
|  | -			cp->hash = DEFAULT_HASH_SIZE;
 | ||||||
|  | -	}
 | ||||||
|  | -
 | ||||||
|  | -	if (p->perfect) {
 | ||||||
|  | -		int i;
 | ||||||
|  | -
 | ||||||
|  | -		if (tcindex_alloc_perfect_hash(net, cp) < 0)
 | ||||||
|  | -			goto errout;
 | ||||||
|  | -		cp->alloc_hash = cp->hash;
 | ||||||
|  | -		for (i = 0; i < min(cp->hash, p->hash); i++)
 | ||||||
|  | -			cp->perfect[i].res = p->perfect[i].res;
 | ||||||
|  | -		balloc = 1;
 | ||||||
|  | -	}
 | ||||||
|  | -	cp->h = p->h;
 | ||||||
|  | -
 | ||||||
|  | -	err = tcindex_filter_result_init(&new_filter_result, cp, net);
 | ||||||
|  | -	if (err < 0)
 | ||||||
|  | -		goto errout_alloc;
 | ||||||
|  | -	if (old_r)
 | ||||||
|  | -		cr = r->res;
 | ||||||
|  | -
 | ||||||
|  | -	err = -EBUSY;
 | ||||||
|  | -
 | ||||||
|  | -	/* Hash already allocated, make sure that we still meet the
 | ||||||
|  | -	 * requirements for the allocated hash.
 | ||||||
|  | -	 */
 | ||||||
|  | -	if (cp->perfect) {
 | ||||||
|  | -		if (!valid_perfect_hash(cp) ||
 | ||||||
|  | -		    cp->hash > cp->alloc_hash)
 | ||||||
|  | -			goto errout_alloc;
 | ||||||
|  | -	} else if (cp->h && cp->hash != cp->alloc_hash) {
 | ||||||
|  | -		goto errout_alloc;
 | ||||||
|  | -	}
 | ||||||
|  | -
 | ||||||
|  | -	err = -EINVAL;
 | ||||||
|  | -	if (tb[TCA_TCINDEX_FALL_THROUGH])
 | ||||||
|  | -		cp->fall_through = nla_get_u32(tb[TCA_TCINDEX_FALL_THROUGH]);
 | ||||||
|  | -
 | ||||||
|  | -	if (!cp->perfect && !cp->h)
 | ||||||
|  | -		cp->alloc_hash = cp->hash;
 | ||||||
|  | -
 | ||||||
|  | -	/* Note: this could be as restrictive as if (handle & ~(mask >> shift))
 | ||||||
|  | -	 * but then, we'd fail handles that may become valid after some future
 | ||||||
|  | -	 * mask change. While this is extremely unlikely to ever matter,
 | ||||||
|  | -	 * the check below is safer (and also more backwards-compatible).
 | ||||||
|  | -	 */
 | ||||||
|  | -	if (cp->perfect || valid_perfect_hash(cp))
 | ||||||
|  | -		if (handle >= cp->alloc_hash)
 | ||||||
|  | -			goto errout_alloc;
 | ||||||
|  | -
 | ||||||
|  | -
 | ||||||
|  | -	err = -ENOMEM;
 | ||||||
|  | -	if (!cp->perfect && !cp->h) {
 | ||||||
|  | -		if (valid_perfect_hash(cp)) {
 | ||||||
|  | -			if (tcindex_alloc_perfect_hash(net, cp) < 0)
 | ||||||
|  | -				goto errout_alloc;
 | ||||||
|  | -			balloc = 1;
 | ||||||
|  | -		} else {
 | ||||||
|  | -			struct tcindex_filter __rcu **hash;
 | ||||||
|  | -
 | ||||||
|  | -			hash = kcalloc(cp->hash,
 | ||||||
|  | -				       sizeof(struct tcindex_filter *),
 | ||||||
|  | -				       GFP_KERNEL);
 | ||||||
|  | -
 | ||||||
|  | -			if (!hash)
 | ||||||
|  | -				goto errout_alloc;
 | ||||||
|  | -
 | ||||||
|  | -			cp->h = hash;
 | ||||||
|  | -			balloc = 2;
 | ||||||
|  | -		}
 | ||||||
|  | -	}
 | ||||||
|  | -
 | ||||||
|  | -	if (cp->perfect) {
 | ||||||
|  | -		r = cp->perfect + handle;
 | ||||||
|  | -	} else {
 | ||||||
|  | -		/* imperfect area is updated in-place using rcu */
 | ||||||
|  | -		update_h = !!tcindex_lookup(cp, handle);
 | ||||||
|  | -		r = &new_filter_result;
 | ||||||
|  | -	}
 | ||||||
|  | -
 | ||||||
|  | -	if (r == &new_filter_result) {
 | ||||||
|  | -		f = kzalloc(sizeof(*f), GFP_KERNEL);
 | ||||||
|  | -		if (!f)
 | ||||||
|  | -			goto errout_alloc;
 | ||||||
|  | -		f->key = handle;
 | ||||||
|  | -		f->next = NULL;
 | ||||||
|  | -		err = tcindex_filter_result_init(&f->result, cp, net);
 | ||||||
|  | -		if (err < 0) {
 | ||||||
|  | -			kfree(f);
 | ||||||
|  | -			goto errout_alloc;
 | ||||||
|  | -		}
 | ||||||
|  | -	}
 | ||||||
|  | -
 | ||||||
|  | -	if (tb[TCA_TCINDEX_CLASSID]) {
 | ||||||
|  | -		cr.classid = nla_get_u32(tb[TCA_TCINDEX_CLASSID]);
 | ||||||
|  | -		tcf_bind_filter(tp, &cr, base);
 | ||||||
|  | -	}
 | ||||||
|  | -
 | ||||||
|  | -	if (old_r && old_r != r) {
 | ||||||
|  | -		err = tcindex_filter_result_init(old_r, cp, net);
 | ||||||
|  | -		if (err < 0) {
 | ||||||
|  | -			kfree(f);
 | ||||||
|  | -			goto errout_alloc;
 | ||||||
|  | -		}
 | ||||||
|  | -	}
 | ||||||
|  | -
 | ||||||
|  | -	oldp = p;
 | ||||||
|  | -	r->res = cr;
 | ||||||
|  | -	tcf_exts_change(&r->exts, &e);
 | ||||||
|  | -
 | ||||||
|  | -	rcu_assign_pointer(tp->root, cp);
 | ||||||
|  | -
 | ||||||
|  | -	if (update_h) {
 | ||||||
|  | -		struct tcindex_filter __rcu **fp;
 | ||||||
|  | -		struct tcindex_filter *cf;
 | ||||||
|  | -
 | ||||||
|  | -		f->result.res = r->res;
 | ||||||
|  | -		tcf_exts_change(&f->result.exts, &r->exts);
 | ||||||
|  | -
 | ||||||
|  | -		/* imperfect area bucket */
 | ||||||
|  | -		fp = cp->h + (handle % cp->hash);
 | ||||||
|  | -
 | ||||||
|  | -		/* lookup the filter, guaranteed to exist */
 | ||||||
|  | -		for (cf = rcu_dereference_bh_rtnl(*fp); cf;
 | ||||||
|  | -		     fp = &cf->next, cf = rcu_dereference_bh_rtnl(*fp))
 | ||||||
|  | -			if (cf->key == (u16)handle)
 | ||||||
|  | -				break;
 | ||||||
|  | -
 | ||||||
|  | -		f->next = cf->next;
 | ||||||
|  | -
 | ||||||
|  | -		cf = rcu_replace_pointer(*fp, f, 1);
 | ||||||
|  | -		tcf_exts_get_net(&cf->result.exts);
 | ||||||
|  | -		tcf_queue_work(&cf->rwork, tcindex_destroy_fexts_work);
 | ||||||
|  | -	} else if (r == &new_filter_result) {
 | ||||||
|  | -		struct tcindex_filter *nfp;
 | ||||||
|  | -		struct tcindex_filter __rcu **fp;
 | ||||||
|  | -
 | ||||||
|  | -		f->result.res = r->res;
 | ||||||
|  | -		tcf_exts_change(&f->result.exts, &r->exts);
 | ||||||
|  | -
 | ||||||
|  | -		fp = cp->h + (handle % cp->hash);
 | ||||||
|  | -		for (nfp = rtnl_dereference(*fp);
 | ||||||
|  | -		     nfp;
 | ||||||
|  | -		     fp = &nfp->next, nfp = rtnl_dereference(*fp))
 | ||||||
|  | -				; /* nothing */
 | ||||||
|  | -
 | ||||||
|  | -		rcu_assign_pointer(*fp, f);
 | ||||||
|  | -	} else {
 | ||||||
|  | -		tcf_exts_destroy(&new_filter_result.exts);
 | ||||||
|  | -	}
 | ||||||
|  | -
 | ||||||
|  | -	if (oldp)
 | ||||||
|  | -		tcf_queue_work(&oldp->rwork, tcindex_partial_destroy_work);
 | ||||||
|  | -	return 0;
 | ||||||
|  | -
 | ||||||
|  | -errout_alloc:
 | ||||||
|  | -	if (balloc == 1)
 | ||||||
|  | -		tcindex_free_perfect_hash(cp);
 | ||||||
|  | -	else if (balloc == 2)
 | ||||||
|  | -		kfree(cp->h);
 | ||||||
|  | -	tcf_exts_destroy(&new_filter_result.exts);
 | ||||||
|  | -errout:
 | ||||||
|  | -	kfree(cp);
 | ||||||
|  | -	tcf_exts_destroy(&e);
 | ||||||
|  | -	return err;
 | ||||||
|  | -}
 | ||||||
|  | -
 | ||||||
|  | -static int
 | ||||||
|  | -tcindex_change(struct net *net, struct sk_buff *in_skb,
 | ||||||
|  | -	       struct tcf_proto *tp, unsigned long base, u32 handle,
 | ||||||
|  | -	       struct nlattr **tca, void **arg, u32 flags,
 | ||||||
|  | -	       struct netlink_ext_ack *extack)
 | ||||||
|  | -{
 | ||||||
|  | -	struct nlattr *opt = tca[TCA_OPTIONS];
 | ||||||
|  | -	struct nlattr *tb[TCA_TCINDEX_MAX + 1];
 | ||||||
|  | -	struct tcindex_data *p = rtnl_dereference(tp->root);
 | ||||||
|  | -	struct tcindex_filter_result *r = *arg;
 | ||||||
|  | -	int err;
 | ||||||
|  | -
 | ||||||
|  | -	pr_debug("tcindex_change(tp %p,handle 0x%08x,tca %p,arg %p),opt %p,"
 | ||||||
|  | -	    "p %p,r %p,*arg %p\n",
 | ||||||
|  | -	    tp, handle, tca, arg, opt, p, r, *arg);
 | ||||||
|  | -
 | ||||||
|  | -	if (!opt)
 | ||||||
|  | -		return 0;
 | ||||||
|  | -
 | ||||||
|  | -	err = nla_parse_nested_deprecated(tb, TCA_TCINDEX_MAX, opt,
 | ||||||
|  | -					  tcindex_policy, NULL);
 | ||||||
|  | -	if (err < 0)
 | ||||||
|  | -		return err;
 | ||||||
|  | -
 | ||||||
|  | -	return tcindex_set_parms(net, tp, base, handle, p, r, tb,
 | ||||||
|  | -				 tca[TCA_RATE], flags, extack);
 | ||||||
|  | -}
 | ||||||
|  | -
 | ||||||
|  | -static void tcindex_walk(struct tcf_proto *tp, struct tcf_walker *walker,
 | ||||||
|  | -			 bool rtnl_held)
 | ||||||
|  | -{
 | ||||||
|  | -	struct tcindex_data *p = rtnl_dereference(tp->root);
 | ||||||
|  | -	struct tcindex_filter *f, *next;
 | ||||||
|  | -	int i;
 | ||||||
|  | -
 | ||||||
|  | -	pr_debug("tcindex_walk(tp %p,walker %p),p %p\n", tp, walker, p);
 | ||||||
|  | -	if (p->perfect) {
 | ||||||
|  | -		for (i = 0; i < p->hash; i++) {
 | ||||||
|  | -			if (!p->perfect[i].res.class)
 | ||||||
|  | -				continue;
 | ||||||
|  | -			if (walker->count >= walker->skip) {
 | ||||||
|  | -				if (walker->fn(tp, p->perfect + i, walker) < 0) {
 | ||||||
|  | -					walker->stop = 1;
 | ||||||
|  | -					return;
 | ||||||
|  | -				}
 | ||||||
|  | -			}
 | ||||||
|  | -			walker->count++;
 | ||||||
|  | -		}
 | ||||||
|  | -	}
 | ||||||
|  | -	if (!p->h)
 | ||||||
|  | -		return;
 | ||||||
|  | -	for (i = 0; i < p->hash; i++) {
 | ||||||
|  | -		for (f = rtnl_dereference(p->h[i]); f; f = next) {
 | ||||||
|  | -			next = rtnl_dereference(f->next);
 | ||||||
|  | -			if (walker->count >= walker->skip) {
 | ||||||
|  | -				if (walker->fn(tp, &f->result, walker) < 0) {
 | ||||||
|  | -					walker->stop = 1;
 | ||||||
|  | -					return;
 | ||||||
|  | -				}
 | ||||||
|  | -			}
 | ||||||
|  | -			walker->count++;
 | ||||||
|  | -		}
 | ||||||
|  | -	}
 | ||||||
|  | -}
 | ||||||
|  | -
 | ||||||
|  | -static void tcindex_destroy(struct tcf_proto *tp, bool rtnl_held,
 | ||||||
|  | -			    struct netlink_ext_ack *extack)
 | ||||||
|  | -{
 | ||||||
|  | -	struct tcindex_data *p = rtnl_dereference(tp->root);
 | ||||||
|  | -	int i;
 | ||||||
|  | -
 | ||||||
|  | -	pr_debug("tcindex_destroy(tp %p),p %p\n", tp, p);
 | ||||||
|  | -
 | ||||||
|  | -	if (p->perfect) {
 | ||||||
|  | -		for (i = 0; i < p->hash; i++) {
 | ||||||
|  | -			struct tcindex_filter_result *r = p->perfect + i;
 | ||||||
|  | -
 | ||||||
|  | -			/* tcf_queue_work() does not guarantee the ordering we
 | ||||||
|  | -			 * want, so we have to take this refcnt temporarily to
 | ||||||
|  | -			 * ensure 'p' is freed after all tcindex_filter_result
 | ||||||
|  | -			 * here. Imperfect hash does not need this, because it
 | ||||||
|  | -			 * uses linked lists rather than an array.
 | ||||||
|  | -			 */
 | ||||||
|  | -			tcindex_data_get(p);
 | ||||||
|  | -
 | ||||||
|  | -			tcf_unbind_filter(tp, &r->res);
 | ||||||
|  | -			if (tcf_exts_get_net(&r->exts))
 | ||||||
|  | -				tcf_queue_work(&r->rwork,
 | ||||||
|  | -					       tcindex_destroy_rexts_work);
 | ||||||
|  | -			else
 | ||||||
|  | -				__tcindex_destroy_rexts(r);
 | ||||||
|  | -		}
 | ||||||
|  | -	}
 | ||||||
|  | -
 | ||||||
|  | -	for (i = 0; p->h && i < p->hash; i++) {
 | ||||||
|  | -		struct tcindex_filter *f, *next;
 | ||||||
|  | -		bool last;
 | ||||||
|  | -
 | ||||||
|  | -		for (f = rtnl_dereference(p->h[i]); f; f = next) {
 | ||||||
|  | -			next = rtnl_dereference(f->next);
 | ||||||
|  | -			tcindex_delete(tp, &f->result, &last, rtnl_held, NULL);
 | ||||||
|  | -		}
 | ||||||
|  | -	}
 | ||||||
|  | -
 | ||||||
|  | -	tcf_queue_work(&p->rwork, tcindex_destroy_work);
 | ||||||
|  | -}
 | ||||||
|  | -
 | ||||||
|  | -
 | ||||||
|  | -static int tcindex_dump(struct net *net, struct tcf_proto *tp, void *fh,
 | ||||||
|  | -			struct sk_buff *skb, struct tcmsg *t, bool rtnl_held)
 | ||||||
|  | -{
 | ||||||
|  | -	struct tcindex_data *p = rtnl_dereference(tp->root);
 | ||||||
|  | -	struct tcindex_filter_result *r = fh;
 | ||||||
|  | -	struct nlattr *nest;
 | ||||||
|  | -
 | ||||||
|  | -	pr_debug("tcindex_dump(tp %p,fh %p,skb %p,t %p),p %p,r %p\n",
 | ||||||
|  | -		 tp, fh, skb, t, p, r);
 | ||||||
|  | -	pr_debug("p->perfect %p p->h %p\n", p->perfect, p->h);
 | ||||||
|  | -
 | ||||||
|  | -	nest = nla_nest_start_noflag(skb, TCA_OPTIONS);
 | ||||||
|  | -	if (nest == NULL)
 | ||||||
|  | -		goto nla_put_failure;
 | ||||||
|  | -
 | ||||||
|  | -	if (!fh) {
 | ||||||
|  | -		t->tcm_handle = ~0; /* whatever ... */
 | ||||||
|  | -		if (nla_put_u32(skb, TCA_TCINDEX_HASH, p->hash) ||
 | ||||||
|  | -		    nla_put_u16(skb, TCA_TCINDEX_MASK, p->mask) ||
 | ||||||
|  | -		    nla_put_u32(skb, TCA_TCINDEX_SHIFT, p->shift) ||
 | ||||||
|  | -		    nla_put_u32(skb, TCA_TCINDEX_FALL_THROUGH, p->fall_through))
 | ||||||
|  | -			goto nla_put_failure;
 | ||||||
|  | -		nla_nest_end(skb, nest);
 | ||||||
|  | -	} else {
 | ||||||
|  | -		if (p->perfect) {
 | ||||||
|  | -			t->tcm_handle = r - p->perfect;
 | ||||||
|  | -		} else {
 | ||||||
|  | -			struct tcindex_filter *f;
 | ||||||
|  | -			struct tcindex_filter __rcu **fp;
 | ||||||
|  | -			int i;
 | ||||||
|  | -
 | ||||||
|  | -			t->tcm_handle = 0;
 | ||||||
|  | -			for (i = 0; !t->tcm_handle && i < p->hash; i++) {
 | ||||||
|  | -				fp = &p->h[i];
 | ||||||
|  | -				for (f = rtnl_dereference(*fp);
 | ||||||
|  | -				     !t->tcm_handle && f;
 | ||||||
|  | -				     fp = &f->next, f = rtnl_dereference(*fp)) {
 | ||||||
|  | -					if (&f->result == r)
 | ||||||
|  | -						t->tcm_handle = f->key;
 | ||||||
|  | -				}
 | ||||||
|  | -			}
 | ||||||
|  | -		}
 | ||||||
|  | -		pr_debug("handle = %d\n", t->tcm_handle);
 | ||||||
|  | -		if (r->res.class &&
 | ||||||
|  | -		    nla_put_u32(skb, TCA_TCINDEX_CLASSID, r->res.classid))
 | ||||||
|  | -			goto nla_put_failure;
 | ||||||
|  | -
 | ||||||
|  | -		if (tcf_exts_dump(skb, &r->exts) < 0)
 | ||||||
|  | -			goto nla_put_failure;
 | ||||||
|  | -		nla_nest_end(skb, nest);
 | ||||||
|  | -
 | ||||||
|  | -		if (tcf_exts_dump_stats(skb, &r->exts) < 0)
 | ||||||
|  | -			goto nla_put_failure;
 | ||||||
|  | -	}
 | ||||||
|  | -
 | ||||||
|  | -	return skb->len;
 | ||||||
|  | -
 | ||||||
|  | -nla_put_failure:
 | ||||||
|  | -	nla_nest_cancel(skb, nest);
 | ||||||
|  | -	return -1;
 | ||||||
|  | -}
 | ||||||
|  | -
 | ||||||
|  | -static void tcindex_bind_class(void *fh, u32 classid, unsigned long cl,
 | ||||||
|  | -			       void *q, unsigned long base)
 | ||||||
|  | -{
 | ||||||
|  | -	struct tcindex_filter_result *r = fh;
 | ||||||
|  | -
 | ||||||
|  | -	if (r && r->res.classid == classid) {
 | ||||||
|  | -		if (cl)
 | ||||||
|  | -			__tcf_bind_filter(q, &r->res, base);
 | ||||||
|  | -		else
 | ||||||
|  | -			__tcf_unbind_filter(q, &r->res);
 | ||||||
|  | -	}
 | ||||||
|  | -}
 | ||||||
|  | -
 | ||||||
|  | -static struct tcf_proto_ops cls_tcindex_ops __read_mostly = {
 | ||||||
|  | -	.kind		=	"tcindex",
 | ||||||
|  | -	.classify	=	tcindex_classify,
 | ||||||
|  | -	.init		=	tcindex_init,
 | ||||||
|  | -	.destroy	=	tcindex_destroy,
 | ||||||
|  | -	.get		=	tcindex_get,
 | ||||||
|  | -	.change		=	tcindex_change,
 | ||||||
|  | -	.delete		=	tcindex_delete,
 | ||||||
|  | -	.walk		=	tcindex_walk,
 | ||||||
|  | -	.dump		=	tcindex_dump,
 | ||||||
|  | -	.bind_class	=	tcindex_bind_class,
 | ||||||
|  | -	.owner		=	THIS_MODULE,
 | ||||||
|  | -};
 | ||||||
|  | -
 | ||||||
|  | -static int __init init_tcindex(void)
 | ||||||
|  | -{
 | ||||||
|  | -	return register_tcf_proto_ops(&cls_tcindex_ops);
 | ||||||
|  | -}
 | ||||||
|  | -
 | ||||||
|  | -static void __exit exit_tcindex(void)
 | ||||||
|  | -{
 | ||||||
|  | -	unregister_tcf_proto_ops(&cls_tcindex_ops);
 | ||||||
|  | -}
 | ||||||
|  | -
 | ||||||
|  | -module_init(init_tcindex)
 | ||||||
|  | -module_exit(exit_tcindex)
 | ||||||
|  | -MODULE_LICENSE("GPL");
 | ||||||
|  | -- 
 | ||||||
|  | 2.31.1 | ||||||
|  | 
 | ||||||
| @ -0,0 +1,119 @@ | |||||||
|  | From 124abc5a2d892bffaa2830d3d596f087555f0fd3 Mon Sep 17 00:00:00 2001 | ||||||
|  | From: "Darrick J. Wong" <djwong@kernel.org> | ||||||
|  | Date: Tue, 8 Aug 2023 12:41:24 +0000 | ||||||
|  | Subject: [PATCH 5/7] xfs: verify buffer contents when we skip log replay | ||||||
|  | 
 | ||||||
|  | commit 22ed903eee23a5b174e240f1cdfa9acf393a5210 upstream | ||||||
|  | Author: Darrick J. Wong <djwong@kernel.org> | ||||||
|  | Date:   Wed Apr 12 15:49:23 2023 +1000 | ||||||
|  | 
 | ||||||
|  |     xfs: verify buffer contents when we skip log replay | ||||||
|  | 
 | ||||||
|  |     syzbot detected a crash during log recovery: | ||||||
|  | 
 | ||||||
|  |     XFS (loop0): Mounting V5 Filesystem bfdc47fc-10d8-4eed-a562-11a831b3f791 | ||||||
|  |     XFS (loop0): Torn write (CRC failure) detected at log block 0x180. Truncating head block from 0x200. | ||||||
|  |     XFS (loop0): Starting recovery (logdev: internal) | ||||||
|  |     ================================================================== | ||||||
|  |     BUG: KASAN: slab-out-of-bounds in xfs_btree_lookup_get_block+0x15c/0x6d0 fs/xfs/libxfs/xfs_btree.c:1813 | ||||||
|  |     Read of size 8 at addr ffff88807e89f258 by task syz-executor132/5074 | ||||||
|  | 
 | ||||||
|  |     CPU: 0 PID: 5074 Comm: syz-executor132 Not tainted 6.2.0-rc1-syzkaller #0 | ||||||
|  |     Hardware name: Google Google Compute Engine/Google Compute Engine, BIOS Google 10/26/2022 | ||||||
|  |     Call Trace: | ||||||
|  |      <TASK> | ||||||
|  |      __dump_stack lib/dump_stack.c:88 [inline] | ||||||
|  |      dump_stack_lvl+0x1b1/0x290 lib/dump_stack.c:106 | ||||||
|  |      print_address_description+0x74/0x340 mm/kasan/report.c:306 | ||||||
|  |      print_report+0x107/0x1f0 mm/kasan/report.c:417 | ||||||
|  |      kasan_report+0xcd/0x100 mm/kasan/report.c:517 | ||||||
|  |      xfs_btree_lookup_get_block+0x15c/0x6d0 fs/xfs/libxfs/xfs_btree.c:1813 | ||||||
|  |      xfs_btree_lookup+0x346/0x12c0 fs/xfs/libxfs/xfs_btree.c:1913 | ||||||
|  |      xfs_btree_simple_query_range+0xde/0x6a0 fs/xfs/libxfs/xfs_btree.c:4713 | ||||||
|  |      xfs_btree_query_range+0x2db/0x380 fs/xfs/libxfs/xfs_btree.c:4953 | ||||||
|  |      xfs_refcount_recover_cow_leftovers+0x2d1/0xa60 fs/xfs/libxfs/xfs_refcount.c:1946 | ||||||
|  |      xfs_reflink_recover_cow+0xab/0x1b0 fs/xfs/xfs_reflink.c:930 | ||||||
|  |      xlog_recover_finish+0x824/0x920 fs/xfs/xfs_log_recover.c:3493 | ||||||
|  |      xfs_log_mount_finish+0x1ec/0x3d0 fs/xfs/xfs_log.c:829 | ||||||
|  |      xfs_mountfs+0x146a/0x1ef0 fs/xfs/xfs_mount.c:933 | ||||||
|  |      xfs_fs_fill_super+0xf95/0x11f0 fs/xfs/xfs_super.c:1666 | ||||||
|  |      get_tree_bdev+0x400/0x620 fs/super.c:1282 | ||||||
|  |      vfs_get_tree+0x88/0x270 fs/super.c:1489 | ||||||
|  |      do_new_mount+0x289/0xad0 fs/namespace.c:3145 | ||||||
|  |      do_mount fs/namespace.c:3488 [inline] | ||||||
|  |      __do_sys_mount fs/namespace.c:3697 [inline] | ||||||
|  |      __se_sys_mount+0x2d3/0x3c0 fs/namespace.c:3674 | ||||||
|  |      do_syscall_x64 arch/x86/entry/common.c:50 [inline] | ||||||
|  |      do_syscall_64+0x3d/0xb0 arch/x86/entry/common.c:80 | ||||||
|  |      entry_SYSCALL_64_after_hwframe+0x63/0xcd | ||||||
|  |     RIP: 0033:0x7f89fa3f4aca | ||||||
|  |     Code: 83 c4 08 5b 5d c3 66 2e 0f 1f 84 00 00 00 00 00 c3 66 2e 0f 1f 84 00 00 00 00 00 0f 1f 44 00 00 49 89 ca b8 a5 00 00 00 0f 05 <48> 3d 01 f0 ff ff 73 01 c3 48 c7 c1 c0 ff ff ff f7 d8 64 89 01 48 | ||||||
|  |     RSP: 002b:00007fffd5fb5ef8 EFLAGS: 00000206 ORIG_RAX: 00000000000000a5 | ||||||
|  |     RAX: ffffffffffffffda RBX: 00646975756f6e2c RCX: 00007f89fa3f4aca | ||||||
|  |     RDX: 0000000020000100 RSI: 0000000020009640 RDI: 00007fffd5fb5f10 | ||||||
|  |     RBP: 00007fffd5fb5f10 R08: 00007fffd5fb5f50 R09: 000000000000970d | ||||||
|  |     R10: 0000000000200800 R11: 0000000000000206 R12: 0000000000000004 | ||||||
|  |     R13: 0000555556c6b2c0 R14: 0000000000200800 R15: 00007fffd5fb5f50 | ||||||
|  |      </TASK> | ||||||
|  | 
 | ||||||
|  |     The fuzzed image contains an AGF with an obviously garbage | ||||||
|  |     agf_refcount_level value of 32, and a dirty log with a buffer log item | ||||||
|  |     for that AGF.  The ondisk AGF has a higher LSN than the recovered log | ||||||
|  |     item.  xlog_recover_buf_commit_pass2 reads the buffer, compares the | ||||||
|  |     LSNs, and decides to skip replay because the ondisk buffer appears to be | ||||||
|  |     newer. | ||||||
|  | 
 | ||||||
|  |     Unfortunately, the ondisk buffer is corrupt, but recovery just read the | ||||||
|  |     buffer with no buffer ops specified: | ||||||
|  | 
 | ||||||
|  |             error = xfs_buf_read(mp->m_ddev_targp, buf_f->blf_blkno, | ||||||
|  |                             buf_f->blf_len, buf_flags, &bp, NULL); | ||||||
|  | 
 | ||||||
|  |     Skipping the buffer leaves its contents in memory unverified.  This sets | ||||||
|  |     us up for a kernel crash because xfs_refcount_recover_cow_leftovers | ||||||
|  |     reads the buffer (which is still around in XBF_DONE state, so no read | ||||||
|  |     verification) and creates a refcountbt cursor of height 32.  This is | ||||||
|  |     impossible so we run off the end of the cursor object and crash. | ||||||
|  | 
 | ||||||
|  |     Fix this by invoking the verifier on all skipped buffers and aborting | ||||||
|  |     log recovery if the ondisk buffer is corrupt.  It might be smarter to | ||||||
|  |     force replay the log item atop the buffer and then see if it'll pass the | ||||||
|  |     write verifier (like ext4 does) but for now let's go with the | ||||||
|  |     conservative option where we stop immediately. | ||||||
|  | 
 | ||||||
|  |     Link: https://syzkaller.appspot.com/bug?extid=7e9494b8b399902e994e | ||||||
|  |     Signed-off-by: Darrick J. Wong <djwong@kernel.org> | ||||||
|  |     Reviewed-by: Dave Chinner <dchinner@redhat.com> | ||||||
|  |     Signed-off-by: Dave Chinner <david@fromorbit.com> | ||||||
|  | 
 | ||||||
|  | CVE: CVE-2023-2124 | ||||||
|  | Signed-off-by: Nagappan Ramasamy Palaniappan <nagappan.ramasamy.palaniappan@oracle.com> | ||||||
|  | Reviewed-by: Laurence Rochfort <laurence.rochfort@oracle.com> | ||||||
|  | ---
 | ||||||
|  |  fs/xfs/xfs_buf_item_recover.c | 10 ++++++++++ | ||||||
|  |  1 file changed, 10 insertions(+) | ||||||
|  | 
 | ||||||
|  | diff --git a/fs/xfs/xfs_buf_item_recover.c b/fs/xfs/xfs_buf_item_recover.c
 | ||||||
|  | index aa4d45701..e8eeaf005 100644
 | ||||||
|  | --- a/fs/xfs/xfs_buf_item_recover.c
 | ||||||
|  | +++ b/fs/xfs/xfs_buf_item_recover.c
 | ||||||
|  | @@ -934,6 +934,16 @@ xlog_recover_buf_commit_pass2(
 | ||||||
|  |  	if (lsn && lsn != -1 && XFS_LSN_CMP(lsn, current_lsn) >= 0) { | ||||||
|  |  		trace_xfs_log_recover_buf_skip(log, buf_f); | ||||||
|  |  		xlog_recover_validate_buf_type(mp, bp, buf_f, NULLCOMMITLSN); | ||||||
|  | +
 | ||||||
|  | +		/*
 | ||||||
|  | +		 * We're skipping replay of this buffer log item due to the log
 | ||||||
|  | +		 * item LSN being behind the ondisk buffer.  Verify the buffer
 | ||||||
|  | +		 * contents since we aren't going to run the write verifier.
 | ||||||
|  | +		 */
 | ||||||
|  | +		if (bp->b_ops) {
 | ||||||
|  | +			bp->b_ops->verify_read(bp);
 | ||||||
|  | +			error = bp->b_error;
 | ||||||
|  | +		}
 | ||||||
|  |  		goto out_release; | ||||||
|  |  	} | ||||||
|  |   | ||||||
|  | -- 
 | ||||||
|  | 2.31.1 | ||||||
|  | 
 | ||||||
| @ -0,0 +1,48 @@ | |||||||
|  | From 24bbece0ab10a61da0356b7d56a07b0055ee143d Mon Sep 17 00:00:00 2001 | ||||||
|  | From: Wei Chen <harperchen1110@gmail.com> | ||||||
|  | Date: Tue, 8 Aug 2023 12:46:05 +0000 | ||||||
|  | Subject: [PATCH 6/7] i2c: xgene-slimpro: Fix out-of-bounds bug in | ||||||
|  |  xgene_slimpro_i2c_xfer() | ||||||
|  | 
 | ||||||
|  | commit 92fbb6d1296f81f41f65effd7f5f8c0f74943d15 upstream | ||||||
|  | Author: Wei Chen <harperchen1110@gmail.com> | ||||||
|  | Date:   Tue Mar 14 16:54:21 2023 +0000 | ||||||
|  | 
 | ||||||
|  |     i2c: xgene-slimpro: Fix out-of-bounds bug in xgene_slimpro_i2c_xfer() | ||||||
|  | 
 | ||||||
|  |     The data->block[0] variable comes from user and is a number between | ||||||
|  |     0-255. Without proper check, the variable may be very large to cause | ||||||
|  |     an out-of-bounds when performing memcpy in slimpro_i2c_blkwr. | ||||||
|  | 
 | ||||||
|  |     Fix this bug by checking the value of writelen. | ||||||
|  | 
 | ||||||
|  |     Fixes: f6505fbabc42 ("i2c: add SLIMpro I2C device driver on APM X-Gene platform") | ||||||
|  |     Signed-off-by: Wei Chen <harperchen1110@gmail.com> | ||||||
|  |     Cc: stable@vger.kernel.org | ||||||
|  |     Reviewed-by: Andi Shyti <andi.shyti@kernel.org> | ||||||
|  |     Signed-off-by: Wolfram Sang <wsa@kernel.org> | ||||||
|  | 
 | ||||||
|  | CVE: CVE-2023-2194 | ||||||
|  | Signed-off-by: Nagappan Ramasamy Palaniappan <nagappan.ramasamy.palaniappan@oracle.com> | ||||||
|  | Reviewed-by: Laurence Rochfort <laurence.rochfort@oracle.com> | ||||||
|  | ---
 | ||||||
|  |  drivers/i2c/busses/i2c-xgene-slimpro.c | 3 +++ | ||||||
|  |  1 file changed, 3 insertions(+) | ||||||
|  | 
 | ||||||
|  | diff --git a/drivers/i2c/busses/i2c-xgene-slimpro.c b/drivers/i2c/busses/i2c-xgene-slimpro.c
 | ||||||
|  | index f694b3c31..985ba3a3a 100644
 | ||||||
|  | --- a/drivers/i2c/busses/i2c-xgene-slimpro.c
 | ||||||
|  | +++ b/drivers/i2c/busses/i2c-xgene-slimpro.c
 | ||||||
|  | @@ -322,6 +322,9 @@ static int slimpro_i2c_blkwr(struct slimpro_i2c_dev *ctx, u32 chip,
 | ||||||
|  |  	u32 msg[3]; | ||||||
|  |  	int rc; | ||||||
|  |   | ||||||
|  | +	if (writelen > I2C_SMBUS_BLOCK_MAX)
 | ||||||
|  | +		return -EINVAL;
 | ||||||
|  | +
 | ||||||
|  |  	memcpy(ctx->dma_buffer, data, writelen); | ||||||
|  |  	paddr = dma_map_single(ctx->dev, ctx->dma_buffer, writelen, | ||||||
|  |  			       DMA_TO_DEVICE); | ||||||
|  | -- 
 | ||||||
|  | 2.31.1 | ||||||
|  | 
 | ||||||
| @ -0,0 +1,45 @@ | |||||||
|  | From 7dcc341e1a59f07dcd6ac591ecd90b41dcd28611 Mon Sep 17 00:00:00 2001 | ||||||
|  | From: Budimir Markovic <markovicbudimir@gmail.com> | ||||||
|  | Date: Tue, 8 Aug 2023 12:48:54 +0000 | ||||||
|  | Subject: [PATCH 7/7] perf: Fix check before add_event_to_groups() in | ||||||
|  |  perf_group_detach() | ||||||
|  | 
 | ||||||
|  | commit fd0815f632c24878e325821943edccc7fde947a2 upstream | ||||||
|  | Author: Budimir Markovic <markovicbudimir@gmail.com> | ||||||
|  | Date:   Wed Mar 15 00:29:01 2023 -0700 | ||||||
|  | 
 | ||||||
|  | Events should only be added to a groups rb tree if they have not been | ||||||
|  | removed from their context by list_del_event(). Since remove_on_exec | ||||||
|  | made it possible to call list_del_event() on individual events before | ||||||
|  | they are detached from their group, perf_group_detach() should check each | ||||||
|  | sibling's attach_state before calling add_event_to_groups() on it. | ||||||
|  | 
 | ||||||
|  | Fixes: 2e498d0a74e5 ("perf: Add support for event removal on exec") | ||||||
|  | 
 | ||||||
|  |     Signed-off-by: Budimir Markovic <markovicbudimir@gmail.com> | ||||||
|  |     Signed-off-by: Peter Zijlstra (Intel) <peterz@infradead.org> | ||||||
|  |     Link: https://lkml.kernel.org/r/ZBFzvQV9tEqoHEtH@gentoo | ||||||
|  | 
 | ||||||
|  | CVE: CVE-2023-2235 | ||||||
|  | Signed-off-by: Nagappan Ramasamy Palaniappan <nagappan.ramasamy.palaniappan@oracle.com> | ||||||
|  | Reviewed-by: Laurence Rochfort <laurence.rochfort@oracle.com> | ||||||
|  | ---
 | ||||||
|  |  kernel/events/core.c | 2 +- | ||||||
|  |  1 file changed, 1 insertion(+), 1 deletion(-) | ||||||
|  | 
 | ||||||
|  | diff --git a/kernel/events/core.c b/kernel/events/core.c
 | ||||||
|  | index d2adc3cbf..182494495 100644
 | ||||||
|  | --- a/kernel/events/core.c
 | ||||||
|  | +++ b/kernel/events/core.c
 | ||||||
|  | @@ -2210,7 +2210,7 @@ static void perf_group_detach(struct perf_event *event)
 | ||||||
|  |  		/* Inherit group flags from the previous leader */ | ||||||
|  |  		sibling->group_caps = event->group_caps; | ||||||
|  |   | ||||||
|  | -		if (!RB_EMPTY_NODE(&event->group_node)) {
 | ||||||
|  | +		if (sibling->attach_state & PERF_ATTACH_CONTEXT) {
 | ||||||
|  |  			add_event_to_groups(sibling, event->ctx); | ||||||
|  |   | ||||||
|  |  			if (sibling->state == PERF_EVENT_STATE_ACTIVE) | ||||||
|  | -- 
 | ||||||
|  | 2.31.1 | ||||||
|  | 
 | ||||||
| @ -38,11 +38,11 @@ | |||||||
| # define buildid .local | # define buildid .local | ||||||
| 
 | 
 | ||||||
| %define rpmversion 4.18.0 | %define rpmversion 4.18.0 | ||||||
| %define pkgrelease 477.15.1.el8_8 | %define pkgrelease 477.21.1.el8_8 | ||||||
| %define tarfile_release 477.13.1.el8_8 | %define tarfile_release 477.13.1.el8_8 | ||||||
| 
 | 
 | ||||||
| # allow pkg_release to have configurable %%{?dist} tag | # allow pkg_release to have configurable %%{?dist} tag | ||||||
| %define specrelease 477.15.1%{?dist} | %define specrelease 477.21.1%{?dist} | ||||||
| 
 | 
 | ||||||
| %define pkg_release %{specrelease}%{?buildid} | %define pkg_release %{specrelease}%{?buildid} | ||||||
| 
 | 
 | ||||||
| @ -527,6 +527,13 @@ Patch1000: debrand-single-cpu.patch | |||||||
| # Patch1001: debrand-rh_taint.patch | # Patch1001: debrand-rh_taint.patch | ||||||
| Patch1002: debrand-rh-i686-cpu.patch | Patch1002: debrand-rh-i686-cpu.patch | ||||||
| Patch1003: 1001-net-tls-fix-possible-race-condition-between-do_tls_g.patch | Patch1003: 1001-net-tls-fix-possible-race-condition-between-do_tls_g.patch | ||||||
|  | Patch1004: 1002-Bluetooth-L2CAP-Fix-accepting-connection-request.patch | ||||||
|  | Patch1005: 1003-net-sched-tcindex-update-imperfect-hash-filters-resp.patch | ||||||
|  | Patch1006: 1004-net-sched-tcindex-search-key-must-be-16-bits.patch | ||||||
|  | Patch1007: 1005-net-sched-Retire-tcindex-classifier.patch | ||||||
|  | Patch1008: 1006-xfs-verify-buffer-contents-when-we-skip-log-replay.patch | ||||||
|  | Patch1009: 1007-i2c-xgene-slimpro-Fix-out-of-bounds-bug-in-xgene_sli.patch | ||||||
|  | Patch1010: 1008-perf-Fix-check-before-add_event_to_groups-in-perf_gr.patch | ||||||
| 
 | 
 | ||||||
| # END OF PATCH DEFINITIONS | # END OF PATCH DEFINITIONS | ||||||
| 
 | 
 | ||||||
| @ -1091,6 +1098,13 @@ ApplyPatch debrand-single-cpu.patch | |||||||
| # ApplyPatch debrand-rh_taint.patch | # ApplyPatch debrand-rh_taint.patch | ||||||
| ApplyPatch debrand-rh-i686-cpu.patch | ApplyPatch debrand-rh-i686-cpu.patch | ||||||
| ApplyPatch 1001-net-tls-fix-possible-race-condition-between-do_tls_g.patch | ApplyPatch 1001-net-tls-fix-possible-race-condition-between-do_tls_g.patch | ||||||
|  | ApplyPatch 1002-Bluetooth-L2CAP-Fix-accepting-connection-request.patch | ||||||
|  | ApplyPatch 1003-net-sched-tcindex-update-imperfect-hash-filters-resp.patch | ||||||
|  | ApplyPatch 1004-net-sched-tcindex-search-key-must-be-16-bits.patch | ||||||
|  | ApplyPatch 1005-net-sched-Retire-tcindex-classifier.patch | ||||||
|  | ApplyPatch 1006-xfs-verify-buffer-contents-when-we-skip-log-replay.patch | ||||||
|  | ApplyPatch 1007-i2c-xgene-slimpro-Fix-out-of-bounds-bug-in-xgene_sli.patch | ||||||
|  | ApplyPatch 1008-perf-Fix-check-before-add_event_to_groups-in-perf_gr.patch | ||||||
| ApplyOptionalPatch linux-kernel-test.patch | ApplyOptionalPatch linux-kernel-test.patch | ||||||
| 
 | 
 | ||||||
| # END OF PATCH APPLICATIONS | # END OF PATCH APPLICATIONS | ||||||
| @ -2694,6 +2708,15 @@ fi | |||||||
| # | # | ||||||
| # | # | ||||||
| %changelog | %changelog | ||||||
|  | * Tue Aug 8 2023 Nagappan Ramasamy Palaniappan <nagappan.ramasamy.palaniappan@oracle.com> [4.18.0-477.21.1.el8_8] | ||||||
|  | - Bluetooth: L2CAP: Fix accepting connection request for invalid SPSM (Tamás Koczka) {CVE-2022-42896} | ||||||
|  | - net/sched: tcindex: update imperfect hash filters respecting rcu (Jamal Hadi Salim) {CVE-2023-1281} | ||||||
|  | - net/sched: tcindex: search key must be 16 bits (Jamal Hadi Salim) {CVE-2023-1281} | ||||||
|  | - net/sched: Retire tcindex classifier (Jamal Hadi Salim) {CVE-2023-1829} | ||||||
|  | - xfs: verify buffer contents when we skip log replay (Darrick J. Wong) {CVE-2023-2124} | ||||||
|  | - i2c: xgene-slimpro: Fix out-of-bounds bug in xgene_slimpro_i2c_xfer() (Wei Chen) {CVE-2023-2194} | ||||||
|  | - perf: Fix check before add_event_to_groups() in perf_group_detach() (Budimir Markovic) {CVE-2023-2235} | ||||||
|  | 
 | ||||||
| * Mon Jul 24 2023 Andrew Lukoshko <alukoshko@almalinux.org> [4.18.0-477.15.1.el8_8] | * Mon Jul 24 2023 Andrew Lukoshko <alukoshko@almalinux.org> [4.18.0-477.15.1.el8_8] | ||||||
| - net: tls: fix possible race condition between do_tls_getsockopt_conf() and do_tls_setsockopt_conf() (Hangyu Hua) {CVE-2023-28466} | - net: tls: fix possible race condition between do_tls_getsockopt_conf() and do_tls_setsockopt_conf() (Hangyu Hua) {CVE-2023-28466} | ||||||
| 
 | 
 | ||||||
|  | |||||||
		Loading…
	
		Reference in New Issue
	
	Block a user