6.1.191-rc1 review
Subsystems (12)
Greg Kroah-Hartman
maintainerPATCH 1289/1887 selftests: tls: add rekey tests
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Sabrina Dubroca <[email protected]>
[ Upstream commit 555f0edb9ff043196655a5b7cc65f67dfd05b530 ]
Test the kernel's ability to:
- update the key (but not the version or cipher), only for TLS1.3
- pause decryption after receiving a KeyUpdate message, until a new RX key has been provided
- reflect the pause/non-readable socket in poll()
Stable-dep-of: 1c8629651cb5 ("tls: rx: restore msg_iter before TLS 1.3 optimistic retry")
--- tools/testing/selftests/net/tls.c | 458 ++++++++++++++++++++++++++++++ 1 file changed, 458 insertions(+)
tools/testing/selftests/net/tls.c +458 -0
@@ -1529,6 +1529,464 @@ TEST_F(tls, recv_efault)EXPECT_EQ (memcmp (rec2, recv_mem +9 , ret -9 ),0 ); } +#define TLS_RECORD_TYPE_HANDSHAKE 0x16 +/* key_update, length 1, update_not_requested */ +static const char key_update_msg[] ="\x18\x00\x00\x01\x00" ; +static void tls_send_keyupdate (struct __test_metadata *_metadata,int fd) +{ +size_t len =sizeof (key_update_msg); + +EXPECT_EQ (tls_send_cmsg (fd,TLS_RECORD_TYPE_HANDSHAKE , + (char *)key_update_msg, len,0 ), + len); +} + +static void tls_recv_keyupdate (struct __test_metadata *_metadata,int fd,int flags) +{ +char buf[100 ]; + +EXPECT_EQ (tls_recv_cmsg (_metadata, fd,TLS_RECORD_TYPE_HANDSHAKE , buf,sizeof (buf), flags), +sizeof (key_update_msg)); +EXPECT_EQ (memcmp (buf, key_update_msg,sizeof (key_update_msg)),0 ); +} + +/* set the key to 0 then 1 for RX, immediately to 1 for TX */ +TEST_F(tls_basic, rekey_rx) +{ +struct tls_crypto_info_keys tls12_0, tls12_1; +char const *test_str ="test_message" ; +int send_len =strlen (test_str) +1 ; +char buf[20 ]; +int ret; + +if (self->notls) +return ; + +tls_crypto_info_init (TLS_1_3_VERSION ,TLS_CIPHER_AES_GCM_128 , + &tls12_0,0 ); +tls_crypto_info_init (TLS_1_3_VERSION ,TLS_CIPHER_AES_GCM_128 , + &tls12_1,1 ); + + ret =setsockopt (self->fd,SOL_TLS ,TLS_TX , &tls12_1, tls12_1.len); +ASSERT_EQ (ret,0 ); + + ret =setsockopt (self->cfd,SOL_TLS ,TLS_RX , &tls12_0, tls12_0.len); +ASSERT_EQ (ret,0 ); + + ret =setsockopt (self->cfd,SOL_TLS ,TLS_RX , &tls12_1, tls12_1.len); +EXPECT_EQ (ret,0 ); + +EXPECT_EQ (send (self->fd, test_str, send_len,0 ), send_len); +EXPECT_EQ (recv (self->cfd, buf, send_len,0 ), send_len); +EXPECT_EQ (memcmp (buf, test_str, send_len),0 ); +} + +/* set the key to 0 then 1 for TX, immediately to 1 for RX */ +TEST_F(tls_basic, rekey_tx) +{ +struct tls_crypto_info_keys tls12_0, tls12_1; +char const *test_str ="test_message" ; +int send_len =strlen (test_str) +1 ; +char buf[20 ]; +int ret; + +if (self->notls) +return ; + +tls_crypto_info_init (TLS_1_3_VERSION ,TLS_CIPHER_AES_GCM_128 , + &tls12_0,0 ); +tls_crypto_info_init (TLS_1_3_VERSION ,TLS_CIPHER_AES_GCM_128 , + &tls12_1,1 ); + + ret =setsockopt (self->fd,SOL_TLS ,TLS_TX , &tls12_0, tls12_0.len); +ASSERT_EQ (ret,0 ); + + ret =setsockopt (self->cfd,SOL_TLS ,TLS_RX , &tls12_1, tls12_1.len); +ASSERT_EQ (ret,0 ); + + ret =setsockopt (self->fd,SOL_TLS ,TLS_TX , &tls12_1, tls12_1.len); +EXPECT_EQ (ret,0 ); + +EXPECT_EQ (send (self->fd, test_str, send_len,0 ), send_len); +EXPECT_EQ (recv (self->cfd, buf, send_len,0 ), send_len); +EXPECT_EQ (memcmp (buf, test_str, send_len),0 ); +} + +TEST_F(tls, rekey) +{ +char const *test_str_1 ="test_message_before_rekey" ; +char const *test_str_2 ="test_message_after_rekey" ; +struct tls_crypto_info_keys tls12; +int send_len; +char buf[100 ]; + +if (variant->tls_version !=TLS_1_3_VERSION ) +return ; + +/* initial send/recv */ + send_len =strlen (test_str_1) +1 ; +EXPECT_EQ (send (self->fd, test_str_1, send_len,0 ), send_len); +EXPECT_EQ (recv (self->cfd, buf, send_len,0 ), send_len); +EXPECT_EQ (memcmp (buf, test_str_1, send_len),0 ); + +/* update TX key */ +tls_send_keyupdate (_metadata, self->fd); +tls_crypto_info_init (variant->tls_version, variant->cipher_type, &tls12,1 ); +EXPECT_EQ (setsockopt (self->fd,SOL_TLS ,TLS_TX , &tls12, tls12.len),0 ); + +/* send after rekey */ + send_len =strlen (test_str_2) +1 ; +EXPECT_EQ (send (self->fd, test_str_2, send_len,0 ), send_len); + +/* can't receive the KeyUpdate without a control message */ +EXPECT_EQ (recv (self->cfd, buf, send_len,0 ),-1 ); + +/* get KeyUpdate */ +tls_recv_keyupdate (_metadata, self->cfd,0 ); + +/* recv blocking -> -EKEYEXPIRED */ +EXPECT_EQ (recv (self->cfd, buf,sizeof (buf),0 ),-1 ); +EXPECT_EQ (errno,EKEYEXPIRED ); + +/* recv non-blocking -> -EKEYEXPIRED */ +EXPECT_EQ (recv (self->cfd, buf,sizeof (buf),MSG_DONTWAIT ),-1 ); +EXPECT_EQ (errno,EKEYEXPIRED ); + +/* update RX key */ +EXPECT_EQ (setsockopt (self->cfd,SOL_TLS ,TLS_RX , &tls12, tls12.len),0 ); + +/* recv after rekey */ +EXPECT_NE (recv (self->cfd, buf, send_len,0 ),-1 ); +EXPECT_EQ (memcmp (buf, test_str_2, send_len),0 ); +} + +TEST_F(tls, rekey_fail) +{ +char const *test_str_1 ="test_message_before_rekey" ; +char const *test_str_2 ="test_message_after_rekey" ; +struct tls_crypto_info_keys tls12; +int send_len; +char buf[100 ]; + +/* initial send/recv */ + send_len =strlen (test_str_1) +1 ; +EXPECT_EQ (send (self->fd, test_str_1, send_len,0 ), send_len); +EXPECT_EQ (recv (self->cfd, buf, send_len,0 ), send_len); +EXPECT_EQ (memcmp (buf, test_str_1, send_len),0 ); + +/* update TX key */ +tls_send_keyupdate (_metadata, self->fd); + +if (variant->tls_version !=TLS_1_3_VERSION ) { +/* just check that rekey is not supported and return */ +tls_crypto_info_init (variant->tls_version, variant->cipher_type, &tls12,1 ); +EXPECT_EQ (setsockopt (self->fd,SOL_TLS ,TLS_TX , &tls12, tls12.len),-1 ); +EXPECT_EQ (errno,EBUSY ); +return ; + } + +/* successful update */ +tls_crypto_info_init (variant->tls_version, variant->cipher_type, &tls12,1 ); +EXPECT_EQ (setsockopt (self->fd,SOL_TLS ,TLS_TX , &tls12, tls12.len),0 ); + +/* invalid update: change of version */ +tls_crypto_info_init (TLS_1_2_VERSION , variant->cipher_type, &tls12,1 ); +EXPECT_EQ (setsockopt (self->fd,SOL_TLS ,TLS_TX , &tls12, tls12.len),-1 ); +EXPECT_EQ (errno,EINVAL ); + +/* invalid update (RX socket): change of version */ +tls_crypto_info_init (TLS_1_2_VERSION , variant->cipher_type, &tls12,1 ); +EXPECT_EQ (setsockopt (self->cfd,SOL_TLS ,TLS_RX , &tls12, tls12.len),-1 ); +EXPECT_EQ (errno,EINVAL ); + +/* invalid update: change of cipher */ +if (variant->cipher_type ==TLS_CIPHER_AES_GCM_256 ) +tls_crypto_info_init (variant->tls_version,TLS_CIPHER_CHACHA20_POLY1305 , &tls12,1 ); +else +tls_crypto_info_init (variant->tls_version,TLS_CIPHER_AES_GCM_256 , &tls12,1 ); +EXPECT_EQ (setsockopt (self->fd,SOL_TLS ,TLS_TX , &tls12, tls12.len),-1 ); +EXPECT_EQ (errno,EINVAL ); + +/* send after rekey, the invalid updates shouldn't have an effect */ + send_len =strlen (test_str_2) +1 ; +EXPECT_EQ (send (self->fd, test_str_2, send_len,0 ), send_len); + +/* can't receive the KeyUpdate without a control message */ +EXPECT_EQ (recv (self->cfd, buf, send_len,0 ),-1 ); + +/* get KeyUpdate */ +tls_recv_keyupdate (_metadata, self->cfd,0 ); + +/* recv blocking -> -EKEYEXPIRED */ +EXPECT_EQ (recv (self->cfd, buf,sizeof (buf),0 ),-1 ); +EXPECT_EQ (errno,EKEYEXPIRED ); + +/* recv non-blocking -> -EKEYEXPIRED */ +EXPECT_EQ (recv (self->cfd, buf,sizeof (buf),MSG_DONTWAIT ),-1 ); +EXPECT_EQ (errno,EKEYEXPIRED ); + +/* update RX key */ +tls_crypto_info_init (variant->tls_version, variant->cipher_type, &tls12,1 ); +EXPECT_EQ (setsockopt (self->cfd,SOL_TLS ,TLS_RX , &tls12, tls12.len),0 ); + +/* recv after rekey */ +EXPECT_NE (recv (self->cfd, buf, send_len,0 ),-1 ); +EXPECT_EQ (memcmp (buf, test_str_2, send_len),0 ); +} + +TEST_F(tls, rekey_peek) +{ +char const *test_str_1 ="test_message_before_rekey" ; +struct tls_crypto_info_keys tls12; +int send_len; +char buf[100 ]; + +if (variant->tls_version !=TLS_1_3_VERSION ) +return ; + + send_len =strlen (test_str_1) +1 ; +EXPECT_EQ (send (self->fd, test_str_1, send_len,0 ), send_len); + +/* update TX key */ +tls_send_keyupdate (_metadata, self->fd); +tls_crypto_info_init (variant->tls_version, variant->cipher_type, &tls12,1 ); +EXPECT_EQ (setsockopt (self->fd,SOL_TLS ,TLS_TX , &tls12, tls12.len),0 ); + +EXPECT_EQ (recv (self->cfd, buf,sizeof (buf),MSG_PEEK ), send_len); +EXPECT_EQ (memcmp (buf, test_str_1, send_len),0 ); + +EXPECT_EQ (recv (self->cfd, buf, send_len,0 ), send_len); +EXPECT_EQ (memcmp (buf, test_str_1, send_len),0 ); + +/* can't receive the KeyUpdate without a control message */ +EXPECT_EQ (recv (self->cfd, buf, send_len,MSG_PEEK ),-1 ); + +/* peek KeyUpdate */ +tls_recv_keyupdate (_metadata, self->cfd,MSG_PEEK ); + +/* get KeyUpdate */ +tls_recv_keyupdate (_metadata, self->cfd,0 ); + +/* update RX key */ +EXPECT_EQ (setsockopt (self->cfd,SOL_TLS ,TLS_RX , &tls12, tls12.len),0 ); +} + +TEST_F(tls, splice_rekey) +{ +int send_len =TLS_PAYLOAD_MAX_LEN /2 ; +char mem_send[TLS_PAYLOAD_MAX_LEN ]; +char mem_recv[TLS_PAYLOAD_MAX_LEN ]; +struct tls_crypto_info_keys tls12; +int p[2 ]; + +if (variant->tls_version !=TLS_1_3_VERSION ) +return ; + +memrnd (mem_send,sizeof (mem_send)); + +ASSERT_GE (pipe (p),0 ); +EXPECT_EQ (send (self->fd, mem_send, send_len,0 ), send_len); + +/* update TX key */ +tls_send_keyupdate (_metadata, self->fd); +tls_crypto_info_init (variant->tls_version, variant->cipher_type, &tls12,1 ); +EXPECT_EQ (setsockopt (self->fd,SOL_TLS ,TLS_TX , &tls12, tls12.len),0 ); + +EXPECT_EQ (send (self->fd, mem_send, send_len,0 ), send_len); + +EXPECT_EQ (splice (self->cfd,NULL , p[1 ],NULL ,TLS_PAYLOAD_MAX_LEN ,0 ), send_len); +EXPECT_EQ (read (p[0 ], mem_recv, send_len), send_len); +EXPECT_EQ (memcmp (mem_send, mem_recv, send_len),0 ); + +/* can't splice the KeyUpdate */ +EXPECT_EQ (splice (self->cfd,NULL , p[1 ],NULL ,TLS_PAYLOAD_MAX_LEN ,0 ),-1 ); +EXPECT_EQ (errno,EINVAL ); + +/* peek KeyUpdate */ +tls_recv_keyupdate (_metadata, self->cfd,MSG_PEEK ); + +/* get KeyUpdate */ +tls_recv_keyupdate (_metadata, self->cfd,0 ); + +/* can't splice before updating the key */ +EXPECT_EQ (splice (self->cfd,NULL , p[1 ],NULL ,TLS_PAYLOAD_MAX_LEN ,0 ),-1 ); +EXPECT_EQ (errno,EKEYEXPIRED ); + +/* update RX key */ +EXPECT_EQ (setsockopt (self->cfd,SOL_TLS ,TLS_RX , &tls12, tls12.len),0 ); + +EXPECT_EQ (splice (self->cfd,NULL , p[1 ],NULL ,TLS_PAYLOAD_MAX_LEN ,0 ), send_len); +EXPECT_EQ (read (p[0 ], mem_recv, send_len), send_len); +EXPECT_EQ (memcmp (mem_send, mem_recv, send_len),0 ); +} + +TEST_F(tls, rekey_peek_splice) +{ +char const *test_str_1 ="test_message_before_rekey" ; +struct tls_crypto_info_keys tls12; +int send_len; +char buf[100 ]; +char mem_recv[TLS_PAYLOAD_MAX_LEN ]; +int p[2 ]; + +if (variant->tls_version !=TLS_1_3_VERSION ) +return ; + +ASSERT_GE (pipe (p),0 ); + + send_len =strlen (test_str_1) +1 ; +EXPECT_EQ (send (self->fd, test_str_1, send_len,0 ), send_len); + +/* update TX key */ +tls_send_keyupdate (_metadata, self->fd); +tls_crypto_info_init (variant->tls_version, variant->cipher_type, &tls12,1 ); +EXPECT_EQ (setsockopt (self->fd,SOL_TLS ,TLS_TX , &tls12, tls12.len),0 ); + +EXPECT_EQ (recv (self->cfd, buf,sizeof (buf),MSG_PEEK ), send_len); +EXPECT_EQ (memcmp (buf, test_str_1, send_len),0 ); + +EXPECT_EQ (splice (self->cfd,NULL , p[1 ],NULL ,TLS_PAYLOAD_MAX_LEN ,0 ), send_len); +EXPECT_EQ (read (p[0 ], mem_recv, send_len), send_len); +EXPECT_EQ (memcmp (mem_recv, test_str_1, send_len),0 ); +} + +TEST_F(tls, rekey_getsockopt) +{ +struct tls_crypto_info_keys tls12; +struct tls_crypto_info_keys tls12_get; +socklen_t len; + +tls_crypto_info_init (variant->tls_version, variant->cipher_type, &tls12,0 ); + + len = tls12.len; +EXPECT_EQ (getsockopt (self->fd,SOL_TLS ,TLS_TX , &tls12_get, &len),0 ); +EXPECT_EQ (len, tls12.len); +EXPECT_EQ (memcmp (&tls12_get, &tls12, tls12.len),0 ); + + len = tls12.len; +EXPECT_EQ (getsockopt (self->cfd,SOL_TLS ,TLS_RX , &tls12_get, &len),0 ); +EXPECT_EQ (len, tls12.len); +EXPECT_EQ (memcmp (&tls12_get, &tls12, tls12.len),0 ); + +if (variant->tls_version !=TLS_1_3_VERSION ) +return ; + +tls_send_keyupdate (_metadata, self->fd); +tls_crypto_info_init (variant->tls_version, variant->cipher_type, &tls12,1 ); +EXPECT_EQ (setsockopt (self->fd,SOL_TLS ,TLS_TX , &tls12, tls12.len),0 ); + +tls_recv_keyupdate (_metadata, self->cfd,0 ); +EXPECT_EQ (setsockopt (self->cfd,SOL_TLS ,TLS_RX , &tls12, tls12.len),0 ); + + len = tls12.len; +EXPECT_EQ (getsockopt (self->fd,SOL_TLS ,TLS_TX , &tls12_get, &len),0 ); +EXPECT_EQ (len, tls12.len); +EXPECT_EQ (memcmp (&tls12_get, &tls12, tls12.len),0 ); + + len = tls12.len; +EXPECT_EQ (getsockopt (self->cfd,SOL_TLS ,TLS_RX , &tls12_get, &len),0 ); +EXPECT_EQ (len, tls12.len); +EXPECT_EQ (memcmp (&tls12_get, &tls12, tls12.len),0 ); +} + +TEST_F(tls, rekey_poll_pending) +{ +char const *test_str ="test_message_after_rekey" ; +struct tls_crypto_info_keys tls12; +struct pollfd pfd = { }; +int send_len; +int ret; + +if (variant->tls_version !=TLS_1_3_VERSION ) +return ; + +/* update TX key */ +tls_send_keyupdate (_metadata, self->fd); +tls_crypto_info_init (variant->tls_version, variant->cipher_type, &tls12,1 ); +EXPECT_EQ (setsockopt (self->fd,SOL_TLS ,TLS_TX , &tls12, tls12.len),0 ); + +/* get KeyUpdate */ +tls_recv_keyupdate (_metadata, self->cfd,0 ); + +/* send immediately after rekey */ + send_len =strlen (test_str) +1 ; +EXPECT_EQ (send (self->fd, test_str, send_len,0 ), send_len); + +/* key hasn't been updated, expect cfd to be non-readable */ + pfd.fd = self->cfd; + pfd.events =POLLIN ; +EXPECT_EQ (poll (&pfd,1 ,0 ),0 ); + + ret =fork (); +ASSERT_GE (ret,0 ); + +if (ret) { +int pid2, status; + +/* wait before installing the new key */ +sleep (1 ); + +/* update RX key while poll() is sleeping */ +EXPECT_EQ (setsockopt (self->cfd,SOL_TLS ,TLS_RX , &tls12, tls12.len),0 ); + + pid2 =wait (&status); +EXPECT_EQ (pid2, ret); +EXPECT_EQ (status,0 ); + }else { + pfd.fd = self->cfd; + pfd.events =POLLIN ; +EXPECT_EQ (poll (&pfd,1 ,5000 ),1 ); + +exit (!__test_passed (_metadata)); + } +} + +TEST_F(tls, rekey_poll_delay) +{ +char const *test_str ="test_message_after_rekey" ; +struct tls_crypto_info_keys tls12; +struct pollfd pfd = { }; +int send_len; +int ret; + +if (variant->tls_version !=TLS_1_3_VERSION ) +return ; + +/* update TX key */ +tls_send_keyupdate (_metadata, self->fd); +tls_crypto_info_init (variant->tls_version, variant->cipher_type, &tls12,1 ); +EXPECT_EQ (setsockopt (self->fd,SOL_TLS ,TLS_TX , &tls12, tls12.len),0 ); + +/* get KeyUpdate */ +tls_recv_keyupdate (_metadata, self->cfd,0 ); + + ret =fork (); +ASSERT_GE (ret,0 ); + +if (ret) { +int pid2, status; + +/* wait before installing the new key */ +sleep (1 ); + +/* update RX key while poll() is sleeping */ +EXPECT_EQ (setsockopt (self->cfd,SOL_TLS ,TLS_RX , &tls12, tls12.len),0 ); + +sleep (1 ); + send_len =strlen (test_str) +1 ; +EXPECT_EQ (send (self->fd, test_str, send_len,0 ), send_len); + + pid2 =wait (&status); +EXPECT_EQ (pid2, ret); +EXPECT_EQ (status,0 ); + }else { + pfd.fd = self->cfd; + pfd.events =POLLIN ; +EXPECT_EQ (poll (&pfd,1 ,5000 ),1 ); +exit (!__test_passed (_metadata)); + } +} +FIXTURE (tls_err) {int fd, cfd;
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1290/1887 tls: rx: restore msg_iter before TLS 1.3 optimistic retry
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Jérémy Jean <[email protected]>
[ Upstream commit 1c8629651cb54f7b51db8fc0b1a9944e4a4b0f5e ]
tls_decrypt_sg() advances msg->msg_iter when it maps user pages for the optimistic TLS 1.3 zero-copy path. If the decrypted record turns out not to be unpadded application data, tls_decrypt_sw() retries into a kernel skb, but leaves the iterator advanced.
The subsequent copy from the skb then writes decrypted bytes again at a later point in the caller iovecs while recvmsg() reports only the post-retry length. A TLS peer can trigger this after the receiver enables TLS_RX_EXPECT_NO_PAD.
Revert the iterator by the number of bytes consumed by the optimistic mapping before retrying without zero-copy.
Add a selftest which sends a TLS 1.3 control record with TLS_RX_EXPECT_NO_PAD enabled and verifies that recvmsg() does not overwrite later iovecs beyond the returned length.
--- net/tls/tls_sw.c | 2 ++ tools/testing/selftests/net/tls.c | 57 +++++++++++++++++++++++++++++++ 2 files changed, 59 insertions(+)
net/tls/tls_sw.c +2 -0
@@ -1807,6 +1807,8 @@ tls_decrypt_sw(struct sock *sk, struct tls_context *tls_ctx,/* If opportunistic TLS 1.3 ZC failed retry without ZC */ if (unlikely (darg->zc && prot->version ==TLS_1_3_VERSION && darg->tail !=TLS_RECORD_TYPE_DATA )) { +iov_iter_revert (&msg->msg_iter,strp_msg (darg->skb)->full_len - + prot->overhead_size); darg->zc = false;if (!darg->tail)TLS_INC_STATS (sock_net (sk),LINUX_MIB_TLSRXNOPADVIOL );
tools/testing/selftests/net/tls.c +57 -0
63 lines not on this page · raw message
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1291/1887 net: tap: set skb->dev before parsing virtio net header in tap_get_user_xdp()
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Dongli Zhang <[email protected]>
[ Upstream commit 3874892dd27d5387aa9a06f58d9060f18f351d24 ]
The commit 4f61f133f354 ("net: tap: NULL pointer derefence in dev_parse_header_protocol when skb->dev is null") fixed a crash in tap_get_user() by assigning skb->dev before calling tun_vnet_hdr_to_skb(). This is required because virtio_net_hdr_to_skb() may invoke dev_parse_header_protocol(), which dereferences skb->dev. Without the assignment, a NULL pointer dereference can occur.
However, tap_get_user_xdp() still parses the virtio-net header before assigning skb->dev. When the vhost TX path passes an XDP buffer containing a GSO virtio-net header but the protocol is set to zero on purpose, tun_vnet_hdr_to_skb() can reach dev_parse_header_protocol() while skb->dev is still NULL, resulting in a crash.
Fix this by looking up the tap device and assigning skb->dev before calling tun_vnet_hdr_to_skb(), matching the ordering already used in tap_get_user(). Preserve the existing RCU read-side critical section across dev_queue_xmit().
--- drivers/net/tap.c | 24 ++++++++++++++---------- 1 file changed, 14 insertions(+), 10 deletions(-)
drivers/net/tap.c +14 -10
@@ -1179,10 +1179,21 @@ static int tap_get_user_xdp(struct tap_queue *q, struct xdp_buff *xdp)skb_reset_mac_header (skb); skb->protocol =eth_hdr (skb)->h_proto; +rcu_read_lock (); + tap =rcu_dereference (q->tap); +if (!tap) { +kfree_skb (skb); +rcu_read_unlock (); +return 0 ; + } + skb->dev = tap->dev; +if (vnet_hdr_len) { err =virtio_net_hdr_to_skb (skb, gso,tap_is_little_endian (q)); -if (err) +if (err) { +rcu_read_unlock (); goto err_kfree; + } }/* Move network header to the right position for VLAN tagged packets */
@@ -1190,15 +1201,8 @@ static int tap_get_user_xdp(struct tap_queue *q, struct xdp_buff *xdp) vlan_get_protocol_and_depth(skb, skb->protocol, &depth) != 0)skb_set_network_header (skb, depth); -rcu_read_lock (); - tap =rcu_dereference (q->tap); -if (tap) { - skb->dev = tap->dev; -skb_probe_transport_header (skb); -dev_queue_xmit (skb); - }else { -kfree_skb (skb); - } +skb_probe_transport_header (skb); +dev_queue_xmit (skb);rcu_read_unlock ();return 0 ;
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1292/1887 watchdog: at91sam9_wdt: prevent timer rearm during teardown
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Hongyan Xu <[email protected]>
[ Upstream commit 8444d66aa6b6e7fe0a26fa1a00a11cb4d0523783 ]
at91_ping() rearms the watchdog timer from its callback. timer_delete() neither waits for a running callback nor prevents it from rearming the timer, so probe failure or driver removal can leave the timer accessing the devm-allocated at91wdt after it has been freed.
Use timer_shutdown_sync() on both teardown paths. It waits for a running callback and rejects any attempt by the callback to rearm the timer.
--- drivers/watchdog/at91sam9_wdt.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-)
drivers/watchdog/at91sam9_wdt.c +2 -2
@@ -242,7 +242,7 @@ static int at91_wdt_init(struct platform_device *pdev, struct at91wdt *wdt)return 0 ; out_stop_timer: -del_timer (&wdt->timer); +timer_shutdown_sync (&wdt->timer);return err; }
@@ -387,7 +387,7 @@ static int __exit at91wdt_remove(struct platform_device *pdev)watchdog_unregister_device (&wdt->wdd);pr_warn ("I quit now, hardware will probably reboot!\n" ); -del_timer (&wdt->timer); +timer_shutdown_sync (&wdt->timer);clk_disable_unprepare (wdt->sclk);return 0 ;
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1293/1887 s390/ism: Fix UAF of sba and ieq during ism_dev_exit()
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Alexandra Winter <[email protected]>
[ Upstream commit b1896543ce59c4258625a35cf41e23a9a1f80ea2 ]
A ism interrupt handler can be active in parallel with ism_dev_exit(), accessing freed data structures.
No new interrupts will be generated after unregister_ieq(). Drain ongoing interrupt handlers by free_irq(), before freeing ism data structures.
--- drivers/s390/net/ism_drv.c | 20 ++++++++++++++++---- 1 file changed, 16 insertions(+), 4 deletions(-)
drivers/s390/net/ism_drv.c +16 -4
@@ -153,13 +153,16 @@ static int unregister_sba(struct ism_dev *ism)if (ret && ret !=ISM_ERROR )return -EIO ; +return 0 ; +} + +static void ism_free_sba (struct ism_dev *ism) +{dma_free_coherent (&ism->pdev->dev,PAGE_SIZE , ism->sba, ism->sba_dma_addr); ism->sba =NULL ; ism->sba_dma_addr =0 ; - -return 0 ; }static int unregister_ieq (struct ism_dev *ism)
@@ -173,13 +176,16 @@ static int unregister_ieq(struct ism_dev *ism)if (ret && ret !=ISM_ERROR )return -EIO ; +return 0 ; +} + +static void ism_free_ieq (struct ism_dev *ism) +{dma_free_coherent (&ism->pdev->dev,PAGE_SIZE , ism->ieq, ism->ieq_dma_addr); ism->ieq =NULL ; ism->ieq_dma_addr =0 ; - -return 0 ; }static int ism_read_local_gid (struct ism_dev *ism)
@@ -537,8 +543,10 @@ static int ism_dev_init(struct ism_dev *ism) unreg_ieq:unregister_ieq (ism); +ism_free_ieq (ism); unreg_sba:unregister_sba (ism); +ism_free_sba (ism); free_irq:free_irq (pci_irq_vector (pdev,0 ), ism); free_vectors:
@@ -611,9 +619,13 @@ static void ism_dev_exit(struct ism_dev *ism)if (SYSTEM_EID .serial_number[0 ] !='0' ||SYSTEM_EID .type[0 ] !='0' )ism_del_vlan_id (ism->smcd,ISM_RESERVED_VLANID ); +/* ism will only generate new IRQs while ieq & sba are registered */ unregister_ieq (ism);unregister_sba (ism); +/* drain ongoing irpt handlers */ free_irq (pci_irq_vector (pdev,0 ), ism); +ism_free_ieq (ism); +ism_free_sba (ism);pci_free_irq_vectors (pdev); }
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1294/1887 netfilter: nf_flow_table: drop existing skb dst before skb_dst_set_noref()
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Eric Dumazet <[email protected]>
[ Upstream commit 8aecf0bbcc72605592134c917c222207d8f63ab0 ]
Incoming skbs passing through netfilter flowtable offload hooks (or XFRM offload path) might already carry a ref-counted dst_entry assigned during earlier RX or routing steps.
Calling skb_dst_set_noref() when skb already holds a ref-counted dst overwrites skb->_skb_refdst, leaking the previous dst_entry reference count and triggering a DEBUG_NET_WARN_ON_ONCE assertion in skb_dst_check_unset():
WARNING: at skb_dst_check_unset include/linux/skbuff.h:1170 WARNING: at skb_dst_set_noref include/linux/skbuff.h:1234 WARNING: at nf_flow_offload_ip_hook+0xf6c/0x2b60 net/netfilter/nf_flow_table_ip.c:864
Drop any existing dst_entry reference with skb_dst_drop(skb) before setting the non-referenced flowtable destination.
--- net/netfilter/nf_flow_table_ip.c | 3 +++ 1 file changed, 3 insertions(+)
net/netfilter/nf_flow_table_ip.c +3 -0
@@ -262,6 +262,7 @@ static unsigned int nf_flow_xmit_xfrm(struct sk_buff *skb, struct dst_entry *dst) {skb_orphan (skb); +skb_dst_drop (skb);skb_dst_set_noref (skb, dst);dst_output (state->net, state->sk, skb);return NF_STOLEN ;
@@ -417,6 +418,7 @@ nf_flow_offload_ip_hook(void *priv, struct sk_buff *skb, outdev = rt->dst.dev; skb->dev = outdev; nexthop =rt_nexthop (rt, flow->tuplehash[!dir].tuple.src_v4.s_addr); +skb_dst_drop (skb);skb_dst_set_noref (skb, &rt->dst);neigh_xmit (NEIGH_ARP_TABLE , outdev, &nexthop, skb); ret =NF_STOLEN ;
@@ -678,6 +680,7 @@ nf_flow_offload_ipv6_hook(void *priv, struct sk_buff *skb, outdev = rt->dst.dev; skb->dev = outdev; nexthop =rt6_nexthop (rt, &flow->tuplehash[!dir].tuple.src_v6); +skb_dst_drop (skb);skb_dst_set_noref (skb, &rt->dst);neigh_xmit (NEIGH_ND_TABLE , outdev, nexthop, skb); ret =NF_STOLEN ;
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1295/1887 net: sched: cls_api: add skip_sw counter
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Asbjørn Sloth Tønnesen <[email protected]>
[ Upstream commit f631ef39d81956a2ee69d25039781ceae1162f62 ]
Maintain a count of skip_sw filters.
This counter is protected by the cb_lock, and is updated at the same time as offloadcnt.
Stable-dep-of: a347304b2ca1 ("net/sched: cls_api: Always acquire rtnl_lock when destroying locked classifiers")
--- include/net/sch_generic.h | 1 + net/sched/cls_api.c | 4 ++++ 2 files changed, 5 insertions(+)
include/net/sch_generic.h +1 -0
@@ -477,6 +477,7 @@ struct tcf_block {struct flow_block flow_block;struct list_head owner_list;bool keep_dst; +atomic_t skipswcnt;/* Number of skip_sw filters */ atomic_t offloadcnt;/* Number of oddloaded filters */ unsigned int nooffloaddevcnt;/* Number of devs unable to do offload */ unsigned int lockeddevcnt;/* Number of devs that require rtnl lock. */
net/sched/cls_api.c +4 -0
@@ -3302,6 +3302,8 @@ static void tcf_block_offload_inc(struct tcf_block *block, u32 *flags)if (*flags &TCA_CLS_FLAGS_IN_HW )return ; *flags |=TCA_CLS_FLAGS_IN_HW ; +if (tc_skip_sw (*flags)) +atomic_inc (&block->skipswcnt);atomic_inc (&block->offloadcnt); }
@@ -3310,6 +3312,8 @@ static void tcf_block_offload_dec(struct tcf_block *block, u32 *flags)if (!(*flags &TCA_CLS_FLAGS_IN_HW ))return ; *flags &= ~TCA_CLS_FLAGS_IN_HW ; +if (tc_skip_sw (*flags)) +atomic_dec (&block->skipswcnt);atomic_dec (&block->offloadcnt); }
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1296/1887 net: sched: cls_api: add filter counter
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Asbjørn Sloth Tønnesen <[email protected]>
[ Upstream commit 2081fd3445fec6b9813c20e8b910c2abd6de31cb ]
Maintain a count of filters per block.
Counter updates are protected by cb_lock, which is also used to protect the offload counters.
Stable-dep-of: a347304b2ca1 ("net/sched: cls_api: Always acquire rtnl_lock when destroying locked classifiers")
--- include/net/sch_generic.h | 2 ++ net/sched/cls_api.c | 19 +++++++++++++++++++ 2 files changed, 21 insertions(+)
include/net/sch_generic.h +2 -0
@@ -429,6 +429,7 @@ struct tcf_proto {*/ spinlock_t lock;bool deleting; +bool counted;refcount_t refcnt;struct rcu_head rcu;struct hlist_node destroy_ht_node;
@@ -477,6 +478,7 @@ struct tcf_block {struct flow_block flow_block;struct list_head owner_list;bool keep_dst; +atomic_t filtercnt;/* Number of filters */ atomic_t skipswcnt;/* Number of skip_sw filters */ atomic_t offloadcnt;/* Number of oddloaded filters */ unsigned int nooffloaddevcnt;/* Number of devs unable to do offload */
net/sched/cls_api.c +19 -0
@@ -305,12 +305,30 @@ static void tcf_proto_get(struct tcf_proto *tp)refcount_inc (&tp->refcnt); } +static void tcf_block_filter_cnt_update (struct tcf_block *block,bool *counted,bool add) +{ +lockdep_assert_not_held (&block->cb_lock); + +down_write (&block->cb_lock); +if (*counted != add) { +if (add) { +atomic_inc (&block->filtercnt); + *counted = true; + }else { +atomic_dec (&block->filtercnt); + *counted = false; + } + } +up_write (&block->cb_lock); +} +static void tcf_chain_put (struct tcf_chain *chain);static void tcf_proto_destroy (struct tcf_proto *tp,bool rtnl_held,bool sig_destroy,struct netlink_ext_ack *extack) { tp->ops->destroy (tp, rtnl_held, extack); +tcf_block_filter_cnt_update (tp->chain->block, &tp->counted, false);if (sig_destroy)tcf_proto_signal_destroyed (tp->chain, tp);tcf_chain_put (tp->chain);
@@ -2208,6 +2226,7 @@ static int tc_new_tfilter(struct sk_buff *skb, struct nlmsghdr *n, err = tp->ops->change (net, skb, tp, cl, t->tcm_handle, tca, &fh, flags, extack);if (err ==0 ) { +tcf_block_filter_cnt_update (block, &tp->counted, true);tfilter_notify (net, skb, n, tp, block, q, parent, fh,RTM_NEWTFILTER , false, rtnl_held, extack);tfilter_put (tp, fh);
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1297/1887 net: sched: cls_api: fix slab-use-after-free in fl_dump_key
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Jianbo Liu <[email protected]>
[ Upstream commit 2ecd487b670fcbb1ad4893fff1af4aafdecb6023 ]
The filter counter is updated under the protection of cb_lock in the cited commit. While waiting for the lock, it's possible the filter is being deleted by other thread, and thus causes UAF when dump it.
Fix this issue by moving tcf_block_filter_cnt_update() after tfilter_put().
==================================================================
BUG: KASAN: slab-use-after-free in fl_dump_key+0x1d3e/0x20d0 [cls_flower] Read of size 4 at addr ffff88814f864000 by task tc/2973 CPU: 7 PID: 2973 Comm: tc Not tainted 6.9.0-rc2_for_upstream_debug_2024_04_02_12_41 #1 Hardware name: QEMU Standard PC (Q35 + ICH9, 2009), BIOS rel-1.13.0-0-gf21b5a4aeb02-prebuilt.qemu.org 04/01/2014 Call Trace: <TASK> dump_stack_lvl+0x7e/0xc0 print_report+0xc1/0x600 ? __virt_addr_valid+0x1cf/0x390 ? fl_dump_key+0x1d3e/0x20d0 [cls_flower] ? fl_dump_key+0x1d3e/0x20d0 [cls_flower] kasan_report+0xb9/0xf0 ? fl_dump_key+0x1d3e/0x20d0 [cls_flower] fl_dump_key+0x1d3e/0x20d0 [cls_flower] ? lock_acquire+0x1c2/0x530 ? fl_dump+0x172/0x5c0 [cls_flower] ? lockdep_hardirqs_on_prepare+0x400/0x400 ? fl_dump_key_options.part.0+0x10f0/0x10f0 [cls_flower] ? do_raw_spin_lock+0x12d/0x270 ? spin_bug+0x1d0/0x1d0 fl_dump+0x21d/0x5c0 [cls_flower] ? fl_tmplt_dump+0x1f0/0x1f0 [cls_flower] ? nla_put+0x15f/0x1c0 tcf_fill_node+0x51b/0x9a0 ? tc_skb_ext_tc_enable+0x150/0x150 ? __alloc_skb+0x17b/0x310 ? __build_skb_around+0x340/0x340 ? down_write+0x1b0/0x1e0 tfilter_notify+0x1a5/0x390 ? fl_terse_dump+0x400/0x400 [cls_flower] tc_new_tfilter+0x963/0x2170 ? tc_del_tfilter+0x1490/0x1490 ? print_usage_bug.part.0+0x670/0x670 ? lock_downgrade+0x680/0x680 ? security_capable+0x51/0x90 ? tc_del_tfilter+0x1490/0x1490 rtnetlink_rcv_msg+0x75e/0xac0 ? if_nlmsg_stats_size+0x4c0/0x4c0 ? lockdep_set_lock_cmp_fn+0x190/0x190 ? __netlink_lookup+0x35e/0x6e0 netlink_rcv_skb+0x12c/0x360 ? if_nlmsg_stats_size+0x4c0/0x4c0 ? netlink_ack+0x15e0/0x15e0 ? lockdep_hardirqs_on_prepare+0x400/0x400 ? netlink_deliver_tap+0xcd/0xa60 ? netlink_deliver_tap+0xcd/0xa60 ? netlink_deliver_tap+0x1c9/0xa60 netlink_unicast+0x43e/0x700 ? netlink_attachskb+0x750/0x750 ? lock_acquire+0x1c2/0x530 ? __might_fault+0xbb/0x170 netlink_sendmsg+0x749/0xc10 ? netlink_unicast+0x700/0x700 ? __might_fault+0xbb/0x170 ? netlink_unicast+0x700/0x700 __sock_sendmsg+0xc5/0x190 ____sys_sendmsg+0x534/0x6b0 ? import_iovec+0x7/0x10 ? kernel_sendmsg+0x30/0x30 ? __copy_msghdr+0x3c0/0x3c0 ? entry_SYSCALL_64_after_hwframe+0x46/0x4e ? lock_acquire+0x1c2/0x530 ? __virt_addr_valid+0x116/0x390 ___sys_sendmsg+0xeb/0x170 ? __virt_addr_valid+0x1ca/0x390 ? copy_msghdr_from_user+0x110/0x110 ? __delete_object+0xb8/0x100 ? __virt_addr_valid+0x1cf/0x390 ? do_sys_openat2+0x102/0x150 ? lockdep_hardirqs_on_prepare+0x284/0x400 ? do_sys_openat2+0x102/0x150 ? __fget_light+0x53/0x1d0 ? sockfd_lookup_light+0x1a/0x150 __sys_sendmsg+0xb5/0x140 ? __sys_sendmsg_sock+0x20/0x20 ? lock_downgrade+0x680/0x680 do_syscall_64+0x70/0x140 entry_SYSCALL_64_after_hwframe+0x46/0x4e RIP: 0033:0x7f98e3713367 Code: 0e 00 f7 d8 64 89 02 48 c7 c0 ff ff ff ff eb b9 0f 1f 00 f3 0f 1e fa 64 8b 04 25 18 00 00 00 85 c0 75 10 b8 2e 00 00 00 0f 05 <48> 3d 00 f0 ff ff 77 51 c3 48 83 ec 28 89 54 24 1c 48 89 74 24 10 RSP: 002b:00007ffc74a64608 EFLAGS: 00000246 ORIG_RAX: 000000000000002e RAX: ffffffffffffffda RBX: 000000000047eae0 RCX: 00007f98e3713367 RDX: 0000000000000000 RSI: 00007ffc74a64670 RDI: 0000000000000003 RBP: 0000000000000008 R08: 0000000000000000 R09: 0000000000000000 R10: 00007f98e360c5e8 R11: 0000000000000246 R12: 00007ffc74a6a508 R13: 00000000660d518d R14: 0000000000484a80 R15: 00007ffc74a6a50b </TASK> Allocated by task 2973: kasan_save_stack+0x20/0x40 kasan_save_track+0x10/0x30 __kasan_kmalloc+0x77/0x90 fl_change+0x27a6/0x4540 [cls_flower] tc_new_tfilter+0x879/0x2170 rtnetlink_rcv_msg+0x75e/0xac0 netlink_rcv_skb+0x12c/0x360 netlink_unicast+0x43e/0x700 netlink_sendmsg+0x749/0xc10 __sock_sendmsg+0xc5/0x190 ____sys_sendmsg+0x534/0x6b0 ___sys_sendmsg+0xeb/0x170 __sys_sendmsg+0xb5/0x140 do_syscall_64+0x70/0x140 entry_SYSCALL_64_after_hwframe+0x46/0x4e Freed by task 283: kasan_save_stack+0x20/0x40 kasan_save_track+0x10/0x30 kasan_save_free_info+0x37/0x50 poison_slab_object+0x105/0x190 __kasan_slab_free+0x11/0x30 kfree+0x111/0x340 process_one_work+0x787/0x1490 worker_thread+0x586/0xd30 kthread+0x2df/0x3b0 ret_from_fork+0x2d/0x70 ret_from_fork_asm+0x11/0x20 Last potentially related work creation: kasan_save_stack+0x20/0x40 __kasan_record_aux_stack+0x9b/0xb0 insert_work+0x25/0x1b0 __queue_work+0x640/0xc90 rcu_work_rcufn+0x42/0x70 rcu_core+0x6a9/0x1850 __do_softirq+0x264/0x88f Second to last potentially related work creation: kasan_save_stack+0x20/0x40 __kasan_record_aux_stack+0x9b/0xb0 __call_rcu_common.constprop.0+0x6f/0xac0 queue_rcu_work+0x56/0x70 fl_mask_put+0x20d/0x270 [cls_flower] __fl_delete+0x352/0x6b0 [cls_flower] fl_delete+0x97/0x160 [cls_flower] tc_del_tfilter+0x7d1/0x1490 rtnetlink_rcv_msg+0x75e/0xac0 netlink_rcv_skb+0x12c/0x360 netlink_unicast+0x43e/0x700 netlink_sendmsg+0x749/0xc10 __sock_sendmsg+0xc5/0x190 ____sys_sendmsg+0x534/0x6b0 ___sys_sendmsg+0xeb/0x170 __sys_sendmsg+0xb5/0x140 do_syscall_64+0x70/0x140 entry_SYSCALL_64_after_hwframe+0x46/0x4e
Stable-dep-of: a347304b2ca1 ("net/sched: cls_api: Always acquire rtnl_lock when destroying locked classifiers")
--- net/sched/cls_api.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
net/sched/cls_api.c +1 -1
@@ -2226,10 +2226,10 @@ static int tc_new_tfilter(struct sk_buff *skb, struct nlmsghdr *n, err = tp->ops->change (net, skb, tp, cl, t->tcm_handle, tca, &fh, flags, extack);if (err ==0 ) { -tcf_block_filter_cnt_update (block, &tp->counted, true);tfilter_notify (net, skb, n, tp, block, q, parent, fh,RTM_NEWTFILTER , false, rtnl_held, extack);tfilter_put (tp, fh); +tcf_block_filter_cnt_update (block, &tp->counted, true);/* q pointer is NULL for shared blocks */ if (q) q->flags &= ~TCQ_F_CAN_BYPASS ;
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1298/1887 net: sched: refine software bypass handling in tc_run
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Xin Long <[email protected]>
[ Upstream commit a12c76a03386e32413ae8eaaefa337e491880632 ]
This patch addresses issues with filter counting in block (tcf_block), particularly for software bypass scenarios, by introducing a more accurate mechanism using useswcnt.
Previously, filtercnt and skipswcnt were introduced by:
Commit 2081fd3445fe ("net: sched: cls_api: add filter counter") and Commit f631ef39d819 ("net: sched: cls_api: add skip_sw counter")
filtercnt tracked all tp (tcf_proto) objects added to a block, and skipswcnt counted tp objects with the skipsw attribute set.
The problem is: a single tp can contain multiple filters, some with skipsw and others without. The current implementation fails in the case:
When the first filter in a tp has skipsw, both skipswcnt and filtercnt are incremented, then adding a second filter without skipsw to the same tp does not modify these counters because tp->counted is already set.
This results in bypass software behavior based solely on skipswcnt equaling filtercnt, even when the block includes filters without skipsw. Consequently, filters without skipsw are inadvertently bypassed.
To address this, the patch introduces useswcnt in block to explicitly count tp objects containing at least one filter without skipsw. Key changes include:
Whenever a filter without skipsw is added, its tp is marked with usesw and counted in useswcnt. tc_run() now uses useswcnt to determine software bypass, eliminating reliance on filtercnt and skipswcnt.
This refined approach prevents software bypass for blocks containing mixed filters, ensuring correct behavior in tc_run().
Additionally, as atomic operations on useswcnt ensure thread safety and tp->lock guards access to tp->usesw and tp->counted, the broader lock down_write(&block->cb_lock) is no longer required in tc_new_tfilter(), and this resolves a performance regression caused by the filter counting mechanism during parallel filter insertions.
The improvement can be demonstrated using the following script:
# cat insert_tc_rules.sh
tc qdisc add dev ens1f0np0 ingress
for i in $(seq 16); do
taskset -c $i tc -b rules_$i.txt &
done
wait
Each of rules_$i.txt files above includes 100000 tc filter rules to a mlx5 driver NIC ens1f0np0.
Without this patch:
# time sh insert_tc_rules.sh
real 0m50.780s
user 0m23.556s
sys 4m13.032sWith this patch:
# time sh insert_tc_rules.sh
real 0m17.718s
user 0m7.807s
sys 3m45.050s[ Adapted to this tree: it has no tc_run() software bypass, so only the
useswcnt accounting and the tcf_sw_enabled_key definition are kept and the tc_run() hunk is dropped. ]
Stable-dep-of: a347304b2ca1 ("net/sched: cls_api: Always acquire rtnl_lock when destroying locked classifiers")
--- include/net/pkt_cls.h | 13 ++++++++++++ include/net/sch_generic.h | 4 ++-- net/core/dev.c | 5 +++++ net/sched/cls_api.c | 43 +++++++++++++++++++++++---------------- net/sched/cls_bpf.c | 2 ++ net/sched/cls_flower.c | 2 ++ net/sched/cls_matchall.c | 2 ++ net/sched/cls_u32.c | 4 ++++ 8 files changed, 55 insertions(+), 20 deletions(-)
include/net/pkt_cls.h +13 -0
@@ -70,6 +70,10 @@ static inline bool tcf_block_non_null_shared(struct tcf_block *block)return block && block->index; } +#ifdef CONFIG_NET_CLS_ACT +DECLARE_STATIC_KEY_FALSE (tcf_sw_enabled_key); +#endif +static inline struct Qdisc *tcf_block_q (struct tcf_block *block) {WARN_ON (tcf_block_shared (block));
@@ -762,6 +766,15 @@ tc_cls_common_offload_init(struct flow_cls_common_offload *cls_common, cls_common->extack = extack; } +static inline void tcf_proto_update_usesw (struct tcf_proto *tp,u32 flags) +{ +if (tp->usesw) +return ; +if (tc_skip_sw (flags) &&tc_in_hw (flags)) +return ; + tp->usesw = true; +} +#if IS_ENABLED (CONFIG_NET_TC_SKB_EXT )static inline struct tc_skb_ext *tc_skb_ext_alloc (struct sk_buff *skb) {
include/net/sch_generic.h +2 -2
@@ -430,6 +430,7 @@ struct tcf_proto {spinlock_t lock;bool deleting;bool counted; +bool usesw;refcount_t refcnt;struct rcu_head rcu;struct hlist_node destroy_ht_node;
@@ -478,8 +479,7 @@ struct tcf_block {struct flow_block flow_block;struct list_head owner_list;bool keep_dst; -atomic_t filtercnt;/* Number of filters */ -atomic_t skipswcnt;/* Number of skip_sw filters */ +atomic_t useswcnt;atomic_t offloadcnt;/* Number of oddloaded filters */ unsigned int nooffloaddevcnt;/* Number of devs unable to do offload */ unsigned int lockeddevcnt;/* Number of devs that require rtnl lock. */
net/core/dev.c +5 -0
@@ -2121,6 +2121,11 @@ void net_dec_egress_queue(void)EXPORT_SYMBOL_GPL (net_dec_egress_queue);#endif +#ifdef CONFIG_NET_CLS_ACT +DEFINE_STATIC_KEY_FALSE (tcf_sw_enabled_key); +EXPORT_SYMBOL (tcf_sw_enabled_key); +#endif +DEFINE_STATIC_KEY_FALSE (netstamp_needed_key);EXPORT_SYMBOL (netstamp_needed_key);#ifdef CONFIG_JUMP_LABEL
net/sched/cls_api.c +25 -18
82 lines not on this page · raw message
net/sched/cls_bpf.c +2 -0
@@ -507,6 +507,8 @@ static int cls_bpf_change(struct net *net, struct sk_buff *in_skb,if (!tc_in_hw (prog->gen_flags)) prog->gen_flags |=TCA_CLS_FLAGS_NOT_IN_HW ; +tcf_proto_update_usesw (tp, prog->gen_flags); +if (oldprog) {idr_replace (&head->handle_idr, prog, handle);list_replace_rcu (&oldprog->link, &prog->link);
net/sched/cls_flower.c +2 -0
@@ -2240,6 +2240,8 @@ static int fl_change(struct net *net, struct sk_buff *in_skb,if (!tc_in_hw (fnew->flags)) fnew->flags |=TCA_CLS_FLAGS_NOT_IN_HW ; +tcf_proto_update_usesw (tp, fnew->flags); +spin_lock (&tp->lock);/* tp was deleted concurrently. -EAGAIN will cause caller to lookup
net/sched/cls_matchall.c +2 -0
@@ -226,6 +226,8 @@ static int mall_change(struct net *net, struct sk_buff *in_skb,if (!tc_in_hw (new->flags)) new->flags |=TCA_CLS_FLAGS_NOT_IN_HW ; +tcf_proto_update_usesw (tp, new->flags); + *arg = head;rcu_assign_pointer (tp->root, new);return 0 ;
net/sched/cls_u32.c +4 -0
@@ -964,6 +964,8 @@ static int u32_change(struct net *net, struct sk_buff *in_skb,if (!tc_in_hw (new->flags)) new->flags |=TCA_CLS_FLAGS_NOT_IN_HW ; +tcf_proto_update_usesw (tp, new->flags); +u32_replace_knode (tp, tp_c, new);tcf_unbind_filter (tp, &n->res);tcf_exts_get_net (&n->exts);
@@ -1196,6 +1198,8 @@ static int u32_change(struct net *net, struct sk_buff *in_skb,if (!tc_in_hw (n->flags)) n->flags |=TCA_CLS_FLAGS_NOT_IN_HW ; +tcf_proto_update_usesw (tp, n->flags); + ins = &ht->ht[TC_U32_HASH (handle)];for (pins =rtnl_dereference (*ins); pins; ins = &pins->next, pins =rtnl_dereference (*ins))
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1299/1887 net/sched: cls_api: Always acquire rtnl_lock when destroying locked classifiers
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Jamal Hadi Salim <[email protected]>
[ Upstream commit a347304b2ca1a5377d5bd2d8a72e4b4f12afe648 ]
Another challenge with unlocked filters.
There is a short window in tc_new_tfilter where a tcf_proto can be found and briefly referenced by a totally unrelated, unlocked classifier's request and cause a race.
Feng created a poc which created this race with two threads, one creating a u32 filter and other a flower filter in the same chain/prio:
1. Both threads enter tc_new_tfilter, both find the chain empty, both drop filter_chain_lock
2. u32 finishes tcf_proto_create("u32") first, calls tcf_chain_tp_insert_unique() -> inserts u32_tp into the chain
3. flower finishes tcf_proto_create("flower") later, calls tcf_chain_tp_insert_unique() -> tcf_chain_tp_find() now sees u32_tp already there, takes a reference on it, destroys flower's own tp_new and returns u32_tp to the caller.
Flower then hits the kind mismatch check (because it requested for kind "flower" but tp->ops->kind is "u32") and goes through the errout path which calls tcf_proto_put() on u32_tp. If the u32 thread has already gone through its own errout (its change() call failed on the PoC's empty options) and dropped its create and insert refs, flower's put is the last one and drops u32_tp's refcnt to zero.
At this point tp->ops->destroy() runs in a context that never took rtnl_lock. When that happens, it might cause a UAF like the following (illustrated by the PoC):
[ +0.000710] BUG: KASAN: slab-use-after-free in u32_init (net/sched/cls_u32.c:393) [ +0.000281] Read of size 8 at addr ffff888120022f00 by task poc_feng_xue/524
Call Trace: u32_init (net/sched/cls_u32.c:393) tc_new_tfilter (net/sched/cls_api.c:2378) Allocated by task 526: u32_init (net/sched/cls_u32.c:378) tc_new_tfilter (net/sched/cls_api.c:2378) Freed by task 522: kfree u32_destroy (net/sched/cls_u32.c:662) tcf_proto_destroy (net/sched/cls_api.c:446) tcf_proto_put (net/sched/cls_api.c:459) tc_new_tfilter (net/sched/cls_api.c:2459)
Fix this by having tcf_proto_destroy() take rtnl_lock around tp->ops->destroy() for locked classifiers whenever rtnl is not held.
To explain why I used a temp variable "not_lockless" I'd like to point to a semi-related note on rtnl_held vs TCF_PROTO_OPS_DOIT_UNLOCKED (adding here for future cleanup if deemed necessary):
The rtnl_held parameter and the TCF_PROTO_OPS_DOIT_UNLOCKED flag are redundant sources of truth for whether rtnl_lock is held. Among the nine classifier destroy(..rtnl_held..) callbacks, only flower consults the rtnl_held parameter which it propagates to tc_setup_cb_destroy() and tc_setup_cb_call(). The other eight (u32, flow, bpf, cgroup, route, basic, fw, mall) ignore it entirely;-> those that call tc_setup_cb_destroy() (u32, bpf, mall) hardcode true always instead of forwarding the parameter.
A future cleanup should remove the rtnl_held parameter from the destroy callback signature entirely and have callers rely solely on their knowledge whether they are running in an unlocked context.
--- net/sched/cls_api.c | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-)
net/sched/cls_api.c +16 -1
@@ -338,7 +338,22 @@ static void tcf_chain_put(struct tcf_chain *chain);static void tcf_proto_destroy (struct tcf_proto *tp,bool rtnl_held,bool sig_destroy,struct netlink_ext_ack *extack) { - tp->ops->destroy (tp, rtnl_held, extack); +/* A locked classifier's destroy callback (e.g. u32_destroy) uses +* rtnl_dereference() and mutates shared structures (e.g. the +* tc_u_common hash list) that are only safe under rtnl_lock. When an +* unlocked classifier's request (e.g. flower on ingress) loses the +* tcf_chain_tp_insert_unique() race and ends up dropping the last +* reference on a locked classifier's proto, destroy() would run +* without rtnl held. Take it here in that case. +*/ +bool not_lockless = !rtnl_held && + !(tp->ops->flags &TCF_PROTO_OPS_DOIT_UNLOCKED ); + +if (not_lockless) +rtnl_lock (); + tp->ops->destroy (tp, rtnl_held || not_lockless, extack); +if (not_lockless) +rtnl_unlock ();tcf_proto_count_usesw (tp, false);if (sig_destroy)tcf_proto_signal_destroyed (tp->chain, tp);
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1300/1887 vhost_iotlb: bound map allocation in add_range
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Linfeng Sun <[email protected]>
[ Upstream commit 1ed35ac7f3fe2b4396bdd29ac3a7f0ebc0829e94 ]
vhost_iotlb_add_range_ctx() only retires an old entry when the table has a non-zero limit, has exactly reached that limit and has VHOST_IOTLB_FLAG_RETIRE set. Non-retiring tables can keep allocating entries after reaching their configured limit.
Existing vhost devices allocate their IOTLB with max_iotlb_entries from vhost.c, which defaults to 2048 and is tunable by module parameter. Use the caller-provided limit at the allocation point instead of adding a separate default in the common IOTLB helper, and reject non-positive values in vhost paths that can report an error.
Other vhost IOTLB users should not create zero-limit tables when entries can be populated from userspace or guest-controlled requests. Add caller-side max_iotlb_entries parameters for mlx5 vDPA, VDUSE and vhost-vDPA. Reject non-positive VDUSE and vhost-vDPA values, and require at least two entries for vdpa_sim and mlx5 vDPA paths that install full-range mappings, since those mappings are split into two IOTLB entries.
Handle full-range mappings in the common helper by checking that the IOTLB can hold both split entries before inserting the first half. This avoids returning an error after leaving a half mapping behind.
When the table is full, keep the existing retire behavior for retiring tables and return -ENOSPC for non-retiring tables. Reuse the retired map node instead of freeing it and allocating a replacement, so a stream of IOTLB updates cannot keep forcing GFP_ATOMIC allocations after the table has reached its limit. If a zero-limit IOTLB still reaches the common helper, treat it as a configuration error and return -EINVAL.
I found this bug myself, though the patch was written with AI assistance.
Message-ID: <AMYAtgAiKmgYcSQT5ukl-4qq.3.1781960405943.Hmail.241270009@hdu.edu.cn>
--- drivers/vdpa/mlx5/core/mlx5_vdpa.h | 2 ++ drivers/vdpa/mlx5/core/mr.c | 3 ++ drivers/vdpa/mlx5/core/resources.c | 11 ++++++- drivers/vdpa/vdpa_sim/vdpa_sim.c | 5 ++- drivers/vdpa/vdpa_user/iova_domain.c | 11 ++++++- drivers/vhost/iotlb.c | 47 +++++++++++++++++++--------- drivers/vhost/vdpa.c | 9 +++++- drivers/vhost/vhost.c | 8 +++++ 8 files changed, 78 insertions(+), 18 deletions(-)
drivers/vdpa/mlx5/core/mlx5_vdpa.h +2 -0
@@ -11,6 +11,8 @@#define MLX5V_ETH_HARD_MTU (ETH_HLEN + VLAN_HLEN + ETH_FCS_LEN) +extern int mlx5_vdpa_max_iotlb_entries; +struct mlx5_vdpa_direct_mr {u64 start;u64 end;
drivers/vdpa/mlx5/core/mr.c +3 -0
@@ -562,6 +562,9 @@ static int _mlx5_vdpa_create_dvq_mr(struct mlx5_vdpa_dev *mvdev,if (mr->initialized)return 0 ; +if (mlx5_vdpa_max_iotlb_entries <2 ) +return -EINVAL ; +if (iotlb) err =create_user_mr (mvdev, iotlb);else
drivers/vdpa/mlx5/core/resources.c +10 -1
@@ -3,8 +3,14 @@#include <linux/iova.h> #include <linux/mlx5/driver.h> +#include <linux/moduleparam.h> #include "mlx5_vdpa.h" +int mlx5_vdpa_max_iotlb_entries =2048 ; +module_param_named (max_iotlb_entries, mlx5_vdpa_max_iotlb_entries, int,0444 ); +MODULE_PARM_DESC (max_iotlb_entries, +"Maximum number of iotlb entries. (default: 2048)" ); +static int alloc_pd (struct mlx5_vdpa_dev *dev,u32 *pdn,u16 uid) {struct mlx5_core_dev *mdev = dev->mdev;
@@ -229,7 +235,10 @@ int mlx5_vdpa_destroy_mkey(struct mlx5_vdpa_dev *mvdev, u32 mkey)static int init_ctrl_vq (struct mlx5_vdpa_dev *mvdev) { - mvdev->cvq.iotlb =vhost_iotlb_alloc (0 ,0 ); +if (mlx5_vdpa_max_iotlb_entries <2 ) +return -EINVAL ; + + mvdev->cvq.iotlb =vhost_iotlb_alloc (mlx5_vdpa_max_iotlb_entries,0 );if (!mvdev->cvq.iotlb)return -ENOMEM ;
drivers/vdpa/vdpa_sim/vdpa_sim.c +4 -1
@@ -34,7 +34,7 @@ MODULE_PARM_DESC(batch_mapping, "Batched mapping 1 -Enable; 0 - Disable");static int max_iotlb_entries =2048 ;module_param (max_iotlb_entries, int,0444 );MODULE_PARM_DESC (max_iotlb_entries, -"Maximum number of iotlb entries for each address space. 0 means unlimited. (default: 2048)" ); +"Maximum number of iotlb entries for each address space. (default: 2048)" );#define VDPASIM_QUEUE_ALIGN PAGE_SIZE#define VDPASIM_QUEUE_MAX 256
@@ -266,6 +266,9 @@ struct vdpasim *vdpasim_create(struct vdpasim_dev_attr *dev_attr,struct device *dev;int i, ret = -ENOMEM ; +if (max_iotlb_entries <2 ) +return ERR_PTR (-EINVAL ); +if (config->mask &BIT_ULL (VDPA_ATTR_DEV_FEATURES )) {if (config->device_features & ~dev_attr->supported_features)
drivers/vdpa/vdpa_user/iova_domain.c +10 -1
@@ -12,11 +12,17 @@#include <linux/file.h> #include <linux/anon_inodes.h> #include <linux/highmem.h> +#include <linux/moduleparam.h> #include <linux/vmalloc.h> #include <linux/vdpa.h> #include "iova_domain.h" +static int max_iotlb_entries =2048 ; +module_param (max_iotlb_entries, int,0444 ); +MODULE_PARM_DESC (max_iotlb_entries, +"Maximum number of iotlb entries. (default: 2048)" ); + static int vduse_iotlb_add_range(struct vduse_iova_domain *domain, u64 start, u64 last, u64 addr, unsigned int perm,
@@ -608,11 +614,14 @@ vduse_domain_create(unsigned long iova_limit, size_t bounce_size)if (iova_limit <= bounce_size)return NULL ; +if (max_iotlb_entries <=0 ) +return NULL ; + domain =kzalloc (sizeof (*domain),GFP_KERNEL );if (!domain)return NULL ; - domain->iotlb =vhost_iotlb_alloc (0 ,0 ); + domain->iotlb =vhost_iotlb_alloc (max_iotlb_entries,0 );if (!domain->iotlb) goto err_iotlb;
drivers/vhost/iotlb.c +33 -14
80 lines not on this page · raw message
drivers/vhost/vdpa.c +8 -1
@@ -34,6 +34,11 @@ enum {#define VHOST_VDPA_DEV_MAX (1U << MINORBITS) +static int max_iotlb_entries =2048 ; +module_param (max_iotlb_entries, int,0444 ); +MODULE_PARM_DESC (max_iotlb_entries, +"Maximum number of iotlb entries. (default: 2048)" ); +#define VHOST_VDPA_IOTLB_BUCKETS 16struct vhost_vdpa_as {
@@ -108,12 +113,14 @@ static struct vhost_vdpa_as *vhost_vdpa_alloc_as(struct vhost_vdpa *v, u32 asid)if (asid >= v->vdpa->nas)return NULL ; +if (max_iotlb_entries <=0 ) +return NULL ; as =kmalloc (sizeof (*as),GFP_KERNEL );if (!as)return NULL ; -vhost_iotlb_init (&as->iotlb,0 ,0 ); +vhost_iotlb_init (&as->iotlb, max_iotlb_entries,0 ); as->id = asid;hlist_add_head (&as->hash_link, head);
drivers/vhost/vhost.c +8 -0
@@ -622,6 +622,9 @@ EXPORT_SYMBOL_GPL(vhost_dev_set_owner);static struct vhost_iotlb *iotlb_alloc (void ) { +if (max_iotlb_entries <=0 ) +return NULL ; +return vhost_iotlb_alloc (max_iotlb_entries,VHOST_IOTLB_FLAG_RETIRE ); }
@@ -1470,6 +1473,8 @@ static long vhost_set_memory(struct vhost_dev *d, struct vhost_memory __user *m)return -EOPNOTSUPP ;if (mem.nregions > max_mem_regions)return -E2BIG ; +if (max_iotlb_entries <=0 ) +return -EINVAL ; newmem =kvzalloc (struct_size (newmem, regions, mem.nregions),GFP_KERNEL );if (!newmem)
@@ -1778,6 +1783,9 @@ int vhost_init_device_iotlb(struct vhost_dev *d, bool enabled)struct vhost_iotlb *niotlb, *oiotlb;int i; +if (max_iotlb_entries <=0 ) +return -EINVAL ; + niotlb =iotlb_alloc ();if (!niotlb)return -ENOMEM ;
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1301/1887 bpf: Fix netns reference imbalance in conntrack kfuncs
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Chengfeng Ye <[email protected]>
[ Upstream commit fdeba03fea78407a8c52faa99177c9f7f29f90eb ]
The opts argument of the BPF conntrack kfuncs can point to a shared map value. __bpf_nf_ct_lookup() and __bpf_nf_ct_alloc_entry() read opts->netns_id separately when acquiring and releasing the network namespace reference.
The reference imbalance can occur as follows:
CPU 0 CPU 1
read opts->netns_id (-1)
skip get_net_ns_by_id()
write opts->netns_id (id)
read opts->netns_id (id)
put_net(net) /* no matching get */
The reverse transition leaks the reference. Repeating the unmatched put can destroy a live namespace and crash later users.
The kernel reported:
Oops: general protection fault, probably for non-canonical address KASAN: null-ptr-deref in range [0x00000000000000e8-0x00000000000000ef] RIP: 0010:bpf_prog_test_run_xdp+0x52c/0x1700 Call Trace: __sys_bpf+0x1662/0x50c0 __x64_sys_bpf+0x73/0xb0 do_syscall_64+0xf9/0x540 entry_SYSCALL_64_after_hwframe+0x77/0x7f Kernel panic - not syncing: Fatal exception
Snapshot every input field of opts with READ_ONCE() before validating or using it. The netns_id snapshot keeps the namespace get/put pair balanced, while the other snapshots keep the remaining options from changing partway through an invocation. The individual reads can still observe an inconsistent combination during a concurrent update, but each selected field value remains stable for that invocation.
--- net/netfilter/nf_conntrack_bpf.c | 42 ++++++++++++++++++++------------ 1 file changed, 26 insertions(+), 16 deletions(-)
net/netfilter/nf_conntrack_bpf.c +26 -16
@@ -113,27 +113,32 @@ __bpf_nf_ct_alloc_entry(struct net *net, struct bpf_sock_tuple *bpf_tuple, {struct nf_conntrack_tuple otuple, rtuple;struct nf_conn *ct; +s32 netns_id; +u8 l4proto;int err; -if (!opts || !bpf_tuple || opts->reserved[0 ] || opts->reserved[1 ] || - opts_len !=NF_BPF_CT_OPTS_SZ ) +if (!opts || !bpf_tuple ||READ_ONCE (opts->reserved[0 ]) || +READ_ONCE (opts->reserved[1 ]) || opts_len !=NF_BPF_CT_OPTS_SZ )return ERR_PTR (-EINVAL ); -if (unlikely (opts->netns_id <BPF_F_CURRENT_NETNS )) + netns_id =READ_ONCE (opts->netns_id); + l4proto =READ_ONCE (opts->l4proto); + +if (unlikely (netns_id <BPF_F_CURRENT_NETNS ))return ERR_PTR (-EINVAL ); - err =bpf_nf_ct_tuple_parse (bpf_tuple, tuple_len, opts->l4proto, + err =bpf_nf_ct_tuple_parse (bpf_tuple, tuple_len, l4proto,IP_CT_DIR_ORIGINAL , &otuple);if (err <0 )return ERR_PTR (err); - err =bpf_nf_ct_tuple_parse (bpf_tuple, tuple_len, opts->l4proto, + err =bpf_nf_ct_tuple_parse (bpf_tuple, tuple_len, l4proto,IP_CT_DIR_REPLY , &rtuple);if (err <0 )return ERR_PTR (err); -if (opts->netns_id >=0 ) { - net =get_net_ns_by_id (net, opts->netns_id); +if (netns_id >=0 ) { + net =get_net_ns_by_id (net, netns_id);if (unlikely (!net))return ERR_PTR (-ENONET ); }
@@ -147,7 +152,7 @@ __bpf_nf_ct_alloc_entry(struct net *net, struct bpf_sock_tuple *bpf_tuple,__nf_ct_set_timeout (ct, timeout *HZ ); out: -if (opts->netns_id >=0 ) +if (netns_id >=0 )put_net (net);return ct;
@@ -161,29 +166,34 @@ static struct nf_conn *__bpf_nf_ct_lookup(struct net *net,struct nf_conntrack_tuple_hash *hash;struct nf_conntrack_tuple tuple;struct nf_conn *ct; +s32 netns_id; +u8 l4proto;int err; -if (!opts || !bpf_tuple || opts->reserved[0 ] || opts->reserved[1 ] || - opts_len !=NF_BPF_CT_OPTS_SZ ) +if (!opts || !bpf_tuple ||READ_ONCE (opts->reserved[0 ]) || +READ_ONCE (opts->reserved[1 ]) || opts_len !=NF_BPF_CT_OPTS_SZ )return ERR_PTR (-EINVAL ); -if (unlikely (opts->l4proto !=IPPROTO_TCP && opts->l4proto !=IPPROTO_UDP )) + + netns_id =READ_ONCE (opts->netns_id); + l4proto =READ_ONCE (opts->l4proto); +if (unlikely (l4proto !=IPPROTO_TCP && l4proto !=IPPROTO_UDP ))return ERR_PTR (-EPROTO ); -if (unlikely (opts->netns_id <BPF_F_CURRENT_NETNS )) +if (unlikely (netns_id <BPF_F_CURRENT_NETNS ))return ERR_PTR (-EINVAL ); - err =bpf_nf_ct_tuple_parse (bpf_tuple, tuple_len, opts->l4proto, + err =bpf_nf_ct_tuple_parse (bpf_tuple, tuple_len, l4proto,IP_CT_DIR_ORIGINAL , &tuple);if (err <0 )return ERR_PTR (err); -if (opts->netns_id >=0 ) { - net =get_net_ns_by_id (net, opts->netns_id); +if (netns_id >=0 ) { + net =get_net_ns_by_id (net, netns_id);if (unlikely (!net))return ERR_PTR (-ENONET ); } hash =nf_conntrack_find_get (net, &nf_ct_zone_dflt, &tuple); -if (opts->netns_id >=0 ) +if (netns_id >=0 )put_net (net);if (!hash)return ERR_PTR (-ENOENT );
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1302/1887 btrfs: lzo: reject inline extents without valid headers
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: David Lee <[email protected]>
[ Upstream commit 0fa78ef637deb5dbe341582f88553a4bce496de0 ]
[BUG]
For a crafted btrfs image, the following KASAN can be triggered when reading an inline lzo compressed file extent:
BUG: KASAN: slab-out-of-bounds in lzo_decompress+0x57d/0x700 Read of size 4 at addr ffff888006f2e644 by task btrfs_lzo_inlin/77 Call Trace: <TASK> dump_stack_lvl+0x5b/0x70 print_report+0xd1/0x610 kasan_report+0xe0/0x110 __asan_report_load_n_noabort+0x13/0x20 lzo_decompress+0x57d/0x700 btrfs_decompress+0x140/0x1c0 uncompress_inline+0x147/0x1b0 btrfs_get_extent+0xb23/0x10a0 btrfs_do_readpage.constprop.0+0x538/0x1ac0 btrfs_readahead+0x32f/0x5f0 read_pages+0x16f/0x850 page_cache_ra_unbounded+0x296/0x490 do_page_cache_ra+0xd9/0x130 page_cache_sync_ra+0x3ee/0x6f0 filemap_get_pages+0x306/0x15c0 filemap_read+0x329/0xd00 btrfs_file_read_iter+0x1f8/0x2b0 vfs_read+0x4ef/0x720 ksys_read+0xf8/0x1d0 __x64_sys_read+0x71/0xb0 x64_sys_call+0x1ab0/0x1b70 do_syscall_64+0x61/0x470 entry_SYSCALL_64_after_hwframe+0x4b/0x53 </TASK>
[CAUSE]
For an inline lzo compressed file extent, there should always be one lzo header, recording the total length of the compressed data, followed by one segment header, recording the compressed lzo payload.
But if a crafted inline lzo compressed file extent contains only an lzo header, without the segment header or payload, lzo_decompress() will still try to read the segment header, causing a read beyond the item boundary.
Furthermore if the inline lzo compressed file extent is the first item of the leaf, it will be at the extent buffer boundary. The above out-of-boundary read will go beyond the extent buffer boundary, triggering the above KASAN report.
[FIX]
Validate the total length of the inlined lzo compressed file extent, to make sure there is at least one LZO header and one segment header, and a non-zero payload.
--- fs/btrfs/lzo.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
fs/btrfs/lzo.c +1 -1
@@ -437,7 +437,7 @@ int lzo_decompress(struct list_head *ws, unsigned char *data_in,char *kaddr;unsigned long bytes; -if (srclen <LZO_LEN || srclen > max_segment_len +LZO_LEN *2 ) +if (srclen <=LZO_LEN *2 || srclen > max_segment_len +LZO_LEN *2 )return -EUCLEAN ; in_len =read_compress_length (data_in);
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1303/1887 soc: aspeed: lpc-snoop: Fix usercopy overflow in snoop_file_read
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Karthikeyan KS <[email protected]>
[ Upstream commit 1acef6d85bfd98bd9dfe1f08bffa397a4dda8a6f ]
put_fifo_with_discard() acts as both producer and consumer on the kfifo:
it calls kfifo_skip() (advances out) and kfifo_put() (advances in) from the IRQ handler without synchronizing with snoop_file_read(), which also consumes via kfifo_to_user(). On SMP systems this concurrent access can leave (in - out) larger than the ring buffer, so __kfifo_to_user()'s clamp to (in - out) is ineffective and kfifo_copy_to_user() can attempt a copy_to_user() past the kmalloc-2k backing store:
usercopy: Kernel memory exposure attempt detected from SLUB object 'kmalloc-2k' (offset 0, size 2049)!
kernel BUG at mm/usercopy.c!
Call trace: usercopy_abort __check_heap_object __check_object_size kfifo_copy_to_user __kfifo_to_user snoop_file_read vfs_read
Serialize kfifo access with a per-channel spinlock shared between the IRQ handler (producer) and the file reader (consumer). Annotate @fifo with __guarded_by(&lock) and opt the driver into context analysis so the compiler enforces that all fifo access holds the lock.
--- drivers/soc/aspeed/aspeed-lpc-snoop.c | 33 +++++++++++++++++++-------- 1 file changed, 24 insertions(+), 9 deletions(-)
drivers/soc/aspeed/aspeed-lpc-snoop.c +24 -9
@@ -11,6 +11,7 @@*/ #include <linux/bitops.h> +#include <linux/cleanup.h> #include <linux/clk.h> #include <linux/interrupt.h> #include <linux/fs.h>
@@ -60,6 +61,7 @@ struct aspeed_lpc_snoop_model_data {struct aspeed_lpc_snoop_channel {bool enabled; +spinlock_t lock;struct kfifo fifo;wait_queue_head_t wq;struct miscdevice miscdev;
@@ -83,6 +85,7 @@ static ssize_t snoop_file_read(struct file *file, char __user *buffer, size_t count, loff_t *ppos) { struct aspeed_lpc_snoop_channel *chan = snoop_file_to_chan(file); + u8 *buf __free(kfree) = NULL;unsigned int copied;int ret =0 ;
@@ -94,9 +97,16 @@ static ssize_t snoop_file_read(struct file *file, char __user *buffer,if (ret == -ERESTARTSYS )return -EINTR ; } - ret =kfifo_to_user (&chan->fifo, buffer, count, &copied); -if (ret) -return ret; + + count =min_t (size_t, count,SNOOP_FIFO_SIZE ); + + buf =kmalloc (count,GFP_KERNEL ); +if (!buf) +return -ENOMEM ; + + copied =kfifo_out_spinlocked (&chan->fifo, buf, count, &chan->lock); +if (copied &©_to_user (buffer, buf, copied)) +return -EFAULT ;return copied; }
@@ -120,11 +130,13 @@ static const struct file_operations snoop_fops = {/* Save a byte to a FIFO and discard the oldest byte if FIFO is full */ static void put_fifo_with_discard (struct aspeed_lpc_snoop_channel *chan,u8 val) { -if (!kfifo_initialized (&chan->fifo)) -return ; -if (kfifo_is_full (&chan->fifo)) -kfifo_skip (&chan->fifo); -kfifo_put (&chan->fifo, val); + scoped_guard(spinlock, &chan->lock) { +if (!kfifo_initialized (&chan->fifo)) +return ; +if (kfifo_is_full (&chan->fifo)) +kfifo_skip (&chan->fifo); +kfifo_put (&chan->fifo, val); + }wake_up_interruptible (&chan->wq); }
@@ -285,7 +297,7 @@ static int aspeed_lpc_snoop_probe(struct platform_device *pdev)struct device *dev;struct device_node *np;u32 port; -int rc; +int rc, i; dev = &pdev->dev;
@@ -293,6 +305,9 @@ static int aspeed_lpc_snoop_probe(struct platform_device *pdev)if (!lpc_snoop)return -ENOMEM ; +for (i =0 ; i <NUM_SNOOP_CHANNELS ; i++) +spin_lock_init (&lpc_snoop->chan[i].lock); + np = pdev->dev.parent->of_node; if (!of_device_is_compatible(np, "aspeed,ast2400-lpc-v2") && !of_device_is_compatible(np, "aspeed,ast2500-lpc-v2") &&
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1304/1887 gpio: pca953x: fix pca953x_irq_bus_sync_unlock regmap lock
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Mark Tomlinson <[email protected]>
[ Upstream commit 9dc325327babe7f159e84cbe9380a45342da0585 ]
Locking is disabled in the regmap config as this driver uses its own lock. This means that all calls to regmap functions (read or write) must hold the i2c_lock. The function pca953x_irq_bus_sync_unlock() did not do this, and it was therefore possible that multiple threads could cause an incorrect register to be read/written.
A previous patch partly fixed this, but only protected the write to the interrupt mask register, and not the read from the direction register.
--- drivers/gpio/gpio-pca953x.c | 18 +++++++++++++----- 1 file changed, 13 insertions(+), 5 deletions(-)
drivers/gpio/gpio-pca953x.c +13 -5
@@ -519,15 +519,23 @@ static int pca953x_read_regs(struct pca953x_chip *chip, int reg, unsigned long *return 0 ; } -static int pca953x_gpio_direction_input (struct gpio_chip *gc,unsigned off) +static int pca953x_gpio_direction_input_unlocked (struct gpio_chip *gc, +unsigned int off) {struct pca953x_chip *chip =gpiochip_get_data (gc);u8 dirreg = chip->recalc_addr (chip, chip->regs->direction, off);u8 bit =BIT (off %BANK_SZ ); +return regmap_write_bits (chip->regmap, dirreg, bit, bit); +} + +static int pca953x_gpio_direction_input (struct gpio_chip *gc,unsigned int off) +{ +struct pca953x_chip *chip =gpiochip_get_data (gc); +guard (mutex)(&chip->i2c_lock); -return regmap_write_bits (chip->regmap, dirreg, bit, bit); +return pca953x_gpio_direction_input_unlocked (gc, off); } static int pca953x_gpio_direction_output(struct gpio_chip *gc,
@@ -756,9 +764,9 @@ static void pca953x_irq_bus_sync_unlock(struct irq_data *d)DECLARE_BITMAP (reg_direction,MAX_LINE );int level; -if (chip->driver_data &PCA_PCAL ) { -guard (mutex)(&chip->i2c_lock); +guard (mutex)(&chip->i2c_lock); +if (chip->driver_data &PCA_PCAL ) {/* Enable latch on interrupt-enabled inputs */ pca953x_write_regs (chip,PCAL953X_IN_LATCH , chip->irq_mask);
@@ -777,7 +785,7 @@ static void pca953x_irq_bus_sync_unlock(struct irq_data *d)/* Look for any newly setup interrupt */ for_each_set_bit (level, irq_mask, gc->ngpio) -pca953x_gpio_direction_input (&chip->gpio_chip, level); +pca953x_gpio_direction_input_unlocked (&chip->gpio_chip, level);mutex_unlock (&chip->irq_lock); }
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1305/1887 l2tp: fix tunnel and session refcount leak on seq_file release
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Eric Dumazet <[email protected]>
[ Upstream commit 9006c116dd111d457bf5d074990210f70a4ad2c8 ]
In pppol2tp_proc_open() and l2tp_dfs_seq_open(), iteration state (pd->tunnel and pd->session) is kept in seq_file private data to allow iteration across multiple read() system calls.
However, if userspace closes /proc/net/pppol2tp or /sys/kernel/debug/l2tp/tunnels before reading to end-of-file (EOF), any tunnel or session reference stored in pd->tunnel / pd->session is left un-dropped when seq_file private data is freed.
Fix this by dropping any remaining pd->tunnel and pd->session references in pppol2tp_proc_release() and l2tp_dfs_seq_release() when closing the file.
--- net/l2tp/l2tp_debugfs.c | 4 +++ net/l2tp/l2tp_ppp.c | 56 ++++++++++++++++++++++++++++++++++++++--- 2 files changed, 57 insertions(+), 3 deletions(-)
net/l2tp/l2tp_debugfs.c +4 -0
@@ -307,6 +307,10 @@ static int l2tp_dfs_seq_release(struct inode *inode, struct file *file) seq = file->private_data; pd = seq->private; +if (pd->session) +l2tp_session_dec_refcount (pd->session); +if (pd->tunnel) +l2tp_tunnel_dec_refcount (pd->tunnel);if (pd->net)put_net_track (pd->net, &pd->ns_tracker);kfree (pd);
net/l2tp/l2tp_ppp.c +53 -3
77 lines not on this page · raw message
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1306/1887 net, sched: Make tc-related drop reason more flexible
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Daniel Borkmann <[email protected]>
[ Upstream commit 54a59aed395ce0f4177b5212e5746a6462de3ad9 ]
Currently, the kfree_skb_reason() in sch_handle_{ingress,egress}() can only express a basic SKB_DROP_REASON_TC_INGRESS or SKB_DROP_REASON_TC_EGRESS reason.
Victor kicked-off an initial proposal to make this more flexible by disambiguating verdict from return code by moving the verdict into struct tcf_result and letting tcf_classify() return a negative error. If hit, then two new drop reasons were added in the proposal, that is SKB_DROP_REASON_TC_INGRESS_ERROR as well as SKB_DROP_REASON_TC_EGRESS_ERROR. Further analysis of the actual error codes would have required to attach to tcf_classify via kprobe/kretprobe to more deeply debug skb and the returned error.
In order to make the kfree_skb_reason() in sch_handle_{ingress,egress}() more extensible, it can be addressed in a more straight forward way, that is: Instead of placing the verdict into struct tcf_result, we can just put the drop reason in there, which does not require changes throughout various classful schedulers given the existing verdict logic can stay as is.
Then, SKB_DROP_REASON_TC_ERROR{,_*} can be added to the enum skb_drop_reason to disambiguate between an error or an intentional drop. New drop reason error codes can be added successively to the tc code base.
For internal error locations which have not yet been annotated with a SKB_DROP_REASON_TC_ERROR{,_*}, the fallback is SKB_DROP_REASON_TC_INGRESS and SKB_DROP_REASON_TC_EGRESS, respectively. Generic errors could be marked with a SKB_DROP_REASON_TC_ERROR code until they are converted to more specific ones if it is found that they would be useful for troubleshooting.
While drop reasons have infrastructure for subsystem specific error codes which are currently used by mac80211 and ovs, Jakub mentioned that it is preferred for tc to use the enum skb_drop_reason core codes given it is a better fit and currently the tooling support is better, too.
With regards to the latter:
[...] I think Alastair (bpftrace) is working on auto-prettifying enums when bpftrace outputs maps. So we can do something like:
$ bpftrace -e 'tracepoint:skb:kfree_skb { @[args->reason] = count(); }'
Attaching 1 probe...
^C @[SKB_DROP_REASON_TC_INGRESS]: 2
@[SKB_CONSUMED]: 34
^^^^^^^^^^^^ names!!
Auto-magically. [...]
Add a small helper tcf_set_drop_reason() which can be used to set the drop reason into the tcf_result.
Stable-dep-of: f60b396ee174 ("net/sched: act_api: fix TOCTOU NULL deref on a->goto_chain")
--- include/net/pkt_cls.h | 6 ++++++ include/net/sch_generic.h | 3 +-- net/core/dev.c | 6 ++++-- 3 files changed, 11 insertions(+), 4 deletions(-)
include/net/pkt_cls.h +6 -0
@@ -181,6 +181,12 @@ __cls_set_class(unsigned long *clp, unsigned long cl)return xchg (clp, cl); } +static inline void tcf_set_drop_reason (struct tcf_result *res, +enum skb_drop_reason reason) +{ + res->drop_reason = reason; +} +static inline void __tcf_bind_filter (struct Qdisc *q,struct tcf_result *r,unsigned long base) {
include/net/sch_generic.h +1 -2
@@ -327,7 +327,6 @@ struct Qdisc_ops {struct module *owner; }; - struct tcf_result { union { struct {
@@ -335,8 +334,8 @@ struct tcf_result {u32 classid; };const struct tcf_proto *goto_tp; - }; +enum skb_drop_reason drop_reason; };struct tcf_chain ;
net/core/dev.c +4 -2
@@ -4080,6 +4080,7 @@ sch_handle_egress(struct sk_buff *skb, int *ret, struct net_device *dev)/* qdisc_skb_cb(skb)->pkt_len was already set by the caller. */ tc_skb_cb (skb)->mru =0 ;tc_skb_cb (skb)->post_ct = false; + cl_res.drop_reason =SKB_DROP_REASON_TC_EGRESS ;mini_qdisc_bstats_cpu_update (miniq, skb);switch (tcf_classify (skb, miniq->block, miniq->filter_list, &cl_res, false)) {
@@ -4090,7 +4091,7 @@ sch_handle_egress(struct sk_buff *skb, int *ret, struct net_device *dev)case TC_ACT_SHOT :mini_qdisc_qstats_cpu_drop (miniq); *ret =NET_XMIT_DROP ; -kfree_skb_reason (skb,SKB_DROP_REASON_TC_EGRESS ); +kfree_skb_reason (skb, cl_res.drop_reason ?:SKB_DROP_REASON_TC_EGRESS );return NULL ;case TC_ACT_STOLEN :case TC_ACT_QUEUED :
@@ -5273,6 +5274,7 @@ sch_handle_ingress(struct sk_buff *skb, struct packet_type **pt_prev, int *ret,tc_skb_cb (skb)->mru =0 ;tc_skb_cb (skb)->post_ct = false; skb->tc_at_ingress =1 ; + cl_res.drop_reason =SKB_DROP_REASON_TC_INGRESS ;mini_qdisc_bstats_cpu_update (miniq, skb);switch (tcf_classify (skb, miniq->block, miniq->filter_list, &cl_res, false)) {
@@ -5282,7 +5284,7 @@ sch_handle_ingress(struct sk_buff *skb, struct packet_type **pt_prev, int *ret,break ;case TC_ACT_SHOT :mini_qdisc_qstats_cpu_drop (miniq); -kfree_skb_reason (skb,SKB_DROP_REASON_TC_INGRESS ); +kfree_skb_reason (skb, cl_res.drop_reason ?:SKB_DROP_REASON_TC_INGRESS ); *ret =NET_RX_DROP ;return NULL ;case TC_ACT_STOLEN :
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1307/1887 net, sched: Fix SKB_NOT_DROPPED_YET splat under debug config
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Jamal Hadi Salim <[email protected]>
[ Upstream commit 40cb2fdfed342e7e578d551a073687789f698d89 ]
Getting the following splat [1] with CONFIG_DEBUG_NET=y and this reproducer [2]. Problem seems to be that classifiers clear 'struct tcf_result::drop_reason', thereby triggering the warning in __kfree_skb_reason() due to reason being 'SKB_NOT_DROPPED_YET' (0).
Fixed by disambiguating a legit error from a verdict with a bogus drop_reason
[1]
WARNING: CPU: 0 PID: 181 at net/core/skbuff.c:1082 kfree_skb_reason+0x38/0x130 Modules linked in: CPU: 0 PID: 181 Comm: mausezahn Not tainted 6.6.0-rc6-custom-ge43e6d9582e0 #682 Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS 1.16.2-1.fc37 04/01/2014 RIP: 0010:kfree_skb_reason+0x38/0x130 [...] Call Trace: <IRQ> __netif_receive_skb_core.constprop.0+0x837/0xdb0 __netif_receive_skb_one_core+0x3c/0x70 process_backlog+0x95/0x130 __napi_poll+0x25/0x1b0 net_rx_action+0x29b/0x310 __do_softirq+0xc0/0x29b do_softirq+0x43/0x60 </IRQ>
[2]
ip link add name veth0 type veth peer name veth1
ip link set dev veth0 up
ip link set dev veth1 up
tc qdisc add dev veth1 clsact
tc filter add dev veth1 ingress pref 1 proto all flower dst_mac 00:11:22:33:44:55 action drop mausezahn veth0 -a own -b 00:11:22:33:44:55 -q -c 1
Ido reported:
[...] getting the following splat [1] with CONFIG_DEBUG_NET=y and this reproducer [2]. Problem seems to be that classifiers clear 'struct tcf_result::drop_reason', thereby triggering the warning in __kfree_skb_reason() due to reason being 'SKB_NOT_DROPPED_YET' (0). [...]
[1]
WARNING: CPU: 0 PID: 181 at net/core/skbuff.c:1082 kfree_skb_reason+0x38/0x130 Modules linked in: CPU: 0 PID: 181 Comm: mausezahn Not tainted 6.6.0-rc6-custom-ge43e6d9582e0 #682 Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS 1.16.2-1.fc37 04/01/2014 RIP: 0010:kfree_skb_reason+0x38/0x130 [...] Call Trace: <IRQ> __netif_receive_skb_core.constprop.0+0x837/0xdb0 __netif_receive_skb_one_core+0x3c/0x70 process_backlog+0x95/0x130 __napi_poll+0x25/0x1b0 net_rx_action+0x29b/0x310 __do_softirq+0xc0/0x29b do_softirq+0x43/0x60 </IRQ>
[2]
#!/bin/bash
ip link add name veth0 type veth peer name veth1
ip link set dev veth0 up
ip link set dev veth1 up
tc qdisc add dev veth1 clsact
tc filter add dev veth1 ingress pref 1 proto all flower dst_mac 00:11:22:33:44:55 action drop mausezahn veth0 -a own -b 00:11:22:33:44:55 -q -c 1
What happens is that inside most classifiers the tcf_result is copied over from a filter template e.g. *res = f->res which then implicitly overrides the prior SKB_DROP_REASON_TC_{INGRESS,EGRESS} default drop code which was set via sch_handle_{ingress,egress}() for kfree_skb_reason().
Commit text above copied verbatim from Daniel. The general idea of the patch is not very different from what Ido originally posted but instead done at the cls_api codepath.
Stable-dep-of: f60b396ee174 ("net/sched: act_api: fix TOCTOU NULL deref on a->goto_chain")
--- net/sched/act_api.c | 2 +- net/sched/cls_api.c | 9 ++++++++- 2 files changed, 9 insertions(+), 2 deletions(-)
net/sched/act_api.c +1 -1
@@ -1131,7 +1131,7 @@ int tcf_action_exec(struct sk_buff *skb, struct tc_action **actions, } }else if (TC_ACT_EXT_CMP (ret,TC_ACT_GOTO_CHAIN )) {if (unlikely (!rcu_access_pointer (a->goto_chain))) { -net_warn_ratelimited ("can't go to NULL chain!\n" ); +tcf_set_drop_reason (res,SKB_DROP_REASON_TC_ERROR );return TC_ACT_SHOT ; }tcf_action_goto_chain_exec (a, res);
net/sched/cls_api.c +8 -1
@@ -1601,6 +1601,7 @@ static inline int __tcf_classify(struct sk_buff *skb,bool compat_mode, u32 *last_executed_chain) { + u32 orig_reason = res->drop_reason;#ifdef CONFIG_NET_CLS_ACT const int max_reclassify_loop =16 ;const struct tcf_proto *first_tp;
@@ -1628,8 +1629,14 @@ static inline int __tcf_classify(struct sk_buff *skb, goto reset; }#endif -if (err >=0 ) +if (err >=0 ) { +/* Policy drop or drop reason is over-written by +* classifiers with a bogus value(0) */ +if (err ==TC_ACT_SHOT && + res->drop_reason ==SKB_NOT_DROPPED_YET ) +tcf_set_drop_reason (res, orig_reason);return err; + } }return TC_ACT_UNSPEC ;/* signal: continue lookup */
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1308/1887 net: sched: Move drop_reason to struct tc_skb_cb
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Victor Nogueira <[email protected]>
[ Upstream commit fb2780721ca5e9f78bbe4544b819b929a982df9c ]
Move drop_reason from struct tcf_result to skb cb - more specifically to struct tc_skb_cb. With that, we'll be able to also set the drop reason for the remaining qdiscs (aside from clsact) that do not have access to tcf_result when time comes to set the skb drop reason.
[ Adapted to the tree: dev.c still uses the open-coded sch_handle_ingress/egress
rather than tc_run(), so those call sites were converted instead; cls_api.c keeps only the removal of the res->drop_reason fallback. ]
Stable-dep-of: f60b396ee174 ("net/sched: act_api: fix TOCTOU NULL deref on a->goto_chain")
--- include/net/pkt_cls.h | 14 ++++++++++++-- include/net/pkt_sched.h | 3 ++- include/net/sch_generic.h | 1 - net/core/dev.c | 8 ++++---- net/sched/act_api.c | 2 +- net/sched/cls_api.c | 9 +-------- 6 files changed, 20 insertions(+), 17 deletions(-)
include/net/pkt_cls.h +12 -2
@@ -181,10 +181,20 @@ __cls_set_class(unsigned long *clp, unsigned long cl)return xchg (clp, cl); } -static inline void tcf_set_drop_reason (struct tcf_result *res, +struct tc_skb_cb ; + +static inline struct tc_skb_cb *tc_skb_cb (const struct sk_buff *skb); + +static inline enum skb_drop_reason +tcf_get_drop_reason (const struct sk_buff *skb) +{ +return tc_skb_cb (skb)->drop_reason; +} + +static inline void tcf_set_drop_reason (const struct sk_buff *skb,enum skb_drop_reason reason) { - res->drop_reason = reason; +tc_skb_cb (skb)->drop_reason = reason; } static inline void
include/net/pkt_sched.h +2 -1
@@ -218,12 +218,13 @@ static inline void skb_txtime_consumed(struct sk_buff *skb)struct tc_skb_cb {struct qdisc_skb_cb qdisc_cb; +u32 drop_reason; +u16 zone;/* Only valid if post_ct = true */ u16 mru;u8 post_ct:1 ;u8 post_ct_snat:1 ;u8 post_ct_dnat:1 ; -u16 zone;/* Only valid if post_ct = true */ };static inline struct tc_skb_cb *tc_skb_cb (const struct sk_buff *skb)
include/net/sch_generic.h +0 -1
@@ -335,7 +335,6 @@ struct tcf_result { };const struct tcf_proto *goto_tp; }; -enum skb_drop_reason drop_reason; };struct tcf_chain ;
net/core/dev.c +4 -4
@@ -4080,7 +4080,7 @@ sch_handle_egress(struct sk_buff *skb, int *ret, struct net_device *dev)/* qdisc_skb_cb(skb)->pkt_len was already set by the caller. */ tc_skb_cb (skb)->mru =0 ;tc_skb_cb (skb)->post_ct = false; - cl_res.drop_reason =SKB_DROP_REASON_TC_EGRESS ; +tcf_set_drop_reason (skb,SKB_DROP_REASON_TC_EGRESS );mini_qdisc_bstats_cpu_update (miniq, skb);switch (tcf_classify (skb, miniq->block, miniq->filter_list, &cl_res, false)) {
@@ -4091,7 +4091,7 @@ sch_handle_egress(struct sk_buff *skb, int *ret, struct net_device *dev)case TC_ACT_SHOT :mini_qdisc_qstats_cpu_drop (miniq); *ret =NET_XMIT_DROP ; -kfree_skb_reason (skb, cl_res.drop_reason ?:SKB_DROP_REASON_TC_EGRESS ); +kfree_skb_reason (skb,tcf_get_drop_reason (skb) ?:SKB_DROP_REASON_TC_EGRESS );return NULL ;case TC_ACT_STOLEN :case TC_ACT_QUEUED :
@@ -5274,7 +5274,7 @@ sch_handle_ingress(struct sk_buff *skb, struct packet_type **pt_prev, int *ret,tc_skb_cb (skb)->mru =0 ;tc_skb_cb (skb)->post_ct = false; skb->tc_at_ingress =1 ; - cl_res.drop_reason =SKB_DROP_REASON_TC_INGRESS ; +tcf_set_drop_reason (skb,SKB_DROP_REASON_TC_INGRESS );mini_qdisc_bstats_cpu_update (miniq, skb);switch (tcf_classify (skb, miniq->block, miniq->filter_list, &cl_res, false)) {
@@ -5284,7 +5284,7 @@ sch_handle_ingress(struct sk_buff *skb, struct packet_type **pt_prev, int *ret,break ;case TC_ACT_SHOT :mini_qdisc_qstats_cpu_drop (miniq); -kfree_skb_reason (skb, cl_res.drop_reason ?:SKB_DROP_REASON_TC_INGRESS ); +kfree_skb_reason (skb,tcf_get_drop_reason (skb) ?:SKB_DROP_REASON_TC_INGRESS ); *ret =NET_RX_DROP ;return NULL ;case TC_ACT_STOLEN :
net/sched/act_api.c +1 -1
@@ -1131,7 +1131,7 @@ int tcf_action_exec(struct sk_buff *skb, struct tc_action **actions, } }else if (TC_ACT_EXT_CMP (ret,TC_ACT_GOTO_CHAIN )) {if (unlikely (!rcu_access_pointer (a->goto_chain))) { -tcf_set_drop_reason (res,SKB_DROP_REASON_TC_ERROR ); +tcf_set_drop_reason (skb,SKB_DROP_REASON_TC_ERROR );return TC_ACT_SHOT ; }tcf_action_goto_chain_exec (a, res);
net/sched/cls_api.c +1 -8
@@ -1601,7 +1601,6 @@ static inline int __tcf_classify(struct sk_buff *skb,bool compat_mode, u32 *last_executed_chain) { - u32 orig_reason = res->drop_reason; #ifdef CONFIG_NET_CLS_ACT const int max_reclassify_loop = 16;const struct tcf_proto *first_tp;
@@ -1629,14 +1628,8 @@ static inline int __tcf_classify(struct sk_buff *skb, goto reset; }#endif -if (err >=0 ) { -/* Policy drop or drop reason is over-written by -* classifiers with a bogus value(0) */ -if (err ==TC_ACT_SHOT && - res->drop_reason ==SKB_NOT_DROPPED_YET ) -tcf_set_drop_reason (res, orig_reason); +if (err >=0 )return err; - } }return TC_ACT_UNSPEC ;/* signal: continue lookup */
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1309/1887 net: sched: Add initial TC error skb drop reasons
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Victor Nogueira <[email protected]>
[ Upstream commit 4cf24dc8934074725042c0bd10b91f4d4b5269bb ]
Continue expanding Daniel's patch by adding new skb drop reasons that are idiosyncratic to TC.
More specifically:
- SKB_DROP_REASON_TC_COOKIE_ERROR: An error occurred whilst processing a tc ext cookie.
- SKB_DROP_REASON_TC_CHAIN_NOTFOUND: tc chain lookup failed.
- SKB_DROP_REASON_TC_RECLASSIFY_LOOP: tc exceeded max reclassify loop iterations
[ Adapted to this tree: only SKB_DROP_REASON_TC_CHAIN_NOTFOUND is added,
to include/net/dropreason.h, and used in tcf_action_exec(); the cls_api.c changes are dropped as that file has no drop reasons here. ]
Stable-dep-of: f60b396ee174 ("net/sched: act_api: fix TOCTOU NULL deref on a->goto_chain")
--- include/net/dropreason.h | 3 +++ net/sched/act_api.c | 3 ++- 2 files changed, 5 insertions(+), 1 deletion(-)
include/net/dropreason.h +3 -0
@@ -68,6 +68,7 @@ FN(IP_INADDRERRORS) \ FN(IP_INNOROUTES) \ FN(PKT_TOO_BIG) \ + FN(TC_CHAIN_NOTFOUND) \ FNe(MAX)/**
@@ -298,6 +299,8 @@ enum skb_drop_reason {* MTU) */ SKB_DROP_REASON_PKT_TOO_BIG , +/** @SKB_DROP_REASON_TC_CHAIN_NOTFOUND: tc chain lookup failed. */ + SKB_DROP_REASON_TC_CHAIN_NOTFOUND,/** * @SKB_DROP_REASON_MAX: the maximum of drop reason, which shouldn't be * used as a real 'reason'
net/sched/act_api.c +2 -1
@@ -1131,7 +1131,8 @@ int tcf_action_exec(struct sk_buff *skb, struct tc_action **actions, } }else if (TC_ACT_EXT_CMP (ret,TC_ACT_GOTO_CHAIN )) {if (unlikely (!rcu_access_pointer (a->goto_chain))) { -tcf_set_drop_reason (skb,SKB_DROP_REASON_TC_ERROR ); +tcf_set_drop_reason (skb, +SKB_DROP_REASON_TC_CHAIN_NOTFOUND );return TC_ACT_SHOT ; }tcf_action_goto_chain_exec (a, res);
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1310/1887 net/sched: act_api: fix TOCTOU NULL deref on a->goto_chain
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Jamal Hadi Salim <[email protected]>
[ Upstream commit f60b396ee174206fe08ebf997d16cd3801b77b22 ]
tcf_action_exec() handles TC_ACT_GOTO_CHAIN by first checking rcu_access_pointer(a->goto_chain) and then calling tcf_action_goto_chain_exec(), which does a second, independent rcu_dereference_bh(a->goto_chain) read and immediately dereferences chain->filter_chain. A concurrent tcf_action_set_ctrlact() (e.g. the gact replace path) can clear a->goto_chain between the two reads, so the second read returns NULL and tcf_action_goto_chain_exec() dereferences NULL.
Fix the race by doing a single rcu_dereference_bh() read of a->goto_chain in tcf_action_exec(), checking it once for NULL, and passing the resulting chain pointer into tcf_action_goto_chain_exec(). This turns the split check/use into a single check/use on one value.
--- net/sched/act_api.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-)
net/sched/act_api.c +5 -5
@@ -40,11 +40,9 @@ int tcf_dev_queue_xmit(struct sk_buff *skb, int (*xmit)(struct sk_buff *skb)) }EXPORT_SYMBOL_GPL (tcf_dev_queue_xmit); -static void tcf_action_goto_chain_exec (const struct tc_action *a, +static void tcf_action_goto_chain_exec (const struct tcf_chain *chain,struct tcf_result *res) { -const struct tcf_chain *chain =rcu_dereference_bh (a->goto_chain); - res->goto_tp =rcu_dereference_bh (chain->filter_chain); }
@@ -1130,12 +1128,14 @@ int tcf_action_exec(struct sk_buff *skb, struct tc_action **actions,return TC_ACT_OK ; } }else if (TC_ACT_EXT_CMP (ret,TC_ACT_GOTO_CHAIN )) { -if (unlikely (!rcu_access_pointer (a->goto_chain))) { +struct tcf_chain *chain =rcu_dereference_bh (a->goto_chain); + +if (unlikely (!chain)) {tcf_set_drop_reason (skb,SKB_DROP_REASON_TC_CHAIN_NOTFOUND );return TC_ACT_SHOT ; } -tcf_action_goto_chain_exec (a, res); +tcf_action_goto_chain_exec (chain, res); }if (ret !=TC_ACT_PIPE )
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1311/1887 ipvs: revalidate ihl to prevent out-of-bounds access
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Julian Anastasov <[email protected]>
[ Upstream commit d93660df4dd1d116f608ada4a29a80a5d6f0a6ed ]
While the outer IP header is already pulled into the skb head, we must be careful and revalidate the embedded headers after reading them from the skb frags to prevent out-of-bounds access.
One such place reported by Sashiko is ip_vs_nat_icmp() where local process can change the ihl field and after skb_ensure_writable() we can see larger value which is a problem for the ip_send_check(cih) calls.
Add check to drop the packet if the ihl field is changed.
--- include/net/ip_vs.h | 2 +- net/netfilter/ipvs/ip_vs_core.c | 11 +++++++++-- net/netfilter/ipvs/ip_vs_xmit.c | 3 ++- 3 files changed, 12 insertions(+), 4 deletions(-)
include/net/ip_vs.h +1 -1
@@ -1583,7 +1583,7 @@ static inline char ip_vs_fwd_tag(struct ip_vs_conn *cp)return fwd; } -void ip_vs_nat_icmp (struct sk_buff *skb,struct ip_vs_protocol *pp, +bool ip_vs_nat_icmp (struct sk_buff *skb,struct ip_vs_protocol *pp,struct ip_vs_conn *cp,int dir,unsigned int toff,bool has_ports,struct ip_vs_iphdr *ciph);
net/netfilter/ipvs/ip_vs_core.c +9 -2
@@ -745,7 +745,7 @@ static int ip_vs_route_me_harder(struct netns_ipvs *ipvs, int af,* Packet has been made sufficiently writable in caller * - inout: 1=in->out, 0=out->in */ -void ip_vs_nat_icmp (struct sk_buff *skb,struct ip_vs_protocol *pp, +bool ip_vs_nat_icmp (struct sk_buff *skb,struct ip_vs_protocol *pp,struct ip_vs_conn *cp,int inout,unsigned int toff,bool has_ports,struct ip_vs_iphdr *ciph) {
@@ -753,6 +753,11 @@ void ip_vs_nat_icmp(struct sk_buff *skb, struct ip_vs_protocol *pp,struct icmphdr *icmph = (struct icmphdr *)(skb->data + toff);struct iphdr *cih = (struct iphdr *)(icmph +1 ); +/* Before now we may used ihl from skb frag, revalidate it after +* copying it into skb head to prevent out-of-bounds access +*/ +if (cih->ihl *4 != ciph->len - ciph->off) +return false;if (inout) { iph->saddr = cp->vaddr.ip;ip_send_check (iph);
@@ -786,6 +791,7 @@ void ip_vs_nat_icmp(struct sk_buff *skb, struct ip_vs_protocol *pp,else IP_VS_DBG_PKT (11 ,AF_INET , pp, skb, ciph->off,"Forwarding altered incoming ICMP" ); +return true; }#ifdef CONFIG_IP_VS_IPV6
@@ -877,7 +883,8 @@ static int handle_response_icmp(int af, struct sk_buff *skb,ip_vs_nat_icmp_v6 (skb, pp, cp,1 , toff, has_ports, ciph); else#endif -ip_vs_nat_icmp (skb, pp, cp,1 , toff, has_ports, ciph); +if (!ip_vs_nat_icmp (skb, pp, cp,1 , toff, has_ports, ciph)) + goto out;if (ip_vs_route_me_harder (cp->ipvs, af, skb, hooknum)) goto out;
net/netfilter/ipvs/ip_vs_xmit.c +2 -1
@@ -1615,7 +1615,8 @@ ip_vs_icmp_xmit(struct sk_buff *skb, struct ip_vs_conn *cp,if (skb_cow (skb, rt->dst.dev->hard_header_len)) goto tx_error; -ip_vs_nat_icmp (skb, pp, cp,0 , toff, has_ports, ciph); +if (!ip_vs_nat_icmp (skb, pp, cp,0 , toff, has_ports, ciph)) + goto tx_error;/* Another hack: avoid icmp_send in ip_fragment */ skb->ignore_df =1 ;
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1312/1887 scsi: core: pair EH runtime PM get and put
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Hongjie Fang <[email protected]>
[ Upstream commit 872f486259ae0bc6b73ca4735a15d013241f73e9 ]
shost->eh_noresume is currently consulted twice in one error handling
iteration: once before scsi_autopm_get_host() and once again before scsi_autopm_put_host().
That is racy when a PM-triggered error path flips shost->eh_noresume while the SCSI EH thread is still running.
The problem flow looks like this:
PM path
ufshcd_set_dev_pwr_mode()
shost->eh_noresume = 1
ufshcd_execute_start_stop <-- trigger EH
...
shost->eh_noresume = 0EH path
scsi_error_handler()
if (!shost->eh_noresume)
scsi_autopm_get_host() <-- skipped
...
if (!shost->eh_noresume)
scsi_autopm_put_host() <-- executed laterIn that case one EH iteration can skip autoresume on entry and still drop a runtime PM reference on exit. That leaves an unmatched runtime PM put and can trigger a runtime PM usage count underflow.
Fix this by making eh_noresume a regular bool so it can be accessed with READ_ONCE() and WRITE_ONCE(). Snapshot it once per EH iteration and use that snapshot for both runtime PM get and put decisions.
--- drivers/scsi/scsi_error.c | 6 ++++-- drivers/ufs/core/ufshcd.c | 4 ++-- include/scsi/scsi_host.h | 6 +++--- 3 files changed, 9 insertions(+), 7 deletions(-)
drivers/scsi/scsi_error.c +4 -2
@@ -2277,6 +2277,7 @@ static void scsi_unjam_host(struct Scsi_Host *shost)int scsi_error_handler (void *data) {struct Scsi_Host *shost = data; +bool eh_noresume;/* * We use TASK_INTERRUPTIBLE so that the thread is not
@@ -2318,7 +2319,8 @@ int scsi_error_handler(void *data)* what we need to do to get it up and online again (if we can). * If we fail, we end up taking the thing offline. */ -if (!shost->eh_noresume &&scsi_autopm_get_host (shost) !=0 ) { + eh_noresume =READ_ONCE (shost->eh_noresume); +if (!eh_noresume &&scsi_autopm_get_host (shost) !=0 ) { SCSI_LOG_ERROR_RECOVERY(1, shost_printk(KERN_ERR, shost, "scsi_eh_%d: unable to autoresume\n",
@@ -2342,7 +2344,7 @@ int scsi_error_handler(void *data)* which are still online. */ scsi_restart_operations (shost); -if (!shost->eh_noresume) +if (!eh_noresume)scsi_autopm_put_host (shost); }__set_current_state (TASK_RUNNING );
drivers/ufs/core/ufshcd.c +2 -2
@@ -8838,7 +8838,7 @@ static int ufshcd_set_dev_pwr_mode(struct ufs_hba *hba,* we are functional while we are here, skip host resume in error * handling context. */ - hba->host->eh_noresume =1 ; +WRITE_ONCE (hba->host->eh_noresume,1 ); cmd[4 ] = pwr_mode <<4 ;
@@ -8872,7 +8872,7 @@ static int ufshcd_set_dev_pwr_mode(struct ufs_hba *hba, hba->curr_dev_pwr_mode = pwr_mode;scsi_device_put (sdp); - hba->host->eh_noresume =0 ; +WRITE_ONCE (hba->host->eh_noresume,0 );return ret; }
include/scsi/scsi_host.h +3 -3
@@ -623,6 +623,9 @@ struct Scsi_Host {*/ unsigned nr_hw_queues;unsigned nr_maps; +/* Don't resume host in EH */ +bool eh_noresume; + unsigned active_mode:2;/*
@@ -644,9 +647,6 @@ struct Scsi_Host {/* Asynchronous scan in progress */ unsigned async_scan:1; -/* Don't resume host in EH */ - unsigned eh_noresume:1; -/* The controller does not support WRITE SAME */ unsigned no_write_same:1;
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1313/1887 ASoC: tas2562: Validate values for volume writes
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Mark Brown <[email protected]>
[ Upstream commit 8fb41964f7e4e4207c8999af2056894caa7a252a ]
tas2562_volume_control_put() does not do any validation of the control value written by userspace, it uses it to look up a value in a fixed size array which can easily be overflowed and then writes whatever value it gets back to the device. Add validation that we are loading a value we have in the array.
--- sound/soc/codecs/tas2562.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-)
sound/soc/codecs/tas2562.c +6 -2
@@ -474,10 +474,14 @@ static int tas2562_volume_control_put(struct snd_kcontrol *kcontrol, {struct snd_soc_component *component =snd_soc_kcontrol_component (kcontrol);struct tas2562_data *tas2562 =snd_soc_component_get_drvdata (component); -int ret; +int ret, index;u32 reg_val; - reg_val = float_vol_db_lookup[ucontrol->value.integer.value[0 ]/2 ]; + index = ucontrol->value.integer.value[0 ] /2 ; +if (index <0 || index >=ARRAY_SIZE (float_vol_db_lookup)) +return -EINVAL ; + + reg_val = float_vol_db_lookup[index];/* * The device applies the 32-bit coefficient to the playback path on * the write to DVC_CFG4 (the LSB, book 0 page 2 reg 0x0F), so the
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1314/1887 s390/vfio_ccw: Limit the number of channel program segments
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Eric Farman <[email protected]>
[ Upstream commit 5405c90d6a47b3014e74ee0618a162449abbbc93 ]
The processing of channel programs, and the CCWs within them, is done recursively. As such, there is an arbitrary (but not architectural) limit to the number of CCWs that can exist in a single channel program.
The vfio-ccw logic breaks these channel programs into segments whenever it encounters a Transfer-In-Channel (TIC) CCW, and the combined number of segments count towards the global limit. Impose an equivalent limit to the number of segments until such logic can be made non-recursive.
--- drivers/s390/cio/vfio_ccw_cp.c | 6 ++++++ drivers/s390/cio/vfio_ccw_cp.h | 8 ++++++++ 2 files changed, 14 insertions(+)
drivers/s390/cio/vfio_ccw_cp.c +6 -0
@@ -376,6 +376,7 @@ static struct ccwchain *ccwchain_alloc(struct channel_program *cp, int len) chain->ch_len = len;list_add_tail (&chain->next, &cp->ccwchain_list); + cp->ccwchain_count++;return chain; }
@@ -478,6 +479,10 @@ static int ccwchain_handle_ccw(u32 cda, struct channel_program *cp)if (len <0 )return len; +/* Limit number of chains in a single channel program */ +if (cp->ccwchain_count >=CCWCHAIN_COUNT_MAX ) +return -EINVAL ; +/* Need alloc a new chain for this one. */ chain =ccwchain_alloc (cp, len);if (!chain)
@@ -709,6 +714,7 @@ int cp_init(struct channel_program *cp, union orb *orb) vdev->dev, "Prefetching channel program even though prefetch not specified in ORB"); + cp->ccwchain_count =0 ;INIT_LIST_HEAD (&cp->ccwchain_list);memcpy (&cp->orb, orb,sizeof (*orb));
drivers/s390/cio/vfio_ccw_cp.h +8 -0
@@ -23,12 +23,19 @@*/ #define CCWCHAIN_LEN_MAX 256 +/* +* Maximum number of chains +*/ +#define CCWCHAIN_COUNT_MAX 16 +/** * struct channel_program - manage information for channel program * @ccwchain_list: list head of ccwchains * @orb: orb for the currently processed ssch request * @mdev: the mediated device to perform page pinning/unpinning * @initialized: whether this instance is actually initialized +* @guest_cp: copy of guest channel program +* @ccwchain_count: number of channel program segments (linked by TIC) * * @ccwchain_list is the head of a ccwchain list, that contents the * translated result of the guest channel program that pointed out by
@@ -39,6 +46,7 @@ struct channel_program {union orb orb;bool initialized;struct ccw1 *guest_cp; +unsigned int ccwchain_count; };int cp_init (struct channel_program *cp,union orb *orb);
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1315/1887 drm/amdgpu: reject oversized IBs with per-ring packet limits
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Candice Li <[email protected]>
[ Upstream commit fd37f9dd5b5ab70a46fa7bc76623c0528d602b27 ]
On GFX rings, amdgpu_cs_p2_ib() passed user-supplied ib_bytes through to ib->length_dw without a limit, while ring_emit_ib() encodes length into packet fields. Oversized values can corrupt adjacent control bits and destabilize command submission.
Add a per-ring IB packet size limit helper and reject command submissions exceeding the corresponding dword limit before IB allocation. Use the documented 20-bit limit for GFX/compute/SDMA/VPE, and apply the MM fallback limit for other ring types.
--- drivers/gpu/drm/amd/amdgpu/amdgpu_cs.c | 26 +++++++++++++++++++++++++- 1 file changed, 25 insertions(+), 1 deletion(-)
drivers/gpu/drm/amd/amdgpu/amdgpu_cs.c +25 -1
@@ -39,6 +39,25 @@#include "amdgpu_gem.h" #include "amdgpu_ras.h" +/* +* Maximum IB length (dwords) for rings whose emit_ib packet format +* documents a 20-bit size field. +*/ +#define AMDGPU_GFX_SDMA_IB_PACKET_SIZE_MAX_DW 0xFFFFF +#define AMDGPU_MM_IB_PACKET_SIZE_MAX_DW 0x7FFFF0 + +static u32 amdgpu_cs_ib_packet_size_max_dw (enum amdgpu_ring_type type) +{ +switch (type) { +case AMDGPU_RING_TYPE_GFX : +case AMDGPU_RING_TYPE_COMPUTE : +case AMDGPU_RING_TYPE_SDMA : +return AMDGPU_GFX_SDMA_IB_PACKET_SIZE_MAX_DW ; +default : +return AMDGPU_MM_IB_PACKET_SIZE_MAX_DW ; + } +} + static int amdgpu_cs_parser_init(struct amdgpu_cs_parser *p, struct amdgpu_device *adev, struct drm_file *filp,
@@ -343,7 +362,6 @@ static int amdgpu_cs_p2_ib(struct amdgpu_cs_parser *p, job = p->jobs[r]; ring =amdgpu_job_ring (job); - ib = &job->ibs[job->num_ibs++];/* MM engine doesn't support user fences */ if (p->uf_entry.tv.bo && ring->funcs->no_user_fence)
@@ -362,6 +380,12 @@ static int amdgpu_cs_p2_ib(struct amdgpu_cs_parser *p,return -EINVAL ; } +if (chunk_ib->ib_bytes /4 > +amdgpu_cs_ib_packet_size_max_dw (ring->funcs->type)) +return -EINVAL ; + + ib = &job->ibs[job->num_ibs++]; +if (chunk_ib->flags &AMDGPU_IB_FLAG_PREAMBLE ) job->preamble_status |=AMDGPU_PREAMBLE_IB_PRESENT ;
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1316/1887 mptcp: avoid combining some incoming suboptions
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Matthieu Baerts (NGI0) <[email protected]>
[ Upstream commit b6ee361524641f57b2e2363f7737f20e17f67827 ]
Some MPTCP suboptions are mutually exclusive according to the RFC8684, but also because in different places, the code doesn't expect some combinations to be present. That's specially true for suboptions that would be present twice, but with different attributes.
The new restrictions are the same as the ones applied on the output side, with mptcp_write_options. The same rules can be reused with a small fix: an MP_FASTCLOSE can be used with a DSS when the sender picks this option [1], which is not the case on Linux. Here are the rules:
Which options can be used together?
X: mutually exclusive
O: often used together
C: can be used together in some cases
P: could be used together but we prefer not to (optimisations)
| Opt: | MPC | MPJ | DSS | ADD | RM | PRIO | FAIL | FC | |------|------|------|------|------|------|------|------|------| | MPC |------|------|------|------|------|------|------|------| | MPJ | X |------|------|------|------|------|------|------| | DSS | X | X |------|------|------|------|------|------| | ADD | X | X | P |------|------|------|------|------| | RM | C | C | C | P |------|------|------|------| | PRIO | X | C | C | C | C |------|------|------| | FAIL | X | X | C | X | X | X |------|------| | FC | X | X | P | X | X | X | X |------| | RST | X | X | X | X | X | X | O | O | |------|------|------|------|------|------|------|------|------|
The only difference is with the 'P': another stack could send and ADD_ADDR with other suboptions (DSS, RM_ADDR), and this should be allowed.
A few points of attention:
- In theory, an MP_CAPABLE could be used with a RM_ADDR, but there is no reason to add it with a SYN. Note that even with a 4th ACK, it doesn't seem to be useful, except when IDs are known in advance via another channel. Better not to break that.
- Now, combining both an MP_CAPABLE and an MP_JOIN will no longer result to a reject of the two options, but only the second suboption is ignored. That seems OK to do that for this unexpected error. At least now all inconsistent combinations are handled the same way. This could change later in next. This also means the explicit checks for having both MPC + MPJ in subflow.c will now be unreachable. That's fine, they will be removed in a follow-up patch.
- In case of conflicting combinations, the extra suboption(s) is/are
ignored: having such combinations either means the remote peer is buggy, or is evil. The simplest action is then taken in this case:
stop processing the current suboption.
- In mp_opt->suboptions, there is also a bit reserved to the checksum, which can be used in an MP_CAPABLE and a DSS. Each time a DSS option can be used in parallel with another option, the checksum can be set, so the verification is combined into a new OPTIONS_MPTCP_DSS macro.
- An MP_CAPABLE ACK can carry a Data-Level Length, and an optional
Checksum: they are the same as the ones found in a DSS, because a DSS cannot be used in parallel to an MP_CAPABLE. Similarly, even if there is room, a DSS cannot be used with an MP_JOIN.
--- net/mptcp/options.c | 70 +++++++++++++++++++++++++++++++++++++++++--- net/mptcp/protocol.h | 1 + 2 files changed, 67 insertions(+), 4 deletions(-)
net/mptcp/options.c +66 -4
@@ -26,6 +26,7 @@ static void mptcp_parse_option(const struct sk_buff *skb, {u8 subtype = *ptr >>4 ;int expected_opsize; +u16 subopt;u8 version;u8 flags;u8 i;
@@ -38,11 +39,23 @@ static void mptcp_parse_option(const struct sk_buff *skb, expected_opsize =TCPOLEN_MPTCP_MPC_ACK_DATA ; else expected_opsize =TCPOLEN_MPTCP_MPC_ACK ; + subopt =OPTION_MPTCP_MPC_ACK ; }else { -if (TCP_SKB_CB (skb)->tcp_flags &TCPHDR_ACK ) +if (TCP_SKB_CB (skb)->tcp_flags &TCPHDR_ACK ) { expected_opsize =TCPOLEN_MPTCP_MPC_SYNACK ; -else + subopt =OPTION_MPTCP_MPC_SYNACK ; + }else { expected_opsize =TCPOLEN_MPTCP_MPC_SYN ; + subopt =OPTION_MPTCP_MPC_SYN ; + } + } + +/* Only the MPC + ACK can be used with a RM_ADDR */ +if (subopt ==OPTION_MPTCP_MPC_ACK ) { +if ((mp_opt->suboptions & ~OPTION_MPTCP_RM_ADDR ) !=0 ) +break ; + }else if (mp_opt->suboptions !=0 ) { +break ; }/* Cfr RFC 8684 Section 3.3.0:
@@ -86,7 +99,7 @@ static void mptcp_parse_option(const struct sk_buff *skb, mp_opt->deny_join_id0 = !!(flags &MPTCP_CAP_DENY_JOIN_ID0 ); - mp_opt->suboptions |=OPTIONS_MPTCP_MPC ; + mp_opt->suboptions |= subopt;if (opsize >=TCPOLEN_MPTCP_MPC_SYNACK ) { mp_opt->sndr_key =get_unaligned_be64 (ptr); ptr +=8 ;
@@ -118,6 +131,11 @@ static void mptcp_parse_option(const struct sk_buff *skb,break ;case MPTCPOPT_MP_JOIN : +/* Can be used with a restricted number of other options */ +if ((mp_opt->suboptions & ~(OPTION_MPTCP_RM_ADDR | +OPTION_MPTCP_PRIO )) !=0 ) +break ; +if (opsize ==TCPOLEN_MPTCP_MPJ_SYN ) { mp_opt->suboptions |=OPTION_MPTCP_MPJ_SYN ; mp_opt->backup = *ptr++ &MPTCPOPT_BACKUP ;
@@ -149,6 +167,14 @@ static void mptcp_parse_option(const struct sk_buff *skb,break ;case MPTCPOPT_DSS : +/* Can be used with a restricted number of other options */ +if ((mp_opt->suboptions & ~(OPTION_MPTCP_ADD_ADDR | +OPTION_MPTCP_RM_ADDR | +OPTION_MPTCP_PRIO | +OPTION_MPTCP_FASTCLOSE | +OPTION_MPTCP_FAIL )) !=0 ) +break ; +pr_debug ("DSS\n" ); ptr++;
@@ -236,6 +262,12 @@ static void mptcp_parse_option(const struct sk_buff *skb,break ;case MPTCPOPT_ADD_ADDR : +/* Can be used with a restricted number of other options */ +if ((mp_opt->suboptions & ~(OPTIONS_MPTCP_DSS | +OPTION_MPTCP_RM_ADDR | +OPTION_MPTCP_PRIO )) !=0 ) +break ; + mp_opt->echo = (*ptr++) &MPTCP_ADDR_ECHO ;if (!mp_opt->echo) { if (opsize == TCPOLEN_MPTCP_ADD_ADDR ||
@@ -295,6 +327,14 @@ static void mptcp_parse_option(const struct sk_buff *skb,break ;case MPTCPOPT_RM_ADDR : +/* Can be used with a restricted number of other options */ +if ((mp_opt->suboptions & ~(OPTION_MPTCP_MPC_ACK | +OPTIONS_MPTCP_MPJ | +OPTIONS_MPTCP_DSS | +OPTION_MPTCP_ADD_ADDR | +OPTION_MPTCP_PRIO )) !=0 ) +break ; +if (opsize <TCPOLEN_MPTCP_RM_ADDR_BASE +1 || opsize >TCPOLEN_MPTCP_RM_ADDR_BASE +MPTCP_RM_IDS_MAX )break ;
@@ -309,6 +349,13 @@ static void mptcp_parse_option(const struct sk_buff *skb,break ;case MPTCPOPT_MP_PRIO : +/* Can be used with a restricted number of other options */ +if ((mp_opt->suboptions & ~(OPTIONS_MPTCP_MPJ | +OPTIONS_MPTCP_DSS | +OPTION_MPTCP_ADD_ADDR | +OPTION_MPTCP_RM_ADDR )) !=0 ) +break ; +if (opsize !=TCPOLEN_MPTCP_PRIO )break ;
@@ -318,6 +365,11 @@ static void mptcp_parse_option(const struct sk_buff *skb,break ;case MPTCPOPT_MP_FASTCLOSE : +/* Can be used with a restricted number of other options */ +if ((mp_opt->suboptions & ~(OPTIONS_MPTCP_DSS | +OPTION_MPTCP_RST )) !=0 ) +break ; +if (opsize !=TCPOLEN_MPTCP_FASTCLOSE )break ;
@@ -329,6 +381,11 @@ static void mptcp_parse_option(const struct sk_buff *skb,break ;case MPTCPOPT_RST : +/* Can be used with a restricted number of other options */ +if ((mp_opt->suboptions & ~(OPTION_MPTCP_FAIL | +OPTION_MPTCP_FASTCLOSE )) !=0 ) +break ; +if (opsize !=TCPOLEN_MPTCP_RST )break ;
@@ -344,6 +401,11 @@ static void mptcp_parse_option(const struct sk_buff *skb,break ;case MPTCPOPT_MP_FAIL : +/* Can be used with a restricted number of other options */ +if ((mp_opt->suboptions & ~(OPTIONS_MPTCP_DSS | +OPTION_MPTCP_RST )) !=0 ) +break ; +if (opsize !=TCPOLEN_MPTCP_FAIL )break ;
@@ -1416,7 +1478,7 @@ void mptcp_write_options(struct tcphdr *th, __be32 *ptr, struct tcp_sock *tp,* RM | C | C | C | P |------|------|------|------| * PRIO | X | C | C | C | C |------|------|------| * FAIL | X | X | C | X | X | X |------|------| -* FC | X | X | X | X | X | X | X |------| +* FC | X | X | P | X | X | X | X |------| * RST | X | X | X | X | X | X | O | O | * ------|------|------|------|------|------|------|------|------| *
net/mptcp/protocol.h +1 -0
@@ -36,6 +36,7 @@ OPTION_MPTCP_MPC_ACK)#define OPTIONS_MPTCP_MPJ (OPTION_MPTCP_MPJ_SYN | OPTION_MPTCP_MPJ_SYNACK | \ OPTION_MPTCP_MPJ_ACK) +#define OPTIONS_MPTCP_DSS (OPTION_MPTCP_DSS | OPTION_MPTCP_CSUMREQD)/* MPTCP option subtypes */ #define MPTCPOPT_MP_CAPABLE 0
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1317/1887 ACPI: processor_idle: Mark LPI enter functions as __cpuidle
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Li RongQing <[email protected]>
[ Upstream commit 956ca5d72c76504824c8eb601879da9476973e15 ]
When function tracing or Kprobes is enabled, entering an ACPI Low Power Idle (LPI) state triggers the following RCU splat:
RCU not on for: acpi_idle_lpi_enter+0x4/0xd8
WARNING: CPU: 8 PID: 0 at include/linux/trace_recursion.h:162 function_trace_call+0x1e8/0x228
The acpi_idle_lpi_enter() function is invoked within the cpuidle path after RCU has already been disabled for the current local CPU. Consequently, ftrace's function_trace_call() expects RCU to be actively watching before recording trace data, emitting a warning if it is not.
Fix this by annotating acpi_idle_lpi_enter(), the generic __weak stub, and the RISC-V implementation of acpi_processor_ffh_lpi_enter() with __cpuidle. This moves these functions into the '.cpuidle.text' section, implicitly disabling ftrace instrumentation (notrace) along this sensitive path and preventing trace-induced RCU warnings during idle entry.
--- drivers/acpi/processor_idle.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-)
drivers/acpi/processor_idle.c +2 -2
@@ -1183,7 +1183,7 @@ static int acpi_processor_get_lpi_info(struct acpi_processor *pr)return 0 ; } -int __weak acpi_processor_ffh_lpi_enter (struct acpi_lpi_state *lpi) +int __weak __cpuidle acpi_processor_ffh_lpi_enter(struct acpi_lpi_state *lpi) {return -ENODEV ; }
@@ -1196,7 +1196,7 @@ int __weak acpi_processor_ffh_lpi_enter(struct acpi_lpi_state *lpi)* * Return: 0 for success or negative value for error */ -static int acpi_idle_lpi_enter (struct cpuidle_device *dev, +static int __cpuidle acpi_idle_lpi_enter(struct cpuidle_device *dev,struct cpuidle_driver *drv,int index) {struct acpi_processor *pr;
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1318/1887 ieee802154: Avoid calling WARN_ON() on -ENOMEM in cfg802154_switch_netns()
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Ivan Abramov <[email protected]>
[ Upstream commit 0569f67ed6a7af838e2141da93c68e6b6013f483 ]
It's pointless to call WARN_ON() in case of an allocation failure in dev_change_net_namespace() and device_rename(), since it only leads to useless splats caused by deliberate fault injections, so avoid it.
Found by Linux Verification Center (linuxtesting.org) with Syzkaller.
--- net/ieee802154/core.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-)
net/ieee802154/core.c +5 -3
@@ -206,8 +206,10 @@ int cfg802154_switch_netns(struct cfg802154_registered_device *rdev,continue ; wpan_dev->netdev->features &= ~NETIF_F_NETNS_LOCAL ; err =dev_change_net_namespace (wpan_dev->netdev, net,"wpan%d" ); -if (err) +if (err) { +WARN_ON (err && err != -ENOMEM );break ; + } wpan_dev->netdev->features |=NETIF_F_NETNS_LOCAL ; }
@@ -223,7 +225,7 @@ int cfg802154_switch_netns(struct cfg802154_registered_device *rdev, wpan_dev->netdev->features &= ~NETIF_F_NETNS_LOCAL ; err =dev_change_net_namespace (wpan_dev->netdev, net,"wpan%d" ); -WARN_ON (err); +WARN_ON (err && err != -ENOMEM ); wpan_dev->netdev->features |=NETIF_F_NETNS_LOCAL ; }
@@ -233,7 +235,7 @@ int cfg802154_switch_netns(struct cfg802154_registered_device *rdev,wpan_phy_net_set (&rdev->wpan_phy, net); err =device_rename (&rdev->wpan_phy.dev,dev_name (&rdev->wpan_phy.dev)); -WARN_ON (err); +WARN_ON (err && err != -ENOMEM );return 0 ; }
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1319/1887 coresight: ete: Always save state on power down
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: James Clark <[email protected]>
[ Upstream commit 2ab4645fe4206c142a5f1491e191c906279686cf ]
System register ETMs and ETE are unlikely to be preserved on CPU power down. The ETE DT binding also never documented "arm,coresight-loses-context-with-cpu" so nobody would have legitimately been able to use that binding to fix it and ACPI has no such binding at all.
Fix it by hard coding the setting for sysreg ETMs (ETE is always sysreg) or ACPI boots. Use a local variable when setting up save_state so that it's immune to concurrent probing when devices have different configurations which is an issue with modifying the global.
This fixes the following error when using Coresight with ACPI on the FVP which supports CPU PM:
coresight ete0: External agent took claim tag
WARNING: drivers/hwtracing/coresight/coresight-core.c:248 at coresight_disclaim_device_unlocked+0xe0/0xe8, CPU#0: perf/117
--- .../coresight/coresight-etm4x-core.c | 45 ++++++++++++++----- 1 file changed, 33 insertions(+), 12 deletions(-)
drivers/hwtracing/coresight/coresight-etm4x-core.c +33 -12
@@ -3,6 +3,7 @@* Copyright (c) 2014, The Linux Foundation. All rights reserved. */ +#include <linux/acpi.h> #include <linux/bitops.h> #include <linux/kernel.h> #include <linux/moduleparam.h>
@@ -51,10 +52,14 @@ MODULE_PARM_DESC(boot_enable, "Enable tracing on boot");#define PARAM_PM_SAVE_NEVER 1/* never save any state */ #define PARAM_PM_SAVE_SELF_HOSTED 2/* save self-hosted state only */ +/* +* Save option for ETM4. ETE, sysreg ETM4s and ACPI boots ignore this option and +* will always save. +*/ static int pm_save_enable =PARAM_PM_SAVE_FIRMWARE ;module_param (pm_save_enable, int,0444 );MODULE_PARM_DESC (pm_save_enable, -"Save/restore state on power down: 1 = never, 2 = self-hosted" ); +"Save/restore state on power down: 1 = never, 2 = self-hosted. MMIO and DT only." );static struct etmv4_drvdata *etmdrvdata[NR_CPUS ];static void etm4_set_default_config (struct etmv4_config *config);
@@ -1994,6 +1999,17 @@ static void etm4_pm_clear(void) } } +static bool etm4x_always_pm_save (struct device *dev,struct csdev_access *csa) +{ +/* +* Only IO mem ETM devices will benefit from skipping PM save and only +* DT has the option to control it, not ACPI. Otherwise system register +* based ETMs and ETEs will always lose context on CPU power down, so +* always save. +*/ +return !csa->io_mem ||is_acpi_device_node (dev_fwnode (dev)); +} +static int etm4_probe (struct device *dev,void __iomem *base,u32 etm_pid) {int ret;
@@ -2003,6 +2019,7 @@ static int etm4_probe(struct device *dev, void __iomem *base, u32 etm_pid)struct etm4_init_arg init_arg = {0 };u8 major, minor;char *type_name; +bool pm_save; drvdata =devm_kzalloc (dev,sizeof (*drvdata),GFP_KERNEL );if (!drvdata)
@@ -2010,17 +2027,6 @@ static int etm4_probe(struct device *dev, void __iomem *base, u32 etm_pid)dev_set_drvdata (dev, drvdata); -if (pm_save_enable ==PARAM_PM_SAVE_FIRMWARE ) - pm_save_enable =coresight_loses_context_with_cpu (dev) ? -PARAM_PM_SAVE_SELF_HOSTED :PARAM_PM_SAVE_NEVER ; - -if (pm_save_enable !=PARAM_PM_SAVE_NEVER ) { - drvdata->save_state =devm_kmalloc (dev, -sizeof (struct etmv4_save_state ),GFP_KERNEL ); -if (!drvdata->save_state) -return -ENOMEM ; - } - drvdata->base = base;spin_lock_init (&drvdata->spinlock);
@@ -2064,6 +2070,21 @@ static int etm4_probe(struct device *dev, void __iomem *base, u32 etm_pid)etm4_init_trace_id (drvdata);etm4_set_default (&drvdata->config); +if (etm4x_always_pm_save (dev, &desc.access)) + pm_save = true; +else if (pm_save_enable ==PARAM_PM_SAVE_FIRMWARE ) + pm_save =coresight_loses_context_with_cpu (dev); +else + pm_save = pm_save_enable !=PARAM_PM_SAVE_NEVER ; + +if (pm_save) { + drvdata->save_state =devm_kmalloc (dev, +sizeof (struct etmv4_save_state ), +GFP_KERNEL ); +if (!drvdata->save_state) +return -ENOMEM ; + } + pdata =coresight_get_platform_data (dev);if (IS_ERR (pdata))return PTR_ERR (pdata);
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1320/1887 ALSA: seq: oss: Serialize readq reset state with q->lock
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Cen Zhang <[email protected]>
[ Upstream commit 49ce92d207820f588b0406add82f053decfbe5d9 ]
snd_seq_oss_readq_clear() resets qlen, head, and tail without q->lock even though the normal reader and producer paths serialize the same ring state under that spinlock. A reset can therefore race snd_seq_oss_readq_free() or snd_seq_oss_readq_put_event() and leave stale records in the queue, drop freshly queued ones, or report the wrong readiness after wakeup. KCSAN reports a data race between snd_seq_oss_readq_clear() and snd_seq_oss_readq_free().
Take q->lock while clearing the ring and resetting input_time. Factor the enqueue logic into a caller-locked helper so snd_seq_oss_readq_put_timestamp() updates its suppression state under the same lock instead of racing the reset path.
The buggy scenario involves two paths, with each column showing the order within that path:
reset path: locked readq updater:
1. snd_seq_oss_reset() or 1. A reader or callback producer
release reaches takes q->lock on the same queue.
snd_seq_oss_readq_clear().
2. snd_seq_oss_readq_clear() 2. The updater tests or modifies
resets qlen, head, tail, qlen, head, and tail.
and input_time.
3. snd_seq_oss_readq_clear() 3. The updater completes its
wakes sleepers on read-modify-write sequence.
q->midi_sleep.
4. Without q->lock, the reset 4. The resulting ring state drives
can overlap the locked later reads and readiness.
update.
KCSAN reports:
BUG: KCSAN: data-race in snd_seq_oss_readq_clear /
snd_seq_oss_readq_free
write to 0xffff8881069fe608 of 4 bytes by task 120516 on cpu 0:
snd_seq_oss_readq_free+0x6c/0x80 snd_seq_oss_read+0xcb/0x250 odev_read+0x38/0x60 vfs_read+0xff/0x600 ksys_read+0xb4/0x140 __x64_sys_read+0x46/0x60 do_syscall_64+0xbb/0x2f0 entry_SYSCALL_64_after_hwframe+0x77/0x7f
read to 0xffff8881069fe608 of 4 bytes by task 120517 on cpu 1:
snd_seq_oss_readq_clear+0x1f/0x90 snd_seq_oss_reset+0xa7/0xf0 snd_seq_oss_ioctl+0x6f6/0x7e0 odev_ioctl+0x56/0xc0 __x64_sys_ioctl+0xd1/0x120 do_syscall_64+0xbb/0x2f0 entry_SYSCALL_64_after_hwframe+0x77/0x7f
value changed: 0x00000001 -> 0x00000000
--- sound/core/seq/oss/seq_oss_readq.c | 83 +++++++++++++++++++----------- 1 file changed, 52 insertions(+), 31 deletions(-)
sound/core/seq/oss/seq_oss_readq.c +52 -31
@@ -73,13 +73,17 @@ snd_seq_oss_readq_delete(struct seq_oss_readq *q)void snd_seq_oss_readq_clear (struct seq_oss_readq *q) { -if (q->qlen) { - q->qlen =0 ; - q->head = q->tail =0 ; + scoped_guard(spinlock_irqsave, &q->lock) { +if (q->qlen) { + q->qlen =0 ; + q->head =0 ; + q->tail =0 ; + } + q->input_time = (unsigned long )-1 ; } +/* if someone sleeping, wake'em up */ wake_up (&q->midi_sleep); - q->input_time = (unsigned long )-1 ; }/*
@@ -136,28 +140,37 @@ int snd_seq_oss_readq_sysex(struct seq_oss_readq *q, int dev,/* * copy an event to input queue: * return zero if enqueued +* caller must hold lock */ -int -snd_seq_oss_readq_put_event (struct seq_oss_readq *q,union evrec *ev) +static int snd_seq_oss_readq_put_event_locked (struct seq_oss_readq *q, +union evrec *ev) { -unsigned long flags; - -spin_lock_irqsave (&q->lock, flags); -if (q->qlen >= q->maxlen -1 ) { -spin_unlock_irqrestore (&q->lock, flags); +if (q->qlen >= q->maxlen -1 )return -ENOMEM ; - }memcpy (&q->q[q->tail], ev,sizeof (*ev)); q->tail = (q->tail +1 ) % q->maxlen; q->qlen++; -/* wake up sleeper */ -wake_up (&q->midi_sleep); +return 0 ; +} -spin_unlock_irqrestore (&q->lock, flags); +/* +* copy an event to input queue: +* return zero if enqueued +*/ +int +snd_seq_oss_readq_put_event (struct seq_oss_readq *q,union evrec *ev) +{ +int rc; -return 0 ; + scoped_guard(spinlock_irqsave, &q->lock) { + rc =snd_seq_oss_readq_put_event_locked (q, ev); +if (!rc) +wake_up (&q->midi_sleep); + } + +return rc; }
@@ -215,23 +228,31 @@ snd_seq_oss_readq_poll(struct seq_oss_readq *q, struct file *file, poll_table *wint snd_seq_oss_readq_put_timestamp (struct seq_oss_readq *q,unsigned long curt,int seq_mode) { -if (curt != q->input_time) { -union evrec rec; -memset (&rec,0 ,sizeof (rec)); -switch (seq_mode) { -case SNDRV_SEQ_OSS_MODE_SYNTH : - rec.echo = (curt <<8 ) |SEQ_WAIT ; -snd_seq_oss_readq_put_event (q, &rec); -break ; -case SNDRV_SEQ_OSS_MODE_MUSIC : - rec.t.code =EV_TIMING ; - rec.t.cmd =TMR_WAIT_ABS ; - rec.t.time = curt; -snd_seq_oss_readq_put_event (q, &rec); -break ; +int queued =0 ; + + scoped_guard(spinlock_irqsave, &q->lock) { +if (curt != q->input_time) { +union evrec rec; + +memset (&rec,0 ,sizeof (rec)); +switch (seq_mode) { +case SNDRV_SEQ_OSS_MODE_SYNTH : + rec.echo = (curt <<8 ) |SEQ_WAIT ; + queued = !snd_seq_oss_readq_put_event_locked (q, &rec); +break ; +case SNDRV_SEQ_OSS_MODE_MUSIC : + rec.t.code =EV_TIMING ; + rec.t.cmd =TMR_WAIT_ABS ; + rec.t.time = curt; + queued = !snd_seq_oss_readq_put_event_locked (q, &rec); +break ; + } + q->input_time = curt; } - q->input_time = curt; } +if (queued) +wake_up (&q->midi_sleep); +return 0 ; }
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1321/1887 octeontx2-af: npc: Fix size of entry2cntr_map
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Ratheesh Kannoth <[email protected]>
[ Upstream commit f9cd6fabe0e7c7f6fc30c6c192c7ed72aba37232 ]
KASAN prints below splat. This is caused by allocating counter for reserved mcam entry for cpt 2nd pass entry. But mcam->entry2cntr_map is not allocated for reserved entries.
BUG: KASAN: slab-out-of-bounds in npc_map_mcam_entry_and_cntr+0xb0/0x1a0 Write of size 2 at addr ffff0001033e7ffe by task kworker/0:1/14 CPU: 0 PID: 14 Comm: kworker/0:1 Not tainted 6.1.67 #1 Hardware name: Marvell CN106XX board (DT) Workqueue: events work_for_cpu_fn Call trace: dump_backtrace.part.0+0xe4/0xf0 show_stack+0x18/0x30 dump_stack_lvl+0x88/0xb4 print_report+0x154/0x458 kasan_report+0xb8/0x194 __asan_store2+0x7c/0xa0 npc_map_mcam_entry_and_cntr+0xb0/0x1a0 rvu_mbox_handler_npc_mcam_write_entry+0x268/0x280 npc_install_flow+0x840/0xfe0 rvu_npc_install_cpt_pass2_entry+0x138/0x190 rvu_nix_init+0x148c/0x2880 rvu_probe+0x1800/0x30b0 local_pci_probe+0x78/0xe0 work_for_cpu_fn+0x30/0x50 process_one_work+0x4cc/0x97c worker_thread+0x360/0x630 kthread+0x1a0/0x1b0 ret_from_fork+0x10/0x20
--- .../ethernet/marvell/octeontx2/af/rvu_npc.c | 40 +++++++------------ 1 file changed, 15 insertions(+), 25 deletions(-)
drivers/net/ethernet/marvell/octeontx2/af/rvu_npc.c +15 -25
@@ -1934,7 +1934,7 @@ static int npc_mcam_rsrcs_init(struct rvu *rvu, int blkaddr)/* Alloc memory for MCAM entry to counter mapping and for tracking * counter's reference count. */ - mcam->entry2cntr_map =devm_kcalloc (rvu->dev, mcam->bmap_entries, + mcam->entry2cntr_map =devm_kcalloc (rvu->dev, mcam->total_entries,sizeof (u16),GFP_KERNEL );if (!mcam->entry2cntr_map) goto free_mem;
@@ -1950,10 +1950,11 @@ static int npc_mcam_rsrcs_init(struct rvu *rvu, int blkaddr)if (!mcam->entry2target_pffunc) goto free_mem; -for (index =0 ; index < mcam->bmap_entries; index++) { +for (index =0 ; index < mcam->bmap_entries; index++) mcam->entry2pfvf_map[index] =NPC_MCAM_INVALID_MAP ; + +for (index =0 ; index < mcam->total_entries; index++) mcam->entry2cntr_map[index] =NPC_MCAM_INVALID_MAP ; - }for (cntr =0 ; cntr < mcam->counters.max; cntr++) mcam->cntr2pfvf_map[cntr] =NPC_MCAM_INVALID_MAP ;
@@ -3040,7 +3041,7 @@ int rvu_mbox_handler_npc_mcam_free_counter(struct rvu *rvu, struct npc_mcam_oper_counter_req *req, struct msg_rsp *rsp) { struct npc_mcam *mcam = &rvu->hw->mcam; -u16 index, entry =0 ; +u16 index;int blkaddr, err; blkaddr =rvu_get_blkaddr (rvu,BLKTYPE_NPC ,0 );
@@ -3058,20 +3059,16 @@ int rvu_mbox_handler_npc_mcam_free_counter(struct rvu *rvu, mcam->cntr2pfvf_map[req->cntr] =NPC_MCAM_INVALID_MAP ;rvu_free_rsrc (&mcam->counters, req->cntr); -/* Disable all MCAM entry's stats which are using this counter */ -while (entry < mcam->bmap_entries) { +/* Disable all MCAM entry's stats which are using this counter. +* Scan the full MCAM index range: AF-reserved rules (e.g. CPT pass-2) +*/ +for (index =0 ; index < mcam->total_entries; index++) {if (!mcam->cntr_refcnt[req->cntr])break ; - - index =find_next_bit (mcam->bmap, mcam->bmap_entries, entry); -if (index >= mcam->bmap_entries) -break ; - entry = index +1 ;if (mcam->entry2cntr_map[index] != req->cntr)continue ; - -npc_unmap_mcam_entry_and_cntr (rvu, mcam, blkaddr, - index, req->cntr); +npc_unmap_mcam_entry_and_cntr (rvu, mcam, blkaddr, index, + req->cntr); }mutex_unlock (&mcam->lock);
@@ -3082,7 +3079,7 @@ int rvu_mbox_handler_npc_mcam_unmap_counter(struct rvu *rvu, struct npc_mcam_unmap_counter_req *req, struct msg_rsp *rsp) { struct npc_mcam *mcam = &rvu->hw->mcam; -u16 index, entry =0 ; +u16 index;int blkaddr, rc; blkaddr =rvu_get_blkaddr (rvu,BLKTYPE_NPC ,0 );
@@ -3105,20 +3102,13 @@ int rvu_mbox_handler_npc_mcam_unmap_counter(struct rvu *rvu, }/* Disable all MCAM entry's stats which are using this counter */ -while (entry < mcam->bmap_entries) { +for (index =0 ; index < mcam->total_entries; index++) {if (!mcam->cntr_refcnt[req->cntr])break ; - - index =find_next_bit (mcam->bmap, mcam->bmap_entries, entry); -if (index >= mcam->bmap_entries) -break ; - entry = index +1 ; -if (mcam->entry2cntr_map[index] != req->cntr)continue ; - -npc_unmap_mcam_entry_and_cntr (rvu, mcam, blkaddr, - index, req->cntr); +npc_unmap_mcam_entry_and_cntr (rvu, mcam, blkaddr, index, + req->cntr); } exit:mutex_unlock (&mcam->lock);
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1322/1887 btrfs: lzo: reject compressed segment that overflows the compressed input
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Weiming Shi <[email protected]>
[ Upstream commit b0d27d43791b7a3057c3c4aedf9b4aa033d37c46 ]
lzo_decompress_bio() validates each on-disk segment length seg_len only against the workspace cbuf size, not against the compressed input size (compressed_len, the total folio bytes of the bio). A crafted extent can carry a segment whose seg_len passes the cbuf check but runs past the end of the bio, so copy_compressed_segment() walks off the last folio:get_current_folio() then returns the NULL folio from bio_next_folio(), and with CONFIG_BTRFS_ASSERT disabled (default) folio_size(NULL) faults.
BUG: KASAN: null-ptr-deref in lzo_decompress_bio (fs/btrfs/lzo.c:383) Read of size 8 at addr 0000000000000000 by task kworker/u8:1/29 Workqueue: btrfs-endio simple_end_io_work kasan_report (mm/kasan/report.c:590) lzo_decompress_bio (fs/btrfs/lzo.c:383) end_bbio_compressed_read (fs/btrfs/compression.c:1065) btrfs_bio_end_io (fs/btrfs/bio.c:135) btrfs_check_read_bio (fs/btrfs/bio.c:180 fs/btrfs/bio.c:285) simple_end_io_work process_one_work worker_thread
Reject any segment whose payload would extend beyond compressed_len before copying it, treating it as corruption like the other on-disk validation failures in this function.
--- fs/btrfs/lzo.c | 12 ++++++++++++ 1 file changed, 12 insertions(+)
fs/btrfs/lzo.c +12 -0
@@ -15,6 +15,7 @@#include <linux/refcount.h> #include "compression.h" #include "ctree.h" +#include "btrfs_inode.h" #define LZO_LEN 4
@@ -390,6 +391,17 @@ int lzo_decompress_bio(struct list_head *ws, struct compressed_bio *cb) goto out; } +/* The segment must not extend beyond the compressed input. */ +if (unlikely (cur_in + seg_len > cb->compressed_len)) { +struct btrfs_inode *inode =BTRFS_I (cb->inode); + +btrfs_err (fs_info, +"lzo segment overflows compressed input, root %llu inode %llu offset %llu cur_in %u len %u compressed len %u" , + inode->root->root_key.objectid,btrfs_ino (inode), + cb->start, cur_in, seg_len, cb->compressed_len); +return -EUCLEAN ; + } +/* Copy the compressed segment payload into workspace */ copy_compressed_segment (cb, workspace->cbuf, seg_len, &cur_in);
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1323/1887 netfilter: flowtable: avoid num_encaps underflow on bridge VLAN untag
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: David Carlier <[email protected]>
[ Upstream commit e052f920773b73be49eb4d8702a9f85de7464363 ]
The DEV_PATH_BR_VLAN_UNTAG case post-decrements info->num_encaps inside WARN_ON_ONCE(). num_encaps is u8, so if it's already 0 the decrement still happens and wraps it to 255. The break only leaves the inner switch -- a later path entry can set info->indev back to a real device, and we end up returning with num_encaps == 255.
nft_dev_forward_path() then walks info.encap[] (size 2) up to num_encaps, which means an OOB stack read and a bogus count copied into the route descriptor.
Should only happen on a malformed bridge path stack, hence the WARN, but worth handling sanely. Move the decrement out of the WARN.
[ While at this, remove the WARN_ON_ONCE since this can only happen
with a buggy bridge path stack --pablo ].
--- net/netfilter/nft_flow_offload.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-)
net/netfilter/nft_flow_offload.c +2 -1
@@ -149,10 +149,11 @@ static void nft_dev_path_info(const struct net_device_path_stack *stack, info->num_encaps++;break ;case DEV_PATH_BR_VLAN_UNTAG : -if (WARN_ON_ONCE (info->num_encaps-- ==0 )) { +if (info->num_encaps ==0 ) { info->indev =NULL ;break ; } + info->num_encaps--;break ;case DEV_PATH_BR_VLAN_KEEP :break ;
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1324/1887 netfilter: make nftables drops visible in net dropmonitor
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Florian Westphal <[email protected]>
[ Upstream commit e0d4593140b01b8da513a0c88c26da28b4906413 ]
net_dropmonitor blames core.c:nf_hook_slow.
Add NF_DROP_REASON() helper and use it in nft_do_chain().
The helper releases the skb, so exact drop location becomes available. Calling code will observe the NF_STOLEN verdict instead.
Adjust nf_hook_slow so we can embed an erro value wih NF_STOLEN verdicts, just like we do for NF_DROP.
After this, drop in nftables can be pinpointed to a drop due to a rule or the chain policy.
Stable-dep-of: 992c20bc8a4a ("netfilter: synproxy: fix unaligned memory access in timestamp adjustment")
--- include/linux/netfilter.h | 10 ++++++++++ net/netfilter/core.c | 6 +++--- net/netfilter/nf_tables_core.c | 6 +++++- 3 files changed, 18 insertions(+), 4 deletions(-)
include/linux/netfilter.h +10 -0
@@ -21,6 +21,16 @@ static inline int NF_DROP_GETERR(int verdict)return -(verdict >>NF_VERDICT_QBITS ); } +static __always_inline int +NF_DROP_REASON (struct sk_buff *skb,enum skb_drop_reason reason,u32 err) +{ +BUILD_BUG_ON (err >0xffff ); + +kfree_skb_reason (skb, reason); + +return ((err <<16 ) |NF_STOLEN ); +} +static inline int nf_inet_addr_cmp (const union nf_inet_addr *a1,const union nf_inet_addr *a2) {
net/netfilter/core.c +3 -3
@@ -627,10 +627,10 @@ int nf_hook_slow(struct sk_buff *skb, struct nf_hook_state *state,if (ret ==1 )continue ;return ret; +case NF_STOLEN : +return NF_DROP_GETERR (verdict);default : -/* Implicit handling for NF_STOLEN, as well as any other -* non conventional verdicts. -*/ +WARN_ON_ONCE (1 );return 0 ; } }
net/netfilter/nf_tables_core.c +5 -1
@@ -284,10 +284,11 @@ nft_do_chain(struct nft_pktinfo *pkt, void *priv)switch (regs.verdict.code &NF_VERDICT_MASK ) {case NF_ACCEPT : -case NF_DROP :case NF_QUEUE :case NF_STOLEN :return regs.verdict.code; +case NF_DROP : +return NF_DROP_REASON (pkt->skb,SKB_DROP_REASON_NETFILTER_DROP ,EPERM ); }switch (regs.verdict.code) {
@@ -322,6 +323,9 @@ nft_do_chain(struct nft_pktinfo *pkt, void *priv)if (static_branch_unlikely (&nft_counters_enabled))nft_update_chain_stats (basechain, pkt); +if (nft_base_chain (basechain)->policy ==NF_DROP ) +return NF_DROP_REASON (pkt->skb,SKB_DROP_REASON_NETFILTER_DROP ,EPERM ); +return nft_base_chain (basechain)->policy; }EXPORT_SYMBOL_GPL (nft_do_chain);
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1325/1887 netfilter: synproxy: drop packets if timestamp adjustment fails
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Fernando Fernandez Mancera <[email protected]>
[ Upstream commit 63d29ee95c4ab5976d660182d2e4733bb4a091d8 ]
If a packet was malformed or if skb_ensure_writable() failed, the synproxy_tstamp_adjust() function returned 0 indicating an error but it was ignored on the callers.
Make the function return a boolean instead to clarify the result and drop the packet if synproxy_tstamp_adjust() failed due to ENOMEM from skb_ensure_writable(). In addition, if there are malformed options, skip the tstamp update but do not drop the packet as that should be done by the policy directly.
Stable-dep-of: 992c20bc8a4a ("netfilter: synproxy: fix unaligned memory access in timestamp adjustment")
--- net/netfilter/nf_synproxy_core.c | 22 +++++++++++++--------- 1 file changed, 13 insertions(+), 9 deletions(-)
net/netfilter/nf_synproxy_core.c +13 -9
@@ -183,7 +183,7 @@ synproxy_check_timestamp_cookie(struct synproxy_options *opts) opts->options |= opts->tsecr & (1 <<5 ) ?NF_SYNPROXY_OPT_ECN :0 ; } -static unsigned int +static bool synproxy_tstamp_adjust(struct sk_buff *skb, unsigned int protoff, struct tcphdr *th, struct nf_conn *ct, enum ip_conntrack_info ctinfo,
@@ -193,13 +193,13 @@ synproxy_tstamp_adjust(struct sk_buff *skb, unsigned int protoff,__be32 *ptr, old;if (synproxy->tsoff ==0 ) -return 1 ; +return true; optoff = protoff +sizeof (struct tcphdr ); optend = protoff + th->doff *4 ;if (skb_ensure_writable (skb, optend)) -return 0 ; +return false; th = (struct tcphdr *)(skb->data + protoff);
@@ -208,7 +208,7 @@ synproxy_tstamp_adjust(struct sk_buff *skb, unsigned int protoff,switch (op[0 ]) {case TCPOPT_EOL : -return 1 ; +return true;case TCPOPT_NOP : optoff++;continue ;
@@ -216,7 +216,7 @@ synproxy_tstamp_adjust(struct sk_buff *skb, unsigned int protoff,if (optoff +1 == optend || optoff + op[1 ] > optend || op[1 ] <2 ) -return 0 ; +return true;if (op[0 ] ==TCPOPT_TIMESTAMP && op[1 ] ==TCPOLEN_TIMESTAMP ) {if (CTINFO2DIR (ctinfo) ==IP_CT_DIR_REPLY ) {
@@ -232,12 +232,12 @@ synproxy_tstamp_adjust(struct sk_buff *skb, unsigned int protoff, }inet_proto_csum_replace4 (&th->check, skb, old, *ptr, false); -return 1 ; +return true; } optoff += op[1 ]; } } -return 1 ; +return true; }#ifdef CONFIG_PROC_FS
@@ -748,7 +748,9 @@ ipv4_synproxy_hook(void *priv, struct sk_buff *skb,break ; } -synproxy_tstamp_adjust (skb, thoff, th, ct, ctinfo, synproxy); +if (!synproxy_tstamp_adjust (skb, thoff, th, ct, ctinfo, synproxy)) +return NF_DROP_REASON (skb,SKB_DROP_REASON_NETFILTER_DROP ,ENOMEM ); +return NF_ACCEPT ; }EXPORT_SYMBOL_GPL (ipv4_synproxy_hook);
@@ -1176,7 +1178,9 @@ ipv6_synproxy_hook(void *priv, struct sk_buff *skb,break ; } -synproxy_tstamp_adjust (skb, thoff, th, ct, ctinfo, synproxy); +if (!synproxy_tstamp_adjust (skb, thoff, th, ct, ctinfo, synproxy)) +return NF_DROP_REASON (skb,SKB_DROP_REASON_NETFILTER_DROP ,ENOMEM ); +return NF_ACCEPT ; }EXPORT_SYMBOL_GPL (ipv6_synproxy_hook);
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1326/1887 netfilter: synproxy: adjust duplicate timestamp options
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Fernando Fernandez Mancera <[email protected]>
[ Upstream commit 22bb132cfb9b94847d52d73614284b8c5ea8d36e ]
RFC 9293 does not mention anything about duplicated options and each networking stack handles it in their own way. Currently, Linux kernel is processing options sequentially and in case of duplicated timestamp options, the value from the latest one overrides the others.
As SYNPROXY is modifying only the first timestamp option found, a packet can reach the backend server and it might parse the wrong timestamp value. Let's just continue parsing the following options and in case a duplicated timestamp is found, adjust it too.
Stable-dep-of: 992c20bc8a4a ("netfilter: synproxy: fix unaligned memory access in timestamp adjustment")
--- net/netfilter/nf_synproxy_core.c | 1 - 1 file changed, 1 deletion(-)
net/netfilter/nf_synproxy_core.c +0 -1
@@ -232,7 +232,6 @@ synproxy_tstamp_adjust(struct sk_buff *skb, unsigned int protoff, }inet_proto_csum_replace4 (&th->check, skb, old, *ptr, false); -return true; } optoff += op[1 ]; }
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1327/1887 netfilter: synproxy: fix unaligned memory access in timestamp adjustment
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Fernando Fernandez Mancera <[email protected]>
[ Upstream commit 992c20bc8a4aba220c8b95b467d049289778dad6 ]
Use get_unaligned_be32() and put_unaligned_be32() to safely read and write the timestamp fields. This prevents performance degradation due to unaligned memory access or even a crash on strict alignment architectures.
This follows the implementation of timestamp parsing in the networking stack at tcp_parse_options() and synproxy_parse_options().
--- net/netfilter/nf_synproxy_core.c | 19 +++++++++---------- 1 file changed, 9 insertions(+), 10 deletions(-)
net/netfilter/nf_synproxy_core.c +9 -10
@@ -190,7 +190,7 @@ synproxy_tstamp_adjust(struct sk_buff *skb, unsigned int protoff, const struct nf_conn_synproxy *synproxy) {unsigned int optoff, optend; -__be32 *ptr, old; +u32 new, old;if (synproxy->tsoff ==0 )return true;
@@ -220,18 +220,17 @@ synproxy_tstamp_adjust(struct sk_buff *skb, unsigned int protoff,if (op[0 ] ==TCPOPT_TIMESTAMP && op[1 ] ==TCPOLEN_TIMESTAMP ) {if (CTINFO2DIR (ctinfo) ==IP_CT_DIR_REPLY ) { - ptr = (__be32 *)&op[2 ]; - old = *ptr; - *ptr =htonl (ntohl (*ptr) - - synproxy->tsoff); + old =get_unaligned_be32 (&op[2 ]); + new = old - synproxy->tsoff; +put_unaligned_be32 (new, &op[2 ]); }else { - ptr = (__be32 *)&op[6 ]; - old = *ptr; - *ptr =htonl (ntohl (*ptr) + - synproxy->tsoff); + old =get_unaligned_be32 (&op[6 ]); + new = old + synproxy->tsoff; +put_unaligned_be32 (new, &op[6 ]); }inet_proto_csum_replace4 (&th->check, skb, - old, *ptr, false); +cpu_to_be32 (old), +cpu_to_be32 (new), false); } optoff += op[1 ]; }
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1328/1887 EDAC/igen6: Fix call trace due to missing release()
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Qiuxu Zhuo <[email protected]>
[ Upstream commit ab1f9d466c7d83ab0d2a529e07984e53b5960dcd ]
When unloading the igen6_edac driver, there is a call trace:
Device '(null)' does not have a release() function, it is broken and must be fixed. See Documentation/core-api/kobject.rst.
WARNING: drivers/base/core.c:2567 at device_release+0x84/0x90, CPU#5: rmmod/127209 ... RIP: 0010:device_release+0x84/0x90 Call Trace: <TASK> kobject_put+0x8c/0x220 put_device+0x17/0x30 igen6_unregister_mcis+0xa2/0xe0 [igen6_edac] igen6_remove+0x82/0xb0 [igen6_edac] ...
Fix the call trace by providing empty release() functions for the memory controller devices.
--- drivers/edac/igen6_edac.c | 6 ++++++ 1 file changed, 6 insertions(+)
drivers/edac/igen6_edac.c +6 -0
@@ -1007,6 +1007,11 @@ static int igen6_pci_setup(struct pci_dev *pdev, u64 *mchbar)return -ENODEV ; } +static void imc_release (struct device *dev) +{ +/* Nothing to do, the 'imc' owns the 'dev' and will also release it. */ +} +static int igen6_register_mci (int mc,u64 mchbar,struct pci_dev *pdev) {struct edac_mc_layer layers[2 ];
@@ -1051,6 +1056,7 @@ static int igen6_register_mci(int mc, u64 mchbar, struct pci_dev *pdev) mci->pvt_info = &igen6_pvt->imc[mc]; imc = mci->pvt_info; + imc->dev.release = imc_release;device_initialize (&imc->dev);/* * EDAC core uses mci->pdev(pointer of structure device) as
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1329/1887 media: atomisp: gc2235: fix UAF and memory leak
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Yuho Choi <[email protected]>
[ Upstream commit 628f763aee0047ff44974388d6f70f75a763026b ]
gc2235_probe() handles its error paths incorrectly.
If media_entity_pads_init() fails, gc2235_remove() is called, which tears down the subdev and frees dev, but then still falls through to atomisp_register_i2c_module(). This results in use-after-free.
If atomisp_register_i2c_module() fails, the media entity and control handler are left initialized and dev is leaked.
gc2235_remove() unconditionally calls media_entity_cleanup() and v4l2_ctrl_handler_free(), but these are not initialized at every error path in gc2235_probe().
Replace gc2235_remove() calls in the probe error paths with explicit unwind labels that free only the resources initialized at each point of failure, in reverse order of initialization.
--- .../media/atomisp/i2c/atomisp-gc2235.c | 29 ++++++++++++------- 1 file changed, 18 insertions(+), 11 deletions(-)
drivers/staging/media/atomisp/i2c/atomisp-gc2235.c +18 -11
@@ -989,7 +989,7 @@ static int gc2235_probe(struct i2c_client *client) ret =gc2235_s_config (&dev->sd, client->irq, gcpdev);if (ret) - goto out_free; + goto err_unregister_subdev; dev->sd.flags |=V4L2_SUBDEV_FL_HAS_DEVNODE ; dev->pad.flags =MEDIA_PAD_FL_SOURCE ;
@@ -998,18 +998,16 @@ static int gc2235_probe(struct i2c_client *client) ret =v4l2_ctrl_handler_init (&dev->ctrl_handler,ARRAY_SIZE (gc2235_controls)); -if (ret) { -gc2235_remove (client); -return ret; - } +if (ret) + goto err_csi_cfg;for (i =0 ; i <ARRAY_SIZE (gc2235_controls); i++)v4l2_ctrl_new_custom (&dev->ctrl_handler, &gc2235_controls[i],NULL );if (dev->ctrl_handler.error) { -gc2235_remove (client); -return dev->ctrl_handler.error; + ret = dev->ctrl_handler.error; + goto err_ctrl_handler; }/* Use same lock for controls as for everything else. */
@@ -1018,14 +1016,23 @@ static int gc2235_probe(struct i2c_client *client) ret =media_entity_pads_init (&dev->sd.entity,1 , &dev->pad);if (ret) -gc2235_remove (client); + goto err_ctrl_handler; + + ret =atomisp_register_i2c_module (&dev->sd, gcpdev,RAW_CAMERA ); +if (ret) + goto err_media_cleanup; -return atomisp_register_i2c_module (&dev->sd, gcpdev,RAW_CAMERA ); +return 0 ; -out_free: +err_media_cleanup: +media_entity_cleanup (&dev->sd.entity); +err_ctrl_handler: +v4l2_ctrl_handler_free (&dev->ctrl_handler); +err_csi_cfg: + dev->platform_data->csi_cfg (&dev->sd,0 ); +err_unregister_subdev:v4l2_device_unregister_subdev (&dev->sd);kfree (dev); -return ret; }
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1330/1887 scsi: hisi_sas: Add slave_destroy interface for v3 hw
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Yihang Li <[email protected]>
[ Upstream commit 67b85a88265df19f049241d8c00571a5408f4eeb ]
WARNING is triggered when executing link reset of remote PHY and rmmod SAS driver simultaneously. Following is the WARNING log:
WARNING: CPU: 61 PID: 21818 at drivers/base/core.c:1347 __device_links_no_driver+0xb4/0xc0 Call trace: __device_links_no_driver+0xb4/0xc0 device_links_driver_cleanup+0xb0/0xfc __device_release_driver+0x198/0x23c device_release_driver+0x38/0x50 bus_remove_device+0x130/0x140 device_del+0x184/0x434 __scsi_remove_device+0x118/0x150 scsi_remove_target+0x1bc/0x240 sas_rphy_remove+0x90/0x94 sas_rphy_delete+0x24/0x3c sas_destruct_devices+0x64/0xa0 [libsas] sas_revalidate_domain+0xe4/0x150 [libsas] process_one_work+0x1e0/0x46c worker_thread+0x15c/0x464 kthread+0x160/0x170 ret_from_fork+0x10/0x20 ---[ end trace 71e059eb58f85d4a ]---
During SAS phy up, link->status is set to DL_STATE_AVAILABLE in device_links_driver_bound, then this setting influences __device_links_no_driver() before driver rmmod and caused WARNING.
Add the slave_destroy interface to make sure link is removed after flush workque.
--- drivers/scsi/hisi_sas/hisi_sas_v3_hw.c | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-)
drivers/scsi/hisi_sas/hisi_sas_v3_hw.c +11 -1
@@ -2860,7 +2860,7 @@ static int slave_configure_v3_hw(struct scsi_device *sdev)return 0 ;if (!device_link_add (&sdev->sdev_gendev, dev, -DL_FLAG_PM_RUNTIME |DL_FLAG_RPM_ACTIVE )) { +DL_FLAG_STATELESS |DL_FLAG_PM_RUNTIME |DL_FLAG_RPM_ACTIVE )) {if (pm_runtime_enabled (dev)) {dev_info (dev,"add device link failed, disable runtime PM for the host\n" );pm_runtime_disable (dev);
@@ -2870,6 +2870,15 @@ static int slave_configure_v3_hw(struct scsi_device *sdev)return 0 ; } +static void hisi_sas_sdev_destroy (struct scsi_device *sdev) +{ +struct Scsi_Host *shost =dev_to_shost (&sdev->sdev_gendev); +struct hisi_hba *hisi_hba =shost_priv (shost); +struct device *dev = hisi_hba->dev; + +device_link_remove (&sdev->sdev_gendev, dev); +} +static struct attribute *host_v3_hw_attrs[] = { &dev_attr_phy_event_threshold.attr, &dev_attr_intr_conv_v3_hw.attr,
@@ -3258,6 +3267,7 @@ static struct scsi_host_template sht_v3_hw = { .eh_device_reset_handler = sas_eh_device_reset_handler, .eh_target_reset_handler = sas_eh_target_reset_handler, .slave_alloc = hisi_sas_slave_alloc, + .slave_destroy = hisi_sas_sdev_destroy, .target_destroy = sas_target_destroy, .ioctl = sas_ioctl,#ifdef CONFIG_COMPAT
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1331/1887 soc/xilinx: zynqmp_power: Convert to platform remove callback returning void
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Uwe Kleine-König <[email protected]>
[ Upstream commit f1013d8405af0f4fe1812b5901cbac9ce4d1fb6f ]
The .remove() callback for a platform driver returns an int which makes many driver authors wrongly assume it's possible to do error handling by returning an error code. However the value returned is ignored (apart from emitting a warning) and this typically results in resource leaks. To improve here there is a quest to make the remove callback return void. In the first step of this quest all drivers are converted to .remove_new() which already returns void. Eventually after all drivers are converted, .remove_new() will be renamed to .remove().
Trivially convert this driver from always returning zero in the remove callback to the void returning variant.
Stable-dep-of: fdee7c66c0d7 ("soc: xilinx: Shutdown and free rx mailbox channel")
--- drivers/soc/xilinx/zynqmp_power.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-)
drivers/soc/xilinx/zynqmp_power.c +2 -4
@@ -276,7 +276,7 @@ static int zynqmp_pm_probe(struct platform_device *pdev)return 0 ; } -static int zynqmp_pm_remove (struct platform_device *pdev) +static void zynqmp_pm_remove (struct platform_device *pdev) {sysfs_remove_file (&pdev->dev.kobj, &dev_attr_suspend_mode.attr);if (event_registered)
@@ -284,8 +284,6 @@ static int zynqmp_pm_remove(struct platform_device *pdev)if (!rx_chan)mbox_free_channel (rx_chan); - -return 0 ; }static const struct of_device_id pm_of_match[] = {
@@ -296,7 +294,7 @@ MODULE_DEVICE_TABLE(of, pm_of_match);static struct platform_driver zynqmp_pm_platform_driver = { .probe = zynqmp_pm_probe, - .remove = zynqmp_pm_remove, + .remove_new = zynqmp_pm_remove, .driver = { .name ="zynqmp_power" , .of_match_table = pm_of_match,
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1332/1887 soc: xilinx: Shutdown and free rx mailbox channel
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Prasanna Kumar T S M <[email protected]>
[ Upstream commit fdee7c66c0d7b6869c36b9f9a915abf29ab5b550 ]
A mbox rx channel is requested using mbox_request_channel_byname() in probe. In remove callback, the rx mailbox channel is cleaned up when the rx_chan is NULL due to incorrect condition check. The mailbox channel is not shutdown and it can receive messages even after the device removal. This leads to use after free. Also the channel resources are not freed. Fix this by checking the rx_chan correctly.
--- drivers/soc/xilinx/zynqmp_power.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-)
drivers/soc/xilinx/zynqmp_power.c +3 -1
@@ -282,8 +282,10 @@ static void zynqmp_pm_remove(struct platform_device *pdev)if (event_registered)xlnx_unregister_event (PM_INIT_SUSPEND_CB ,0 ,0 , suspend_event_callback,NULL ); -if (!rx_chan) +if (rx_chan) {mbox_free_channel (rx_chan); + rx_chan =NULL ; + } }static const struct of_device_id pm_of_match[] = {
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1333/1887 netfilter: nf_conntrack_expect: use conntrack GC to reap expectations
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Pablo Neira Ayuso <[email protected]>
[ Upstream commit b8b09dc2bf35a00d4e0556b5d6308c7b917ebda2 ]
This patch replaces the timer API by GC worker approach for expectations, as it already happened in many other subsystems.
Use the existing conntrack GC worker to iterate over the local list of expectations in the master conntrack to reap expired expectations. Check IPS_HELPER_BIT to run GC for expectations, set it on for nft_ct expectation which nevers sets it. Hold the expectation spinlock while iterating over the master conntrack expectation list to synchronize with nf_ct_remove_expectations(). This also performs runtime packet path garbage collection through the expectation insertion and lookup functions while walking over one of the chains of the global expectation hashtables. Unconfirmed conntrack entries are skipped since ct->ext can be reallocated and dying are skipped since those will be gone soon. Set on IPS_HELPER_BIT if the helper ct extension is added, then the new GC worker does not need to bump the ct refcount to check if the ct->ext helper is available.
This removes the extra bump on the refcount for expectation timers, this allows to remove several nf_ct_expect_put() calls after the unlink, after this update only refcount remains at 1 while on the expectation hashes.
This patch implicitly addresses a race with the existing timer API allowing an expectation to access a stale exp->master pointer which has been already released when expectation removal loses races with an expiring timer, ie. timer_del() reporting false.
Add a new NF_CT_EXPECT_DEAD flag to reap this expectation via GC. This is needed by nf_conntrack_unexpect_related() which is called in error paths to invalidate newly created expectations that has been added into the hashes. These expectactions cannot be inmediately released as GC or nf_ct_remove_expectations() could race to make it. On expectation insert, the runtime GC reaps stale expectations before checking the expectation limit set by policy.
Set current timestamp in nf_ct_expect_alloc(), then add the expectation policy timeout (or custom timeout specified added on top of this) to specify the expectation lifetime.
--- include/net/netfilter/nf_conntrack_expect.h | 16 +- .../linux/netfilter/nf_conntrack_common.h | 1 + net/netfilter/nf_conntrack_core.c | 33 +++- net/netfilter/nf_conntrack_expect.c | 148 +++++++++--------- net/netfilter/nf_conntrack_h323_main.c | 4 +- net/netfilter/nf_conntrack_helper.c | 10 +- net/netfilter/nf_conntrack_netlink.c | 22 ++- net/netfilter/nf_conntrack_sip.c | 13 +- net/netfilter/nft_ct.c | 3 +- 9 files changed, 140 insertions(+), 110 deletions(-)
include/net/netfilter/nf_conntrack_expect.h +13 -3
@@ -54,8 +54,8 @@ struct nf_conntrack_expect {/* The conntrack of the master connection */ struct nf_conn *master; -/* Timer function; deletes the expectation. */ -struct timer_list timeout; +/* jiffies32 when this expectation expires */ +u32 timeout;#if IS_ENABLED (CONFIG_NF_NAT )union nf_inet_addr saved_addr;
@@ -69,6 +69,14 @@ struct nf_conntrack_expect {struct rcu_head rcu; }; +static inline bool nf_ct_exp_is_expired (const struct nf_conntrack_expect *exp) +{ +if (READ_ONCE (exp->flags) &NF_CT_EXPECT_DEAD ) +return true; + +return (__s32)(READ_ONCE (exp->timeout) - nfct_time_stamp) <=0 ; +} +static inline struct net *nf_ct_exp_net (struct nf_conntrack_expect *exp) {return read_pnet (&exp->net);
@@ -130,7 +138,6 @@ static inline void nf_ct_unlink_expect(struct nf_conntrack_expect *exp)void nf_ct_remove_expectations (struct nf_conn *ct);void nf_ct_unexpect_related (struct nf_conntrack_expect *exp); -bool nf_ct_remove_expect (struct nf_conntrack_expect *exp);void nf_ct_expect_iterate_destroy (bool (*iter)(struct nf_conntrack_expect *e,void *data),void *data); void nf_ct_expect_iterate_net(struct net *net,
@@ -153,5 +160,8 @@ static inline int nf_ct_expect_related(struct nf_conntrack_expect *expect, return nf_ct_expect_related_report(expect, 0, 0, flags); } +struct nf_conn_help ; +void nf_ct_expectation_gc (struct nf_conn_help *master_help); +#endif /*_NF_CONNTRACK_EXPECT_H*/
include/uapi/linux/netfilter/nf_conntrack_common.h +1 -0
@@ -160,6 +160,7 @@ enum ip_conntrack_expect_events {#define NF_CT_EXPECT_USERSPACE 0x4#ifdef __KERNEL__ +#define NF_CT_EXPECT_DEAD 0x8#define NF_CT_EXPECT_MASK (NF_CT_EXPECT_PERMANENT | NF_CT_EXPECT_INACTIVE | \ NF_CT_EXPECT_USERSPACE)#endif
net/netfilter/nf_conntrack_core.c +32 -1
@@ -1493,6 +1493,31 @@ static bool gc_worker_can_early_drop(const struct nf_conn *ct)return false; } +static void nf_ct_help_gc (struct nf_conn *ct) +{ +struct nf_conn_help *help; + +if (!refcount_inc_not_zero (&ct->ct_general.use)) +return ; + +/* load ->status after refcount increase */ +smp_acquire__after_ctrl_dep (); + +if (!nf_ct_is_confirmed (ct) ||nf_ct_is_dying (ct)) { +nf_ct_put (ct); +return ; + } + +/* re-check helper due to SLAB_TYPESAFE_BY_RCU */ +if (test_bit (IPS_HELPER_BIT , &ct->status)) { + help =nfct_help (ct); +if (help) +nf_ct_expectation_gc (help); + } + +nf_ct_put (ct); +} +static void gc_worker (struct work_struct *work) {unsigned int i, hashsz, nf_conntrack_max95 =0 ;
@@ -1570,7 +1595,13 @@ static void gc_worker(struct work_struct *work) expires = (expires - (long )next_run) / ++count; next_run += expires; -if (nf_conntrack_max95 ==0 ||gc_worker_skip_ct (tmp)) +if (gc_worker_skip_ct (tmp)) +continue ; + +if (test_bit (IPS_HELPER_BIT , &tmp->status)) +nf_ct_help_gc (tmp); + +if (nf_conntrack_max95 ==0 )continue ; net =nf_ct_net (tmp);
net/netfilter/nf_conntrack_expect.c +73 -75
295 lines not on this page · raw message
net/netfilter/nf_conntrack_h323_main.c +2 -2
@@ -1396,8 +1396,8 @@ static int process_rcf(struct sk_buff *skb, struct nf_conn *ct,"timeout to %u seconds for" , info->timeout);nf_ct_dump_tuple (&exp->tuple); -mod_timer_pending (&exp->timeout, - jiffies + info->timeout *HZ ); +WRITE_ONCE (exp->timeout, + nfct_time_stamp + (info->timeout *HZ )); }spin_unlock_bh (&nf_conntrack_expect_lock); }
net/netfilter/nf_conntrack_helper.c +4 -6
@@ -178,10 +178,10 @@ nf_ct_helper_ext_add(struct nf_conn *ct, gfp_t gfp)struct nf_conn_help *help; help =nf_ct_ext_add (ct,NF_CT_EXT_HELPER , gfp); -if (help) +if (help) { +__set_bit (IPS_HELPER_BIT , &ct->status);INIT_HLIST_HEAD (&help->expectations); -else -pr_debug ("failed to add helper extension area" ); + }return help; }EXPORT_SYMBOL_GPL (nf_ct_helper_ext_add);
@@ -205,10 +205,8 @@ int __nf_ct_try_assign_helper(struct nf_conn *ct, struct nf_conn *tmpl,return 0 ; help =nfct_help (tmpl); -if (help !=NULL ) { +if (help) helper =rcu_dereference (help->helper); -set_bit (IPS_HELPER_BIT , &ct->status); - } help =nfct_help (ct);
net/netfilter/nf_conntrack_netlink.c +9 -13
@@ -2999,8 +2999,8 @@ static int ctnetlink_exp_dump_expect(struct sk_buff *skb, const struct nf_conntrack_expect *exp) { + __s32 timeout = (__s32)(READ_ONCE(exp->timeout) - nfct_time_stamp) / HZ;struct nf_conn *master = exp->master; -long timeout = ((long )exp->timeout.expires - (long )jiffies) /HZ ;struct nf_conntrack_helper *helper;#if IS_ENABLED (CONFIG_NF_NAT )struct nlattr *nest_parms;
@@ -3163,6 +3163,9 @@ ctnetlink_exp_dump_table(struct sk_buff *skb, struct netlink_callback *cb) restart:hlist_for_each_entry_rcu (exp, &nf_ct_expect_hash[cb->args[0 ]], hnode) { +if (nf_ct_exp_is_expired (exp)) +continue ; +if (l3proto && exp->tuple.src.l3num != l3proto)continue ;
@@ -3442,11 +3445,8 @@ static int ctnetlink_del_expect(struct sk_buff *skb, }/* after list removal, usage count == 1 */ -if (del_timer (&exp->timeout)) { -nf_ct_unlink_expect_report (exp,NETLINK_CB (skb).portid, -nlmsg_report (info->nlh)); -nf_ct_expect_put (exp); - } +nf_ct_unlink_expect_report (exp,NETLINK_CB (skb).portid, +nlmsg_report (info->nlh));spin_unlock_bh (&nf_conntrack_expect_lock);/* have to put what we 'get' above. * after this line usage count == 0 */
@@ -3470,14 +3470,10 @@ static int ctnetlink_change_expect(struct nf_conntrack_expect *x, const struct nlattr * const cda[]) { - if (cda[CTA_EXPECT_TIMEOUT]) { - if (!del_timer(&x->timeout)) - return -ETIME; + if (cda[CTA_EXPECT_TIMEOUT]) + WRITE_ONCE(x->timeout, nfct_time_stamp + + ntohl(nla_get_be32(cda[CTA_EXPECT_TIMEOUT])) * HZ); - x->timeout.expires = jiffies + -ntohl (nla_get_be32 (cda[CTA_EXPECT_TIMEOUT ])) *HZ ; -add_timer (&x->timeout); - }return 0 ; }
net/netfilter/nf_conntrack_sip.c +5 -8
@@ -894,11 +894,10 @@ static int refresh_signalling_expectation(struct nf_conn *ct, exp->tuple.dst.protonum != proto || exp->tuple.dst.u.udp.port != port) continue; -if (mod_timer_pending (&exp->timeout, jiffies + expires *HZ )) { - exp->flags &= ~NF_CT_EXPECT_INACTIVE ; - found =1 ; -break ; - } +WRITE_ONCE (exp->timeout, nfct_time_stamp + (expires *HZ )); +WRITE_ONCE (exp->flags, exp->flags & ~NF_CT_EXPECT_INACTIVE ); + found =1 ; +break ; }spin_unlock_bh (&nf_conntrack_expect_lock);return found;
@@ -914,8 +913,7 @@ static void flush_expectations(struct nf_conn *ct, bool media)hlist_for_each_entry_safe (exp, next, &help->expectations, lnode) {if ((exp->class !=SIP_EXPECT_SIGNALLING ) ^ media)continue ; -if (!nf_ct_remove_expect (exp)) -continue ; +nf_ct_unlink_expect (exp);if (!media)break ; }
@@ -1385,7 +1383,6 @@ static int process_register_request(struct sk_buff *skb, unsigned int protoff,nf_ct_expect_init (exp,SIP_EXPECT_SIGNALLING ,nf_ct_l3num (ct), saddr, &daddr, proto,NULL , &port); - exp->timeout.expires = sip_timeout *HZ ;rcu_assign_pointer (exp->assign_helper, helper); exp->flags =NF_CT_EXPECT_PERMANENT |NF_CT_EXPECT_INACTIVE ;
net/netfilter/nft_ct.c +1 -2
@@ -1159,7 +1159,6 @@ static void nft_ct_helper_obj_eval(struct nft_object *obj, help =nf_ct_helper_ext_add (ct,GFP_ATOMIC );if (help) {rcu_assign_pointer (help->helper, to_assign); -set_bit (IPS_HELPER_BIT , &ct->status);if ((ct->status &IPS_NAT_MASK ) && !nfct_seqadj (ct))if (!nfct_seqadj_ext_add (ct))
@@ -1341,7 +1340,7 @@ static void nft_ct_expect_obj_eval(struct nft_object *obj, &ct->tuplehash[!dir].tuple.src.u3, &ct->tuplehash[!dir].tuple.dst.u3, priv->l4proto, NULL, &priv->dport); - exp->timeout.expires = jiffies + priv->timeout *HZ ; + exp->timeout += priv->timeout *HZ ;if (nf_ct_expect_related (exp,0 ) !=0 ) regs->verdict.code =NF_DROP ;
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1334/1887 net: ethernet: mtk_eth_soc: pass eth to mtk_handle_irq_rx in poll_controller
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Chenguang Zhao <[email protected]>
[ Upstream commit e095f249e2209674f6366f6db0383a2b96e19239 ]
mtk_handle_irq_rx expects a struct mtk_eth * (matching the request_irq cookie), but mtk_poll_controller incorrectly passed the net_device *. Calling ndo_poll_controller with CONFIG_NET_POLL_CONTROLLER enabled would then crash.
--- drivers/net/ethernet/mediatek/mtk_eth_soc.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
drivers/net/ethernet/mediatek/mtk_eth_soc.c +1 -1
@@ -2916,7 +2916,7 @@ static void mtk_poll_controller(struct net_device *dev)mtk_tx_irq_disable (eth,MTK_TX_DONE_INT );mtk_rx_irq_disable (eth, eth->soc->txrx.rx_irq_done_mask); -mtk_handle_irq_rx (eth->irq[2 ], dev); +mtk_handle_irq_rx (eth->irq[2 ], eth);mtk_tx_irq_enable (eth,MTK_TX_DONE_INT );mtk_rx_irq_enable (eth, eth->soc->txrx.rx_irq_done_mask); }
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1335/1887 hwmon: (sht3x) Fix unaligned accesses
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Guenter Roeck <[email protected]>
[ Upstream commit f46d5ab43a572b84773015a76966f5da56fc1748 ]
Sashiko reports:
In sht3x_update_client(), the 16-bit temperature and humidity values are extracted from a stack-allocated byte array using be16_to_cpup(). The pointers passed to this function are calculated as buf and buf + 3. Since the difference between the two pointers is an odd number of bytes, at least one of them is guaranteed to be at an unaligned offset.
This will trigger an alignment fault on strict-alignment architectures such as ARMv5 or SPARC, resulting in a kernel panic.
Fix the problem by using get_unaligned_be16() instead of be16_to_cpup(), and put_unaligned_be16() instead of cpu_to_be16().
--- drivers/hwmon/sht3x.c | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-)
drivers/hwmon/sht3x.c +5 -4
@@ -21,6 +21,7 @@#include <linux/slab.h> #include <linux/jiffies.h> #include <linux/platform_data/sht3x.h> +#include <asm/unaligned.h> /* commands (high precision mode) */ static const unsigned char sht3x_cmd_measure_blocking_hpm[] = {0x2c ,0x06 };
@@ -241,9 +242,9 @@ static struct sht3x_data *sht3x_update_client(struct device *dev)if (ret) goto out; - val =be16_to_cpup ((__be16 *)buf); + val =get_unaligned_be16 (buf); data->temperature =sht3x_extract_temperature (val); - val =be16_to_cpup ((__be16 *)(buf +3 )); + val =get_unaligned_be16 (buf +3 ); data->humidity =sht3x_extract_humidity (val); data->last_update = jiffies; }
@@ -302,7 +303,7 @@ static int limits_update(struct sht3x_data *data)if (ret)return ret; - raw =be16_to_cpup ((__be16 *)buffer); + raw =get_unaligned_be16 (buffer); temperature =sht3x_extract_temperature ((raw &0x01ff ) <<7 ); humidity =sht3x_extract_humidity (raw &0xfe00 ); data->temperature_limits[index] = temperature;
@@ -364,7 +365,7 @@ static size_t limit_store(struct device *dev, raw = ((u32)(temperature +45000 ) *24543 ) >> (16 +7 ); raw |= ((humidity *42950 ) >>16 ) &0xfe00 ; - *((__be16 *)position) =cpu_to_be16 (raw); +put_unaligned_be16 (raw, position); position +=SHT3X_WORD_LEN ; *position = crc8(sht3x_crc8_table, position - SHT3X_WORD_LEN,
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1336/1887 dmaengine: idxd: fix double free of wq, engine, and group structs
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Yuho Choi <[email protected]>
[ Upstream commit ec2d428b2e32dd157de8f86a86dd85c5b2c8f45c ]
The release callbacks for wq, engine, and group devices (idxd_conf_wq_release, idxd_conf_engine_release, idxd_conf_group_release) each call kfree() on the enclosing struct. The setup error paths and cleanup functions also call kfree() explicitly after put_device(), producing a double free whenever put_device() drops the reference count to zero and fires the release.
In the setup functions, device_initialize() is called before device_add(), so the reference count is exactly 1 at the error sites. put_device() unconditionally fires the release, which frees the struct; the subsequent explicit kfree() then operates on freed memory.
For idxd_setup_wqs(), the wq release callback also owns opcap_bmap and wqcfg. The error unwind additionally freed those fields explicitly before calling put_device(), causing further double frees on both.
Remove the redundant explicit kfree() calls from all setup error paths and cleanup functions for wq, engine, and group structs, delegating sole ownership of those allocations to the release callbacks.
--- drivers/dma/idxd/init.c | 36 +++++------------------------------- 1 file changed, 5 insertions(+), 31 deletions(-)
drivers/dma/idxd/init.c +5 -31
@@ -143,18 +143,12 @@ static void idxd_cleanup_interrupts(struct idxd_device *idxd)static void idxd_clean_wqs (struct idxd_device *idxd) { -struct idxd_wq *wq;struct device *conf_dev;int i;for (i =0 ; i < idxd->max_wqs; i++) { - wq = idxd->wqs[i]; -if (idxd->hw.wq_cap.op_config) -bitmap_free (wq->opcap_bmap); -kfree (wq->wqcfg); - conf_dev =wq_confdev (wq); + conf_dev =wq_confdev (idxd->wqs[i]);put_device (conf_dev); -kfree (wq); }bitmap_free (idxd->wq_enable_map);kfree (idxd->wqs);
@@ -196,7 +190,6 @@ static int idxd_setup_wqs(struct idxd_device *idxd) rc =dev_set_name (conf_dev,"wq%d.%d" , idxd->id, wq->id);if (rc <0 ) {put_device (conf_dev); -kfree (wq); goto err_unwind; }
@@ -210,7 +203,6 @@ static int idxd_setup_wqs(struct idxd_device *idxd) wq->wqcfg =kzalloc_node (idxd->wqcfg_size,GFP_KERNEL ,dev_to_node (dev));if (!wq->wqcfg) {put_device (conf_dev); -kfree (wq); rc = -ENOMEM ; goto err_unwind; }
@@ -218,9 +210,7 @@ static int idxd_setup_wqs(struct idxd_device *idxd)if (idxd->hw.wq_cap.op_config) { wq->opcap_bmap =bitmap_zalloc (IDXD_MAX_OPCAP_BITS ,GFP_KERNEL );if (!wq->opcap_bmap) { -kfree (wq->wqcfg);put_device (conf_dev); -kfree (wq); rc = -ENOMEM ; goto err_unwind; }
@@ -235,13 +225,8 @@ static int idxd_setup_wqs(struct idxd_device *idxd) err_unwind:while (--i >=0 ) { - wq = idxd->wqs[i]; -if (idxd->hw.wq_cap.op_config) -bitmap_free (wq->opcap_bmap); -kfree (wq->wqcfg); - conf_dev =wq_confdev (wq); + conf_dev =wq_confdev (idxd->wqs[i]);put_device (conf_dev); -kfree (wq); }bitmap_free (idxd->wq_enable_map);
@@ -253,15 +238,12 @@ static int idxd_setup_wqs(struct idxd_device *idxd)static void idxd_clean_engines (struct idxd_device *idxd) { -struct idxd_engine *engine;struct device *conf_dev;int i;for (i =0 ; i < idxd->max_engines; i++) { - engine = idxd->engines[i]; - conf_dev =engine_confdev (engine); + conf_dev =engine_confdev (idxd->engines[i]);put_device (conf_dev); -kfree (engine); }kfree (idxd->engines); }
@@ -296,7 +278,6 @@ static int idxd_setup_engines(struct idxd_device *idxd) rc =dev_set_name (conf_dev,"engine%d.%d" , idxd->id, engine->id);if (rc <0 ) {put_device (conf_dev); -kfree (engine); goto err; }
@@ -307,10 +288,8 @@ static int idxd_setup_engines(struct idxd_device *idxd) err:while (--i >=0 ) { - engine = idxd->engines[i]; - conf_dev =engine_confdev (engine); + conf_dev =engine_confdev (idxd->engines[i]);put_device (conf_dev); -kfree (engine); }kfree (idxd->engines);
@@ -319,13 +298,10 @@ static int idxd_setup_engines(struct idxd_device *idxd)static void idxd_clean_groups (struct idxd_device *idxd) { -struct idxd_group *group;int i;for (i =0 ; i < idxd->max_groups; i++) { - group = idxd->groups[i]; -put_device (group_confdev (group)); -kfree (group); +put_device (group_confdev (idxd->groups[i])); }kfree (idxd->groups); }
@@ -360,7 +336,6 @@ static int idxd_setup_groups(struct idxd_device *idxd) rc =dev_set_name (conf_dev,"group%d.%d" , idxd->id, group->id);if (rc <0 ) {put_device (conf_dev); -kfree (group); goto err; }
@@ -380,7 +355,6 @@ static int idxd_setup_groups(struct idxd_device *idxd)while (--i >=0 ) { group = idxd->groups[i];put_device (group_confdev (group)); -kfree (group); }kfree (idxd->groups);
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1337/1887 s390/appldata: remove power management callbacks
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Heiko Carstens <[email protected]>
[ Upstream commit 78c045c08a393285e615260c50cedf9cea5a7fa1 ]
Support for power managemant has been removed from s390 since quite some time. Therefore remove unused power managemant code from the appldata device driver.
Stable-dep-of: 7f40b346462f ("s390/dasd: Fix undersized format-check buffer")
--- arch/s390/appldata/appldata_base.c | 113 +---------------------------- 1 file changed, 2 insertions(+), 111 deletions(-)
arch/s390/appldata/appldata_base.c +2 -111
@@ -26,8 +26,6 @@#include <linux/notifier.h> #include <linux/cpu.h> #include <linux/workqueue.h> -#include <linux/suspend.h> -#include <linux/platform_device.h> #include <asm/appldata.h> #include <asm/vtimer.h> #include <linux/uaccess.h>
@@ -44,8 +42,6 @@#define TOD_MICRO 0x01000/* nr. of TOD clock units for 1 microsecond */ -static struct platform_device *appldata_pdev; -/* * /proc entries (sysctl) */
@@ -88,7 +84,6 @@ static struct vtimer_list appldata_timer;static DEFINE_SPINLOCK (appldata_timer_lock);static int appldata_interval =APPLDATA_CPU_INTERVAL ;static int appldata_timer_active; -static int appldata_timer_suspended =0 ;/* * Work queue
@@ -412,88 +407,6 @@ void appldata_unregister_ops(struct appldata_ops *ops)/********************** module-ops management <END> **************************/ -/**************************** suspend / resume *******************************/ -static int appldata_freeze (struct device *dev) -{ -struct appldata_ops *ops; -int rc; -struct list_head *lh; - -spin_lock (&appldata_timer_lock); -if (appldata_timer_active) { -__appldata_vtimer_setup (APPLDATA_DEL_TIMER ); - appldata_timer_suspended =1 ; - } -spin_unlock (&appldata_timer_lock); - -mutex_lock (&appldata_ops_mutex); -list_for_each (lh, &appldata_ops_list) { - ops = list_entry(lh, struct appldata_ops, list); -if (ops->active ==1 ) { - rc =appldata_diag (ops->record_nr,APPLDATA_STOP_REC , - (unsigned long ) ops->data, ops->size, - ops->mod_lvl); -if (rc !=0 ) -pr_err ("Stopping the data collection for %s " -"failed with rc=%d\n" , ops->name, rc); - } - } -mutex_unlock (&appldata_ops_mutex); -return 0 ; -} - -static int appldata_restore (struct device *dev) -{ -struct appldata_ops *ops; -int rc; -struct list_head *lh; - -spin_lock (&appldata_timer_lock); -if (appldata_timer_suspended) { -__appldata_vtimer_setup (APPLDATA_ADD_TIMER ); - appldata_timer_suspended =0 ; - } -spin_unlock (&appldata_timer_lock); - -mutex_lock (&appldata_ops_mutex); -list_for_each (lh, &appldata_ops_list) { - ops = list_entry(lh, struct appldata_ops, list); -if (ops->active ==1 ) { - ops->callback (ops->data);// init record - rc =appldata_diag (ops->record_nr, -APPLDATA_START_INTERVAL_REC , - (unsigned long ) ops->data, ops->size, - ops->mod_lvl); -if (rc !=0 ) { -pr_err ("Starting the data collection for %s " -"failed with rc=%d\n" , ops->name, rc); - } - } - } -mutex_unlock (&appldata_ops_mutex); -return 0 ; -} - -static int appldata_thaw (struct device *dev) -{ -return appldata_restore (dev); -} - -static const struct dev_pm_ops appldata_pm_ops = { - .freeze = appldata_freeze, - .thaw = appldata_thaw, - .restore = appldata_restore, -}; - -static struct platform_driver appldata_pdrv = { - .driver = { - .name ="appldata" , - .pm = &appldata_pm_ops, - }, -}; -/************************* suspend / resume <END> ****************************/ - -/******************************* init / exit *********************************/ /*
@@ -503,36 +416,14 @@ static struct platform_driver appldata_pdrv = {*/ static int __init appldata_init (void ) { -int rc; -init_virt_timer (&appldata_timer); appldata_timer.function = appldata_timer_function; appldata_timer.data = (unsigned long ) &appldata_work; - - rc =platform_driver_register (&appldata_pdrv); -if (rc) -return rc; - - appldata_pdev =platform_device_register_simple ("appldata" ,-1 ,NULL , -0 ); -if (IS_ERR (appldata_pdev)) { - rc =PTR_ERR (appldata_pdev); - goto out_driver; - } appldata_wq =alloc_ordered_workqueue ("appldata" ,0 ); -if (!appldata_wq) { - rc = -ENOMEM ; - goto out_device; - } - +if (!appldata_wq) +return -ENOMEM ; appldata_sysctl_header =register_sysctl_table (appldata_dir_table);return 0 ; - -out_device: -platform_device_unregister (appldata_pdev); -out_driver: -platform_driver_unregister (&appldata_pdrv); -return rc; }__initcall (appldata_init);
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1338/1887 s390/cpum_sf: move functions from header file to source file
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Thomas Richter <[email protected]>
[ Upstream commit a64e45c2ea62d9622bcebb586f359ea95f0a5152 ]
Some inline helper functions are defined in a header file but used in only one source file. Move these functions to the source file. No functional change.
Stable-dep-of: 7f40b346462f ("s390/dasd: Fix undersized format-check buffer")
--- arch/s390/include/asm/cpu_mf.h | 53 --------------------------------- arch/s390/kernel/perf_cpum_sf.c | 52 ++++++++++++++++++++++++++++++++ 2 files changed, 52 insertions(+), 53 deletions(-)
arch/s390/include/asm/cpu_mf.h +0 -53
@@ -42,7 +42,6 @@ static inline int cpum_sf_avail(void)return test_facility (40 ) &&test_facility (68 ); } -struct cpumf_ctr_info {u16 cfvn;u16 auth_ctl;
@@ -275,56 +274,4 @@ static inline int lsctl(struct hws_lsctl_request_block *req) return cc ? -EINVAL : 0; } - -/* Sampling control helper functions */ - -#include <linux/time.h> - -static inline unsigned long freq_to_sample_rate (struct hws_qsi_info_block *qsi, -unsigned long freq) -{ -return (USEC_PER_SEC / freq) * qsi->cpu_speed; -} - -static inline unsigned long sample_rate_to_freq (struct hws_qsi_info_block *qsi, -unsigned long rate) -{ -return USEC_PER_SEC * qsi->cpu_speed / rate; -} - -/* Return TOD timestamp contained in an trailer entry */ -static inline unsigned long long trailer_timestamp (struct hws_trailer_entry *te) -{ -/* TOD in STCKE format */ -if (te->header.t) -return *((unsigned long long *) &te->timestamp[1 ]); - -/* TOD in STCK format */ -return *((unsigned long long *) &te->timestamp[0 ]); -} - -/* Return pointer to trailer entry of an sample data block */ -static inline unsigned long *trailer_entry_ptr (unsigned long v) -{ -void *ret; - - ret = (void *) v; - ret +=PAGE_SIZE ; - ret -=sizeof (struct hws_trailer_entry ); - -return (unsigned long *) ret; -} - -/* Return true if the entry in the sample data block table (sdbt) -* is a link to the next sdbt */ -static inline int is_link_entry (unsigned long *s) -{ -return *s &0x1ul ?1 :0 ; -} - -/* Return pointer to the linked sdbt */ -static inline unsigned long *get_next_sdbt (unsigned long *s) -{ -return (unsigned long *) (*s & ~0x1ul ); -}#endif /* _ASM_S390_CPU_MF_H */
arch/s390/kernel/perf_cpum_sf.c +52 -0
64 lines not on this page · raw message
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1339/1887 s390/mm: do not include <asm-generic/io.h> directly
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Baoquan He <[email protected]>
[ Upstream commit 51f513fd9659faf00976071a9525474b08764ccb ]
We should always include <asm/io.h> in ARCH, but not <asm-generic/io.h> directly. Otherwise, macro defined by ARCH won't be seen and could cause building error.
Stable-dep-of: 7f40b346462f ("s390/dasd: Fix undersized format-check buffer")
--- arch/s390/kernel/perf_cpum_sf.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
arch/s390/kernel/perf_cpum_sf.c +1 -1
@@ -22,7 +22,7 @@#include <asm/irq.h> #include <asm/debug.h> #include <asm/timex.h> -#include <asm-generic/io.h> +#include <asm/io.h> /* Minimum number of sample-data-block-tables: * At least one table is required for the sampling buffer structure.
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1340/1887 s390: include linux/io.h instead of asm/io.h
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Heiko Carstens <[email protected]>
[ Upstream commit b378a982614360686f45c3e6b63fd5d1acd02d08 ]
Include linux/io.h instead of asm/io.h everywhere. linux/io.h includes asm/io.h, so this shouldn't cause any problems. Instead this might help for some randconfig build errors which were reported due to some undefined io related functions.
Also move the changed include so it stays grouped together with other includes from the same directory.
For ctcm_mpc.c also remove not needed comments (actually questions).
Stable-dep-of: 7f40b346462f ("s390/dasd: Fix undersized format-check buffer")
--- arch/s390/appldata/appldata_base.c | 4 ++-- arch/s390/appldata/appldata_mem.c | 2 +- arch/s390/include/asm/appldata.h | 2 +- arch/s390/include/asm/dma.h | 2 +- arch/s390/kernel/cpcmd.c | 2 +- arch/s390/kernel/dis.c | 2 +- arch/s390/kernel/perf_cpum_sf.c | 2 +- arch/s390/kernel/process.c | 2 +- arch/s390/kvm/priv.c | 3 +-- arch/s390/lib/spinlock.c | 2 +- arch/s390/mm/maccess.c | 2 +- drivers/s390/block/dasd_diag.c | 2 +- drivers/s390/block/dasd_eckd.c | 4 ++-- drivers/s390/block/dasd_fba.c | 2 +- drivers/s390/block/dcssblk.c | 2 +- drivers/s390/char/con3215.c | 2 +- drivers/s390/char/monwriter.c | 2 +- drivers/s390/net/ctcm_mpc.c | 10 +++++----- drivers/s390/net/netiucv.c | 2 +- 19 files changed, 25 insertions(+), 26 deletions(-)
arch/s390/appldata/appldata_base.c +2 -2
@@ -26,10 +26,10 @@#include <linux/notifier.h> #include <linux/cpu.h> #include <linux/workqueue.h> +#include <linux/uaccess.h> +#include <linux/io.h> #include <asm/appldata.h> #include <asm/vtimer.h> -#include <linux/uaccess.h> -#include <asm/io.h> #include <asm/smp.h> #include "appldata.h"
arch/s390/appldata/appldata_mem.c +1 -1
@@ -15,7 +15,7 @@#include <linux/pagemap.h> #include <linux/swap.h> #include <linux/slab.h> -#include <asm/io.h> +#include <linux/io.h> #include "appldata.h"
arch/s390/include/asm/appldata.h +1 -1
@@ -8,8 +8,8 @@#ifndef _ASM_S390_APPLDATA_H#define _ASM_S390_APPLDATA_H +#include <linux/io.h> #include <asm/diag.h> -#include <asm/io.h> #define APPLDATA_START_INTERVAL_REC 0x80#define APPLDATA_STOP_REC 0x81
arch/s390/include/asm/dma.h +1 -1
@@ -2,7 +2,7 @@#ifndef _ASM_S390_DMA_H#define _ASM_S390_DMA_H -#include <asm/io.h> +#include <linux/io.h> /* * MAX_DMA_ADDRESS is ambiguous because on s390 its completely unrelated
arch/s390/kernel/cpcmd.c +1 -1
@@ -16,10 +16,10 @@#include <linux/stddef.h> #include <linux/string.h> #include <linux/mm.h> +#include <linux/io.h> #include <asm/diag.h> #include <asm/ebcdic.h> #include <asm/cpcmd.h> -#include <asm/io.h> static DEFINE_SPINLOCK (cpcmd_lock);static char cpcmd_buf[241 ];
arch/s390/kernel/dis.c +1 -1
@@ -24,8 +24,8 @@#include <linux/kdebug.h> #include <linux/uaccess.h> #include <linux/atomic.h> +#include <linux/io.h> #include <asm/dis.h> -#include <asm/io.h> #include <asm/cpcmd.h> #include <asm/lowcore.h> #include <asm/debug.h>
arch/s390/kernel/perf_cpum_sf.c +1 -1
@@ -22,7 +22,7 @@#include <asm/irq.h> #include <asm/debug.h> #include <asm/timex.h> -#include <asm/io.h> +#include <linux/io.h> /* Minimum number of sample-data-block-tables: * At least one table is required for the sampling buffer structure.
arch/s390/kernel/process.c +1 -1
@@ -30,8 +30,8 @@#include <linux/export.h> #include <linux/init_task.h> #include <linux/entry-common.h> +#include <linux/io.h> #include <asm/cpu_mf.h> -#include <asm/io.h> #include <asm/processor.h> #include <asm/vtimer.h> #include <asm/exec.h>
arch/s390/kvm/priv.c +1 -2
@@ -13,7 +13,7 @@#include <linux/errno.h> #include <linux/mm_types.h> #include <linux/pgtable.h> - +#include <linux/io.h> #include <asm/asm-offsets.h> #include <asm/facility.h> #include <asm/current.h>
@@ -22,7 +22,6 @@#include <asm/sysinfo.h> #include <asm/page-states.h> #include <asm/gmap.h> -#include <asm/io.h> #include <asm/ptrace.h> #include <asm/sclp.h> #include <asm/ap.h>
arch/s390/lib/spinlock.c +1 -1
@@ -13,8 +13,8 @@#include <linux/init.h> #include <linux/smp.h> #include <linux/percpu.h> +#include <linux/io.h> #include <asm/alternative.h> -#include <asm/io.h> int spin_retry =-1 ;
arch/s390/mm/maccess.c +1 -1
@@ -13,9 +13,9 @@#include <linux/gfp.h> #include <linux/cpu.h> #include <linux/uio.h> +#include <linux/io.h> #include <asm/asm-extable.h> #include <asm/ctl_reg.h> -#include <asm/io.h> #include <asm/abs_lowcore.h> #include <asm/stacktrace.h> #include <asm/maccess.h>
drivers/s390/block/dasd_diag.c +1 -1
@@ -24,7 +24,7 @@#include <asm/debug.h> #include <asm/diag.h> #include <asm/ebcdic.h> -#include <asm/io.h> +#include <linux/io.h> #include <asm/irq.h> #include <asm/vtoc.h>
drivers/s390/block/dasd_eckd.c +2 -2
@@ -21,13 +21,13 @@#include <linux/compat.h> #include <linux/init.h> #include <linux/seq_file.h> +#include <linux/uaccess.h> +#include <linux/io.h> #include <asm/css_chars.h> #include <asm/debug.h> #include <asm/idals.h> #include <asm/ebcdic.h> -#include <asm/io.h> -#include <linux/uaccess.h> #include <asm/cio.h> #include <asm/ccwdev.h> #include <asm/itcw.h>
drivers/s390/block/dasd_fba.c +1 -1
@@ -16,10 +16,10 @@#include <linux/bio.h> #include <linux/module.h> #include <linux/init.h> +#include <linux/io.h> #include <asm/idals.h> #include <asm/ebcdic.h> -#include <asm/io.h> #include <asm/ccwdev.h> #include "dasd_int.h"
drivers/s390/block/dcssblk.c +1 -1
@@ -20,8 +20,8 @@#include <linux/pfn_t.h> #include <linux/uio.h> #include <linux/dax.h> +#include <linux/io.h> #include <asm/extmem.h> -#include <asm/io.h> #define DCSSBLK_NAME "dcssblk"#define DCSSBLK_MINORS_PER_DISK 1
drivers/s390/char/con3215.c +1 -1
@@ -25,7 +25,7 @@#include <linux/slab.h> #include <asm/ccwdev.h> #include <asm/cio.h> -#include <asm/io.h> +#include <linux/io.h> #include <asm/ebcdic.h> #include <linux/uaccess.h> #include <asm/delay.h>
drivers/s390/char/monwriter.c +1 -1
@@ -22,8 +22,8 @@#include <linux/mutex.h> #include <linux/slab.h> #include <linux/uaccess.h> +#include <linux/io.h> #include <asm/ebcdic.h> -#include <asm/io.h> #include <asm/appldata.h> #include <asm/monwriter.h>
drivers/s390/net/ctcm_mpc.c +5 -5
@@ -43,13 +43,13 @@#include <linux/netdevice.h> #include <net/dst.h> -#include <linux/io.h> /* instead of <asm/io.h> ok ? */ -#include <asm/ccwdev.h> -#include <asm/ccwgroup.h> -#include <linux/bitops.h> /* instead of <asm/bitops.h> ok ? */ -#include <linux/uaccess.h> /* instead of <asm/uaccess.h> ok ? */ +#include <linux/io.h> +#include <linux/bitops.h> +#include <linux/uaccess.h> #include <linux/wait.h> #include <linux/moduleparam.h> +#include <asm/ccwdev.h> +#include <asm/ccwgroup.h> #include <asm/idals.h> #include "ctcm_main.h"
drivers/s390/net/netiucv.c +1 -1
@@ -47,7 +47,7 @@#include <linux/ctype.h> #include <net/dst.h> -#include <asm/io.h> +#include <linux/io.h> #include <linux/uaccess.h> #include <asm/ebcdic.h>
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1341/1887 s390/dasd: Fix undersized format-check buffer
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Stefan Haberland <[email protected]>
[ Upstream commit 7f40b346462f563a0d6e841a77b5163d2a882a04 ]
fmt_buffer_size in dasd_eckd_check_device_format() is declared as int, even though one of the multiplicands, sizeof(struct eckd_count), is a size_t. The expression
trkcount * rpt_max * sizeof(struct eckd_count)
is therefore correctly evaluated at 64-bit width, but the result is silently truncated when it is stored back into the 32-bit fmt_buffer_size variable. For a sufficiently large track range (start_unit/stop_unit are caller-controlled) this truncation yields a buffer size far smaller than the number of tracks actually requested. kzalloc() then succeeds with an undersized allocation, while the subsequent channel program build still operates on the untruncated track count and writes past the end of that buffer.
Compute the buffer size with check_mul_overflow() and keep it in a size_t, so that a value that no longer fits results in -EINVAL instead of a silently truncated allocation size.
--- drivers/s390/block/dasd_eckd.c | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-)
drivers/s390/block/dasd_eckd.c +7 -4
@@ -23,6 +23,7 @@#include <linux/seq_file.h> #include <linux/uaccess.h> #include <linux/io.h> +#include <linux/overflow.h> #include <asm/css_chars.h> #include <asm/debug.h>
@@ -3518,11 +3519,11 @@ static int dasd_eckd_check_device_format(struct dasd_device *base, {struct dasd_eckd_private *private = base->private;struct eckd_count *fmt_buffer; -struct irb irb; +size_t fmt_buffer_size; +unsigned int trkcount;int rpt_max, rpt_exp; -int fmt_buffer_size; +struct irb irb;int trk_per_cyl; -int trkcount;int tpm =0 ;int rc;
@@ -3533,7 +3534,9 @@ static int dasd_eckd_check_device_format(struct dasd_device *base, rpt_exp =recs_per_track (&private->rdc_data,0 , cdata->expect.blksize); trkcount = cdata->expect.stop_unit - cdata->expect.start_unit +1 ; - fmt_buffer_size = trkcount * rpt_max *sizeof (struct eckd_count ); +if (check_mul_overflow (trkcount, rpt_max, &fmt_buffer_size) || +check_mul_overflow (fmt_buffer_size,sizeof (struct eckd_count ), &fmt_buffer_size)) +return -EINVAL ; fmt_buffer =kzalloc (fmt_buffer_size,GFP_KERNEL |GFP_DMA );if (!fmt_buffer)
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1342/1887 bpf: Check sk_state before sk_protocol in bpf_tcp_*_syncookie
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Luxiao Xu <[email protected]>
[ Upstream commit 31a420a822ff92e2090bd5d65efe8e34e2d6d9b8 ]
bpf_tcp_gen_syncookie and bpf_tcp_check_syncookie accept a socket pointer 'sk' with argument type ARG_PTR_TO_BTF_ID_SOCK_COMMON. However, they access sk->sk_protocol without validating whether 'sk' represents a full socket.
Fix this issue by checking sk->sk_state != TCP_LISTEN before inspecting sk->sk_protocol in both bpf_tcp_gen_syncookie and bpf_tcp_check_syncookie. Since mini-sockets are never in the TCP_LISTEN state, the condition short-circuits and prevents dereferencing fullsock-specific fields.
--- net/core/filter.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-)
net/core/filter.c +2 -2
@@ -7333,7 +7333,7 @@ BPF_CALL_5(bpf_tcp_check_syncookie, struct sock *, sk, void *, iph, u32, iph_lenreturn -EINVAL ;/* sk_listener() allows TCP_NEW_SYN_RECV, which makes no sense here. */ -if (sk->sk_protocol !=IPPROTO_TCP || sk->sk_state !=TCP_LISTEN ) +if (sk->sk_state !=TCP_LISTEN || sk->sk_protocol !=IPPROTO_TCP )return -EINVAL ;if (!READ_ONCE (sock_net (sk)->ipv4.sysctl_tcp_syncookies))
@@ -7408,7 +7408,7 @@ BPF_CALL_5(bpf_tcp_gen_syncookie, struct sock *, sk, void *, iph, u32, iph_len,if (unlikely (!sk || th_len <sizeof (*th) || th_len != th->doff *4 ))return -EINVAL ; -if (sk->sk_protocol !=IPPROTO_TCP || sk->sk_state !=TCP_LISTEN ) +if (sk->sk_state !=TCP_LISTEN || sk->sk_protocol !=IPPROTO_TCP )return -EINVAL ;if (!READ_ONCE (sock_net (sk)->ipv4.sysctl_tcp_syncookies))
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1343/1887 net/mlx5e: TC, Check if flow is PEER before acquiring devcom lock
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Shay Drory <[email protected]>
[ Upstream commit 6ddfba2ea98db21b001e0e5c472499156224650c ]
In case __mlx5e_add_fdb_flow() fails in lower levels, the flow is deleted via mlx5e_tc_del_flow(), and mlx5e_tc_del_flow() is acquiring ESW devcom lock without condition. In addition, in case of peer_flow, __mlx5e_add_fdb_flow() is called while holding ESW devcom comp lock. This results in an AA deadlock.
To fix this, introduce a new PEER flag that is set on flows created as peer flows (the duplicate flows on peer devices), and check it in mlx5e_tc_del_flow() before acquiring ESW devcom lock.
Lockdep splat:
============================================
WARNING: possible recursive locking detected
============================================
Possible unsafe locking scenario:
CPU0
----
lock(&comp->lock_key#2);
lock(&comp->lock_key#2);
*** DEADLOCK ***
Call Trace:
<TASK>
dump_stack_lvl+0x69/0xa0
print_deadlock_bug.cold+0xbd/0xca
__lock_acquire+0x1671/0x2ec0
lock_acquire+0x10e/0x2e0
down_read+0x95/0x430
mlx5_devcom_for_each_peer_begin+0x4e/0xe0 [mlx5_core]
mlx5e_tc_del_flow+0x11d/0xa70 [mlx5_core]
mlx5e_flow_put+0x99/0x100 [mlx5_core]
__mlx5e_add_fdb_flow+0x409/0xf00 [mlx5_core]
mlx5e_configure_flower+0x2a86/0x4100 [mlx5_core]
mlx5e_rep_setup_tc_cls_flower+0x12f/0x1b0 [mlx5_core]
mlx5e_rep_setup_tc_cb+0x153/0x750 [mlx5_core]
tc_setup_cb_add+0x1dc/0x470
fl_change+0x2f4d/0x626d [cls_flower]
tc_new_tfilter+0x79b/0x2310
rtnetlink_rcv_msg+0x778/0xad0
do_syscall_64+0x70/0x960
entry_SYSCALL_64_after_hwframe+0x4b/0x53
</TASK>--- drivers/net/ethernet/mellanox/mlx5/core/en/tc_priv.h | 1 + drivers/net/ethernet/mellanox/mlx5/core/en_tc.c | 4 +++- 2 files changed, 4 insertions(+), 1 deletion(-)
drivers/net/ethernet/mellanox/mlx5/core/en/tc_priv.h +1 -0
@@ -30,6 +30,7 @@ enum {MLX5E_TC_FLOW_FLAG_TUN_RX =MLX5E_TC_FLOW_BASE +9 ,MLX5E_TC_FLOW_FLAG_FAILED =MLX5E_TC_FLOW_BASE +10 ,MLX5E_TC_FLOW_FLAG_SAMPLE =MLX5E_TC_FLOW_BASE +11 , + MLX5E_TC_FLOW_FLAG_PEER = MLX5E_TC_FLOW_BASE + 12, }; struct mlx5e_tc_flow_parse_attr {
drivers/net/ethernet/mellanox/mlx5/core/en_tc.c +3 -1
@@ -2005,7 +2005,8 @@ static void mlx5e_tc_del_flow(struct mlx5e_priv *priv, struct mlx5e_tc_flow *flow) {if (mlx5e_is_eswitch_flow (flow)) { -mlx5e_tc_del_fdb_peer_flow (flow); +if (!flow_flag_test (flow,PEER )) +mlx5e_tc_del_fdb_peer_flow (flow);mlx5e_tc_del_fdb_flow (priv, flow); }else {mlx5e_tc_del_nic_flow (priv, flow);
@@ -4389,6 +4390,7 @@ static int mlx5e_tc_add_fdb_peer_flow(struct flow_cls_offload *f,else in_mdev = priv->mdev; + flow_flags |=BIT (MLX5E_TC_FLOW_FLAG_PEER ); parse_attr = flow->attr->parse_attr; peer_flow = __mlx5e_add_fdb_flow(peer_priv, f, flow_flags, parse_attr->filter_dev,
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1344/1887 drm/amdkfd: Fix infinite loop parsing CRAT with zero subtype length
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Yongqiang Sun <[email protected]>
[ Upstream commit 961323c26ad4c895e3b0ea1711fc41dfd6368c12 ]
Malformed ACPI CRAT tables can advertise a zero or undersized subtype length. The parser then fails to advance the cursor and loops forever while the remaining image still looks large enough for a generic header.
Validate sub_type_hdr->length on each iteration before parsing or advancing. Return -EINVAL and warn when length is zero or smaller than the generic subtype header.
Stable-dep-of: 6e7566ba4739 ("drm/amdkfd: Add bounds check for CRAT subtype length")
--- drivers/gpu/drm/amd/amdkfd/kfd_crat.c | 8 ++++++++ 1 file changed, 8 insertions(+)
drivers/gpu/drm/amd/amdkfd/kfd_crat.c +8 -0
@@ -1316,6 +1316,14 @@ int kfd_parse_crat_table(void *crat_image, struct list_head *device_list, sub_type_hdr = (struct crat_subtype_generic *)(crat_table+1 );while ((char *)sub_type_hdr +sizeof (struct crat_subtype_generic ) < ((char *)crat_image) + image_len) { +if (!sub_type_hdr->length || + sub_type_hdr->length <sizeof (struct crat_subtype_generic )) { +pr_warn ("Invalid CRAT subtype length %u\n" , + sub_type_hdr->length); + ret = -EINVAL ; +break ; + } +if (sub_type_hdr->flags &CRAT_SUBTYPE_FLAGS_ENABLED ) { ret =kfd_parse_subtype (sub_type_hdr, device_list);if (ret)
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1345/1887 drm/amdkfd: Add bounds check for CRAT subtype length
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: William Palacek <[email protected]>
[ Upstream commit 6e7566ba4739dd573c331adde1c96690f7a567bd ]
The CRAT parser validates that the subtype header fits within the image, but does not verify that the advertised subtype length fits. A malformed CRAT table with an oversized length field causes out-of-bounds reads when kfd_parse_subtype() casts the header to specific subtype structures.
Add validation that sub_type_hdr + length does not exceed the image boundary before parsing the subtype contents.
--- drivers/gpu/drm/amd/amdkfd/kfd_crat.c | 9 +++++++++ 1 file changed, 9 insertions(+)
drivers/gpu/drm/amd/amdkfd/kfd_crat.c +9 -0
@@ -1324,6 +1324,15 @@ int kfd_parse_crat_table(void *crat_image, struct list_head *device_list,break ; } +/* Validate subtype fits within remaining image */ +if ((char *)sub_type_hdr + sub_type_hdr->length > + (char *)crat_image + image_len) { +pr_warn ("CRAT subtype length %u exceeds image bounds\n" , + sub_type_hdr->length); + ret = -EINVAL ; +break ; + } +if (sub_type_hdr->flags &CRAT_SUBTYPE_FLAGS_ENABLED ) { ret =kfd_parse_subtype (sub_type_hdr, device_list);if (ret)
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1346/1887 selinux: reject a permission value exceeding the class permission count
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Bryam Vargas <[email protected]>
[ Upstream commit d14b5d0e97fccd27974fedc03b903408872907fd ]
perm_read() bounds a permission value by SEL_VEC_MAX but never by the nprim of the owning class or common, which is taken verbatim from the policy image. security_get_permissions() then writes perms[value - 1] into an nprim-sized kcalloc() array, so a class declaring fewer permissions than its largest permission value drives an out-of-bounds heap write. The top-level symbol tables are validated this way; the nested per-class permission table is not.
Reject a permission whose value exceeds nprim, which is already set when perm_read() runs. Well-formed policies are unaffected.
--- security/selinux/ss/policydb.c | 4 ++++ 1 file changed, 4 insertions(+)
security/selinux/ss/policydb.c +4 -0
@@ -1126,6 +1126,10 @@ static int perm_read(struct policydb *p, struct symtab *s, void *fp) len =le32_to_cpu (buf[0 ]); perdatum->value =le32_to_cpu (buf[1 ]); + rc = -EINVAL ; +/* indexes an nprim-sized array in security_get_permissions() */ +if (perdatum->value > s->nprim) + goto bad; rc =str_read (&key,GFP_KERNEL , fp, len);if (rc)
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1347/1887 Bluetooth: ISO: zero the sockaddr before returning it in getname
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Ali Ahmet Memis <[email protected]>
[ Upstream commit 884cf2cc957da7ac178a0e6c6c69ddfec0481cc8 ]
iso_sock_getname() fills a struct sockaddr_iso in place and returns its size without clearing it first, so bytes it does not write are copied to user space from the kernel stack. The getsockname(2) and getpeername(2) paths both run through do_getsockname(), which hands getname() an uninitialized sockaddr_storage on the stack and copies back up to the number of bytes getname() returns, so the driver has to initialize every byte it accounts for.
Two ranges are left uninitialized:
- struct sockaddr_iso is 10 bytes but only 9 are written (family, iso_bdaddr, iso_bdaddr_type), leaking the trailing pad byte on every call.
- for a broadcast peer (BIS_LINK or PA_LINK) the returned length grows by sizeof(struct sockaddr_iso_bc), but only bc_sid, bc_num_bis and bc_bis are filled; bc_bdaddr and bc_bdaddr_type, the first 7 bytes of that structure, are never written.
An unprivileged process can open a BTPROTO_ISO socket and reach the pad leak with getsockname(); the broadcast leak needs an established BIS/PA connection. l2cap and rfcomm already memset their sockaddr in getname for the same reason; do the same here.
--- net/bluetooth/iso.c | 1 + 1 file changed, 1 insertion(+)
net/bluetooth/iso.c +1 -0
@@ -1080,6 +1080,7 @@ static int iso_sock_getname(struct socket *sock, struct sockaddr *addr,BT_DBG ("sock %p, sk %p" , sock, sk); +memset (sa,0 ,sizeof (struct sockaddr_iso )); addr->sa_family =AF_BLUETOOTH ;if (peer) {
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1348/1887 fbdev: Wrap user-invoked calls to fb_set_var() in helper
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Thomas Zimmermann <[email protected]>
[ Upstream commit 6f611e5e5f3327cf2e2daabe6ee5acac58cc784e ]
Handle fbcon during display updates in fb_set_var_from_user(). Check with fbcon if the mode change is possible, update hardware state and finally update fbcon. Update all callers.
Only the FBIOPUT_VSCREENINFO ioctl currently does all steps. Other mode-changes callers in sysfs and driver code are missing fbcon-related steps.
With the new helper, ps3fb and sh_mobile_lcdcfb no longer maintain fbcon state themselves.
--- drivers/video/fbdev/core/fbcon.c | 2 -- drivers/video/fbdev/core/fbmem.c | 19 ++++++++++++++----- drivers/video/fbdev/core/fbsysfs.c | 4 +--- drivers/video/fbdev/ps3fb.c | 5 +---- drivers/video/fbdev/sh_mobile_lcdcfb.c | 5 +---- include/linux/fb.h | 3 +++ 6 files changed, 20 insertions(+), 18 deletions(-)
drivers/video/fbdev/core/fbcon.c +0 -2
@@ -2774,7 +2774,6 @@ void fbcon_update_vcs(struct fb_info *info, bool all)else fbcon_modechanged (info); } -EXPORT_SYMBOL (fbcon_update_vcs);/* let fbcon check if it supports a new screen resolution */ int fbcon_modechange_possible (struct fb_info *info,struct fb_var_screeninfo *var)
@@ -2802,7 +2801,6 @@ int fbcon_modechange_possible(struct fb_info *info, struct fb_var_screeninfo *vareturn 0 ; } -EXPORT_SYMBOL_GPL (fbcon_modechange_possible);int fbcon_mode_deleted (struct fb_info *info,struct fb_videomode *mode)
drivers/video/fbdev/core/fbmem.c +14 -5
@@ -1074,6 +1074,19 @@ fb_set_var(struct fb_info *info, struct fb_var_screeninfo *var) }EXPORT_SYMBOL (fb_set_var); +int fb_set_var_from_user (struct fb_info *info,struct fb_var_screeninfo *var) +{ +int ret =fbcon_modechange_possible (info, var); + +if (!ret) + ret =fb_set_var (info, var); +if (!ret) +fbcon_update_vcs (info, var->activate &FB_ACTIVATE_ALL ); + +return ret; +} +EXPORT_SYMBOL (fb_set_var_from_user); +int fb_blank (struct fb_info *info,int blank) {
@@ -1122,11 +1135,7 @@ static long do_fb_ioctl(struct fb_info *info, unsigned int cmd, var.activate &= ~FB_ACTIVATE_KD_TEXT ;console_lock ();lock_fb_info (info); - ret =fbcon_modechange_possible (info, &var); -if (!ret) - ret =fb_set_var (info, &var); -if (!ret) -fbcon_update_vcs (info, var.activate &FB_ACTIVATE_ALL ); + ret =fb_set_var_from_user (info, &var);unlock_fb_info (info);console_unlock ();if (!ret &©_to_user (argp, &var,sizeof (var)))
drivers/video/fbdev/core/fbsysfs.c +1 -3
@@ -100,9 +100,7 @@ static int activate(struct fb_info *fb_info, struct fb_var_screeninfo *var) var->activate |=FB_ACTIVATE_FORCE ;console_lock ();lock_fb_info (fb_info); - err =fb_set_var (fb_info, var); -if (!err) -fbcon_update_vcs (fb_info, var->activate &FB_ACTIVATE_ALL ); + err =fb_set_var_from_user (fb_info, var);unlock_fb_info (fb_info);console_unlock ();if (err)
drivers/video/fbdev/ps3fb.c +1 -4
@@ -29,7 +29,6 @@#include <linux/freezer.h> #include <linux/uaccess.h> #include <linux/fb.h> -#include <linux/fbcon.h> #include <linux/init.h> #include <asm/cell-regs.h>
@@ -828,9 +827,7 @@ static int ps3fb_ioctl(struct fb_info *info, unsigned int cmd,/* Force, in case only special bits changed */ var.activate |=FB_ACTIVATE_FORCE ; par->new_mode_id = val; - retval =fb_set_var (info, &var); -if (!retval) -fbcon_update_vcs (info, var.activate &FB_ACTIVATE_ALL ); + retval =fb_set_var_from_user (info, &var);console_unlock (); }break ;
drivers/video/fbdev/sh_mobile_lcdcfb.c +1 -4
@@ -15,7 +15,6 @@#include <linux/ctype.h> #include <linux/dma-mapping.h> #include <linux/delay.h> -#include <linux/fbcon.h> #include <linux/init.h> #include <linux/interrupt.h> #include <linux/ioctl.h>
@@ -1770,11 +1769,9 @@ static void sh_mobile_fb_reconfig(struct fb_info *info) var.height = ch->display.height; var.activate =FB_ACTIVATE_NOW ; -if (fb_set_var (info, &var) <0 ) +if (fb_set_var_from_user (info, &var) <0 )/* Couldn't reconfigure, hopefully, can continue as before */ return ; - -fbcon_update_vcs (info, true); }/*
include/linux/fb.h +3 -0
@@ -601,6 +601,9 @@ static inline struct apertures_struct *alloc_apertures(unsigned int max_num) {extern int fb_set_var (struct fb_info *info,struct fb_var_screeninfo *var);extern int fb_pan_display (struct fb_info *info,struct fb_var_screeninfo *var);extern int fb_blank (struct fb_info *info,int blank); + +int fb_set_var_from_user (struct fb_info *info,struct fb_var_screeninfo *var); +extern void cfb_fillrect (struct fb_info *info,const struct fb_fillrect *rect);extern void cfb_copyarea (struct fb_info *info,const struct fb_copyarea *area);extern void cfb_imageblit (struct fb_info *info,const struct fb_image *image);
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1349/1887 crypto: virtio - Less function calls in __virtio_crypto_akcipher_do_req() after error detection
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Markus Elfring <[email protected]>
[ Upstream commit e01966e643c97eb8916bbbbbeceb687afb11f345 ]
The kfree() function was called in up to two cases by the __virtio_crypto_akcipher_do_req() function during error handling even if the passed variable contained a null pointer. This issue was detected by using the Coccinelle software.
* Adjust jump targets.
* Delete two initialisations which became unnecessary with this refactoring.
Stable-dep-of: f77a956f6a19 ("crypto: virtio - bound the akcipher result length")
--- drivers/crypto/virtio/virtio_crypto_akcipher_algs.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-)
drivers/crypto/virtio/virtio_crypto_akcipher_algs.c +6 -6
@@ -225,11 +225,11 @@ static int __virtio_crypto_akcipher_do_req(struct virtio_crypto_akcipher_requeststruct virtio_crypto *vcrypto = ctx->vcrypto;struct virtio_crypto_op_data_req *req_data = vc_req->req_data;struct scatterlist *sgs[4 ], outhdr_sg, inhdr_sg, srcdata_sg, dstdata_sg; -void *src_buf =NULL , *dst_buf =NULL ; +void *src_buf, *dst_buf =NULL ;unsigned int num_out =0 , num_in =0 ;int node =dev_to_node (&vcrypto->vdev->dev);unsigned long flags; -int ret = -ENOMEM ; +int ret;bool verify = vc_akcipher_req->opcode ==VIRTIO_CRYPTO_AKCIPHER_VERIFY ;unsigned int src_len = verify ? req->src_len + req->dst_len : req->src_len;
@@ -240,7 +240,7 @@ static int __virtio_crypto_akcipher_do_req(struct virtio_crypto_akcipher_request/* src data */ src_buf =kcalloc_node (src_len,1 ,GFP_KERNEL , node);if (!src_buf) - goto err; +return -ENOMEM ;if (verify) {/* for verify operation, both src and dst data work as OUT direction */
@@ -255,7 +255,7 @@ static int __virtio_crypto_akcipher_do_req(struct virtio_crypto_akcipher_request/* dst data */ dst_buf =kcalloc_node (req->dst_len,1 ,GFP_KERNEL , node);if (!dst_buf) - goto err; + goto free_src;sg_init_one (&dstdata_sg, dst_buf, req->dst_len); sgs[num_out + num_in++] = &dstdata_sg;
@@ -278,9 +278,9 @@ static int __virtio_crypto_akcipher_do_req(struct virtio_crypto_akcipher_requestreturn 0 ; err: -kfree (src_buf);kfree (dst_buf); - +free_src: +kfree (src_buf);return -ENOMEM ; }
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1350/1887 crypto: virtio - Drop sign/verify operations
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Lukas Wunner <[email protected]>
[ Upstream commit 5b553e06b3215fa97d222ebddc2bc964f1824c5b ]
The virtio crypto driver exposes akcipher sign/verify operations in a user space ABI. This blocks removal of sign/verify from akcipher_alg.
Herbert opines:
"I would say that this is something that we can break. Breaking it
is no different to running virtio on a host that does not support these algorithms. After all, a software implementation must always be present.
I deliberately left akcipher out of crypto_user because the API is still in flux. We should not let virtio constrain ourselves."
https://lore.kernel.org/all/[email protected]/
"I would remove virtio akcipher support in its entirety. This API
was never meant to be exposed outside of the kernel."
https://lore.kernel.org/all/[email protected]/
Drop sign/verify support from virtio crypto. There's no strong reason to also remove encrypt/decrypt support, so keep it.
A key selling point of virtio crypto is to allow guest access to crypto accelerators on the host. So far the only akcipher algorithm supported by virtio crypto is RSA. Dropping sign/verify merely means that the PKCS#1 padding is now always generated or verified inside the guest, but the actual signature generation/verification (which is an RSA decrypt/encrypt operation) may still use an accelerator on the host.
Generating or verifying the PKCS#1 padding is cheap, so a hardware accelerator won't be of much help there. Which begs the question whether virtio crypto support for sign/verify makes sense at all.
It would make sense for the sign operation if the host has a security chip to store asymmetric private keys. But the kernel doesn't even have an asymmetric_key_subtype yet for hardware-based private keys. There's at least one rudimentary driver for such chips (atmel-ecc.c for ATECC508A), but it doesn't implement the sign operation. The kernel would first have to grow support for a hardware asymmetric_key_subtype and at least one driver implementing the sign operation before exposure to guests via virtio makes sense.
Stable-dep-of: f77a956f6a19 ("crypto: virtio - bound the akcipher result length")
--- .../virtio/virtio_crypto_akcipher_algs.c | 65 ++++++------------- include/uapi/linux/virtio_crypto.h | 1 + 2 files changed, 22 insertions(+), 44 deletions(-)
drivers/crypto/virtio/virtio_crypto_akcipher_algs.c +21 -44
@@ -83,23 +83,16 @@ static void virtio_crypto_dataq_akcipher_callback(struct virtio_crypto_request *case VIRTIO_CRYPTO_BADMSG : error = -EBADMSG ;break ; - -case VIRTIO_CRYPTO_KEY_REJECTED : - error = -EKEYREJECTED ; -break ; -default : error = -EIO ;break ; } akcipher_req = vc_akcipher_req->akcipher_req; -if (vc_akcipher_req->opcode !=VIRTIO_CRYPTO_AKCIPHER_VERIFY ) { -/* actuall length maybe less than dst buffer */ - akcipher_req->dst_len = len -sizeof (vc_req->status); -sg_copy_from_buffer (akcipher_req->dst,sg_nents (akcipher_req->dst), - vc_akcipher_req->dst_buf, akcipher_req->dst_len); - } +/* actual length maybe less than dst buffer */ + akcipher_req->dst_len = len -sizeof (vc_req->status); +sg_copy_from_buffer (akcipher_req->dst,sg_nents (akcipher_req->dst), + vc_akcipher_req->dst_buf, akcipher_req->dst_len);virtio_crypto_akcipher_finalize_req (vc_akcipher_req, akcipher_req, error); }
@@ -230,36 +223,27 @@ static int __virtio_crypto_akcipher_do_req(struct virtio_crypto_akcipher_requestint node =dev_to_node (&vcrypto->vdev->dev);unsigned long flags;int ret; -bool verify = vc_akcipher_req->opcode ==VIRTIO_CRYPTO_AKCIPHER_VERIFY ; -unsigned int src_len = verify ? req->src_len + req->dst_len : req->src_len;/* out header */ sg_init_one (&outhdr_sg, req_data,sizeof (*req_data)); sgs[num_out++] = &outhdr_sg;/* src data */ - src_buf =kcalloc_node (src_len,1 ,GFP_KERNEL , node); + src_buf =kcalloc_node (req->src_len,1 ,GFP_KERNEL , node);if (!src_buf)return -ENOMEM ; -if (verify) { -/* for verify operation, both src and dst data work as OUT direction */ -sg_copy_to_buffer (req->src,sg_nents (req->src), src_buf, src_len); -sg_init_one (&srcdata_sg, src_buf, src_len); - sgs[num_out++] = &srcdata_sg; - }else { -sg_copy_to_buffer (req->src,sg_nents (req->src), src_buf, src_len); -sg_init_one (&srcdata_sg, src_buf, src_len); - sgs[num_out++] = &srcdata_sg; +sg_copy_to_buffer (req->src,sg_nents (req->src), src_buf, req->src_len); +sg_init_one (&srcdata_sg, src_buf, req->src_len); + sgs[num_out++] = &srcdata_sg; -/* dst data */ - dst_buf =kcalloc_node (req->dst_len,1 ,GFP_KERNEL , node); -if (!dst_buf) - goto free_src; +/* dst data */ + dst_buf =kcalloc_node (req->dst_len,1 ,GFP_KERNEL , node); +if (!dst_buf) + goto free_src; -sg_init_one (&dstdata_sg, dst_buf, req->dst_len); - sgs[num_out + num_in++] = &dstdata_sg; - } +sg_init_one (&dstdata_sg, dst_buf, req->dst_len); + sgs[num_out + num_in++] = &dstdata_sg; vc_akcipher_req->src_buf = src_buf; vc_akcipher_req->dst_buf = dst_buf;
@@ -352,16 +336,6 @@ static int virtio_crypto_rsa_decrypt(struct akcipher_request *req)return virtio_crypto_rsa_req (req,VIRTIO_CRYPTO_AKCIPHER_DECRYPT ); } -static int virtio_crypto_rsa_sign (struct akcipher_request *req) -{ -return virtio_crypto_rsa_req (req,VIRTIO_CRYPTO_AKCIPHER_SIGN ); -} - -static int virtio_crypto_rsa_verify (struct akcipher_request *req) -{ -return virtio_crypto_rsa_req (req,VIRTIO_CRYPTO_AKCIPHER_VERIFY ); -} - static int virtio_crypto_rsa_set_key(struct crypto_akcipher *tfm, const void *key, unsigned int keylen,
@@ -522,8 +496,11 @@ static struct virtio_crypto_akcipher_algo virtio_crypto_akcipher_algs[] = { .algo = { .encrypt = virtio_crypto_rsa_encrypt, .decrypt = virtio_crypto_rsa_decrypt, - .sign = virtio_crypto_rsa_sign, - .verify = virtio_crypto_rsa_verify, +/* +* Must specify an arbitrary hash algorithm upon +* set_{pub,priv}_key (even though it's not used +* by encrypt/decrypt) because qemu checks for it. +*/ .set_pub_key = virtio_crypto_p1pad_rsa_sha1_set_pub_key, .set_priv_key = virtio_crypto_p1pad_rsa_sha1_set_priv_key, .max_size = virtio_crypto_rsa_max_size,
@@ -531,8 +508,8 @@ static struct virtio_crypto_akcipher_algo virtio_crypto_akcipher_algs[] = { .exit = virtio_crypto_rsa_exit_tfm, .reqsize = sizeof(struct virtio_crypto_akcipher_request), .base = { - .cra_name = "pkcs1pad(rsa,sha1)", - .cra_driver_name = "virtio-pkcs1-rsa-with-sha1", + .cra_name = "pkcs1pad(rsa)", + .cra_driver_name = "virtio-pkcs1-rsa", .cra_priority = 150, .cra_module = THIS_MODULE, .cra_ctxsize = sizeof(struct virtio_crypto_akcipher_ctx),
include/uapi/linux/virtio_crypto.h +1 -0
@@ -329,6 +329,7 @@ struct virtio_crypto_op_header { VIRTIO_CRYPTO_OPCODE(VIRTIO_CRYPTO_SERVICE_AKCIPHER, 0x00)#define VIRTIO_CRYPTO_AKCIPHER_DECRYPT \ VIRTIO_CRYPTO_OPCODE(VIRTIO_CRYPTO_SERVICE_AKCIPHER, 0x01) +/* akcipher sign/verify opcodes are deprecated */ #define VIRTIO_CRYPTO_AKCIPHER_SIGN \ VIRTIO_CRYPTO_OPCODE(VIRTIO_CRYPTO_SERVICE_AKCIPHER, 0x02)#define VIRTIO_CRYPTO_AKCIPHER_VERIFY \
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1351/1887 crypto: virtio - Drop superfluous [as]kcipher_ctx pointer
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Lukas Wunner <[email protected]>
[ Upstream commit dc91d858fb9251b25828ab63ac7220145cef282c ]
The request context virtio_crypto_{akcipher,sym}_request contains a pointer to the transform context virtio_crypto_[as]kcipher_ctx.
The pointer is superfluous as it can be calculated with the cheap crypto_akcipher_reqtfm() + akcipher_tfm_ctx() and crypto_skcipher_reqtfm() + crypto_skcipher_ctx() combos.
Drop the superfluous pointer.
Stable-dep-of: f77a956f6a19 ("crypto: virtio - bound the akcipher result length")
--- drivers/crypto/virtio/virtio_crypto_akcipher_algs.c | 8 ++++---- drivers/crypto/virtio/virtio_crypto_skcipher_algs.c | 5 +---- 2 files changed, 5 insertions(+), 8 deletions(-)
drivers/crypto/virtio/virtio_crypto_akcipher_algs.c +4 -4
@@ -36,7 +36,6 @@ struct virtio_crypto_akcipher_ctx {struct virtio_crypto_akcipher_request {struct virtio_crypto_request base; -struct virtio_crypto_akcipher_ctx *akcipher_ctx;struct akcipher_request *akcipher_req;void *src_buf;void *dst_buf;
@@ -213,7 +212,8 @@ static int virtio_crypto_alg_akcipher_close_session(struct virtio_crypto_akciphestatic int __virtio_crypto_akcipher_do_req (struct virtio_crypto_akcipher_request *vc_akcipher_req,struct akcipher_request *req,struct data_queue *data_vq) { -struct virtio_crypto_akcipher_ctx *ctx = vc_akcipher_req->akcipher_ctx; +struct crypto_akcipher *atfm =crypto_akcipher_reqtfm (req); +struct virtio_crypto_akcipher_ctx *ctx =akcipher_tfm_ctx (atfm);struct virtio_crypto_request *vc_req = &vc_akcipher_req->base;struct virtio_crypto *vcrypto = ctx->vcrypto;struct virtio_crypto_op_data_req *req_data = vc_req->req_data;
@@ -273,7 +273,8 @@ static int virtio_crypto_rsa_do_req(struct crypto_engine *engine, void *vreq) struct akcipher_request *req = container_of(vreq, struct akcipher_request, base);struct virtio_crypto_akcipher_request *vc_akcipher_req =akcipher_request_ctx (req);struct virtio_crypto_request *vc_req = &vc_akcipher_req->base; -struct virtio_crypto_akcipher_ctx *ctx = vc_akcipher_req->akcipher_ctx; +struct crypto_akcipher *atfm =crypto_akcipher_reqtfm (req); +struct virtio_crypto_akcipher_ctx *ctx =akcipher_tfm_ctx (atfm);struct virtio_crypto *vcrypto = ctx->vcrypto;struct data_queue *data_vq = vc_req->dataq;struct virtio_crypto_op_header *header;
@@ -319,7 +320,6 @@ static int virtio_crypto_rsa_req(struct akcipher_request *req, uint32_t opcode) vc_req->dataq = data_vq; vc_req->alg_cb = virtio_crypto_dataq_akcipher_callback; - vc_akcipher_req->akcipher_ctx = ctx; vc_akcipher_req->akcipher_req = req; vc_akcipher_req->opcode = opcode;
drivers/crypto/virtio/virtio_crypto_skcipher_algs.c +1 -4
@@ -31,7 +31,6 @@ struct virtio_crypto_sym_request {/* Cipher or aead */ uint32_t type; -struct virtio_crypto_skcipher_ctx *skcipher_ctx;struct skcipher_request *skcipher_req;uint8_t *iv;/* Encryption? */
@@ -328,7 +327,7 @@ __virtio_crypto_skcipher_do_req(struct virtio_crypto_sym_request *vc_sym_req, struct data_queue *data_vq) {struct crypto_skcipher *tfm =crypto_skcipher_reqtfm (req); -struct virtio_crypto_skcipher_ctx *ctx = vc_sym_req->skcipher_ctx; +struct virtio_crypto_skcipher_ctx *ctx =crypto_skcipher_ctx (tfm);struct virtio_crypto_request *vc_req = &vc_sym_req->base;unsigned int ivsize =crypto_skcipher_ivsize (tfm);struct virtio_crypto *vcrypto = ctx->vcrypto;
@@ -484,7 +483,6 @@ static int virtio_crypto_skcipher_encrypt(struct skcipher_request *req) vc_req->dataq = data_vq; vc_req->alg_cb = virtio_crypto_dataq_sym_callback; - vc_sym_req->skcipher_ctx = ctx; vc_sym_req->skcipher_req = req; vc_sym_req->encrypt = true;
@@ -509,7 +507,6 @@ static int virtio_crypto_skcipher_decrypt(struct skcipher_request *req) vc_req->dataq = data_vq; vc_req->alg_cb = virtio_crypto_dataq_sym_callback; - vc_sym_req->skcipher_ctx = ctx; vc_sym_req->skcipher_req = req; vc_sym_req->encrypt = false;
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1352/1887 crypto: virtio - Drop superfluous [as]kcipher_req pointer
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Lukas Wunner <[email protected]>
[ Upstream commit 62d027fb49c76475c5256ab69059752f42c3730f ]
The request context virtio_crypto_{akcipher,sym}_request contains a pointer to the [as]kcipher_request itself.
The pointer is superfluous as it can be calculated with container_of().
Drop the superfluous pointer.
Stable-dep-of: f77a956f6a19 ("crypto: virtio - bound the akcipher result length")
--- drivers/crypto/virtio/virtio_crypto_akcipher_algs.c | 9 ++++----- drivers/crypto/virtio/virtio_crypto_skcipher_algs.c | 8 +++----- 2 files changed, 7 insertions(+), 10 deletions(-)
drivers/crypto/virtio/virtio_crypto_akcipher_algs.c +4 -5
@@ -36,7 +36,6 @@ struct virtio_crypto_akcipher_ctx {struct virtio_crypto_akcipher_request {struct virtio_crypto_request base; -struct akcipher_request *akcipher_req;void *src_buf;void *dst_buf;uint32_t opcode;
@@ -68,7 +67,9 @@ static void virtio_crypto_dataq_akcipher_callback(struct virtio_crypto_request * {struct virtio_crypto_akcipher_request *vc_akcipher_req = container_of(vc_req, struct virtio_crypto_akcipher_request, base); -struct akcipher_request *akcipher_req; +struct akcipher_request *akcipher_req = + container_of((void *)vc_akcipher_req, struct akcipher_request, + __ctx);int error;switch (vc_req->status) {
@@ -87,8 +88,7 @@ static void virtio_crypto_dataq_akcipher_callback(struct virtio_crypto_request *break ; } - akcipher_req = vc_akcipher_req->akcipher_req; -/* actual length maybe less than dst buffer */ +/* actual length may be less than dst buffer */ akcipher_req->dst_len = len -sizeof (vc_req->status);sg_copy_from_buffer (akcipher_req->dst,sg_nents (akcipher_req->dst), vc_akcipher_req->dst_buf, akcipher_req->dst_len);
@@ -320,7 +320,6 @@ static int virtio_crypto_rsa_req(struct akcipher_request *req, uint32_t opcode) vc_req->dataq = data_vq; vc_req->alg_cb = virtio_crypto_dataq_akcipher_callback; - vc_akcipher_req->akcipher_req = req; vc_akcipher_req->opcode = opcode;return crypto_transfer_akcipher_request_to_engine (data_vq->engine, req);
drivers/crypto/virtio/virtio_crypto_skcipher_algs.c +3 -5
@@ -31,7 +31,6 @@ struct virtio_crypto_sym_request {/* Cipher or aead */ uint32_t type; -struct skcipher_request *skcipher_req;uint8_t *iv;/* Encryption? */ bool encrypt;
@@ -59,7 +58,9 @@ static void virtio_crypto_dataq_sym_callback {struct virtio_crypto_sym_request *vc_sym_req = container_of(vc_req, struct virtio_crypto_sym_request, base); -struct skcipher_request *ablk_req; +struct skcipher_request *ablk_req = + container_of((void *)vc_sym_req, struct skcipher_request, + __ctx);int error;/* Finish the encrypt or decrypt process */
@@ -79,7 +80,6 @@ static void virtio_crypto_dataq_sym_callback error = -EIO ;break ; } - ablk_req = vc_sym_req->skcipher_req;virtio_crypto_skcipher_finalize_req (vc_sym_req, ablk_req, error); }
@@ -483,7 +483,6 @@ static int virtio_crypto_skcipher_encrypt(struct skcipher_request *req) vc_req->dataq = data_vq; vc_req->alg_cb = virtio_crypto_dataq_sym_callback; - vc_sym_req->skcipher_req = req; vc_sym_req->encrypt = true;return crypto_transfer_skcipher_request_to_engine (data_vq->engine, req);
@@ -507,7 +506,6 @@ static int virtio_crypto_skcipher_decrypt(struct skcipher_request *req) vc_req->dataq = data_vq; vc_req->alg_cb = virtio_crypto_dataq_sym_callback; - vc_sym_req->skcipher_req = req; vc_sym_req->encrypt = false;return crypto_transfer_skcipher_request_to_engine (data_vq->engine, req);
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1353/1887 crypto: virtio - bound the akcipher result length
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Bryam Vargas <[email protected]>
[ Upstream commit f77a956f6a19f9463ef1527c9d0cda50dded6b92 ]
virtio_crypto_dataq_akcipher_callback() sets the result length from the device-reported response length without bounding it to the destination buffer, which was allocated for the original request length. sg_copy_from_buffer() then reads that many bytes from the destination buffer; a backend reporting a larger length over-reads adjacent kernel heap into the caller's scatterlist (an out-of-bounds read).
Clamp the reported length to the originally requested destination length. A conforming device reports no more than that, so valid results are unaffected.
Message-ID: <[email protected]>
--- drivers/crypto/virtio/virtio_crypto_akcipher_algs.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-)
drivers/crypto/virtio/virtio_crypto_akcipher_algs.c +2 -1
@@ -89,7 +89,8 @@ static void virtio_crypto_dataq_akcipher_callback(struct virtio_crypto_request * }/* actual length may be less than dst buffer */ - akcipher_req->dst_len = len -sizeof (vc_req->status); + akcipher_req->dst_len = min_t(unsigned int, len - sizeof(vc_req->status), + akcipher_req->dst_len);sg_copy_from_buffer (akcipher_req->dst,sg_nents (akcipher_req->dst), vc_akcipher_req->dst_buf, akcipher_req->dst_len);virtio_crypto_akcipher_finalize_req (vc_akcipher_req, akcipher_req, error);
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1354/1887 netfilter: nf_tables: dont queue packet path object notifications
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Fourie Zhang <[email protected]>
[ Upstream commit 7904b94768e983bcb2be34a8d6d1f3450f5b838b ]
All file:line references below are against v7.2-rc4 (ac5b0e5651b1). The trace was captured on 7.2.0-rc6-kasan72rc6 (075b74841bd0), where the same lines apply.
nft_obj_notify() is exported and reached from the packet path. Its only in-tree caller is nft_quota_obj_eval() (net/netfilter/nft_quota.c:68), which notifies with GFP_ATOMIC while evaluating a rule for a transiting packet, holding no mutex.
Since commit 67cc570edaa0 ("netfilter: nf_tables: coalesce multiple notifications into one skbuff") that notification is no longer sent immediately. __nft_obj_notify() queues it onto nft_net->notify_list via nft_notify_enqueue() (net/netfilter/nf_tables_api.c:1211), which is a bare list_add_tail(). notify_list has no lock of its own (include/net/netfilter/nf_tables.h:1951), it is serialised by commit_mutex:
the six other enqueue sites all run inside a netlink transaction, and the drain in nft_commit_notify() (net/netfilter/nf_tables_api.c:10746) does list_del() + kfree_skb() from nf_tables_commit() with commit_mutex held.
Sending packets through a chain that references a depleted quota object therefore races an unlocked list_add_tail() against list_del() + kfree_skb() on another CPU. The WRITE_ONCE(prev->next, new) in __list_add() then stores through an sk_buff that has already been freed:
BUG: KASAN: slab-use-after-free in __nft_obj_notify+0x2c5/0x2d0
Write of size 8 at addr ff110001047183c0 by task poc/76
CPU: 0 UID: 1000 PID: 76 Comm: poc Tainted: G W 7.2.0-rc6-kasan72rc6 #4
Call Trace:
<IRQ>
__nft_obj_notify (include/linux/list.h:164 include/linux/list.h:191
net/netfilter/nf_tables_api.c:1211
net/netfilter/nf_tables_api.c:8743)
nft_quota_obj_eval (net/netfilter/nft_quota.c:68)
nft_do_chain_inet
nf_hook_slow
__ip_local_out
ip_push_pending_frames
udp_send_skb
udp_sendmsg
__x64_sys_sendto
Allocated by task 77:
__alloc_skb (net/core/skbuff.c:704)
__nft_obj_notify (include/net/netlink.h:1055
net/netfilter/nf_tables_api.c:8731)
nft_quota_obj_eval (net/netfilter/nft_quota.c:68)
nft_do_chain
Freed by task 79:
nf_tables_commit (include/linux/skbuff.h:1332
net/netfilter/nf_tables_api.c:10759
net/netfilter/nf_tables_api.c:11185)
nfnetlink_rcv_batch (net/netfilter/nfnetlink.c:574)
netlink_unicast
netlink_sendmsg
The buggy address belongs to the cache skbuff_head_cache of size 232Queueing from the packet path is wrong even leaving the race aside:notify_list is only drained by nft_commit_notify() from nf_tables_commit() (:11185), so a notification enqueued outside a transaction is not sent until some later netlink batch commits, if one ever does.
The gfp argument that nft_obj_notify() still takes is a leftover of the pre-67cc570edaa0 behaviour, where this path called nfnetlink_send() directly. Restore that: split the message construction out into nft_obj_notify_alloc() and let each caller decide what to do with the skb. nft_obj_notify(), the exported one reached from the packet path, sends it straight away; nf_tables_obj_notify(), which runs under commit_mutex, keeps queueing it, so transaction notifications are still coalesced.
--- net/netfilter/nf_tables_api.c | 36 ++++++++++++++++++++++------------- 1 file changed, 23 insertions(+), 13 deletions(-)
net/netfilter/nf_tables_api.c +23 -13
@@ -7831,18 +7831,17 @@ static int nf_tables_delobj(struct sk_buff *skb, const struct nfnl_info *info,return nft_delobj (&ctx, obj); } -static void -__nft_obj_notify (struct net *net,const struct nft_table *table, -struct nft_object *obj,u32 portid,u32 seq,int event, -u16 flags,int family,int report,gfp_t gfp) +static struct sk_buff * +nft_obj_notify_alloc (struct net *net,const struct nft_table *table, +struct nft_object *obj,u32 portid,u32 seq,int event, +u16 flags,int family,int report,gfp_t gfp) { -struct nftables_pernet *nft_net =nft_pernet (net);struct sk_buff *skb;int err;if (!report && !nfnetlink_has_listeners (net,NFNLGRP_NFTABLES )) -return ; +return NULL ; skb =nlmsg_new (NLMSG_GOODSIZE , gfp);if (skb ==NULL )
@@ -7856,10 +7855,10 @@ __nft_obj_notify(struct net *net, const struct nft_table *table, goto err; } -nft_notify_enqueue (skb, report, &nft_net->notify_list); -return ; +return skb; err:nfnetlink_set_err (net, portid,NFNLGRP_NFTABLES , -ENOBUFS ); +return NULL ; } void nft_obj_notify(struct net *net, const struct nft_table *table,
@@ -7869,6 +7868,7 @@ void nft_obj_notify(struct net *net, const struct nft_table *table,struct nftables_pernet *nft_net =nft_pernet (net);char *buf =kasprintf (gfp,"%s:%u" , table->name, nft_net->base_seq); +struct sk_buff *skb; audit_log_nfcfg(buf, family,
@@ -7879,17 +7879,27 @@ void nft_obj_notify(struct net *net, const struct nft_table *table, gfp);kfree (buf); -__nft_obj_notify (net, table, obj, portid, seq, event, - flags, family, report, gfp); +/* Called from the packet path, holding no mutex: notify_list is +* serialised by commit_mutex, so send this notification directly. +*/ + skb =nft_obj_notify_alloc (net, table, obj, portid, seq, event, + flags, family, report, gfp); +if (skb) +nfnetlink_send (skb, net, portid,NFNLGRP_NFTABLES , report, gfp); }EXPORT_SYMBOL_GPL (nft_obj_notify);static void nf_tables_obj_notify (const struct nft_ctx *ctx,struct nft_object *obj,int event) { -__nft_obj_notify (ctx->net, ctx->table, obj, ctx->portid, - ctx->seq, event, ctx->flags, ctx->family, - ctx->report,GFP_KERNEL ); +struct nftables_pernet *nft_net =nft_pernet (ctx->net); +struct sk_buff *skb; + + skb =nft_obj_notify_alloc (ctx->net, ctx->table, obj, ctx->portid, + ctx->seq, event, ctx->flags, ctx->family, + ctx->report,GFP_KERNEL ); +if (skb) +nft_notify_enqueue (skb, ctx->report, &nft_net->notify_list); }/*
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1355/1887 net/packet: defer vmalloc TX_RING free until skbs finish
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Kyle Zeng <[email protected]>
[ Upstream commit 992cc9f94ca924089a506ba9b327caa9af797529 ]
AF_PACKET TX_RING skbs keep a raw pointer to their ring frame. The skb page references preserve page-backed ring blocks after pg_vec is freed, but they do not preserve a vmalloc mapping.
tpacket_destruct_skb() currently drops the pending reference before writing the timestamp and TP_STATUS_AVAILABLE to the frame. Move the decrement after those stores. The smp_wmb() in __packet_set_status() orders the frame stores before the decrement.
Also recheck pending TX frames under pg_vec_lock before non-closing ring replacement, so a racing send cannot add a pending skb between the initial check and the ring swap.
Ring allocation can produce a mixture of page-backed and vmalloc-backed blocks. Allocate deferred-work storage during TX ring setup when the first vmalloc-backed block is encountered, and keep its pointer in the pg_vec allocation header. If allocation fails, return -ENOMEM from ring setup. On socket close, a non-NULL pointer identifies a vmalloc-backed vector without a scan. If TX skbs remain, defer the whole vector to system_long_wq.
After pg_vec is detached, a late destructor can skip the pending decrement. Use socket write-memory accounting as the deferred lifetime gate instead: an skb remains charged through its final sock_wfree(), after all ring-frame accesses. The delayed work retains a socket reference and reschedules itself until no TX skbs remain.
Move pending_refcnt release to packet_sock_destruct() so late skb destructors and deferred cleanup can safely use it after packet_release(). Page-backed teardown remains synchronous, and no lock is added to the TX completion hot path.
--- net/packet/af_packet.c | 97 ++++++++++++++++++++++++++++++++++++++---- 1 file changed, 88 insertions(+), 9 deletions(-)
net/packet/af_packet.c +88 -9
@@ -87,6 +87,7 @@#include <linux/errqueue.h> #include <linux/net_tstamp.h> #include <linux/percpu.h> +#include <linux/workqueue.h> #ifdef CONFIG_INET #include <net/inet_common.h> #endif
@@ -1396,6 +1397,8 @@ static void packet_sock_destruct(struct sock *sk)WARN_ON (atomic_read (&sk->sk_rmem_alloc));WARN_ON (refcount_read (&sk->sk_wmem_alloc)); +packet_free_pending (pkt_sk (sk)); +if (!sock_flag (sk,SOCK_DEAD )) {pr_err ("Attempt to release alive packet socket: %p\n" , sk);return ;
@@ -2598,11 +2601,11 @@ static void tpacket_destruct_skb(struct sk_buff *skb)__u32 ts; ph =skb_zcopy_get_nouarg (skb); -packet_dec_pending (&po->tx_ring); ts =__packet_set_timestamp (po, ph, skb);__packet_set_status (po, ph,TP_STATUS_AVAILABLE | ts); +packet_dec_pending (&po->tx_ring);complete (&po->skb_completion); }
@@ -3266,7 +3269,6 @@ static int packet_release(struct socket *sock)/* Purge queues */ skb_queue_purge (&sk->sk_receive_queue); -packet_free_pending (po);sk_refcnt_debug_release (sk);sock_put (sk);
@@ -4402,11 +4404,26 @@ static const struct vm_operations_struct packet_mmap_ops = { .close = packet_mm_close, }; +struct packet_pg_vec { +struct packet_pg_vec_free *deferred; +unsigned int order; +unsigned int len; +struct pgv pg_vec[]; +}; + +struct packet_pg_vec_free { +struct delayed_work work; +struct sock *sk; +struct packet_pg_vec *vec; +}; +static void free_pg_vec (struct pgv *pg_vec,unsigned int order,unsigned int len) { +struct packet_pg_vec *vec;int i; + vec = container_of_const(pg_vec, struct packet_pg_vec, pg_vec[0]);for (i =0 ; i < len; i++) {if (likely (pg_vec[i].buffer)) {if (is_vmalloc_addr (pg_vec[i].buffer))
@@ -4417,7 +4434,46 @@ static void free_pg_vec(struct pgv *pg_vec, unsigned int order, pg_vec[i].buffer =NULL ; } } -kfree (pg_vec); +kfree (vec->deferred); +kfree (vec); +} + +static void packet_free_pg_vec_work (struct work_struct *work) +{ +struct packet_pg_vec_free *deferred; +struct packet_pg_vec *vec; +struct sock *sk; + + deferred =container_of_const (to_delayed_work (work), + struct packet_pg_vec_free, work); + vec = deferred->vec; + sk = deferred->sk; +if (sk_wmem_alloc_get (sk)) { +queue_delayed_work (system_long_wq, &deferred->work,1 ); +return ; + } + +free_pg_vec (vec->pg_vec, vec->order, vec->len); +sock_put (sk); +} + +static void packet_free_tx_ring (struct sock *sk,struct pgv *pg_vec, +unsigned int order,unsigned int len) +{ +struct packet_pg_vec_free *deferred; +struct packet_pg_vec *vec; + + vec = container_of_const(pg_vec, struct packet_pg_vec, pg_vec[0]); + deferred = vec->deferred; +if (!deferred || !sk_wmem_alloc_get (sk)) { +free_pg_vec (pg_vec, order, len); +return ; + } + +/* A detached ring's pending count can miss late skb destructors. */ + deferred->sk = sk; +sock_hold (sk); +queue_delayed_work (system_long_wq, &deferred->work,0 ); }static char *alloc_one_pg_vec_page (unsigned long order)
@@ -4445,20 +4501,36 @@ static char *alloc_one_pg_vec_page(unsigned long order)return NULL ; } -static struct pgv *alloc_pg_vec (struct tpacket_req *req,int order) +static struct pgv *alloc_pg_vec (struct tpacket_req *req,int order,bool tx_ring) {unsigned int block_nr = req->tp_block_nr; +struct packet_pg_vec *vec;struct pgv *pg_vec;int i; - pg_vec =kcalloc (block_nr,sizeof (struct pgv ),GFP_KERNEL | __GFP_NOWARN); -if (unlikely (!pg_vec)) - goto out; + vec =kzalloc (struct_size (vec, pg_vec, block_nr), +GFP_KERNEL | __GFP_NOWARN); +if (unlikely (!vec)) +return NULL ; + vec->order = order; + vec->len = block_nr; + pg_vec = vec->pg_vec;for (i =0 ; i < block_nr; i++) { pg_vec[i].buffer =alloc_one_pg_vec_page (order);if (unlikely (!pg_vec[i].buffer)) goto out_free_pgvec; + +if (tx_ring && !vec->deferred && +is_vmalloc_addr (pg_vec[i].buffer)) { + vec->deferred =kzalloc (sizeof (*vec->deferred), +GFP_KERNEL | __GFP_NOWARN); +if (!vec->deferred) + goto out_free_pgvec; + vec->deferred->vec = vec; +INIT_DELAYED_WORK (&vec->deferred->work, + packet_free_pg_vec_work); + } } out:
@@ -4541,7 +4613,7 @@ static int packet_set_ring(struct sock *sk, union tpacket_req_u *req_u, err = -ENOMEM ; order =get_order (req->tp_block_size); - pg_vec =alloc_pg_vec (req, order); + pg_vec =alloc_pg_vec (req, order, tx_ring);if (unlikely (!pg_vec)) goto out;switch (po->tp_version) {
@@ -4593,6 +4665,9 @@ static int packet_set_ring(struct sock *sk, union tpacket_req_u *req_u, err = -EBUSY ;mutex_lock (&po->pg_vec_lock);if (closing ||atomic_long_read (&po->mapped) ==0 ) { +if (tx_ring && !closing &&packet_read_pending (rb)) + goto out_unlock; + err =0 ;spin_lock_bh (&rb_queue->lock);swap (rb->pg_vec, pg_vec);
@@ -4614,6 +4689,7 @@ static int packet_set_ring(struct sock *sk, union tpacket_req_u *req_u,pr_err ("packet_mmap: vma is busy: %ld\n" ,atomic_long_read (&po->mapped)); } +out_unlock:mutex_unlock (&po->pg_vec_lock);spin_lock (&po->bind_lock);
@@ -4635,7 +4711,10 @@ static int packet_set_ring(struct sock *sk, union tpacket_req_u *req_u, out_free_pg_vec:if (pg_vec) {bitmap_free (rx_owner_map); -free_pg_vec (pg_vec, order, req->tp_block_nr); +if (tx_ring && closing) +packet_free_tx_ring (sk, pg_vec, order, req->tp_block_nr); +else +free_pg_vec (pg_vec, order, req->tp_block_nr); } out:return err;
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1356/1887 tcp: clamp route advmss to TCP_MIN_MSS
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Yong Wang <[email protected]>
[ Upstream commit 870a9e42ecc6fe1b8c25d87af043cb0d9c178fe1 ]
tcp_select_initial_window() assumes that callers never pass an MSS smaller than 1, but route-derived advmss values can violate that assumption.
A too-small explicit RTAX_ADVMSS is one way to get there, but it is not the only one. The same divide-by-zero can also be reached through the "default advmss" path when RTAX_ADVMSS is left at 0 and the effective advmss is later driven down by route MTU and min_adv_mss.
Introduce a tcp_dst_advmss() helper that clamps route advmss to TCP_MIN_MSS before TCP consumes it, and use it in the TCP paths that derive advmss from dst metrics. This keeps the effective MSS from dropping to zero before tcp_select_initial_window() rounds the receive window.
--- include/net/tcp.h | 5 +++++ net/ipv4/tcp_ipv4.c | 2 +- net/ipv4/tcp_minisocks.c | 2 +- net/ipv4/tcp_output.c | 6 +++--- net/ipv6/tcp_ipv6.c | 2 +- 5 files changed, 11 insertions(+), 6 deletions(-)
include/net/tcp.h +5 -0
@@ -1483,6 +1483,11 @@ static inline int tcp_full_space(const struct sock *sk)return tcp_win_from_space (sk,READ_ONCE (sk->sk_rcvbuf)); } +static inline u32 tcp_dst_advmss (const struct dst_entry *dst) +{ +return max_t (u32,dst_metric_advmss (dst),TCP_MIN_MSS ); +} +static inline void __tcp_adjust_rcv_ssthresh (struct sock *sk,u32 new_ssthresh) {int unused_mem =sk_unused_reserved_mem (sk);
net/ipv4/tcp_ipv4.c +1 -1
@@ -1572,7 +1572,7 @@ struct sock *tcp_v4_syn_recv_sock(const struct sock *sk, struct sk_buff *skb,tcp_ca_openreq_child (newsk, dst);tcp_sync_mss (newsk,dst_mtu (dst)); - newtp->advmss =tcp_mss_clamp (tcp_sk (sk),dst_metric_advmss (dst)); + newtp->advmss =tcp_mss_clamp (tcp_sk (sk),tcp_dst_advmss (dst));tcp_initialize_rcv_mss (newsk);
net/ipv4/tcp_minisocks.c +1 -1
@@ -378,7 +378,7 @@ void tcp_openreq_init_rwin(struct request_sock *req,u32 rcv_wnd;int mss; - mss =tcp_mss_clamp (tp,dst_metric_advmss (dst)); + mss =tcp_mss_clamp (tp,tcp_dst_advmss (dst)); window_clamp =READ_ONCE (tp->window_clamp);/* Set this up on the first call only */ req->rsk_window_clamp = window_clamp ? :dst_metric (dst,RTAX_WINDOW );
net/ipv4/tcp_output.c +3 -3
@@ -125,7 +125,7 @@ static __u16 tcp_advertise_mss(struct sock *sk)int mss = tp->advmss;if (dst) { -unsigned int metric =dst_metric_advmss (dst); +unsigned int metric =tcp_dst_advmss (dst);if (metric < mss) { mss = metric;
@@ -3639,7 +3639,7 @@ struct sk_buff *tcp_make_synack(const struct sock *sk, struct dst_entry *dst, }skb_dst_set (skb, dst); - mss =tcp_mss_clamp (tp,dst_metric_advmss (dst)); + mss =tcp_mss_clamp (tp,tcp_dst_advmss (dst));memset (&opts,0 ,sizeof (opts)); now =tcp_clock_ns ();
@@ -3756,7 +3756,7 @@ static void tcp_connect_init(struct sock *sk)if (!tp->window_clamp) tp->window_clamp =dst_metric (dst,RTAX_WINDOW ); - tp->advmss =tcp_mss_clamp (tp,dst_metric_advmss (dst)); + tp->advmss =tcp_mss_clamp (tp,tcp_dst_advmss (dst));tcp_initialize_rcv_mss (sk);
net/ipv6/tcp_ipv6.c +1 -1
@@ -1335,7 +1335,7 @@ static struct sock *tcp_v6_syn_recv_sock(const struct sock *sk, struct sk_buff *tcp_ca_openreq_child (newsk, dst);tcp_sync_mss (newsk,dst_mtu (dst)); - newtp->advmss =tcp_mss_clamp (tcp_sk (sk),dst_metric_advmss (dst)); + newtp->advmss =tcp_mss_clamp (tcp_sk (sk),tcp_dst_advmss (dst));tcp_initialize_rcv_mss (newsk);
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1357/1887 RDMA/rxe: Fix responder UAF on IB_QP_MAX_DEST_RD_ATOMIC modify_qp
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Ibrahim Hashimov <[email protected]>
[ Upstream commit 6f7014237405e7f032b5c53a82d9eccf6161c291 ]
rxe_qp_from_attr() handles IB_QP_MAX_DEST_RD_ATOMIC outside the IB_QP_STATE path, so it holds no state_lock and runs while the responder task rxe_receiver() (recv_task on rxe_wq) is live. A modify_qp() setting only that attribute calls free_rd_atomic_resources() then alloc_rd_atomic_resources(), swapping qp->resp.resources[] while rxe_prepare_res()/find_resource() walk it; free_rd_atomic_resources() also leaves the cached pointer qp->resp.res dangling. A local unprivileged user can race the free/realloc into a use-after-free in rxe_receiver() (local DoS).
Drain recv_task around the swap with rxe_disable_task()/rxe_enable_task(), as rxe_qp_reset() already does when tearing this array down, re-enabling only after alloc_rd_atomic_resources() succeeds so the responder never resumes against a NULL qp->resp.resources on the ENOMEM path. Also clear qp->resp.res in free_rd_atomic_resources(), like the rxe_resp.c completion paths.
Reproduced under KASAN; the slab-use-after-free in rxe_receiver() is gone.
--- drivers/infiniband/sw/rxe/rxe_qp.c | 9 +++++++++ 1 file changed, 9 insertions(+)
drivers/infiniband/sw/rxe/rxe_qp.c +9 -0
@@ -124,6 +124,7 @@ static void free_rd_atomic_resources(struct rxe_qp *qp) }kfree (qp->resp.resources); qp->resp.resources =NULL ; + qp->resp.res =NULL ; } }
@@ -583,10 +584,18 @@ int rxe_qp_from_attr(struct rxe_qp *qp, struct ib_qp_attr *attr, int mask,int max_dest_rd_atomic = attr->max_dest_rd_atomic ?roundup_pow_of_two (attr->max_dest_rd_atomic) :0 ; +/* +* Not gated by IB_QP_STATE, so the responder task is live. +* Quiesce resp.task like rxe_qp_reset() before swapping the +* rd_atomic array, so rxe_responder() cannot race the free/ +* realloc. +*/ +rxe_disable_task (&qp->resp.task);free_rd_atomic_resources (qp); qp->attr.max_dest_rd_atomic = max_dest_rd_atomic; err =alloc_rd_atomic_resources (qp, max_dest_rd_atomic); +rxe_enable_task (&qp->resp.task);if (err)return err; }
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1358/1887 tipc: avoid busy looping in tipc_exit_net()
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Eric Dumazet <[email protected]>
[ Upstream commit c1481c94e74c955e0448ddf46b8615a44d840c1e ]
Blamed commit introduced a busy-wait loop in tipc_exit_net() to wait for pending UDP bearer cleanup works to complete:
while (atomic_read(&tn->wq_count))
cond_resched();This loop can busy-wait for a long time if cond_resched() is a NOP. This typically happens if the netns exit is executed by a high priority task, or under kernels configured without preemption (CONFIG_PREEMPT_NONE). In such cases, it wastes CPU cycles and can lead to soft lockups.
Fix this by replacing the busy loop with wait_var_event(), allowing the thread to sleep properly until the work queue count reaches zero.
Accordingly, update cleanup_bearer() to use atomic_dec_and_test() and wake_up_var() to wake up the waiter when the count drops to zero.
This uses the global wait queue hash table, avoiding the need to bloat struct tipc_net with a wait_queue_head_t. The atomic_dec_and_test() provides the necessary memory barrier to ensure the wakeup is not missed.
--- net/tipc/core.c | 4 ++-- net/tipc/udp_media.c | 4 +++- 2 files changed, 5 insertions(+), 3 deletions(-)
net/tipc/core.c +2 -2
@@ -45,6 +45,7 @@#include "crypto.h" #include <linux/module.h> +#include <linux/wait_bit.h> /* configurable TIPC parameters */ unsigned int tipc_net_id__read_mostly ;
@@ -118,8 +119,7 @@ static void __net_exit tipc_exit_net(struct net *net)#ifdef CONFIG_TIPC_CRYPTO tipc_crypto_stop (&tipc_net (net)->crypto_tx);#endif -while (atomic_read (&tn->wq_count)) -cond_resched (); +wait_var_event (&tn->wq_count,atomic_read (&tn->wq_count) ==0 ); } static void __net_exit tipc_pernet_pre_exit(struct net *net)
net/tipc/udp_media.c +3 -1
@@ -40,6 +40,7 @@#include <linux/igmp.h> #include <linux/kernel.h> #include <linux/workqueue.h> +#include <linux/wait_bit.h> #include <linux/list.h> #include <net/sock.h> #include <net/ip.h>
@@ -831,7 +832,8 @@ static void cleanup_bearer(struct work_struct *work)synchronize_net ();dst_cache_destroy (&ub->rcast.dst_cache); -atomic_dec (&tn->wq_count); +if (atomic_dec_and_test (&tn->wq_count)) +wake_up_var (&tn->wq_count);kfree (ub); }
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1359/1887 NTB: core: Add .get_dma_dev() callback to ntb_dev_ops
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Koichiro Den <[email protected]>
[ Upstream commit 362a4549f2acfb03390ddfcd91041e65a11a739f ]
Some NTB implementations are backed by a PCI function that is not the right struct device to use with DMA API helpers (e.g. due to IOMMU topology, or because the NTB device is virtual).
Add an optional .get_dma_dev() callback to struct ntb_dev_ops and provide a helper, ntb_get_dma_dev(), so NTB clients can use the appropriate struct device for DMA allocations and mappings.
If the callback is not implemented, ntb_get_dma_dev() returns the current default (ntb->dev.parent). Drivers that implement .get_dma_dev() must return a non-NULL device.
Stable-dep-of: da6d997ac556 ("ntb: Store original DMA address for future release")
--- include/linux/ntb.h | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+)
include/linux/ntb.h +24 -0
@@ -256,6 +256,7 @@ static inline int ntb_ctx_ops_is_valid(const struct ntb_ctx_ops *ops)* @msg_clear_mask: See ntb_msg_clear_mask(). * @msg_read: See ntb_msg_read(). * @peer_msg_write: See ntb_peer_msg_write(). +* @get_dma_dev: See ntb_get_dma_dev(). */ struct ntb_dev_ops {int (*port_number)(struct ntb_dev *ntb);
@@ -329,6 +330,7 @@ struct ntb_dev_ops {int (*msg_clear_mask)(struct ntb_dev *ntb,u64 mask_bits);u32 (*msg_read)(struct ntb_dev *ntb,int *pidx,int midx);int (*peer_msg_write)(struct ntb_dev *ntb,int pidx,int midx,u32 msg); +struct device *(*get_dma_dev)(struct ntb_dev *ntb); };static inline int ntb_dev_ops_is_valid (const struct ntb_dev_ops *ops)
@@ -391,6 +393,8 @@ static inline int ntb_dev_ops_is_valid(const struct ntb_dev_ops *ops)/* !ops->msg_clear_mask == !ops->msg_count && */ !ops->msg_read == !ops->msg_count && !ops->peer_msg_write == !ops->msg_count && + +/* ops->get_dma_dev is optional */ 1 ; }
@@ -1563,6 +1567,26 @@ static inline int ntb_peer_msg_write(struct ntb_dev *ntb, int pidx, int midx,return ntb->ops->peer_msg_write (ntb, pidx, midx, msg); } +/** +* ntb_get_dma_dev() - get the device to use for DMA allocations/mappings +* @ntb: NTB device context. +* +* Return a struct device suitable for DMA API allocations and mappings. +* This is typically the parent of the NTB device, but may be overridden by a +* driver by implementing .get_dma_dev(). +* +* Drivers that implement .get_dma_dev() must return a non-NULL pointer. +* +* Return: device pointer to use for DMA operations. +*/ +static inline struct device *ntb_get_dma_dev (struct ntb_dev *ntb) +{ +if (!ntb->ops->get_dma_dev) +return ntb->dev.parent; + +return ntb->ops->get_dma_dev (ntb); +} +/** * ntb_peer_resource_idx() - get a resource index for a given peer idx * @ntb: NTB device context.
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1360/1887 NTB: ntb_transport: Use ntb_get_dma_dev() for DMA buffers
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Koichiro Den <[email protected]>
[ Upstream commit 852b94ff92cbe26a0dbb15eed9474f5493767f3b ]
ntb_transport currently uses ndev->pdev->dev for coherent allocations and frees.
Switch the coherent buffer allocation/free paths to use ntb_get_dma_dev(), so ntb_transport can work with NTB implementations where the NTB PCI function is not the right device to use for DMA mappings.
Stable-dep-of: da6d997ac556 ("ntb: Store original DMA address for future release")
--- drivers/ntb/ntb_transport.c | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-)
drivers/ntb/ntb_transport.c +7 -7
@@ -791,13 +791,13 @@ static void ntb_transport_msi_desc_changed(void *data)static void ntb_free_mw (struct ntb_transport_ctx *nt,int num_mw) {struct ntb_transport_mw *mw = &nt->mw_vec[num_mw]; -struct pci_dev *pdev = nt->ndev->pdev; +struct device *dma_dev =ntb_get_dma_dev (nt->ndev);if (!mw->virt_addr)return ;ntb_mw_clear_trans (nt->ndev,PIDX , num_mw); -dma_free_coherent (&pdev->dev, mw->alloc_size, +dma_free_coherent (dma_dev, mw->alloc_size, mw->alloc_addr, mw->dma_addr); mw->xlat_size =0 ; mw->buff_size =0 ;
@@ -867,7 +867,7 @@ static int ntb_set_mw(struct ntb_transport_ctx *nt, int num_mw, resource_size_t size) {struct ntb_transport_mw *mw = &nt->mw_vec[num_mw]; -struct pci_dev *pdev = nt->ndev->pdev; +struct device *dma_dev =ntb_get_dma_dev (nt->ndev);size_t xlat_size, buff_size;resource_size_t xlat_align;resource_size_t xlat_align_size;
@@ -896,12 +896,12 @@ static int ntb_set_mw(struct ntb_transport_ctx *nt, int num_mw, mw->buff_size = buff_size; mw->alloc_size = buff_size; - rc =ntb_alloc_mw_buffer (mw, &pdev->dev, xlat_align); + rc =ntb_alloc_mw_buffer (mw, dma_dev, xlat_align);if (rc) { mw->alloc_size *=2 ; - rc =ntb_alloc_mw_buffer (mw, &pdev->dev, xlat_align); + rc =ntb_alloc_mw_buffer (mw, dma_dev, xlat_align);if (rc) { -dev_err (&pdev->dev, +dev_err (dma_dev,"Unable to alloc aligned MW buff\n" ); mw->xlat_size =0 ; mw->buff_size =0 ;
@@ -914,7 +914,7 @@ static int ntb_set_mw(struct ntb_transport_ctx *nt, int num_mw, rc =ntb_mw_set_trans (nt->ndev,PIDX , num_mw, mw->dma_addr, mw->xlat_size);if (rc) { -dev_err (&pdev->dev,"Unable to set mw%d translation" , num_mw); +dev_err (dma_dev,"Unable to set mw%d translation" , num_mw);ntb_free_mw (nt, num_mw);return -EIO ; }
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1361/1887 ntb: Store original DMA address for future release
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Leon Romanovsky <[email protected]>
[ Upstream commit da6d997ac556479c112554ab5d95cbd04683eb11 ]
The DMA API requires that dma_free_attrs receive the exact dma_handle originally returned by the allocation function. Do not modify it.
--- drivers/ntb/ntb_transport.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-)
drivers/ntb/ntb_transport.c +3 -1
@@ -211,6 +211,7 @@ struct ntb_transport_mw {void *alloc_addr;void *virt_addr;dma_addr_t dma_addr; +dma_addr_t original_dma_addr; };struct ntb_transport_client_dev {
@@ -798,7 +799,7 @@ static void ntb_free_mw(struct ntb_transport_ctx *nt, int num_mw)ntb_mw_clear_trans (nt->ndev,PIDX , num_mw);dma_free_coherent (dma_dev, mw->alloc_size, - mw->alloc_addr, mw->dma_addr); + mw->alloc_addr, mw->original_dma_addr); mw->xlat_size =0 ; mw->buff_size =0 ; mw->alloc_size =0 ;
@@ -834,6 +835,7 @@ static int ntb_alloc_mw_buffer(struct ntb_transport_mw *mw,return -ENOMEM ; } virt_addr = alloc_addr; + mw->original_dma_addr = dma_addr;/* * we must ensure that the memory address allocated is BAR size
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1362/1887 tap: Keep hdr_len in tap_get_user()
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Akihiko Odaki <[email protected]>
[ Upstream commit 74212f20f366db41dd3148b951284ac38ef9bb10 ]
hdr_len is repeatedly used so keep it in a local variable.
Stable-dep-of: cbb35cbe8db2 ("net: tap: fix wrong transport_header when sending VLAN-tagged frame")
--- drivers/net/tap.c | 28 ++++++++++------------------ 1 file changed, 10 insertions(+), 18 deletions(-)
drivers/net/tap.c +10 -18
@@ -638,6 +638,7 @@ static ssize_t tap_get_user(struct tap_queue *q, void *msg_control,int err;struct virtio_net_hdr vnet_hdr = {0 };int vnet_hdr_len =0 ; +int hdr_len =0 ;int copylen =0 ;int depth;bool zerocopy = false;
@@ -656,13 +657,13 @@ static ssize_t tap_get_user(struct tap_queue *q, void *msg_control,if (!copy_from_iter_full (&vnet_hdr,sizeof (vnet_hdr), from)) goto err;iov_iter_advance (from, vnet_hdr_len -sizeof (vnet_hdr)); -if ((vnet_hdr.flags &VIRTIO_NET_HDR_F_NEEDS_CSUM ) && -tap16_to_cpu (q, vnet_hdr.csum_start) + -tap16_to_cpu (q, vnet_hdr.csum_offset) +2 > -tap16_to_cpu (q, vnet_hdr.hdr_len)) - vnet_hdr.hdr_len =cpu_to_tap16 (q, -tap16_to_cpu (q, vnet_hdr.csum_start) + -tap16_to_cpu (q, vnet_hdr.csum_offset) +2 ); + hdr_len =tap16_to_cpu (q, vnet_hdr.hdr_len); +if (vnet_hdr.flags &VIRTIO_NET_HDR_F_NEEDS_CSUM ) { + hdr_len =max (tap16_to_cpu (q, vnet_hdr.csum_start) + +tap16_to_cpu (q, vnet_hdr.csum_offset) +2 , + hdr_len); + vnet_hdr.hdr_len =cpu_to_tap16 (q, hdr_len); + } err = -EINVAL ;if (tap16_to_cpu (q, vnet_hdr.hdr_len) > len) goto err;
@@ -675,12 +676,7 @@ static ssize_t tap_get_user(struct tap_queue *q, void *msg_control,if (msg_control &&sock_flag (&q->sk,SOCK_ZEROCOPY )) {struct iov_iter i; - copylen = vnet_hdr.hdr_len ? -tap16_to_cpu (q, vnet_hdr.hdr_len) :GOODCOPY_LEN ; -if (copylen > good_linear) - copylen = good_linear; -else if (copylen <ETH_HLEN ) - copylen =ETH_HLEN ; + copylen =clamp (hdr_len ?:GOODCOPY_LEN ,ETH_HLEN , good_linear); linear = copylen; i = *from;iov_iter_advance (&i, copylen);
@@ -690,11 +686,7 @@ static ssize_t tap_get_user(struct tap_queue *q, void *msg_control,if (!zerocopy) { copylen = len; - linear =tap16_to_cpu (q, vnet_hdr.hdr_len); -if (linear > good_linear) - linear = good_linear; -else if (linear <ETH_HLEN ) - linear =ETH_HLEN ; + linear =clamp (hdr_len,ETH_HLEN , good_linear); } skb = tap_alloc_skb(&q->sk, TAP_RESERVE, copylen,
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1363/1887 net: tap: fix wrong transport_header when sending VLAN-tagged frame
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Wei Fang <[email protected]>
[ Upstream commit cbb35cbe8db268fefe34c23df15348cf99025298 ]
In tap_get_user_xdp(), when processing a VLAN-tagged frame (e.g. ETH_P_8021Q), skb_set_network_header() is called first to advance network_header past the VLAN tag to the inner protocol header. skb_probe_transport_header() is then called with skb->protocol still set to ETH_P_8021Q, while nhoff (derived from skb_network_offset()) already points past the VLAN tag to the inner protocol header.
In __skb_flow_dissect(), proto is initialized to ETH_P_8021Q and nhoff points past the VLAN tag. When the dissector hits case ETH_P_8021Q, it reads a struct vlan_hdr at the current nhoff via __skb_header_pointer(), but that offset contains the inner protocol header (e.g. an IP header). The bytes are misinterpreted as a VLAN header, yielding a garbage encapsulated EtherType that matches no known protocol. The dissector returns false, so skb_probe_transport_header() never calls skb_set_transport_header(), leaving transport_header at its uninitialized sentinel value (~0U).
Move skb_set_network_header() to after skb_probe_transport_header(). At the time skb_probe_transport_header() is called, network_header still points to the VLAN header (offset ETH_HLEN), so nhoff is correct and the flow dissector can parse the VLAN header, extract the inner EtherType, and advance nhoff to the inner protocol header, allowing transport_header to be set correctly.
--- drivers/net/tap.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-)
drivers/net/tap.c +2 -1
@@ -1188,12 +1188,13 @@ static int tap_get_user_xdp(struct tap_queue *q, struct xdp_buff *xdp) } } +skb_probe_transport_header (skb); +/* Move network header to the right position for VLAN tagged packets */ if (eth_type_vlan (skb->protocol) &&vlan_get_protocol_and_depth (skb, skb->protocol, &depth) !=0 )skb_set_network_header (skb, depth); -skb_probe_transport_header (skb);dev_queue_xmit (skb);rcu_read_unlock ();
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1364/1887 drm/amd/amdgpu: Fix errors & warnings in amdgpu _uvd, _vce.c
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Srinivasan Shanmugam <[email protected]>
[ Upstream commit f10984a353c87e696872de8f9614a58689deb0d0 ]
Fix below checkpatch errors & warnings:
In amdgpu_uvd.c:
WARNING: Prefer 'unsigned int' to bare use of 'unsigned'
WARNING: Prefer 'unsigned int *' to bare use of 'unsigned *'
WARNING: Missing a blank line after declarations
WARNING: %Lx is non-standard C, use %llx
ERROR: space required before the open parenthesis '('
ERROR: space required before the open brace '{'
WARNING: %LX is non-standard C, use %llX
WARNING: Block comments use * on subsequent lines
+/* multiple fence commands without any stream commands in between can
+ crash the vcpu so just try to emmit a dummy create/destroy msg to
WARNING: Block comments use a trailing */ on a separate line
+ avoid this */
WARNING: braces {} are not necessary for single statement blocks
+ for (j = 0; j < adev->uvd.num_enc_rings; ++j) {
+ fences += amdgpu_fence_count_emitted(&adev->uvd.inst[i].ring_enc[j]);
+ }
In amdgpu_vce.c:
WARNING: Prefer 'unsigned int' to bare use of 'unsigned'
WARNING: Missing a blank line after declarations
WARNING: %Lx is non-standard C, use %llx
WARNING: Possible repeated word: 'we'
ERROR: space required before the open parenthesis '('
Stable-dep-of: 21a8084cd762 ("drm/amdgpu: Fix UVD dpb min size calculation for H264")
--- drivers/gpu/drm/amd/amdgpu/amdgpu_uvd.c | 83 +++++++++++++------------ drivers/gpu/drm/amd/amdgpu/amdgpu_vce.c | 39 ++++++------ 2 files changed, 63 insertions(+), 59 deletions(-)
drivers/gpu/drm/amd/amdgpu/amdgpu_uvd.c +43 -40
@@ -96,16 +96,16 @@*/ struct amdgpu_uvd_cs_ctx {struct amdgpu_cs_parser *parser; -unsigned reg, count; -unsigned data0, data1; -unsigned idx; +unsigned int reg, count; +unsigned int data0, data1; +unsigned int idx;struct amdgpu_ib *ib;/* does the IB has a msg command */ bool has_msg_cmd;/* minimum buffer sizes */ -unsigned *buf_sizes; +unsigned int *buf_sizes; };#ifdef CONFIG_DRM_AMDGPU_SI
@@ -186,7 +186,7 @@ int amdgpu_uvd_sw_init(struct amdgpu_device *adev)unsigned long bo_size;const char *fw_name;const struct common_firmware_header *hdr; -unsigned family_id; +unsigned int family_id;int i, j, r;INIT_DELAYED_WORK (&adev->uvd.idle_work, amdgpu_uvd_idle_work_handler);
@@ -283,7 +283,7 @@ int amdgpu_uvd_sw_init(struct amdgpu_device *adev) family_id =le32_to_cpu (hdr->ucode_version) &0xff ;if (adev->asic_type <CHIP_VEGA20 ) { -unsigned version_major, version_minor; +unsigned int version_major, version_minor; version_major = (le32_to_cpu (hdr->ucode_version) >>24 ) &0xff ; version_minor = (le32_to_cpu (hdr->ucode_version) >>8 ) &0xff ;
@@ -425,7 +425,7 @@ int amdgpu_uvd_entity_init(struct amdgpu_device *adev)int amdgpu_uvd_suspend (struct amdgpu_device *adev) { -unsigned size; +unsigned int size;void *ptr;int i, j, idx;bool in_ras_intr =amdgpu_ras_intr_triggered ();
@@ -474,7 +474,7 @@ int amdgpu_uvd_suspend(struct amdgpu_device *adev)int amdgpu_uvd_resume (struct amdgpu_device *adev) { -unsigned size; +unsigned int size;void *ptr;int i, idx;
@@ -496,7 +496,7 @@ int amdgpu_uvd_resume(struct amdgpu_device *adev) adev->uvd.inst[i].saved_bo =NULL ; }else {const struct common_firmware_header *hdr; -unsigned offset; +unsigned int offset; hdr = (const struct common_firmware_header *)adev->uvd.fw->data;if (adev->firmware.load_type !=AMDGPU_FW_LOAD_PSP ) {
@@ -547,6 +547,7 @@ void amdgpu_uvd_free_handles(struct amdgpu_device *adev, struct drm_file *filp)static void amdgpu_uvd_force_into_uvd_segment (struct amdgpu_bo *abo) {int i; +for (i =0 ; i < abo->placement.num_placement; ++i) { abo->placements[i].fpfn =0 >>PAGE_SHIFT ; abo->placements[i].lpfn = (256 *1024 *1024 ) >>PAGE_SHIFT ;
@@ -584,7 +585,7 @@ static int amdgpu_uvd_cs_pass1(struct amdgpu_uvd_cs_ctx *ctx) r =amdgpu_cs_find_mapping (ctx->parser, addr, &bo, &mapping);if (r) { -DRM_ERROR ("Can't find BO for addr 0x%08Lx\n" , addr); +DRM_ERROR ("Can't find BO for addr 0x%08llx\n" , addr);return r; }
@@ -594,6 +595,7 @@ static int amdgpu_uvd_cs_pass1(struct amdgpu_uvd_cs_ctx *ctx)if (cmd ==0x0 || cmd ==0x3 ) {/* yes, force it into VRAM */ uint32_t domain =AMDGPU_GEM_DOMAIN_VRAM ; +amdgpu_bo_placement_from_domain (bo, domain); }amdgpu_uvd_force_into_uvd_segment (bo);
@@ -614,21 +616,21 @@ static int amdgpu_uvd_cs_pass1(struct amdgpu_uvd_cs_ctx *ctx)* Peek into the decode message and calculate the necessary buffer sizes. */ static int amdgpu_uvd_cs_msg_decode (struct amdgpu_device *adev,uint32_t *msg, -unsigned buf_sizes[]) +unsigned int buf_sizes[]) { -unsigned stream_type = msg[4 ]; -unsigned width = msg[6 ]; -unsigned height = msg[7 ]; -unsigned dpb_size = msg[9 ]; -unsigned pitch = msg[28 ]; -unsigned level = msg[57 ]; +unsigned int stream_type = msg[4 ]; +unsigned int width = msg[6 ]; +unsigned int height = msg[7 ]; +unsigned int dpb_size = msg[9 ]; +unsigned int pitch = msg[28 ]; +unsigned int level = msg[57 ]; -unsigned width_in_mb = width /16 ; -unsigned height_in_mb =ALIGN (height /16 ,2 ); -unsigned fs_in_mb = width_in_mb * height_in_mb; +unsigned int width_in_mb = width /16 ; +unsigned int height_in_mb =ALIGN (height /16 ,2 ); +unsigned int fs_in_mb = width_in_mb * height_in_mb; -unsigned image_size, tmp, min_dpb_size, num_dpb_buffer; -unsigned min_ctx_size = ~0 ; +unsigned int image_size, tmp, min_dpb_size, num_dpb_buffer; +unsigned int min_ctx_size = ~0 ;/* Reject invalid dimensions */ if (width <16 || height <16 || width >4096 || height >4096 ) {
@@ -644,7 +646,7 @@ static int amdgpu_uvd_cs_msg_decode(struct amdgpu_device *adev, uint32_t *msg,switch (stream_type) {case 0 :/* H264 */ -switch (level) { +switch (level) {case 30 : num_dpb_buffer =8100 / fs_in_mb;break ;
@@ -722,7 +724,7 @@ static int amdgpu_uvd_cs_msg_decode(struct amdgpu_device *adev, uint32_t *msg,break ;case 7 :/* H264 Perf */ -switch (level) { +switch (level) {case 30 : num_dpb_buffer =8100 / fs_in_mb;break ;
@@ -755,7 +757,7 @@ static int amdgpu_uvd_cs_msg_decode(struct amdgpu_device *adev, uint32_t *msg,/* reference picture buffer */ min_dpb_size = image_size * num_dpb_buffer; -if (!adev->uvd.use_ctx_buf){ +if (!adev->uvd.use_ctx_buf) {/* macroblock context buffer */ min_dpb_size += width_in_mb * height_in_mb * num_dpb_buffer *192 ;
@@ -821,7 +823,7 @@ static int amdgpu_uvd_cs_msg_decode(struct amdgpu_device *adev, uint32_t *msg,* Make sure that we don't open up to many sessions. */ static int amdgpu_uvd_cs_msg (struct amdgpu_uvd_cs_ctx *ctx, -struct amdgpu_bo *bo,unsigned offset) +struct amdgpu_bo *bo,unsigned int offset) {struct amdgpu_device *adev = ctx->parser->adev;int32_t *msg, msg_type, handle;
@@ -927,7 +929,7 @@ static int amdgpu_uvd_cs_pass2(struct amdgpu_uvd_cs_ctx *ctx) r =amdgpu_cs_find_mapping (ctx->parser, addr, &bo, &mapping);if (r) { -DRM_ERROR ("Can't find BO for addr 0x%08Lx\n" , addr); +DRM_ERROR ("Can't find BO for addr 0x%08llx\n" , addr);return r; }
@@ -946,7 +948,7 @@ static int amdgpu_uvd_cs_pass2(struct amdgpu_uvd_cs_ctx *ctx)if (cmd <0x4 ) {if ((end - start) < ctx->buf_sizes[cmd]) {DRM_ERROR ("buffer (%d) to small (%d / %d)!\n" , cmd, - (unsigned )(end - start), + (unsigned int )(end - start), ctx->buf_sizes[cmd]);return -EINVAL ; }
@@ -954,7 +956,7 @@ static int amdgpu_uvd_cs_pass2(struct amdgpu_uvd_cs_ctx *ctx) }else if (cmd ==0x206 ) {if ((end - start) < ctx->buf_sizes[4 ]) {DRM_ERROR ("buffer (%d) to small (%d / %d)!\n" , cmd, - (unsigned )(end - start), + (unsigned int )(end - start), ctx->buf_sizes[4 ]);return -EINVAL ; }
@@ -965,14 +967,14 @@ static int amdgpu_uvd_cs_pass2(struct amdgpu_uvd_cs_ctx *ctx)if (!ctx->parser->adev->uvd.address_64_bit) {if ((start >>28 ) != ((end -1 ) >>28 )) { -DRM_ERROR ("reloc %LX-%LX crossing 256MB boundary!\n" , +DRM_ERROR ("reloc %llx-%llx crossing 256MB boundary!\n" , start, end);return -EINVAL ; }if ((cmd ==0 || cmd ==0x3 ) && (start >>28 ) != (ctx->parser->adev->uvd.inst->gpu_addr >>28 )) { -DRM_ERROR ("msg/fb buffer %LX-%LX out of 256MB segment!\n" , +DRM_ERROR ("msg/fb buffer %llx-%llx out of 256MB segment!\n" , start, end);return -EINVAL ; }
@@ -1006,7 +1008,7 @@ static int amdgpu_uvd_cs_reg(struct amdgpu_uvd_cs_ctx *ctx, ctx->idx++;for (i =0 ; i <= ctx->count; ++i) { -unsigned reg = ctx->reg + i; +unsigned int reg = ctx->reg + i;if (ctx->idx >= ctx->ib->length_dw) {DRM_ERROR ("Register command after end of CS!\n" );
@@ -1052,7 +1054,8 @@ static int amdgpu_uvd_cs_packets(struct amdgpu_uvd_cs_ctx *ctx,for (ctx->idx =0 ; ctx->idx < ctx->ib->length_dw; ) {uint32_t cmd =amdgpu_ib_get_value (ctx->ib, ctx->idx); -unsigned type =CP_PACKET_GET_TYPE (cmd); +unsigned int type =CP_PACKET_GET_TYPE (cmd); +switch (type) {case PACKET_TYPE0 : ctx->reg =CP_PACKET0_GET_REG (cmd);
@@ -1086,7 +1089,7 @@ int amdgpu_uvd_ring_parse_cs(struct amdgpu_cs_parser *parser, struct amdgpu_ib *ib) {struct amdgpu_uvd_cs_ctx ctx = {}; -unsigned buf_sizes[] = { +unsigned int buf_sizes[] = { [0x00000000 ] =2048 , [0x00000001 ] =0xFFFFFFFF , [0x00000002 ] =0xFFFFFFFF ,
@@ -1213,8 +1216,9 @@ static int amdgpu_uvd_send_msg(struct amdgpu_ring *ring, struct amdgpu_bo *bo, }/* multiple fence commands without any stream commands in between can -crash the vcpu so just try to emmit a dummy create/destroy msg to -avoid this */ +* crash the vcpu so just try to emmit a dummy create/destroy msg to +* avoid this +*/ int amdgpu_uvd_get_create_msg (struct amdgpu_ring *ring,uint32_t handle,struct dma_fence **fence) {
@@ -1280,15 +1284,14 @@ static void amdgpu_uvd_idle_work_handler(struct work_struct *work) {struct amdgpu_device *adev = container_of(work, struct amdgpu_device, uvd.idle_work.work); -unsigned fences =0 , i, j; +unsigned int fences =0 , i, j;for (i =0 ; i < adev->uvd.num_uvd_inst; ++i) {if (adev->uvd.harvest_config & (1 << i))continue ; fences +=amdgpu_fence_count_emitted (&adev->uvd.inst[i].ring); -for (j =0 ; j < adev->uvd.num_enc_rings; ++j) { +for (j =0 ; j < adev->uvd.num_enc_rings; ++j) fences +=amdgpu_fence_count_emitted (&adev->uvd.inst[i].ring_enc[j]); - } }if (fences ==0 ) {
@@ -1384,7 +1387,7 @@ int amdgpu_uvd_ring_test_ib(struct amdgpu_ring *ring, long timeout)*/ uint32_t amdgpu_uvd_used_handles (struct amdgpu_device *adev) { -unsigned i; +unsigned int i;uint32_t used_handles =0 ;for (i =0 ; i < adev->uvd.max_handles; ++i) {
drivers/gpu/drm/amd/amdgpu/amdgpu_vce.c +20 -19
@@ -99,7 +99,7 @@ int amdgpu_vce_sw_init(struct amdgpu_device *adev, unsigned long size) {const char *fw_name;const struct common_firmware_header *hdr; -unsigned ucode_version, version_major, version_minor, binary_id; +unsigned int ucode_version, version_major, version_minor, binary_id;int i, r;switch (adev->asic_type) {
@@ -213,7 +213,7 @@ int amdgpu_vce_sw_init(struct amdgpu_device *adev, unsigned long size)*/ int amdgpu_vce_sw_fini (struct amdgpu_device *adev) { -unsigned i; +unsigned int i;if (adev->vce.vcpu_bo ==NULL )return 0 ;
@@ -292,7 +292,7 @@ int amdgpu_vce_resume(struct amdgpu_device *adev) {void *cpu_addr;const struct common_firmware_header *hdr; -unsigned offset; +unsigned int offset;int r, idx;if (adev->vce.vcpu_bo ==NULL )
@@ -338,7 +338,7 @@ static void amdgpu_vce_idle_work_handler(struct work_struct *work) {struct amdgpu_device *adev = container_of(work, struct amdgpu_device, vce.idle_work.work); -unsigned i, count =0 ; +unsigned int i, count =0 ;for (i =0 ; i < adev->vce.num_rings; i++) count +=amdgpu_fence_count_emitted (&adev->vce.ring[i]);
@@ -415,6 +415,7 @@ void amdgpu_vce_free_handles(struct amdgpu_device *adev, struct drm_file *filp) {struct amdgpu_ring *ring = &adev->vce.ring[0 ];int i, r; +for (i =0 ; i <AMDGPU_MAX_VCE_HANDLES ; ++i) {uint32_t handle =atomic_read (&adev->vce.handles[i]);
@@ -442,7 +443,7 @@ void amdgpu_vce_free_handles(struct amdgpu_device *adev, struct drm_file *filp)static int amdgpu_vce_get_create_msg (struct amdgpu_ring *ring,uint32_t handle,struct dma_fence **fence) { -const unsigned ib_size_dw =1024 ; +const unsigned int ib_size_dw =1024 ;struct amdgpu_job *job;struct amdgpu_ib *ib;struct amdgpu_ib ib_msg;
@@ -534,7 +535,7 @@ static int amdgpu_vce_get_create_msg(struct amdgpu_ring *ring, uint32_t handle,static int amdgpu_vce_get_destroy_msg (struct amdgpu_ring *ring,uint32_t handle,bool direct,struct dma_fence **fence) { -const unsigned ib_size_dw =1024 ; +const unsigned int ib_size_dw =1024 ;struct amdgpu_job *job;struct amdgpu_ib *ib;struct dma_fence *f =NULL ;
@@ -601,12 +602,12 @@ static int amdgpu_vce_get_destroy_msg(struct amdgpu_ring *ring, uint32_t handle,*/ static int amdgpu_vce_validate_bo (struct amdgpu_cs_parser *p,struct amdgpu_ib *ib,int lo,int hi, -unsigned size,int32_t index) +unsigned int size,int32_t index) {int64_t offset = ((uint64_t )size) * ((int64_t )index);struct ttm_operation_ctx ctx = { false, false };struct amdgpu_bo_va_mapping *mapping; -unsigned i, fpfn, lpfn; +unsigned int i, fpfn, lpfn;struct amdgpu_bo *bo;uint64_t addr;int r;
@@ -624,7 +625,7 @@ static int amdgpu_vce_validate_bo(struct amdgpu_cs_parser *p, r =amdgpu_cs_find_mapping (p, addr, &bo, &mapping);if (r) { -DRM_ERROR ("Can't find BO for addr 0x%010Lx %d %d %d %d\n" , +DRM_ERROR ("Can't find BO for addr 0x%010llx %d %d %d %d\n" , addr, lo, hi, size, index);return r; }
@@ -651,7 +652,7 @@ static int amdgpu_vce_validate_bo(struct amdgpu_cs_parser *p,* Patch relocation inside command stream with real buffer address */ static int amdgpu_vce_cs_reloc (struct amdgpu_cs_parser *p,struct amdgpu_ib *ib, -int lo,int hi,unsigned size,uint32_t index) +int lo,int hi,unsigned int size,uint32_t index) {struct amdgpu_bo_va_mapping *mapping;struct amdgpu_bo *bo;
@@ -670,14 +671,14 @@ static int amdgpu_vce_cs_reloc(struct amdgpu_cs_parser *p, struct amdgpu_ib *ib, r =amdgpu_cs_find_mapping (p, addr, &bo, &mapping);if (r) { -DRM_ERROR ("Can't find BO for addr 0x%010Lx %d %d %d %d\n" , +DRM_ERROR ("Can't find BO for addr 0x%010llx %d %d %d %d\n" , addr, lo, hi, size, index);return r; }if ((addr + (uint64_t )size) > (mapping->last +1 ) *AMDGPU_GPU_PAGE_SIZE ) { -DRM_ERROR ("BO too small for addr 0x%010Lx %d %d\n" , +DRM_ERROR ("BO too small for addr 0x%010llx %d %d\n" , addr, lo, hi);return -EINVAL ; }
@@ -700,12 +701,12 @@ static int amdgpu_vce_cs_reloc(struct amdgpu_cs_parser *p, struct amdgpu_ib *ib,* @allocated: allocated a new handle? * * Validates the handle and return the found session index or -EINVAL -* we we don't have another free session index. +* we don't have another free session index. */ static int amdgpu_vce_validate_handle (struct amdgpu_cs_parser *p,uint32_t handle,uint32_t *allocated) { -unsigned i; +unsigned int i;/* validate the handle */ for (i =0 ; i <AMDGPU_MAX_VCE_HANDLES ; ++i) {
@@ -743,7 +744,7 @@ int amdgpu_vce_ring_parse_cs(struct amdgpu_cs_parser *p,struct amdgpu_job *job, struct amdgpu_ib *ib) { - unsigned fb_idx = 0, bs_idx = 0; + unsigned int fb_idx = 0, bs_idx = 0;int session_idx =-1 ;uint32_t destroyed =0 ;uint32_t created =0 ;
@@ -751,7 +752,7 @@ int amdgpu_vce_ring_parse_cs(struct amdgpu_cs_parser *p,uint32_t tmp, handle =0 ;uint32_t dummy =0xffffffff ;uint32_t *size = &dummy; -unsigned idx; +unsigned int idx;int i, r =0 ; job->vm =NULL ;
@@ -1104,7 +1105,7 @@ void amdgpu_vce_ring_emit_ib(struct amdgpu_ring *ring,* */ void amdgpu_vce_ring_emit_fence (struct amdgpu_ring *ring,u64 addr,u64 seq, -unsigned flags) +unsigned int flags) {WARN_ON (flags &AMDGPU_FENCE_FLAG_64BIT );
@@ -1126,7 +1127,7 @@ int amdgpu_vce_ring_test_ring(struct amdgpu_ring *ring) {struct amdgpu_device *adev = ring->adev;uint32_t rptr; -unsigned i; +unsigned int i;int r, timeout = adev->usec_timeout;/* skip ring test for sriov*/
@@ -1191,7 +1192,7 @@ int amdgpu_vce_ring_test_ib(struct amdgpu_ring *ring, long timeout)enum amdgpu_ring_priority_level amdgpu_vce_get_ring_prio (int ring) { -switch (ring) { +switch (ring) {case 0 :return AMDGPU_RING_PRIO_0 ;case 1 :
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1365/1887 drm/amdgpu: Fix UVD dpb min size calculation for H264
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: David Rosca <[email protected]>
[ Upstream commit 21a8084cd76223a13493237e04d45f5226d7cee6 ]
This should use actual number of references from the decode message, instead of maximum derived from level.
--- drivers/gpu/drm/amd/amdgpu/amdgpu_uvd.c | 62 ++----------------------- 1 file changed, 4 insertions(+), 58 deletions(-)
drivers/gpu/drm/amd/amdgpu/amdgpu_uvd.c +4 -58
@@ -623,11 +623,9 @@ static int amdgpu_uvd_cs_msg_decode(struct amdgpu_device *adev, uint32_t *msg,unsigned int height = msg[7 ];unsigned int dpb_size = msg[9 ];unsigned int pitch = msg[28 ]; -unsigned int level = msg[57 ];unsigned int width_in_mb = width /16 ;unsigned int height_in_mb =ALIGN (height /16 ,2 ); -unsigned int fs_in_mb = width_in_mb * height_in_mb;unsigned int image_size, tmp, min_dpb_size, num_dpb_buffer;unsigned int min_ctx_size = ~0 ;
@@ -646,35 +644,9 @@ static int amdgpu_uvd_cs_msg_decode(struct amdgpu_device *adev, uint32_t *msg,switch (stream_type) {case 0 :/* H264 */ -switch (level) { -case 30 : - num_dpb_buffer =8100 / fs_in_mb; -break ; -case 31 : - num_dpb_buffer =18000 / fs_in_mb; -break ; -case 32 : - num_dpb_buffer =20480 / fs_in_mb; -break ; -case 41 : - num_dpb_buffer =32768 / fs_in_mb; -break ; -case 42 : - num_dpb_buffer =34816 / fs_in_mb; -break ; -case 50 : - num_dpb_buffer =110400 / fs_in_mb; -break ; -case 51 : - num_dpb_buffer =184320 / fs_in_mb; -break ; -default : - num_dpb_buffer =184320 / fs_in_mb; -break ; - } - num_dpb_buffer++; + num_dpb_buffer = ((msg[61 ] >>16 ) &0xff ) +1 ;if (num_dpb_buffer >17 ) - num_dpb_buffer =17 ; +return -EINVAL ;/* reference picture buffer */ min_dpb_size = image_size * num_dpb_buffer;
@@ -724,35 +696,9 @@ static int amdgpu_uvd_cs_msg_decode(struct amdgpu_device *adev, uint32_t *msg,break ;case 7 :/* H264 Perf */ -switch (level) { -case 30 : - num_dpb_buffer =8100 / fs_in_mb; -break ; -case 31 : - num_dpb_buffer =18000 / fs_in_mb; -break ; -case 32 : - num_dpb_buffer =20480 / fs_in_mb; -break ; -case 41 : - num_dpb_buffer =32768 / fs_in_mb; -break ; -case 42 : - num_dpb_buffer =34816 / fs_in_mb; -break ; -case 50 : - num_dpb_buffer =110400 / fs_in_mb; -break ; -case 51 : - num_dpb_buffer =184320 / fs_in_mb; -break ; -default : - num_dpb_buffer =184320 / fs_in_mb; -break ; - } - num_dpb_buffer++; + num_dpb_buffer = ((msg[61 ] >>16 ) &0xff ) +1 ;if (num_dpb_buffer >17 ) - num_dpb_buffer =17 ; +return -EINVAL ;/* reference picture buffer */ min_dpb_size = image_size * num_dpb_buffer;
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1366/1887 vlan: fix skb_under_panic and races when toggling HW VLAN offload
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Eric Dumazet <[email protected]>
[ Upstream commit 447cbe95ebb95392b5d8f6a01c0556826919ce23 ]
Toggling hardware VLAN TX offload (NETIF_F_HW_VLAN_CTAG_TX or NETIF_F_HW_VLAN_STAG_TX) on a lower device invokes vlan_transfer_features(), which dynamically changed vlandev->hard_header_len.
This causes two issues:
1. Lockless TX paths (e.g. packet_snd in af_packet.c, ip6_finish_output2) read dev->hard_header_len without holding RTNL lock. Mutating hard_header_len dynamically under RTNL creates a data race where upper layers reserve insufficient headroom based on a stale hard_header_len, resulting in skb_under_panic when vlan_dev_hard_header() is called.
2. In addition, vlan_transfer_features() updated hard_header_len without updating header_ops, causing a mismatch between allocated headroom and header creation.
Always setting dev->hard_header_len = real_dev->hard_header_len and dev->needed_headroom = real_dev->needed_headroom + VLAN_HLEN unconditionally ensures:
- dev->hard_header_len remains 100% static and immutable at real_dev->hard_header_len, eliminating all dynamic runtime updates and data races on hard_header_len.
- Upper layers allocating skbs via LL_RESERVED_SPACE() will always reserve sufficient headroom for software VLAN tag insertion (real_dev->hard_header_len + real_dev->needed_headroom + VLAN_HLEN).
- vlandev inherits real_dev->needed_tailroom so underlying trailer/padding/ICV requirements are honored.
- AF_PACKET SOCK_RAW network header offsets remain correctly aligned at real_dev->hard_header_len.
- vlan_header_ops is used unconditionally.
Note to stable teams: Make sure to backport these commits:
e16e960d55a4 ("ipvlan: inherit needed_headroom and needed_tailroom from phy_dev") cef51860becd ("macvlan: inherit needed_headroom and needed_tailroom from lowerdev")
--- net/8021q/vlan.c | 7 +++---- net/8021q/vlan_dev.c | 32 ++++---------------------------- 2 files changed, 7 insertions(+), 32 deletions(-)
net/8021q/vlan.c +3 -4
@@ -324,10 +324,9 @@ static void vlan_transfer_features(struct net_device *dev,netif_inherit_tso_max (vlandev, dev); -if (vlan_hw_offload_capable (dev->features, vlan->vlan_proto)) - vlandev->hard_header_len = dev->hard_header_len; -else - vlandev->hard_header_len = dev->hard_header_len +VLAN_HLEN ; + vlandev->needed_headroom = dev->needed_headroom +VLAN_HLEN ; + vlandev->needed_tailroom = dev->needed_tailroom; + vlandev->hard_header_len = dev->hard_header_len;#if IS_ENABLED (CONFIG_FCOE ) vlandev->fcoe_ddp_xid = dev->fcoe_ddp_xid;
net/8021q/vlan_dev.c +4 -28
@@ -505,26 +505,6 @@ static const struct header_ops vlan_header_ops = { .parse_protocol = vlan_parse_protocol, }; -static int vlan_passthru_hard_header (struct sk_buff *skb,struct net_device *dev, -unsigned short type, -const void *daddr,const void *saddr, -unsigned int len) -{ -struct vlan_dev_priv *vlan =vlan_dev_priv (dev); -struct net_device *real_dev = vlan->real_dev; - -if (saddr ==NULL ) - saddr = dev->dev_addr; - -return dev_hard_header (skb, real_dev, type, daddr, saddr, len); -} - -static const struct header_ops vlan_passthru_header_ops = { - .create = vlan_passthru_hard_header, - .parse = eth_header_parse, - .parse_protocol = vlan_parse_protocol, -}; -static struct device_type vlan_type = { .name ="vlan" , };
@@ -577,14 +557,10 @@ static int vlan_dev_init(struct net_device *dev) dev->fcoe_ddp_xid = real_dev->fcoe_ddp_xid;#endif - dev->needed_headroom = real_dev->needed_headroom; -if (vlan_hw_offload_capable (real_dev->features, vlan->vlan_proto)) { - dev->header_ops = &vlan_passthru_header_ops; - dev->hard_header_len = real_dev->hard_header_len; - }else { - dev->header_ops = &vlan_header_ops; - dev->hard_header_len = real_dev->hard_header_len +VLAN_HLEN ; - } + dev->needed_headroom = real_dev->needed_headroom +VLAN_HLEN ; + dev->needed_tailroom = real_dev->needed_tailroom; + dev->header_ops = &vlan_header_ops; + dev->hard_header_len = real_dev->hard_header_len; dev->netdev_ops = &vlan_netdev_ops;
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1367/1887 wifi: mt76: mt7915: set correct background radar capability
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: StanleyYP Wang <[email protected]>
[ Upstream commit 888208d1ccc41bebe97744445787183b17bb3ea4 ]
Some of the variants do not support background radar, so add a helper to report background radar capability.
For mt7916, only the variant of 5G 2T2R + 1R supports background radar.
Stable-dep-of: 44b5adfe4949 ("wifi: mt76: mt7915: bound the device EEPROM address before the EFUSE copy")
--- .../wireless/mediatek/mt76/mt7915/debugfs.c | 5 +++ .../wireless/mediatek/mt76/mt7915/eeprom.c | 33 ++++++++++++++++++- .../wireless/mediatek/mt76/mt7915/eeprom.h | 1 + .../net/wireless/mediatek/mt76/mt7915/init.c | 7 ++-- .../net/wireless/mediatek/mt76/mt7915/mcu.c | 8 +++-- .../wireless/mediatek/mt76/mt7915/mt7915.h | 3 +- 6 files changed, 49 insertions(+), 8 deletions(-)
drivers/net/wireless/mediatek/mt76/mt7915/debugfs.c +5 -0
@@ -452,6 +452,11 @@ mt7915_rdd_monitor(struct seq_file *s, void *data)mutex_lock (&dev->mt76.mutex); +if (!mt7915_eeprom_has_background_radar (dev)) { +seq_puts (s,"no background radar capability\n" ); + goto out; + } +if (!cfg80211_chandef_valid (chandef)) { ret = -EINVAL ; goto out;
drivers/net/wireless/mediatek/mt76/mt7915/eeprom.c +32 -1
@@ -123,7 +123,7 @@ static int mt7915_eeprom_load(struct mt7915_dev *dev)/* read eeprom data from efuse */ block_num =DIV_ROUND_UP (eeprom_size, eeprom_blk_size);for (i =0 ; i < block_num; i++) { - ret =mt7915_mcu_get_eeprom (dev, i * eeprom_blk_size); + ret =mt7915_mcu_get_eeprom (dev, i * eeprom_blk_size,NULL );if (ret <0 )return ret; }
@@ -326,6 +326,37 @@ s8 mt7915_eeprom_get_power_delta(struct mt7915_dev *dev, int band)return val &MT_EE_RATE_DELTA_SIGN ? delta : -delta; } +bool +mt7915_eeprom_has_background_radar (struct mt7915_dev *dev) +{ +u8 val, buf[MT7915_EEPROM_BLOCK_SIZE ]; +u8 band_sel, tx_path, rx_path; +int offs =MT_EE_WIFI_CONF +1 ; + +switch (mt76_chip (&dev->mt76)) { +case 0x7915 : +return true; +case 0x7906 : +/* read efuse to check background radar capability */ +if (mt7915_mcu_get_eeprom (dev, offs, buf)) +break ; + + val = buf[offs %MT7915_EEPROM_BLOCK_SIZE ]; + band_sel =u8_get_bits (val,MT_EE_WIFI_CONF0_BAND_SEL ); + tx_path =u8_get_bits (val,MT_EE_WIFI_CONF0_TX_PATH ); + rx_path =u8_get_bits (val,MT_EE_WIFI_CONF0_RX_PATH ); + +return (band_sel ==MT_EE_V2_BAND_SEL_5GHZ && + tx_path == rx_path && rx_path ==2 ); +case 0x7981 : +case 0x7986 : +default : +break ; + } + +return false; +} +const u8 mt7915_sku_group_len[] = { [SKU_CCK ] =4 , [SKU_OFDM ] =8 ,
drivers/net/wireless/mediatek/mt76/mt7915/eeprom.h +1 -0
@@ -45,6 +45,7 @@ enum mt7915_eeprom_field {#define MT_EE_CAL_DPD_SIZE (54 * MT_EE_CAL_UNIT)#define MT_EE_WIFI_CONF0_TX_PATH GENMASK(2, 0) +#define MT_EE_WIFI_CONF0_RX_PATH GENMASK(5, 3)#define MT_EE_WIFI_CONF0_BAND_SEL GENMASK(7, 6)#define MT_EE_WIFI_CONF1_BAND_SEL GENMASK(7, 6)#define MT_EE_WIFI_CONF_STREAM_NUM GENMASK(7, 5)
drivers/net/wireless/mediatek/mt76/mt7915/init.c +4 -3
@@ -353,9 +353,10 @@ mt7915_init_wiphy(struct ieee80211_hw *hw)wiphy_ext_feature_set (wiphy,NL80211_EXT_FEATURE_UNSOL_BCAST_PROBE_RESP );wiphy_ext_feature_set (wiphy,NL80211_EXT_FEATURE_FILS_DISCOVERY ); -if (!mdev->dev->of_node || - !of_property_read_bool (mdev->dev->of_node, -"mediatek,disable-radar-background" )) +if (mt7915_eeprom_has_background_radar (phy->dev) && + (!mdev->dev->of_node || + !of_property_read_bool (mdev->dev->of_node, +"mediatek,disable-radar-background" )))wiphy_ext_feature_set (wiphy,NL80211_EXT_FEATURE_RADAR_BACKGROUND );
drivers/net/wireless/mediatek/mt76/mt7915/mcu.c +5 -3
@@ -2751,7 +2751,7 @@ int mt7915_mcu_set_eeprom(struct mt7915_dev *dev) &req, sizeof(req), true); } -int mt7915_mcu_get_eeprom(struct mt7915_dev *dev, u32 offset) +int mt7915_mcu_get_eeprom(struct mt7915_dev *dev, u32 offset, u8 *read_buf) { struct mt7915_mcu_eeprom_info req = { .addr = cpu_to_le32(round_down(offset,
@@ -2759,8 +2759,8 @@ int mt7915_mcu_get_eeprom(struct mt7915_dev *dev, u32 offset) };struct mt7915_mcu_eeprom_info *res;struct sk_buff *skb; +u8 *buf = read_buf;int ret; -u8 *buf; ret = mt76_mcu_send_and_get_msg(&dev->mt76, MCU_EXT_QUERY(EFUSE_ACCESS),
@@ -2769,8 +2769,10 @@ int mt7915_mcu_get_eeprom(struct mt7915_dev *dev, u32 offset)return ret; res = (struct mt7915_mcu_eeprom_info *)skb->data; - buf = dev->mt76.eeprom.data +le32_to_cpu (res->addr); +if (!buf) + buf = dev->mt76.eeprom.data +le32_to_cpu (res->addr);memcpy (buf, res->data,MT7915_EEPROM_BLOCK_SIZE ); +dev_kfree_skb (skb);return 0 ;
drivers/net/wireless/mediatek/mt76/mt7915/mt7915.h +2 -1
@@ -465,6 +465,7 @@ int mt7915_eeprom_get_target_power(struct mt7915_dev *dev,struct ieee80211_channel *chan, u8 chain_idx);s8 mt7915_eeprom_get_power_delta (struct mt7915_dev *dev,int band); +bool mt7915_eeprom_has_background_radar (struct mt7915_dev *dev);int mt7915_dma_init (struct mt7915_dev *dev,struct mt7915_phy *phy2);void mt7915_dma_prefetch (struct mt7915_dev *dev);void mt7915_dma_cleanup (struct mt7915_dev *dev);
@@ -511,7 +512,7 @@ int mt7915_mcu_set_fixed_rate_ctrl(struct mt7915_dev *dev,struct ieee80211_sta *sta, void *data, u32 field);int mt7915_mcu_set_eeprom (struct mt7915_dev *dev); -int mt7915_mcu_get_eeprom (struct mt7915_dev *dev,u32 offset); +int mt7915_mcu_get_eeprom (struct mt7915_dev *dev,u32 offset,u8 *read_buf);int mt7915_mcu_get_eeprom_free_block (struct mt7915_dev *dev,u8 *block_num);int mt7915_mcu_set_mac (struct mt7915_dev *dev,int band,bool enable,bool hdr_trans);
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1368/1887 wifi: mt76: mt7915: bound the device EEPROM address before the EFUSE copy
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Bryam Vargas <[email protected]>
[ Upstream commit 44b5adfe49499f53002737f5fe81d608c08122fc ]
mt7915_mcu_get_eeprom() copies a fixed EFUSE block into the driver's dev->mt76.eeprom.data buffer at the offset reported by the MCU response (res->addr, a device-controlled __le32) without checking it against the buffer size. A malicious or malfunctioning device can report an arbitrary address and drive a 16-byte out-of-bounds write past eeprom.data.
Reject a response whose address would place the copy outside eeprom.data before deriving the destination pointer. Devices that echo the requested in-bounds offset are unaffected.
--- drivers/net/wireless/mediatek/mt76/mt7915/mcu.c | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-)
drivers/net/wireless/mediatek/mt76/mt7915/mcu.c +9 -2
@@ -2769,8 +2769,15 @@ int mt7915_mcu_get_eeprom(struct mt7915_dev *dev, u32 offset, u8 *read_buf)return ret; res = (struct mt7915_mcu_eeprom_info *)skb->data; -if (!buf) - buf = dev->mt76.eeprom.data +le32_to_cpu (res->addr); +if (!buf) { +u32 addr =le32_to_cpu (res->addr); + +if (addr > dev->mt76.eeprom.size -MT7915_EEPROM_BLOCK_SIZE ) { +dev_kfree_skb (skb); +return -EINVAL ; + } + buf = dev->mt76.eeprom.data + addr; + }memcpy (buf, res->data,MT7915_EEPROM_BLOCK_SIZE );dev_kfree_skb (skb);
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1369/1887 wifi: iwlwifi: dvm: fix memory leak in iwl_op_mode_dvm_start()
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Dawei Feng <[email protected]>
[ Upstream commit 67105abd6195a685a84dcb8a5daf54a1f4bfdb60 ]
In iwl_op_mode_dvm_start(), jumping to out_free_eeprom currently bypasses the out_free_eeprom_blob label. Consequently, error paths triggered after successfully parsing the EEPROM free priv->nvm_data but leak priv->eeprom_blob.
Fix this memory leak by reordering the error handling labels so that out_free_eeprom falls through to out_free_eeprom_blob.
The bug was first flagged by an experimental analysis tool we are developing for kernel memory-management bugs while analyzing v6.13-rc1. The tool is still under development and is not yet publicly available. Manual inspection confirms that the bug is still present in v7.1-rc6.
An x86_64 allyesconfig build showed no new warnings. As we do not have supported Intel DVM wireless hardware and firmware to test with, no runtime testing was able to be performed.
--- drivers/net/wireless/intel/iwlwifi/dvm/main.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-)
drivers/net/wireless/intel/iwlwifi/dvm/main.c +2 -2
@@ -1502,10 +1502,10 @@ static struct iwl_op_mode *iwl_op_mode_dvm_start(struct iwl_trans *trans, priv->workqueue =NULL ; out_uninit_drv:iwl_uninit_drv (priv); -out_free_eeprom_blob: -kfree (priv->eeprom_blob); out_free_eeprom:kfree (priv->nvm_data); +out_free_eeprom_blob: +kfree (priv->eeprom_blob); out_free_hw:ieee80211_free_hw (priv->hw); out:
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1370/1887 mfd: sm501: Remove #ifdef guards for PM related functions
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Paul Cercueil <[email protected]>
[ Upstream commit 3833239b5ba22256389c2fd83ca70b6a9028435b ]
Use the new pm_sleep_ptr() macro to handle the .suspend/.resume callbacks.
This macro allow the suspend and resume functions to be automatically dropped by the compiler when CONFIG_SUSPEND is disabled, without having to use #ifdef guards.
This has the advantage of always compiling these functions in, independently of any Kconfig option. Thanks to that, bugs and other regressions are subsequently easier to catch.
Stable-dep-of: 83feedd9d83c ("mfd: sm501: Fix potential memory leaks during remove")
--- drivers/mfd/sm501.c | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-)
drivers/mfd/sm501.c +2 -8
@@ -1434,8 +1434,6 @@ static int sm501_plat_probe(struct platform_device *dev) } -#ifdef CONFIG_PM -/* power management support */ static void sm501_set_power (struct sm501_devdata *sm,int on)
@@ -1511,10 +1509,6 @@ static int sm501_plat_resume(struct platform_device *pdev)return 0 ; } -#else -#define sm501_plat_suspend NULL -#define sm501_plat_resume NULL -#endif /* Initialisation data for PCI devices */
@@ -1716,8 +1710,8 @@ static struct platform_driver sm501_plat_driver = { }, .probe = sm501_plat_probe, .remove = sm501_plat_remove, - .suspend = sm501_plat_suspend, - .resume = sm501_plat_resume, + .suspend = pm_sleep_ptr(sm501_plat_suspend), + .resume = pm_sleep_ptr(sm501_plat_resume), };static int __init sm501_base_init (void )
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1371/1887 mfd: sm501: Convert to platform remove callback returning void
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Uwe Kleine-König <[email protected]>
[ Upstream commit c20fddf7acfb54d856c34208926701d32c25eb18 ]
The .remove() callback for a platform driver returns an int which makes many driver authors wrongly assume it's possible to do error handling by returning an error code. However the value returned is ignored (apart from emitting a warning) and this typically results in resource leaks.
To improve here there is a quest to make the remove callback return void. In the first step of this quest all drivers are converted to .remove_new(), which already returns void. Eventually after all drivers are converted, .remove_new() will be renamed to .remove().
Trivially convert this driver from always returning zero in the remove callback to the void returning variant.
Stable-dep-of: 83feedd9d83c ("mfd: sm501: Fix potential memory leaks during remove")
--- drivers/mfd/sm501.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-)
drivers/mfd/sm501.c +2 -4
@@ -1669,7 +1669,7 @@ static void sm501_pci_remove(struct pci_dev *dev)pci_disable_device (dev); } -static int sm501_plat_remove (struct platform_device *dev) +static void sm501_plat_remove (struct platform_device *dev) {struct sm501_devdata *sm =platform_get_drvdata (dev);
@@ -1677,8 +1677,6 @@ static int sm501_plat_remove(struct platform_device *dev)iounmap (sm->regs);release_mem_region (sm->io_res->start,0x100 ); - -return 0 ; }static const struct pci_device_id sm501_pci_tbl[] = {
@@ -1709,7 +1707,7 @@ static struct platform_driver sm501_plat_driver = { .of_match_table = of_sm501_match_tbl, }, .probe = sm501_plat_probe, - .remove = sm501_plat_remove, + .remove_new = sm501_plat_remove, .suspend = pm_sleep_ptr(sm501_plat_suspend), .resume = pm_sleep_ptr(sm501_plat_resume), };
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1372/1887 mfd: sm501: Fix potential memory leaks during remove
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Abdun Nihaal <[email protected]>
[ Upstream commit 83feedd9d83c0c5199f98c72df0a6196b4aefb4d ]
The memory allocated for struct sm501_devdata in sm501_pci_probe() and sm501_plat_probe() is not freed by the corresponding remove functions sm501_pci_remove() and sm501_plat_remove(). Fix that by adding a call to kfree().
--- drivers/mfd/sm501.c | 2 ++ 1 file changed, 2 insertions(+)
drivers/mfd/sm501.c +2 -0
@@ -1667,6 +1667,7 @@ static void sm501_pci_remove(struct pci_dev *dev)release_mem_region (sm->io_res->start,0x100 );pci_disable_device (dev); +kfree (sm); }static void sm501_plat_remove (struct platform_device *dev)
@@ -1677,6 +1678,7 @@ static void sm501_plat_remove(struct platform_device *dev)iounmap (sm->regs);release_mem_region (sm->io_res->start,0x100 ); +kfree (sm); }static const struct pci_device_id sm501_pci_tbl[] = {
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1373/1887 net/smc: stop killed, freed and out_of_sync sharing a byte
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Hidayath Khan <[email protected]>
[ Upstream commit db51a8658c11a82432b64999519a269c3aabb447 ]
The three connection state flags are single-bit bitfields, so they occupy one byte of struct smc_connection and every store to one is a read-modify-write of the other two:
u8 killed : 1;
u8 freed : 1;
u8 out_of_sync : 1;They are not written under a common lock. smc_cdc_msg_validate() sets out_of_sync from the receive tasklet, while smc_conn_kill() sets killed from process context under lock_sock(), and the receive path does not defer to the backlog when the socket is owned -- smc_cdc_msg_recv() takes only bh_lock_sock().
Give each flag its own byte so a store no longer touches its neighbours. All readers test them as booleans and are unchanged. struct smc_connection grows by two bytes.
--- net/smc/smc.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-)
net/smc/smc.h +3 -3
@@ -233,9 +233,9 @@ struct smc_connection {* 0 for SMC-R, 32 for SMC-D */ u64 peer_token;/* SMC-D token of peer */ - u8 killed : 1; /* abnormal termination */ - u8 freed : 1; /* normal termiation */ - u8 out_of_sync : 1; /* out of sync with peer */ +u8 killed;/* abnormal termination */ +u8 freed;/* normal termiation */ +u8 out_of_sync;/* out of sync with peer */ };struct smc_sock {/* smc sock container */
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1374/1887 net: thunderbolt: Release the Rx HopID that was handed out on mismatch
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Fan Ye <[email protected]>
[ Upstream commit 2f1463554d0561a2fead81e3888604e5c1125e29 ]
tb_xdomain_alloc_in_hopid() passes the wanted HopID to ida_alloc_range() as the lower bound, so a taken id is not an error there: the allocator returns the next free one above it. tbnet_connected_work() asks for the peer's transmit path, treats any other id as a failure and returns without releasing what it got, so that allocation stays live for the rest of the XDomain connection with nothing left holding a reference to it.
Release the id when it is not the one we asked for, the same way the error unwind at the end of the function releases the expected one.
Stable-dep-of: 3c8b26ebf525 ("net: thunderbolt: Mark the connection down when bringing it up fails")
--- drivers/net/thunderbolt.c | 2 ++ 1 file changed, 2 insertions(+)
drivers/net/thunderbolt.c +2 -0
@@ -625,6 +625,8 @@ static void tbnet_connected_work(struct work_struct *work) ret =tb_xdomain_alloc_in_hopid (net->xd, net->remote_transmit_path);if (ret != net->remote_transmit_path) {netdev_err (net->dev,"failed to allocate Rx HopID\n" ); +if (ret >=0 ) +tb_xdomain_release_in_hopid (net->xd, ret);return ; }
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1375/1887 net: thunderbolt: Mark the connection down when bringing it up fails
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Fan Ye <[email protected]>
[ Upstream commit 3c8b26ebf525ba5960510f48c6e9936a79ebe76f ]
Every failure path in tbnet_connected_work() undoes its own work and returns without clearing login_sent, so the connection still looks established. The next tbnet_tear_down() therefore takes its main branch and repeats a teardown that already happened: it stops rings that are already stopped, which is a dev_WARN() and fatal under panic_on_warn, and it releases net->remote_transmit_path even on the HopID mismatch path, where this connection never owned that id, silently freeing one that someone else is still using.
Clear login_sent on those paths. That is enough for tbnet_tear_down() to leave the unwound state alone, and login_received has to stay set: it records that the peer has logged in and carries the transmit path it gave us, which nothing on this side can make the peer send again. Two things change beyond keeping the teardown out of the way: the logout request in that block is no longer sent, and the peer's next login request now re-queues our login work rather than connected_work, giving the connection a fresh login instead of a retry on stale state.
--- drivers/net/thunderbolt.c | 10 ++++++++++ 1 file changed, 10 insertions(+)
drivers/net/thunderbolt.c +10 -0
@@ -606,6 +606,14 @@ static int tbnet_alloc_tx_buffers(struct tbnet *net)return 0 ; } +static void tbnet_connect_failed (struct tbnet *net) +{ +/* Leave login_received set: only the peer can make it true again. */ +mutex_lock (&net->connection_lock); + net->login_sent = false; +mutex_unlock (&net->connection_lock); +} +static void tbnet_connected_work (struct work_struct *work) {struct tbnet *net =container_of (work,typeof (*net), connected_work);
@@ -627,6 +635,7 @@ static void tbnet_connected_work(struct work_struct *work)netdev_err (net->dev,"failed to allocate Rx HopID\n" );if (ret >=0 )tb_xdomain_release_in_hopid (net->xd, ret); +tbnet_connect_failed (net);return ; }
@@ -669,6 +678,7 @@ static void tbnet_connected_work(struct work_struct *work)tb_ring_stop (net->rx_ring.ring);tb_ring_stop (net->tx_ring.ring);tb_xdomain_release_in_hopid (net->xd, net->remote_transmit_path); +tbnet_connect_failed (net); }static void tbnet_login_work (struct work_struct *work)
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1376/1887 net: ravb: serialize PTP clock teardown
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Xuanqiang Luo <[email protected]>
[ Upstream commit 1cb9663789c5b7a12fcd419fcca6d6254c398252 ]
ravb_ptp_interrupt() can race with ravb_ptp_stop() and pass the clock to ptp_clock_event() while ptp_clock_unregister() is freeing it. This can lead to a use-after-free.
Use READ_ONCE() and WRITE_ONCE() for lockless access to the clock pointer. Atomically detach it with xchg() before disabling PTP interrupts, then synchronize all IRQs which can invoke ravb_ptp_interrupt() before unregistering the detached clock.
A handler which read the old pointer completes before the clock is unregistered, while later handlers read NULL and skip the event.
--- drivers/net/ethernet/renesas/ravb_ptp.c | 37 +++++++++++++++++++------ 1 file changed, 29 insertions(+), 8 deletions(-)
drivers/net/ethernet/renesas/ravb_ptp.c +29 -8
@@ -306,16 +306,17 @@ static const struct ptp_clock_info ravb_ptp_info = {void ravb_ptp_interrupt (struct net_device *ndev) {struct ravb_private *priv =netdev_priv (ndev); +struct ptp_clock *clock =READ_ONCE (priv->ptp.clock);u32 gis =ravb_read (ndev,GIS ); gis &=ravb_read (ndev,GIC ); -if (gis &GIS_PTCF ) { +if ((gis &GIS_PTCF ) && clock) {struct ptp_clock_event event; event.type =PTP_CLOCK_EXTTS ; event.index =0 ; event.timestamp =ravb_read (ndev,GCPT ); -ptp_clock_event (priv->ptp.clock, &event); +ptp_clock_event (clock, &event); }if (gis &GIS_PTMF ) {struct ravb_ptp_perout *perout = priv->ptp.perout;
@@ -351,19 +352,39 @@ void ravb_ptp_init(struct net_device *ndev, struct platform_device *pdev) clock =NULL ; } - priv->ptp.clock = clock; +WRITE_ONCE (priv->ptp.clock, clock);if (clock)WRITE_ONCE (priv->ptp.phc_index,ptp_clock_index (clock)); } -void ravb_ptp_stop (struct net_device *ndev) +static void ravb_ptp_disable (struct net_device *ndev) { -struct ravb_private *priv =netdev_priv (ndev); -ravb_write (ndev,0 ,GIC );ravb_write (ndev,0 ,GIS ); +} + +static void ravb_ptp_sync_irqs (struct net_device *ndev) +{ +struct ravb_private *priv =netdev_priv (ndev); + +synchronize_irq (ndev->irq); +if (priv->info->err_mgmt_irqs) { +synchronize_irq (priv->erra_irq); +synchronize_irq (priv->mgmta_irq); + } +} + +void ravb_ptp_stop (struct net_device *ndev) +{ +struct ravb_private *priv =netdev_priv (ndev); +struct ptp_clock *clock;WRITE_ONCE (priv->ptp.phc_index,-1 ); -if (priv->ptp.clock) -ptp_clock_unregister (priv->ptp.clock); + clock =xchg (&priv->ptp.clock,NULL ); + +ravb_ptp_disable (ndev); +ravb_ptp_sync_irqs (ndev); + +if (clock) +ptp_clock_unregister (clock); }
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1377/1887 net: l2tp: do not propagate multicast notification errors
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Zihan Xi <[email protected]>
[ Upstream commit af20e269f7459d2ce69887fdf2fad7caf986c865 ]
The tunnel create, tunnel modify, session create, and session modify netlink handlers send multicast notifications through helpers that can fail while allocating or encoding a message, or while multicasting it.
For tunnel and session create/modify, a notification is sent after the live operation has completed. Returning a best-effort notification error as the command result can therefore report failure for an operation that already committed and can cause callers to retry and accumulate live objects.
Keep sending notifications for listener visibility, but do not propagate their best-effort status as the command result. This also keeps the tunnel modify command consistent with the other notification-only paths.
--- net/l2tp/l2tp_netlink.c | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-)
net/l2tp/l2tp_netlink.c +8 -8
@@ -247,8 +247,8 @@ static int l2tp_nl_cmd_tunnel_create(struct sk_buff *skb, struct genl_info *infokfree (tunnel); goto out; } - ret =l2tp_tunnel_notify (&l2tp_nl_family, info, tunnel, -L2TP_CMD_TUNNEL_CREATE ); +l2tp_tunnel_notify (&l2tp_nl_family, info, tunnel, +L2TP_CMD_TUNNEL_CREATE );l2tp_tunnel_dec_refcount (tunnel); out:
@@ -304,8 +304,8 @@ static int l2tp_nl_cmd_tunnel_modify(struct sk_buff *skb, struct genl_info *info goto out; } - ret =l2tp_tunnel_notify (&l2tp_nl_family, info, - tunnel,L2TP_CMD_TUNNEL_MODIFY ); +l2tp_tunnel_notify (&l2tp_nl_family, info, + tunnel,L2TP_CMD_TUNNEL_MODIFY );l2tp_tunnel_dec_refcount (tunnel);
@@ -637,8 +637,8 @@ static int l2tp_nl_cmd_session_create(struct sk_buff *skb, struct genl_info *infif (ret >=0 ) { session =l2tp_tunnel_get_session (tunnel, session_id);if (session) { - ret =l2tp_session_notify (&l2tp_nl_family, info, session, -L2TP_CMD_SESSION_CREATE ); +l2tp_session_notify (&l2tp_nl_family, info, session, +L2TP_CMD_SESSION_CREATE );l2tp_session_dec_refcount (session); } }
@@ -702,8 +702,8 @@ static int l2tp_nl_cmd_session_modify(struct sk_buff *skb, struct genl_info *infif (info->attrs[L2TP_ATTR_RECV_TIMEOUT ]) session->reorder_timeout =nla_get_msecs (info->attrs[L2TP_ATTR_RECV_TIMEOUT ]); - ret =l2tp_session_notify (&l2tp_nl_family, info, - session,L2TP_CMD_SESSION_MODIFY ); +l2tp_session_notify (&l2tp_nl_family, info, + session,L2TP_CMD_SESSION_MODIFY );l2tp_session_dec_refcount (session);
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1378/1887 platform/x86/amd/pmc: Propagate SMU errors and validate S2D address
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Mario Limonciello <[email protected]>
[ Upstream commit 0225c1d637687b03726f00ac65b6def843d2c464 ]
amd_stb_s2d_init() discards the return value of several S2D SMU commands. When the SMU refuses a command (e.g. "SMU cmd failed. err: 0xff") the failure is only noticed indirectly - if at all - and reported as -EIO, masking the real error.
More seriously, the S2D_PHYS_ADDR_LOW/HIGH return values are ignored, so on failure phys_addr_low/hi are left uninitialised and the assembled address is passed straight to devm_ioremap(). When the SMU leaves them at zero this maps physical address 0 and trips the ioremap-on-RAM warning:
amd_pmc AMDI000B:00: SMU cmd failed. err: 0xff ioremap on RAM at 0x0000000000000000 - 0x0000000000ffffff
WARNING: CPU: 13 PID: 4592 at arch/x86/mm/ioremap.c:...
Check the return value of each SMU command and propagate it, and reject a zero physical address before calling devm_ioremap().
--- drivers/platform/x86/amd/pmc.c | 26 ++++++++++++++++++++------ 1 file changed, 20 insertions(+), 6 deletions(-)
drivers/platform/x86/amd/pmc.c +20 -6
@@ -872,21 +872,31 @@ static int amd_pmc_s2d_init(struct amd_pmc_dev *dev)u32 phys_addr_low, phys_addr_hi;u64 stb_phys_addr;u32 size =0 ; +int ret;/* Spill to DRAM feature uses separate SMU message port */ dev->msg_port =1 ; -amd_pmc_send_cmd (dev,S2D_TELEMETRY_SIZE , &size,STB_SPILL_TO_DRAM ,1 ); -if (size !=S2D_TELEMETRY_BYTES_MAX ) -return -EIO ; + ret =amd_pmc_send_cmd (dev,S2D_TELEMETRY_SIZE , &size,STB_SPILL_TO_DRAM ,1 ); +if (ret) + goto out; +if (size !=S2D_TELEMETRY_BYTES_MAX ) { + ret = -EIO ; + goto out; + }/* Get STB DRAM address */ -amd_pmc_send_cmd (dev,S2D_PHYS_ADDR_LOW , &phys_addr_low,STB_SPILL_TO_DRAM ,1 ); -amd_pmc_send_cmd (dev,S2D_PHYS_ADDR_HIGH , &phys_addr_hi,STB_SPILL_TO_DRAM ,1 ); + ret =amd_pmc_send_cmd (dev,S2D_PHYS_ADDR_LOW , &phys_addr_low,STB_SPILL_TO_DRAM ,1 ); +if (ret) + goto out; + ret =amd_pmc_send_cmd (dev,S2D_PHYS_ADDR_HIGH , &phys_addr_hi,STB_SPILL_TO_DRAM ,1 ); +if (ret) + goto out;if (!phys_addr_hi && !phys_addr_low) {dev_err (dev->dev,"STB is not enabled on the system; disable enable_stb or contact system vendor\n" ); -return -EINVAL ; + ret = -EINVAL ; + goto out; } stb_phys_addr = ((u64 )phys_addr_hi <<32 | phys_addr_low);
@@ -899,6 +909,10 @@ static int amd_pmc_s2d_init(struct amd_pmc_dev *dev)return -ENOMEM ;return 0 ; + +out: + dev->msg_port =0 ; +return ret; }#ifdef CONFIG_SUSPEND
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1379/1887 platform/x86: intel_sar: Check ACPI_HANDLE() against NULL
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Rafael J. Wysocki <[email protected]>
[ Upstream commit 2765f16c12af7c2533763e46b8113b727354012d ]
Every platform driver can be forced to match a device that doesn't match its list of device IDs because of device_match_driver_override(), so platform drivers that rely on the existence of a device's ACPI companion object need to verify its presence.
Accordingly, add a requisite ACPI_HANDLE() check against NULL to the platform/x86 intel_sar driver.
Stable-dep-of: 30c906cff490 ("platform/x86: int1092: Fix potential memory leak in sar_probe()")
--- drivers/platform/x86/intel/int1092/intel_sar.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-)
drivers/platform/x86/intel/int1092/intel_sar.c +6 -1
@@ -246,15 +246,20 @@ static void sar_get_data(int reg, struct wwan_sar_context *context)static int sar_probe (struct platform_device *device) {struct wwan_sar_context *context; +acpi_handle handle;int reg;int result; + handle =ACPI_HANDLE (&device->dev); +if (!handle) +return -ENODEV ; + context =kzalloc (sizeof (*context),GFP_KERNEL );if (!context)return -ENOMEM ; context->sar_device = device; - context->handle =ACPI_HANDLE (&device->dev); + context->handle = handle;dev_set_drvdata (&device->dev, context); result =guid_parse (SAR_DSM_UUID , &context->guid);
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1380/1887 platform/x86: int1092: Fix potential memory leak in sar_probe()
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Abdun Nihaal <[email protected]>
[ Upstream commit 30c906cff490c3601ee9ff110fe8115fabe75fd4 ]
The memory allocated for device_mode_info in parse_package() called by sar_get_data() is not freed in some of the error paths in sar_probe(). Fix that by converting to use device managed allocations.
--- .../platform/x86/intel/int1092/intel_sar.c | 32 ++++++------------- 1 file changed, 10 insertions(+), 22 deletions(-)
drivers/platform/x86/intel/int1092/intel_sar.c +10 -22
@@ -91,8 +91,10 @@ static acpi_status parse_package(struct wwan_sar_context *context, union acpi_ob item->package.count <= data->total_dev_mode)return AE_ERROR ; - data->device_mode_info =kmalloc_array (data->total_dev_mode, -sizeof (struct wwan_device_mode_info ),GFP_KERNEL ); + data->device_mode_info =devm_kmalloc_array (&context->sar_device->dev, + data->total_dev_mode, +sizeof (*data->device_mode_info), +GFP_KERNEL );if (!data->device_mode_info)return AE_ERROR ;
@@ -254,7 +256,7 @@ static int sar_probe(struct platform_device *device)if (!handle)return -ENODEV ; - context =kzalloc (sizeof (*context),GFP_KERNEL ); + context =devm_kzalloc (&device->dev,sizeof (*context),GFP_KERNEL );if (!context)return -ENOMEM ;
@@ -265,7 +267,7 @@ static int sar_probe(struct platform_device *device) result =guid_parse (SAR_DSM_UUID , &context->guid);if (result) {dev_err (&device->dev,"SAR UUID parse error: %d\n" , result); - goto r_free; +return result; }for (reg =0 ; reg <MAX_REGULATORY ; reg++)
@@ -273,43 +275,29 @@ static int sar_probe(struct platform_device *device)if (sar_get_device_mode (device) !=AE_OK ) {dev_err (&device->dev,"Failed to get device mode\n" ); - result = -EIO ; - goto r_free; +return -EIO ; } result =sysfs_create_group (&device->dev.kobj, &intcsar_group);if (result) {dev_err (&device->dev,"sysfs creation failed\n" ); - goto r_free; +return result; }if (acpi_install_notify_handler (ACPI_HANDLE (&device->dev),ACPI_DEVICE_NOTIFY , sar_notify, (void *)device) !=AE_OK ) {dev_err (&device->dev,"Failed acpi_install_notify_handler\n" ); - result = -EIO ; - goto r_sys; +sysfs_remove_group (&device->dev.kobj, &intcsar_group); +return -EIO ; }return 0 ; - -r_sys: -sysfs_remove_group (&device->dev.kobj, &intcsar_group); -r_free: -kfree (context); -return result; }static int sar_remove (struct platform_device *device) { -struct wwan_sar_context *context =dev_get_drvdata (&device->dev); -int reg; -acpi_remove_notify_handler (ACPI_HANDLE (&device->dev),ACPI_DEVICE_NOTIFY , sar_notify);sysfs_remove_group (&device->dev.kobj, &intcsar_group); -for (reg =0 ; reg <MAX_REGULATORY ; reg++) -kfree (context->config_data[reg].device_mode_info); - -kfree (context);return 0 ; }
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1381/1887 iommu: Add max_pasids field in struct iommu_device
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Lu Baolu <[email protected]>
[ Upstream commit 1adf3cc20d693569ebee90fd91fa34b0570fcd6f ]
Use this field to keep the number of supported PASIDs that an IOMMU hardware is able to support. This is a generic attribute of an IOMMU and lifting it into the per-IOMMU device structure makes it possible to allocate a PASID for device without calls into the IOMMU drivers. Any iommu driver that supports PASID related features should set this field before enabling them on the devices.
In the Intel IOMMU driver, intel_iommu_sm is moved to CONFIG_INTEL_IOMMU enclave so that the pasid_supported() helper could be used in dmar.c without compilation errors.
Stable-dep-of: 607432b2618b ("iommu/vt-d: Force requesting ACS when tboot is enabled")
--- drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c | 1 + drivers/iommu/intel/dmar.c | 7 +++++++ drivers/iommu/intel/iommu.h | 4 ++-- include/linux/iommu.h | 2 ++ 4 files changed, 12 insertions(+), 2 deletions(-)
drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c +1 -0
@@ -3623,6 +3623,7 @@ static int arm_smmu_device_hw_probe(struct arm_smmu_device *smmu)/* SID/SSID sizes */ smmu->ssid_bits =FIELD_GET (IDR1_SSIDSIZE , reg); smmu->sid_bits =FIELD_GET (IDR1_SIDSIZE , reg); + smmu->iommu.max_pasids =1UL << smmu->ssid_bits;/* * If the SMMU supports fewer bits than would fill a single L2 stream
drivers/iommu/intel/dmar.c +7 -0
@@ -1106,6 +1106,13 @@ static int alloc_iommu(struct dmar_drhd_unit *drhd)raw_spin_lock_init (&iommu->register_lock); +/* +* A value of N in PSS field of eCap register indicates hardware +* supports PASID field of N+1 bits. +*/ +if (pasid_supported (iommu)) + iommu->iommu.max_pasids =2UL <<ecap_pss (iommu->ecap); +/* * This is only for hotplug; at boot time intel_iommu_enabled won't * be set yet. When intel_iommu_init() runs, it registers the units
drivers/iommu/intel/iommu.h +2 -2
@@ -480,8 +480,6 @@ enum {#define VTD_FLAG_IRQ_REMAP_PRE_ENABLED (1 << 1)#define VTD_FLAG_SVM_CAPABLE (1 << 2) -extern int intel_iommu_sm; -#define sm_supported (iommu) (intel_iommu_sm && ecap_smts((iommu)->ecap))#define pasid_supported (iommu) (sm_supported(iommu) && \ ecap_pasid((iommu)->ecap))
@@ -799,6 +797,7 @@ struct context_entry *iommu_context_addr(struct intel_iommu *iommu, u8 bus,extern const struct iommu_ops intel_iommu_ops;#ifdef CONFIG_INTEL_IOMMU +extern int intel_iommu_sm;extern int iommu_calculate_agaw (struct intel_iommu *iommu);extern int iommu_calculate_max_sagaw (struct intel_iommu *iommu);extern int dmar_disabled;
@@ -814,6 +813,7 @@ static inline int iommu_calculate_max_sagaw(struct intel_iommu *iommu) }#define dmar_disabled (1)#define intel_iommu_enabled (0) +#define intel_iommu_sm (0)#endif static inline const char *decode_prq_descriptor(char *str, size_t size,
include/linux/iommu.h +2 -0
@@ -322,12 +322,14 @@ struct iommu_domain_ops {* @list: Used by the iommu-core to keep a list of registered iommus * @ops: iommu-ops for talking to this iommu * @dev: struct device for sysfs handling +* @max_pasids: number of supported PASIDs */ struct iommu_device {struct list_head list;const struct iommu_ops *ops;struct fwnode_handle *fwnode;struct device *dev; +u32 max_pasids; };/**
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1382/1887 iommu/vt-d: Force requesting ACS when tboot is enabled
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Kevin Tian <[email protected]>
[ Upstream commit 607432b2618b61df81134be0ef2562b8300c1216 ]
Currently the conditions of requesting ACS in detect_intel_iommu() don't include tboot, leading to a possible misconfiguration with ACS disabled (e.g. due to user opts) while iommu is later forced on by tboot_force_iommu().
Fix it by checking tboot in detect_intel_iommu().
--- drivers/iommu/intel/dmar.c | 15 +++++++++++++-- drivers/iommu/intel/iommu.c | 2 +- drivers/iommu/intel/iommu.h | 2 ++ 3 files changed, 16 insertions(+), 3 deletions(-)
drivers/iommu/intel/dmar.c +13 -2
@@ -912,6 +912,18 @@ dmar_validate_one_drhd(struct acpi_dmar_header *entry, void *arg)return 0 ; } +static bool dmar_required (void ) +{ +/* tboot supersedes any user/platform opt */ +if (!intel_iommu_tboot_noforce &&tboot_enabled ()) +return true; + +if (!no_iommu && (!dmar_disabled ||dmar_platform_optin ())) +return true; + +return false; +} +void __init detect_intel_iommu (void ) {int ret;
@@ -925,8 +937,7 @@ void __init detect_intel_iommu(void)if (!ret) ret =dmar_walk_dmar_table ((struct acpi_table_dmar *)dmar_tbl, &validate_drhd_cb); -if (!ret && !no_iommu && !iommu_detected && - (!dmar_disabled ||dmar_platform_optin ())) { +if (!ret && !iommu_detected &&dmar_required ()) { iommu_detected =1 ;/* Make sure ACS will be enabled */ pci_request_acs ();
drivers/iommu/intel/iommu.c +1 -1
@@ -138,7 +138,7 @@ static int rwbf_quirk;* (used when kernel is launched w/ TXT) */ static int force_on =0 ; -static int intel_iommu_tboot_noforce; +int intel_iommu_tboot_noforce;static int no_platform_optin;#define ROOT_ENTRY_NR (VTD_PAGE_SIZE/sizeof(struct root_entry))
drivers/iommu/intel/iommu.h +2 -0
@@ -802,6 +802,7 @@ extern int iommu_calculate_agaw(struct intel_iommu *iommu);extern int iommu_calculate_max_sagaw (struct intel_iommu *iommu);extern int dmar_disabled;extern int intel_iommu_enabled; +extern int intel_iommu_tboot_noforce;#else static inline int iommu_calculate_agaw (struct intel_iommu *iommu) {
@@ -814,6 +815,7 @@ static inline int iommu_calculate_max_sagaw(struct intel_iommu *iommu)#define dmar_disabled (1)#define intel_iommu_enabled (0)#define intel_iommu_sm (0) +#define intel_iommu_tboot_noforce (0)#endif static inline const char *decode_prq_descriptor(char *str, size_t size,
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1383/1887 iommu/msm: Unwind probe state on registration failure
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Weimin Xiong <[email protected]>
[ Upstream commit 535a200220ca2c83bc8bf54bd2cbe045d6ee70c4 ]
msm_iommu_probe() adds its devm-managed IOMMU object to qcom_iommu_devices before adding the IOMMU sysfs device and registering it with the IOMMU core.
If iommu_device_sysfs_add() fails, probe returns with the object still on qcom_iommu_devices. The driver core then releases the devm allocation, leaving a dangling list entry that later list walks may dereference.
If iommu_device_register() fails, the same dangling list entry remains and the sysfs device is left registered as well.
Unwind the sysfs device and global list entry in reverse setup order on the corresponding failure paths.
--- drivers/iommu/msm_iommu.c | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-)
drivers/iommu/msm_iommu.c +7 -2
@@ -783,19 +783,24 @@ static int msm_iommu_probe(struct platform_device *pdev) "msm-smmu.%pa", &ioaddr);if (ret) {pr_err ("Could not add msm-smmu at %pa to sysfs\n" , &ioaddr); - goto fail; + goto err_remove_list; } ret =iommu_device_register (&iommu->iommu, &msm_iommu_ops, &pdev->dev);if (ret) {pr_err ("Could not register msm-smmu at %pa\n" , &ioaddr); - goto fail; + goto err_remove_sysfs; }pr_info ("device mapped at %p, irq %d with %d ctx banks\n" , iommu->base, iommu->irq, iommu->ncb);return ret; + +err_remove_sysfs: +iommu_device_sysfs_remove (&iommu->iommu); +err_remove_list: +list_del (&iommu->dev_node); fail:clk_unprepare (iommu->clk);clk_unprepare (iommu->pclk);
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1384/1887 power: supply: max17040: propagate register read errors
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Jianing Li <[email protected]>
[ Upstream commit 659cc3d8d5ef246263873fce72c8cadeeed073cc ]
max17040_get_vcell() and max17040_get_soc() ignore errors returned by regmap_read(). When an I2C transfer fails, the uninitialized register value is converted and reported to userspace as a valid voltage or state of charge. The polling worker can also replace the cached state of charge with the bogus value and emit a spurious change event.
Propagate read errors through the power supply get_property callback and keep the last valid cached state of charge when polling fails.
--- drivers/power/supply/max17040_battery.c | 27 ++++++++++++++++++++----- 1 file changed, 22 insertions(+), 5 deletions(-)
drivers/power/supply/max17040_battery.c +22 -5
@@ -190,8 +190,11 @@ static int max17040_raw_vcell_to_uvolts(struct max17040_chip *chip, u16 vcell)static int max17040_get_vcell (struct max17040_chip *chip) {u32 vcell; +int ret; -regmap_read (chip->regmap,MAX17040_VCELL , &vcell); + ret =regmap_read (chip->regmap,MAX17040_VCELL , &vcell); +if (ret) +return ret;return max17040_raw_vcell_to_uvolts (chip, vcell); }
@@ -199,8 +202,11 @@ static int max17040_get_vcell(struct max17040_chip *chip)static int max17040_get_soc (struct max17040_chip *chip) {u32 soc; +int ret; -regmap_read (chip->regmap,MAX17040_SOC , &soc); + ret =regmap_read (chip->regmap,MAX17040_SOC , &soc); +if (ret) +return ret;return soc >> (chip->quirk_double_soc ?9 :8 ); }
@@ -259,7 +265,11 @@ static int max17040_get_of_data(struct max17040_chip *chip)static void max17040_check_changes (struct max17040_chip *chip) { - chip->soc =max17040_get_soc (chip); +int soc; + + soc =max17040_get_soc (chip); +if (soc >=0 ) + chip->soc = soc; }static void max17040_queue_work (struct max17040_chip *chip)
@@ -386,16 +396,23 @@ static int max17040_get_property(struct power_supply *psy, union power_supply_propval *val) {struct max17040_chip *chip =power_supply_get_drvdata (psy); +int ret;switch (psp) {case POWER_SUPPLY_PROP_ONLINE : val->intval =max17040_get_online (chip);break ;case POWER_SUPPLY_PROP_VOLTAGE_NOW : - val->intval =max17040_get_vcell (chip); + ret =max17040_get_vcell (chip); +if (ret <0 ) +return ret; + val->intval = ret;break ;case POWER_SUPPLY_PROP_CAPACITY : - val->intval =max17040_get_soc (chip); + ret =max17040_get_soc (chip); +if (ret <0 ) +return ret; + val->intval = ret;break ;case POWER_SUPPLY_PROP_CAPACITY_ALERT_MIN : val->intval = chip->low_soc_alert;
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1385/1887 power: supply: lp8788-charger: Convert to platform remove callback returning void
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Uwe Kleine-König <[email protected]>
[ Upstream commit 7810ba3c5110ce66652ec6bd2abb92da5d726c3b ]
The .remove() callback for a platform driver returns an int which makes many driver authors wrongly assume it's possible to do error handling by returning an error code. However the value returned is ignored (apart from emitting a warning) and this typically results in resource leaks. To improve here there is a quest to make the remove callback return void. In the first step of this quest all drivers are converted to .remove_new() which already returns void. Eventually after all drivers are converted, .remove_new() is renamed to .remove().
Trivially convert this driver from always returning zero in the remove callback to the void returning variant.
Stable-dep-of: 831c29a12d56 ("power: supply: lp8788-charger: fix use-after-free on remove")
--- drivers/power/supply/lp8788-charger.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-)
drivers/power/supply/lp8788-charger.c +2 -4
@@ -715,20 +715,18 @@ static int lp8788_charger_probe(struct platform_device *pdev)return 0 ; } -static int lp8788_charger_remove (struct platform_device *pdev) +static void lp8788_charger_remove (struct platform_device *pdev) {struct lp8788_charger *pchg =platform_get_drvdata (pdev);flush_work (&pchg->charger_work);lp8788_irq_unregister (pdev, pchg);lp8788_psy_unregister (pchg); - -return 0 ; }static struct platform_driver lp8788_charger_driver = { .probe = lp8788_charger_probe, - .remove = lp8788_charger_remove, + .remove_new = lp8788_charger_remove, .driver = { .name =LP8788_DEV_CHARGER , },
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1386/1887 power: supply: lp8788: Use devm_power_supply_register() helper
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Andrew Davis <[email protected]>
[ Upstream commit 2abb571143c39f581df9951d263948726db42d86 ]
Use the device lifecycle managed register function. This helps prevent mistakes like unregistering out of order in cleanup functions and forgetting to unregister on error paths.
Stable-dep-of: 831c29a12d56 ("power: supply: lp8788-charger: fix use-after-free on remove")
--- drivers/power/supply/lp8788-charger.c | 21 ++++++--------------- 1 file changed, 6 insertions(+), 15 deletions(-)
drivers/power/supply/lp8788-charger.c +6 -15
@@ -406,12 +406,6 @@ static const struct power_supply_desc lp8788_psy_battery_desc = { .get_property = lp8788_battery_get_property, }; -static void lp8788_psy_unregister (struct lp8788_charger *pchg) -{ -power_supply_unregister (pchg->battery); -power_supply_unregister (pchg->charger); -} -static void lp8788_charger_event (struct work_struct *work) { struct lp8788_charger *pchg =
@@ -667,18 +661,16 @@ static int lp8788_psy_register(struct platform_device *pdev, charger_cfg.supplied_to = battery_supplied_to; charger_cfg.num_supplicants =ARRAY_SIZE (battery_supplied_to); - pchg->charger =power_supply_register (&pdev->dev, - &lp8788_psy_charger_desc, - &charger_cfg); + pchg->charger =devm_power_supply_register (&pdev->dev, + &lp8788_psy_charger_desc, + &charger_cfg);if (IS_ERR (pchg->charger))return -EPERM ; - pchg->battery =power_supply_register (&pdev->dev, - &lp8788_psy_battery_desc,NULL ); -if (IS_ERR (pchg->battery)) { -power_supply_unregister (pchg->charger); + pchg->battery =devm_power_supply_register (&pdev->dev, + &lp8788_psy_battery_desc,NULL ); +if (IS_ERR (pchg->battery))return -EPERM ; - }return 0 ; }
@@ -721,7 +713,6 @@ static void lp8788_charger_remove(struct platform_device *pdev)flush_work (&pchg->charger_work);lp8788_irq_unregister (pdev, pchg); -lp8788_psy_unregister (pchg); }static struct platform_driver lp8788_charger_driver = {
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1387/1887 power: supply: lp8788-charger: fix use-after-free on remove
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Fan Wu <[email protected]>
[ Upstream commit 831c29a12d560f8a3225f43050b3fbb5dfd79c66 ]
lp8788_charger_remove() flushes charger_work before unregistering the IRQs. An IRQ thread can queue charger_work after flush_work() has returned. The work can then run after devres frees pchg and dereference it in lp8788_charger_event().
Unregister the IRQs first. free_irq() waits for any running threaded handler, so no handler can queue more work afterwards. Then use cancel_work_sync() to cancel pending work or wait for running work to finish.
This issue was found by an in-house static analysis tool.
--- drivers/power/supply/lp8788-charger.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
drivers/power/supply/lp8788-charger.c +1 -1
@@ -711,8 +711,8 @@ static void lp8788_charger_remove(struct platform_device *pdev) {struct lp8788_charger *pchg =platform_get_drvdata (pdev); -flush_work (&pchg->charger_work);lp8788_irq_unregister (pdev, pchg); +cancel_work_sync (&pchg->charger_work); }static struct platform_driver lp8788_charger_driver = {
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1388/1887 power: supply: charger-manager: Convert to platform remove callback returning void
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Uwe Kleine-König <[email protected]>
[ Upstream commit 403eebf95c38302cacc48c127e575461f0e798be ]
The .remove() callback for a platform driver returns an int which makes many driver authors wrongly assume it's possible to do error handling by returning an error code. However the value returned is ignored (apart from emitting a warning) and this typically results in resource leaks. To improve here there is a quest to make the remove callback return void. In the first step of this quest all drivers are converted to .remove_new() which already returns void. Eventually after all drivers are converted, .remove_new() is renamed to .remove().
Trivially convert this driver from always returning zero in the remove callback to the void returning variant.
Stable-dep-of: c57cb36f76eb ("power: supply: charger-manager: register regulators before exposing sysfs")
--- drivers/power/supply/charger-manager.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-)
drivers/power/supply/charger-manager.c +2 -4
@@ -1630,7 +1630,7 @@ static int charger_manager_probe(struct platform_device *pdev)return ret; } -static int charger_manager_remove (struct platform_device *pdev) +static void charger_manager_remove (struct platform_device *pdev) {struct charger_manager *cm =platform_get_drvdata (pdev);struct charger_desc *desc = cm->desc;
@@ -1650,8 +1650,6 @@ static int charger_manager_remove(struct platform_device *pdev)power_supply_unregister (cm->charger_psy);try_charger_enable (cm, false); - -return 0 ; }static const struct platform_device_id charger_manager_id[] = {
@@ -1742,7 +1740,7 @@ static struct platform_driver charger_manager_driver = { .of_match_table = charger_manager_match, }, .probe = charger_manager_probe, - .remove = charger_manager_remove, + .remove_new = charger_manager_remove, .id_table = charger_manager_id, };
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1389/1887 power: supply: charger-manager: register regulators before exposing sysfs
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Fan Wu <[email protected]>
[ Upstream commit c57cb36f76eb7ced45f57af1a890d8f3a6d76342 ]
charger_manager_remove() and the err_reg_extcon probe error path free each charger regulator with regulator_put() before tearing down the power_supply sysfs entries (power_supply_unregister()). charger_manager_remove() also calls try_charger_enable(cm, false) after the regulator_put() loop. A concurrent write to a charger's externally_control sysfs attribute that lands between regulator_put() and power_supply_unregister() can run charger_externally_control_store() and call try_charger_enable(), which, when charging is enabled, dereferences the already-freed consumer handle. When charging is enabled, try_charger_enable(cm, false) in .remove() also dereferences the freed handles directly. Both leave use-after-free windows. Symmetrically, probe registers the sysfs entries (power_supply_register) before acquiring the regulators (regulator_get, inside charger_manager_register_extcon), so userspace can reach externally_control before the regulators are available.
Split charger_manager_register_extcon() on the sync/async boundary:charger_manager_get_regulators() (regulator_get only, no async producer) now runs before power_supply_register() so sysfs is not live before regulators are available, and charger_manager_register_extcon() keeps only the extcon notifier/work setup, still after power_supply_register() so a power_supply_register() failure cannot reach extcon setup. This keeps the sysfs setup/teardown ordering symmetric without introducing an asynchronous producer on the earlier probe-error path.
Move power_supply_unregister() and try_charger_enable(cm, false) ahead of the regulator_put() loop on both teardown paths, and adjust err_reg_extcon (power_supply_unregister() then fall through err_regulator for regulator_put(); get_regulators self-rolls back on its own failure).
This does not address the separate extcon-notifier-driven deref of the same handles, which needs its own synchronization design.
Found by an in-house static analysis tool.
--- drivers/power/supply/charger-manager.c | 54 +++++++++++++++++++------- 1 file changed, 39 insertions(+), 15 deletions(-)
drivers/power/supply/charger-manager.c +39 -15
@@ -1017,6 +1017,29 @@ static int charger_extcon_init(struct charger_manager *cm,return 0 ; } +static int charger_manager_get_regulators (struct charger_manager *cm) +{ +struct charger_desc *desc = cm->desc; +struct charger_regulator *charger; +int i, ret; + +for (i =0 ; i < desc->num_charger_regulators; i++) { + charger = &desc->charger_regulators[i]; + charger->consumer =regulator_get (cm->dev, + charger->regulator_name); +if (IS_ERR (charger->consumer)) { +dev_err (cm->dev,"Cannot find charger(%s)\n" , + charger->regulator_name); + ret =PTR_ERR (charger->consumer); +while (i-- >0 ) +regulator_put (desc->charger_regulators[i].consumer); +return ret; + } + charger->cm = cm; + } +return 0 ; +} +/** * charger_manager_register_extcon - Register extcon device to receive state * of charger cable.
@@ -1039,15 +1062,6 @@ static int charger_manager_register_extcon(struct charger_manager *cm)for (i =0 ; i < desc->num_charger_regulators; i++) { charger = &desc->charger_regulators[i]; - charger->consumer =regulator_get (cm->dev, - charger->regulator_name); -if (IS_ERR (charger->consumer)) { -dev_err (cm->dev,"Cannot find charger(%s)\n" , - charger->regulator_name); -return PTR_ERR (charger->consumer); - } - charger->cm = cm; -for (j =0 ; j < charger->num_cables; j++) {struct charger_cable *cable = &charger->cables[j];
@@ -1582,13 +1596,23 @@ static int charger_manager_probe(struct platform_device *pdev) } psy_cfg.attr_grp = desc->sysfs_groups; +/* +* Acquire charger regulators before exposing the sysfs entries, so +* userspace cannot reach externally_control before the regulators +* (and charger->cm) are available. Mirrors the order in remove(). +*/ + ret =charger_manager_get_regulators (cm); +if (ret <0 ) +return ret; + cm->charger_psy =power_supply_register (&pdev->dev, &cm->charger_psy_desc, &psy_cfg);if (IS_ERR (cm->charger_psy)) {dev_err (&pdev->dev,"Cannot register charger-manager with name \"%s\"\n" , cm->charger_psy_desc.name); -return PTR_ERR (cm->charger_psy); + ret =PTR_ERR (cm->charger_psy); + goto err_regulator; }/* Register extcon device for charger cable */
@@ -1622,11 +1646,11 @@ static int charger_manager_probe(struct platform_device *pdev)return 0 ; err_reg_extcon: +power_supply_unregister (cm->charger_psy); +err_regulator:for (i =0 ; i < desc->num_charger_regulators; i++)regulator_put (desc->charger_regulators[i].consumer); -power_supply_unregister (cm->charger_psy); -return ret; }
@@ -1644,12 +1668,12 @@ static void charger_manager_remove(struct platform_device *pdev)cancel_work_sync (&setup_polling);cancel_delayed_work_sync (&cm_monitor_work); -for (i =0 ; i < desc->num_charger_regulators ; i++) -regulator_put (desc->charger_regulators[i].consumer); +try_charger_enable (cm, false);power_supply_unregister (cm->charger_psy); -try_charger_enable (cm, false); +for (i =0 ; i < desc->num_charger_regulators ; i++) +regulator_put (desc->charger_regulators[i].consumer); }static const struct platform_device_id charger_manager_id[] = {
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1390/1887 lockd: fix NULL dereference on lockowner allocation failure
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Shuangpeng Bai <[email protected]>
[ Upstream commit 4c7fc129db061c7daab841c4f3c342d894832362 ]
nlmclnt_locks_init_private() installs NLM file lock operations even when nlmclnt_find_lockowner() fails to allocate a lockowner. nlmclnt_proc() then returns -ENOMEM, but the VFS still tears down the partially initialized file_lock and calls locks_release_private().
That invokes nlmclnt_locks_release_private(), which dereferences fl->fl_u.nfs_fl.owner and crashes because the owner was never installed.
Clear fl_ops before attempting to initialize the NLM private state, and install the NLM lock operations only after a lockowner has been allocated successfully.
--- fs/lockd/clntproc.c | 3 +++ 1 file changed, 3 insertions(+)
fs/lockd/clntproc.c +3 -0
@@ -479,8 +479,11 @@ static const struct file_lock_operations nlmclnt_lock_ops = {static void nlmclnt_locks_init_private (struct file_lock *fl,struct nlm_host *host) { fl->fl_u.nfs_fl.state =0 ; + fl->fl_ops =NULL ; fl->fl_u.nfs_fl.owner =nlmclnt_find_lockowner (host, fl->fl_owner);INIT_LIST_HEAD (&fl->fl_u.nfs_fl.list); +if (!fl->fl_u.nfs_fl.owner) +return ; fl->fl_ops = &nlmclnt_lock_ops; }
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1391/1887 sched/core: Make core-sched flips wait for in-flight selections
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Tejun Heo <[email protected]>
[ Upstream commit f3629c63a4af3e491381780bc6c123cb498c4c40 ]
Core scheduling's pick_next_task() operates on all sibling rqs under one acquisition of the shared core-wide lock. A ->pick_task() that releases the rq lock leaves every sibling __lock momentarily free, letting __sched_core_flip(false) complete mid-selection and rebind rq_lockp() under it. The selection resumes on the split locks, touching sibling state it no longer protects, and __schedule() finally releases a lock that was never taken while leaking the one that was.
Count in-flight core-wide selections in the leader's rq->core_pick_in_flight and make __sched_core_flip() wait for the count to drain. The count only changes under the shared lock, which the flip holds while sampling, so no other ordering is needed. The wait can repeat while selections overlap, but the flip backs off between samples and flips are rare cookie-lifetime events.
sched_core_cpu_deactivate() moves the count to the new leader - a stale copy left behind would bias it forever if that CPU later returns as its own leader.
--- kernel/sched/core.c | 22 ++++++++++++++++++++++ kernel/sched/sched.h | 1 + 2 files changed, 23 insertions(+)
kernel/sched/core.c +22 -0
@@ -345,6 +345,17 @@ static void __sched_core_flip(bool enabled)sched_core_lock (cpu, &flags); +/* +* A core-wide selection may have the shared rq lock temporarily +* released by a lock-dropping ->pick_task(). Flipping would +* rebind rq_lockp() under it. Wait it out. +*/ +while (cpu_rq (cpu)->core->core_pick_in_flight) { +sched_core_unlock (cpu, &flags); +cpu_relax (); +sched_core_lock (cpu, &flags); + } +for_each_cpu (t, smt_mask)cpu_rq (t)->core_enabled = enabled;
@@ -5959,6 +5970,8 @@ pick_next_task(struct rq *rq, struct task_struct *prev, struct rq_flags *rf)return __pick_next_task (rq, prev, rf); } + rq->core->core_pick_in_flight++; +/* * If there were no {en,de}queues since we picked (IOW, the task * pointers are all still valid), and we haven't scheduled the last
@@ -6152,6 +6165,7 @@ pick_next_task(struct rq *rq, struct task_struct *prev, struct rq_flags *rf) out_set_next:set_next_task (rq, next); out: + rq->core->core_pick_in_flight--;if (rq->core->core_forceidle_count && next == rq->idle)queue_core_balance (rq);
@@ -6344,6 +6358,13 @@ static void sched_core_cpu_deactivate(unsigned int cpu) core_rq->core_forceidle_seq = rq->core_forceidle_seq; core_rq->core_forceidle_occupation = rq->core_forceidle_occupation; +/* +* A stale leftover would bias the count forever if this CPU later +* returns as its own leader. Move, don't copy. +*/ + core_rq->core_pick_in_flight = rq->core_pick_in_flight; + rq->core_pick_in_flight =0 ; +/* * Accounting edge for forced idle is handled in pick_next_task(). * Don't need another one here, since the hotplug thread shouldn't
@@ -9862,6 +9883,7 @@ void __init sched_init(void) rq->core_forceidle_count =0 ; rq->core_forceidle_occupation =0 ; rq->core_forceidle_start =0 ; + rq->core_pick_in_flight =0 ; rq->core_cookie =0UL ;#endif
kernel/sched/sched.h +1 -0
@@ -1151,6 +1151,7 @@ struct rq {unsigned int core_forceidle_seq;unsigned int core_forceidle_occupation;u64 core_forceidle_start; +unsigned int core_pick_in_flight;#endif };
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1392/1887 svcrdma: Allocate new transports on devices NUMA node
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Chuck Lever <[email protected]>
[ Upstream commit fe2b401e55482cf90a0056209c8a232b2d39056c ]
The physical device's NUMA node ID is available when allocating an svc_xprt for an incoming connection. Use that value to ensure the svc_xprt structure is allocated on the NUMA node closest to the device.
Stable-dep-of: e346ef7bcb13 ("svcrdma: Use svc_xprt_put to free listener on create failure")
--- net/sunrpc/xprtrdma/svc_rdma_transport.c | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-)
net/sunrpc/xprtrdma/svc_rdma_transport.c +9 -9
@@ -64,7 +64,7 @@#define RPCDBG_FACILITY RPCDBG_SVCXPRTstatic struct svcxprt_rdma *svc_rdma_create_xprt (struct svc_serv *serv, -struct net *net); +struct net *net,int node); static struct svc_xprt *svc_rdma_create(struct svc_serv *serv, struct net *net, struct sockaddr *sa, int salen,
@@ -125,14 +125,14 @@ static void qp_event_handler(struct ib_event *event, void *context) }static struct svcxprt_rdma *svc_rdma_create_xprt (struct svc_serv *serv, -struct net *net) +struct net *net,int node) { -struct svcxprt_rdma *cma_xprt =kzalloc (sizeof *cma_xprt,GFP_KERNEL ); +struct svcxprt_rdma *cma_xprt; -if (!cma_xprt) { -dprintk ("svcrdma: failed to create new transport\n" ); + cma_xprt =kzalloc_node (sizeof (*cma_xprt),GFP_KERNEL , node); +if (!cma_xprt)return NULL ; - } +svc_xprt_init (net, &svc_rdma_class, &cma_xprt->sc_xprt, serv);INIT_LIST_HEAD (&cma_xprt->sc_accept_q);INIT_LIST_HEAD (&cma_xprt->sc_rq_dto_q);
@@ -195,9 +195,9 @@ static void handle_connect_req(struct rdma_cm_id *new_cma_id,struct svcxprt_rdma *newxprt;struct sockaddr *sa; -/* Create a new transport */ newxprt =svc_rdma_create_xprt (listen_xprt->sc_xprt.xpt_server, - listen_xprt->sc_xprt.xpt_net); + listen_xprt->sc_xprt.xpt_net, +ibdev_to_node (new_cma_id->device));if (!newxprt)return ; newxprt->sc_cm_id = new_cma_id;
@@ -306,7 +306,7 @@ static struct svc_xprt *svc_rdma_create(struct svc_serv *serv,if (sa->sa_family !=AF_INET && sa->sa_family !=AF_INET6 )return ERR_PTR (-EAFNOSUPPORT ); - cma_xprt =svc_rdma_create_xprt (serv, net); + cma_xprt =svc_rdma_create_xprt (serv, net,NUMA_NO_NODE );if (!cma_xprt)return ERR_PTR (-ENOMEM );set_bit (XPT_LISTENER , &cma_xprt->sc_xprt.xpt_flags);
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1393/1887 svcrdma: Refactor the creation of listener CMA ID
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Chuck Lever <[email protected]>
[ Upstream commit 283d28546234b1764a0a37cb3df30cc3321c75b4 ]
In a moment, I will add a second consumer of CMA ID creation in svcrdma. Refactor so this code can be reused.
Stable-dep-of: e346ef7bcb13 ("svcrdma: Use svc_xprt_put to free listener on create failure")
--- net/sunrpc/xprtrdma/svc_rdma_transport.c | 67 ++++++++++++++---------- 1 file changed, 40 insertions(+), 27 deletions(-)
net/sunrpc/xprtrdma/svc_rdma_transport.c +40 -27
@@ -65,6 +65,8 @@static struct svcxprt_rdma *svc_rdma_create_xprt (struct svc_serv *serv,struct net *net,int node); +static int svc_rdma_listen_handler (struct rdma_cm_id *cma_id, +struct rdma_cm_event *event); static struct svc_xprt *svc_rdma_create(struct svc_serv *serv, struct net *net, struct sockaddr *sa, int salen,
@@ -124,6 +126,41 @@ static void qp_event_handler(struct ib_event *event, void *context) } } +static struct rdma_cm_id * +svc_rdma_create_listen_id (struct net *net,struct sockaddr *sap, +void *context) +{ +struct rdma_cm_id *listen_id; +int ret; + + listen_id =rdma_create_id (net, svc_rdma_listen_handler, context, +RDMA_PS_TCP ,IB_QPT_RC ); +if (IS_ERR (listen_id)) +return listen_id; + +/* Allow both IPv4 and IPv6 sockets to bind a single port +* at the same time. +*/ +#if IS_ENABLED (CONFIG_IPV6 ) + ret =rdma_set_afonly (listen_id,1 ); +if (ret) + goto out_destroy; +#endif + ret =rdma_bind_addr (listen_id, sap); +if (ret) + goto out_destroy; + + ret =rdma_listen (listen_id,RPCRDMA_LISTEN_BACKLOG ); +if (ret) + goto out_destroy; + +return listen_id; + +out_destroy: +rdma_destroy_id (listen_id); +return ERR_PTR (ret); +} +static struct svcxprt_rdma *svc_rdma_create_xprt (struct svc_serv *serv,struct net *net,int node) {
@@ -302,7 +339,6 @@ static struct svc_xprt *svc_rdma_create(struct svc_serv *serv, {struct rdma_cm_id *listen_id;struct svcxprt_rdma *cma_xprt; -int ret;if (sa->sa_family !=AF_INET && sa->sa_family !=AF_INET6 )return ERR_PTR (-EAFNOSUPPORT );
@@ -312,30 +348,13 @@ static struct svc_xprt *svc_rdma_create(struct svc_serv *serv,set_bit (XPT_LISTENER , &cma_xprt->sc_xprt.xpt_flags);strcpy (cma_xprt->sc_xprt.xpt_remotebuf,"listener" ); - listen_id =rdma_create_id (net, svc_rdma_listen_handler, cma_xprt, -RDMA_PS_TCP ,IB_QPT_RC ); + listen_id =svc_rdma_create_listen_id (net, sa, cma_xprt);if (IS_ERR (listen_id)) { - ret =PTR_ERR (listen_id); - goto err0; +kfree (cma_xprt); +return (struct svc_xprt *)listen_id; } - -/* Allow both IPv4 and IPv6 sockets to bind a single port -* at the same time. -*/ -#if IS_ENABLED (CONFIG_IPV6 ) - ret =rdma_set_afonly (listen_id,1 ); -if (ret) - goto err1; -#endif - ret =rdma_bind_addr (listen_id, sa); -if (ret) - goto err1; cma_xprt->sc_cm_id = listen_id; - ret =rdma_listen (listen_id,RPCRDMA_LISTEN_BACKLOG ); -if (ret) - goto err1; -/* * We need to use the address from the cm_id in case the * caller specified 0 for the port number.
@@ -344,12 +363,6 @@ static struct svc_xprt *svc_rdma_create(struct svc_serv *serv,svc_xprt_set_local (&cma_xprt->sc_xprt, sa, salen);return &cma_xprt->sc_xprt; - - err1: -rdma_destroy_id (listen_id); - err0: -kfree (cma_xprt); -return ERR_PTR (ret); }/*
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1394/1887 sunrpc: xprtrdma: Use ERR_CAST() to return
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Yan Zhen <[email protected]>
[ Upstream commit aeddf8e6c5662d60d434ce59f7e08ea020162323 ]
Using ERR_CAST() is more reasonable and safer, When it is necessary to convert the type of an error pointer and return it.
Stable-dep-of: e346ef7bcb13 ("svcrdma: Use svc_xprt_put to free listener on create failure")
--- net/sunrpc/xprtrdma/svc_rdma_transport.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
net/sunrpc/xprtrdma/svc_rdma_transport.c +1 -1
@@ -351,7 +351,7 @@ static struct svc_xprt *svc_rdma_create(struct svc_serv *serv, listen_id =svc_rdma_create_listen_id (net, sa, cma_xprt);if (IS_ERR (listen_id)) {kfree (cma_xprt); -return (struct svc_xprt *)listen_id; +return ERR_CAST (listen_id); } cma_xprt->sc_cm_id = listen_id;
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1395/1887 svcrdma: Use svc_xprt_put to free listener on create failure
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Chuck Lever <[email protected]>
[ Upstream commit e346ef7bcb137f50c49f969330ab7dcf64ea1654 ]
svc_rdma_create() calls kfree(cma_xprt) when svc_rdma_create_listen_id() fails. svc_xprt_init() has already acquired a net namespace reference via get_net_track(); kfree bypasses svc_xprt_free() which releases it.
Replace the kfree() with svc_xprt_put() so the kref_init birth reference drops to zero and svc_xprt_free() dispatches svc_rdma_free() to clean up properly. sc_cm_id is still NULL at that point; the preceding patch added the necessary NULL guard in svc_rdma_free().
svc_xprt_free() also drops the module reference via module_put(), but the caller _svc_xprt_create() does the same on xpo_create failure, double-putting the single try_module_get() it acquired. Take a compensating __module_get() before the svc_xprt_put() to keep the count balanced, matching the convention in svc_rdma_accept()'s error path.
--- net/sunrpc/xprtrdma/svc_rdma_transport.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-)
net/sunrpc/xprtrdma/svc_rdma_transport.c +7 -1
@@ -350,7 +350,13 @@ static struct svc_xprt *svc_rdma_create(struct svc_serv *serv, listen_id =svc_rdma_create_listen_id (net, sa, cma_xprt);if (IS_ERR (listen_id)) { -kfree (cma_xprt); +/* _svc_xprt_create() acquired one module reference and +* puts it on xpo_create failure. svc_xprt_free() puts +* a second one when the kref drops to zero. Take a +* compensating reference so both puts are balanced. +*/ +__module_get (cma_xprt->sc_xprt.xpt_class->xcl_owner); +svc_xprt_put (&cma_xprt->sc_xprt);return ERR_CAST (listen_id); } cma_xprt->sc_cm_id = listen_id;
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1396/1887 svcrdma: Reject inline replies that overflow the pull-up buffer
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Chuck Lever <[email protected]>
[ Upstream commit 0fbe20dfe74b783d255bf389a6ea77aa25dc7860 ]
An RPC-over-RDMA client can request a reply, such as an NFS READ payload, without providing a Write list or a Reply chunk to carry it. When such a reply needs more scatter/gather entries than the device's Send Queue supports, svc_rdma_pull_up_needed() selects pull-up and svc_rdma_pull_up_reply_msg() linearizes the whole reply into sctxt->sc_xprt_buf. That buffer is only sc_max_req_size bytes, while the reply on this path is bounded only by the client's request, so svc_rdma_xb_linearize() copies past the end of the buffer and corrupts adjacent slab memory. The oversized length is then stored in sc_sges[0].length and posted, so the device also reads beyond the mapped region.
The SGE-exhaustion branch is the only pull-up path that can exceed the buffer: the threshold branch pulls up only replies smaller than RPCRDMA_PULLUP_THRESH, and replies that fit the device's SGE budget are sent directly without linearization. Make svc_rdma_pull_up_needed() report -E2BIG when the reply it would pull up cannot fit sc_max_req_size, and fail the request with ERR_CHUNK as RFC 8166 Section 4.5.3 directs rather than dropping the connection.
The helper no longer answers a simple yes/no question: it now reports pull-up, no pull-up, or -E2BIG for a reply too large to linearize. Rename svc_rdma_pull_up_needed() to svc_rdma_check_pull_up() so its name no longer implies a boolean predicate.
--- net/sunrpc/xprtrdma/svc_rdma_sendto.c | 47 ++++++++++++++++++--------- 1 file changed, 32 insertions(+), 15 deletions(-)
net/sunrpc/xprtrdma/svc_rdma_sendto.c +32 -15
@@ -645,20 +645,21 @@ static int svc_rdma_xb_count_sges(const struct xdr_buf *xdr, }/** -* svc_rdma_pull_up_needed - Determine whether to use pull-up +* svc_rdma_check_pull_up - Determine whether to use pull-up * @rdma: controlling transport * @sctxt: send_ctxt for the Send WR * @rctxt: Write and Reply chunks provided by client * @xdr: xdr_buf containing RPC message to transmit * * Returns: -* %true if pull-up must be used -* %false otherwise +* %1 if pull-up must be used +* %0 if pull-up is not needed +* %-E2BIG if the reply is too large to be pulled up */ -static bool svc_rdma_pull_up_needed (const struct svcxprt_rdma *rdma, -const struct svc_rdma_send_ctxt *sctxt, -const struct svc_rdma_recv_ctxt *rctxt, -const struct xdr_buf *xdr) +static int svc_rdma_check_pull_up (const struct svcxprt_rdma *rdma, +const struct svc_rdma_send_ctxt *sctxt, +const struct svc_rdma_recv_ctxt *rctxt, +const struct xdr_buf *xdr) {/* Resources needed for the transport header */ struct svc_rdma_pullup_data args = {
@@ -670,11 +671,22 @@ static bool svc_rdma_pull_up_needed(const struct svcxprt_rdma *rdma, ret =pcl_process_nonpayloads (&rctxt->rc_write_pcl, xdr, svc_rdma_xb_count_sges, &args);if (ret <0 ) -return false; +return 0 ;if (args.pd_length <RPCRDMA_PULLUP_THRESH ) -return true; -return args.pd_num_sges >= rdma->sc_max_send_sges; +return 1 ; +if (args.pd_num_sges < rdma->sc_max_send_sges) +return 0 ; + +/* +* The reply has too many SGEs to Send inline, so it has to be +* linearized into sc_xprt_buf. That buffer holds only +* sc_max_req_size bytes, so a larger reply cannot be pulled up. +* RFC 8166 Section 4.5.3 requires responding with ERR_CHUNK. +*/ +if (args.pd_length > rdma->sc_max_req_size) +return -E2BIG ; +return 1 ; }/**
@@ -730,7 +742,7 @@ static int svc_rdma_xb_linearize(const struct xdr_buf *xdr,* Assemble the elements of @xdr into the transport header buffer. * * Assumptions: -* pull_up_needed has determined that @xdr will fit in the buffer. +* check_pull_up has determined that @xdr will fit in the buffer. * * Returns: * %0 if pull-up was successful
@@ -764,6 +776,7 @@ static int svc_rdma_pull_up_reply_msg(const struct svcxprt_rdma *rdma,* * Returns: * %0 if DMA mapping was successful. +* %-E2BIG if the reply is too large to be pulled up * %-EMSGSIZE if a buffer manipulation problem occurred * %-EIO if DMA mapping failed *
@@ -778,6 +791,7 @@ int svc_rdma_map_reply_msg(struct svcxprt_rdma *rdma, .md_rdma = rdma, .md_ctxt = sctxt, }; +int ret;/* Set up the (persistently-mapped) transport header SGE. */ sctxt->sc_send_wr.num_sge =1 ;
@@ -792,7 +806,10 @@ int svc_rdma_map_reply_msg(struct svcxprt_rdma *rdma,/* For pull-up, svc_rdma_send() will sync the transport header. * No additional DMA mapping is necessary. */ -if (svc_rdma_pull_up_needed (rdma, sctxt, rctxt, xdr)) + ret =svc_rdma_check_pull_up (rdma, sctxt, rctxt, xdr); +if (ret <0 ) +return ret; +if (ret)return svc_rdma_pull_up_reply_msg (rdma, sctxt, rctxt, xdr); return pcl_process_nonpayloads(&rctxt->rc_write_pcl, xdr,
@@ -955,7 +972,7 @@ int svc_rdma_sendto(struct svc_rqst *rqstp) ret =svc_rdma_send_reply_chunk (rdma, rctxt, &rqstp->rq_res);if (ret <0 ) - goto reply_chunk; + goto send_err; rc_size = ret; *p++ = *rdma_argp;
@@ -975,7 +992,7 @@ int svc_rdma_sendto(struct svc_rqst *rqstp) ret =svc_rdma_send_reply_msg (rdma, sctxt, rctxt, rqstp);if (ret <0 ) - goto put_ctxt; + goto send_err;/* Prevent svc_xprt_release() from releasing the page backing * rq_res.head[0].iov_base. It's no longer being accessed by
@@ -983,7 +1000,7 @@ int svc_rdma_sendto(struct svc_rqst *rqstp) rqstp->rq_respages++;return 0 ; -reply_chunk: +send_err:if (ret != -E2BIG && ret != -EINVAL ) goto put_ctxt;
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1397/1887 svcrdma: Handle ADDR_CHANGE CM event properly
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Chuck Lever <[email protected]>
[ Upstream commit d1b586e75ec619dde1af47e21a41a6b1b51874c2 ]
Sagi tells me that when a bonded device reports an address change, the consumer must destroy its listener IDs and create new ones.
See commit a032e4f6d60d ("nvmet-rdma: fix bonding failover possible NULL deref").
Stable-dep-of: 0944462247dc ("svcrdma: Reject connection when transport allocation fails")
--- net/sunrpc/xprtrdma/svc_rdma_transport.c | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-)
net/sunrpc/xprtrdma/svc_rdma_transport.c +15 -1
@@ -279,17 +279,31 @@ static void handle_connect_req(struct rdma_cm_id *new_cma_id,* * Return values: * %0: Do not destroy @cma_id -* %1: Destroy @cma_id (never returned here) +* %1: Destroy @cma_id * * NB: There is never a DEVICE_REMOVAL event for INADDR_ANY listeners. */ static int svc_rdma_listen_handler (struct rdma_cm_id *cma_id,struct rdma_cm_event *event) { +struct sockaddr *sap = (struct sockaddr *)&cma_id->route.addr.src_addr; +struct svcxprt_rdma *cma_xprt = cma_id->context; +struct svc_xprt *cma_rdma = &cma_xprt->sc_xprt; +struct rdma_cm_id *listen_id; +switch (event->event) {case RDMA_CM_EVENT_CONNECT_REQUEST :handle_connect_req (cma_id, &event->param.conn);break ; +case RDMA_CM_EVENT_ADDR_CHANGE : + listen_id =svc_rdma_create_listen_id (cma_rdma->xpt_net, + sap, cma_xprt); +if (IS_ERR (listen_id)) { +pr_err ("Listener dead, address change failed for device %s\n" , + cma_id->device->name); + }else + cma_xprt->sc_cm_id = listen_id; +return 1 ;default :break ; }
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1398/1887 svcrdma: Reject connection when transport allocation fails
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Chuck Lever <[email protected]>
[ Upstream commit 0944462247dcb7de7622cdaaadf5f05c52707dab ]
handle_connect_req() returns without action when svc_rdma_create_xprt() fails to allocate the new transport. The CM core returns 0 for CONNECT_REQUEST events, so it does not destroy the new rdma_cm_id. Each allocation failure under memory pressure leaks one rdma_cm_id, and a remote peer driving connection attempts can amplify this.
Reject the connection by returning a non-zero status from the CM event handler, which tells the CM core to destroy the orphaned cm_id.
--- net/sunrpc/xprtrdma/svc_rdma_transport.c | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-)
net/sunrpc/xprtrdma/svc_rdma_transport.c +10 -6
@@ -221,12 +221,16 @@ svc_rdma_parse_connect_private(struct svcxprt_rdma *newxprt,* structure for the listening endpoint. * * This function creates a new xprt for the new connection and enqueues it on -* the accept queue for the listent xprt. When the listen thread is kicked, it +* the accept queue for the listen xprt. When the listen thread is kicked, it * will call the recvfrom method on the listen xprt which will accept the new * connection. +* +* Return values: +* %0: Do not destroy @new_cma_id +* %1: Destroy @new_cma_id (allocation failure) */ -static void handle_connect_req (struct rdma_cm_id *new_cma_id, -struct rdma_conn_param *param) +static int handle_connect_req (struct rdma_cm_id *new_cma_id, +struct rdma_conn_param *param) {struct svcxprt_rdma *listen_xprt = new_cma_id->context;struct svcxprt_rdma *newxprt;
@@ -236,7 +240,7 @@ static void handle_connect_req(struct rdma_cm_id *new_cma_id, listen_xprt->sc_xprt.xpt_net, ibdev_to_node(new_cma_id->device));if (!newxprt) -return ; +return 1 ; newxprt->sc_cm_id = new_cma_id; new_cma_id->context = newxprt;svc_rdma_parse_connect_private (newxprt, param);
@@ -270,6 +274,7 @@ static void handle_connect_req(struct rdma_cm_id *new_cma_id,set_bit (XPT_CONN , &listen_xprt->sc_xprt.xpt_flags);svc_xprt_enqueue (&listen_xprt->sc_xprt); +return 0 ; }/**
@@ -293,8 +298,7 @@ static int svc_rdma_listen_handler(struct rdma_cm_id *cma_id,switch (event->event) {case RDMA_CM_EVENT_CONNECT_REQUEST : -handle_connect_req (cma_id, &event->param.conn); -break ; +return handle_connect_req (cma_id, &event->param.conn);case RDMA_CM_EVENT_ADDR_CHANGE : listen_id =svc_rdma_create_listen_id (cma_rdma->xpt_net, sap, cma_xprt);
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1399/1887 SUNRPC: Reject short RFC 4121 MIC tokens in gss_krb5_verify_mic_v2
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Chuck Lever <[email protected]>
[ Upstream commit b94f6719dcd9f7a609bc5f459f85795900e77d25 ]
gss_krb5_verify_mic_v2() reads the token ID at ptr[0..1], the flags byte at ptr[2], and padding at ptr[3..7], then passes
ptr + GSS_KRB5_TOK_HDR_LEN and cksum_len to gss_krb5_mic_build_sg(). None of these accesses check read_token->len first.
The minimum safe token size is GSS_KRB5_TOK_HDR_LEN (16) plus ctx->krb5e->cksum_len (12-24, depending on the enctype). All callers accept shorter tokens from the wire:
- gss_unwrap_resp_integ() enforces only an upper bound (offset + len <= rcv_buf->len) before allocating mic.data = kmalloc(len) and passing it to gss_verify_mic(). A malicious NFS server can therefore supply a short checksum opaque, producing a small slab allocation that the Kerberos MIC verifier reads past.
- gss_validate() enforces only len <= RPC_MAX_AUTH_SIZE (400) before passing the wire-supplied length to gss_validate_seqno_mic(), which constructs a mic xdr_netobj and calls gss_verify_mic().
- svcauth_gss_verify_header() enforces only checksum.len >= XDR_UNIT (4 bytes) before dispatching to gss_verify_mic().
- svcauth_gss_unwrap_integ() checks only that the checksum fits in gsd->gsd_scratch.
Add a length guard at the top of gss_krb5_verify_mic_v2(), before any ptr[] access or scatterlist construction. Well-formed MIC tokens from gss_krb5_get_mic_v2() already have exactly GSS_KRB5_TOK_HDR_LEN + cksum_len bytes, so valid traffic is unaffected.
--- net/sunrpc/auth_gss/gss_krb5_unseal.c | 3 +++ 1 file changed, 3 insertions(+)
net/sunrpc/auth_gss/gss_krb5_unseal.c +3 -0
@@ -159,6 +159,9 @@ gss_verify_mic_v2(struct krb5_ctx *ctx,dprintk ("RPC: %s\n" , __func__); +if (read_token->len <GSS_KRB5_TOK_HDR_LEN + ctx->gk5e->cksumlength) +return GSS_S_DEFECTIVE_TOKEN ; +memcpy (&be16_ptr, (char *) ptr,2 );if (be16_to_cpu (be16_ptr) !=KG2_TOK_MIC )return GSS_S_DEFECTIVE_TOKEN ;
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1400/1887 sunrpc: fix use-after-free in __rpc_clnt_handle_event and __rpc_clnt_remove_pipedir
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Luxiao Xu <[email protected]>
[ Upstream commit 932a8cf6abb2b2f8677b79153a823108d8861fe2 ]
Normal client creation goes through rpc_setup_pipedir(), which records clnt->pipefs_sb, but the mount-event path in __rpc_clnt_handle_event() calls rpc_setup_pipedir_sb() directly and never refreshes that field. The umount path also removes the directory without clearing clnt->pipefs_sb.
After a late pipefs mount or any remount, rpc_clnt_remove_pipedir() compares the current superblock against a stale pipefs_sb pointer and skips cleanup, leaving pipefs dentries whose inode private data still points at a freed rpc_clnt, leading to a potential use-after-free during subsequent rpc_info_open() or rpc_show_info() calls.
Fix this by properly updating clnt->pipefs_sb upon mount events and clearing it during unmount or failure paths.
--- net/sunrpc/clnt.c | 22 ++++++++++++++++------ 1 file changed, 16 insertions(+), 6 deletions(-)
net/sunrpc/clnt.c +16 -6
@@ -101,7 +101,10 @@ static void rpc_unregister_client(struct rpc_clnt *clnt)static void __rpc_clnt_remove_pipedir (struct rpc_clnt *clnt) { -rpc_remove_client_dir (clnt); +if (clnt->pipefs_sb) { +rpc_remove_client_dir (clnt); + clnt->pipefs_sb =NULL ; + } }static void rpc_clnt_remove_pipedir (struct rpc_clnt *clnt)
@@ -186,23 +189,30 @@ static int __rpc_clnt_handle_event(struct rpc_clnt *clnt, unsigned long event, struct super_block *sb) {struct dentry *dentry; +int err =0 ;switch (event) {case RPC_PIPEFS_MOUNT : + clnt->pipefs_sb = sb; dentry =rpc_setup_pipedir_sb (sb, clnt);if (!dentry) -return -ENOENT ; -if (IS_ERR (dentry)) -return PTR_ERR (dentry); + err = -ENOENT ; +else if (IS_ERR (dentry)) + err =PTR_ERR (dentry); +if (err) + clnt->pipefs_sb =NULL ;break ;case RPC_PIPEFS_UMOUNT : -__rpc_clnt_remove_pipedir (clnt); +if (clnt->pipefs_sb == sb) { +__rpc_clnt_remove_pipedir (clnt); + clnt->pipefs_sb =NULL ; + }break ;default :printk (KERN_ERR "%s: unknown event: %ld\n" , __func__, event);return -ENOTSUPP ; } -return 0 ; +return err; } static int __rpc_pipefs_event(struct rpc_clnt *clnt, unsigned long event,
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1401/1887 sunrpc: defer rq_argp and rq_resp free until after RCU grace period
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Jeff Layton <[email protected]>
[ Upstream commit c479bde671cbe2f9e152834a8b0eb7c3c295bbaf ]
svc_rqst_free() frees rqstp->rq_argp and rqstp->rq_resp synchronously via kfree(), but defers the rqstp struct free via kfree_rcu(). After svc_exit_thread() calls list_del_rcu() and svc_rqst_free(), there is a window where RCU readers that started before list_del_rcu() can still traverse the thread list and find the rqstp. These readers (e.g. nfsd_nl_rpc_status_get_dumpit()) dereference rqstp->rq_argp, which has already been freed — a use-after-free.
Fix this by moving the kfree of rq_argp and rq_resp into an explicit call_rcu() callback alongside the struct free. Resources not accessed by RCU readers (bvec, buffer pages, scratch folio, auth_data) remain synchronously freed.
--- net/sunrpc/svc.c | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-)
net/sunrpc/svc.c +10 -3
@@ -874,6 +874,15 @@ void svc_rqst_replace_page(struct svc_rqst *rqstp, struct page *page) }EXPORT_SYMBOL_GPL (svc_rqst_replace_page); +static void svc_rqst_free_rcu (struct rcu_head *head) +{ + struct svc_rqst *rqstp = container_of(head, struct svc_rqst, rq_rcu_head); + +kfree (rqstp->rq_resp); +kfree (rqstp->rq_argp); +kfree (rqstp); +} +/* * Called from a server thread as it's exiting. Caller must hold the "service * mutex" for the service.
@@ -884,10 +893,8 @@ svc_rqst_free(struct svc_rqst *rqstp)svc_release_buffer (rqstp);if (rqstp->rq_scratch_page)put_page (rqstp->rq_scratch_page); -kfree (rqstp->rq_resp); -kfree (rqstp->rq_argp);kfree (rqstp->rq_auth_data); -kfree_rcu (rqstp, rq_rcu_head); +call_rcu (&rqstp->rq_rcu_head, svc_rqst_free_rcu); }EXPORT_SYMBOL_GPL (svc_rqst_free);
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1402/1887 SUNRPC: Fix crasher in unwrap_integ_data()
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Chuck Lever <[email protected]>
[ Upstream commit 4dd9daa9124aad3c3d4ceca4f1d417cc62d59156 ]
If a zero length is passed to kmalloc() it returns 0x10, which is not a valid address. gss_verify_mic() subsequently crashes when it attempts to dereference that pointer.
Instead of allocating this memory on every call based on an untrusted size value, use a piece of dynamically-allocated scratch memory that is always available.
Stable-dep-of: a919c5c88769 ("SUNRPC: svcauth_gss: enforce krb5 token minimum length")
--- net/sunrpc/auth_gss/svcauth_gss.c | 55 ++++++++++++++++++------------- 1 file changed, 32 insertions(+), 23 deletions(-)
net/sunrpc/auth_gss/svcauth_gss.c +32 -23
@@ -49,11 +49,36 @@#include <linux/sunrpc/svcauth.h> #include <linux/sunrpc/svcauth_gss.h> #include <linux/sunrpc/cache.h> +#include <linux/sunrpc/gss_krb5.h> #include <trace/events/rpcgss.h> #include "gss_rpc_upcall.h" +/* +* Unfortunately there isn't a maximum checksum size exported via the +* GSS API. Manufacture one based on GSS mechanisms supported by this +* implementation. +*/ +#define GSS_MAX_CKSUMSIZE (GSS_KRB5_TOK_HDR_LEN + GSS_KRB5_MAX_CKSUM_LEN) + +/* +* This value may be increased in the future to accommodate other +* usage of the scratch buffer. +*/ +#define GSS_SCRATCH_SIZE GSS_MAX_CKSUMSIZE + +struct gss_svc_data { +/* decoded gss client cred: */ +struct rpc_gss_wire_cred clcred; +/* save a pointer to the beginning of the encoded verifier, +* for use in encryption/checksumming in svcauth_gss_release: */ +__be32 *verf_start; +struct rsc *rsci; + +/* for temporary results */ +u8 gsd_scratch[GSS_SCRATCH_SIZE ]; +};/* The rpcsec_init cache is used for mapping RPCSEC_GSS_{,CONT_}INIT requests * into replies.
@@ -887,13 +912,11 @@ read_u32_from_xdr_buf(struct xdr_buf *buf, int base, u32 *obj)static int unwrap_integ_data (struct svc_rqst *rqstp,struct xdr_buf *buf,u32 seq,struct gss_ctx *ctx) { +struct gss_svc_data *gsd = rqstp->rq_auth_data;u32 integ_len, rseqno, maj_stat; -int stat = -EINVAL ;struct xdr_netobj mic;struct xdr_buf integ_buf; - mic.data =NULL ; -/* NFS READ normally uses splice to send data in-place. However * the data in cache can change after the reply's MIC is computed * but before the RPC reply is sent. To prevent the client from
@@ -917,11 +940,9 @@ unwrap_integ_data(struct svc_rqst *rqstp, struct xdr_buf *buf, u32 seq, struct g/* copy out mic... */ if (read_u32_from_xdr_buf (buf, integ_len, &mic.len)) goto unwrap_failed; -if (mic.len >RPC_MAX_AUTH_SIZE ) - goto unwrap_failed; - mic.data =kmalloc (mic.len,GFP_KERNEL ); -if (!mic.data) +if (mic.len >sizeof (gsd->gsd_scratch)) goto unwrap_failed; + mic.data = gsd->gsd_scratch;if (read_bytes_from_xdr_buf (buf, integ_len +4 , mic.data, mic.len)) goto unwrap_failed; maj_stat =gss_verify_mic (ctx, &integ_buf, &mic);
@@ -932,20 +953,17 @@ unwrap_integ_data(struct svc_rqst *rqstp, struct xdr_buf *buf, u32 seq, struct g goto bad_seqno;/* trim off the mic and padding at the end before returning */ xdr_buf_trim (buf,round_up_to_quad (mic.len) +4 ); - stat =0 ; -out: -kfree (mic.data); -return stat; +return 0 ; unwrap_failed:trace_rpcgss_svc_unwrap_failed (rqstp); - goto out; +return -EINVAL ; bad_seqno:trace_rpcgss_svc_seqno_bad (rqstp, seq, rseqno); - goto out; +return -EINVAL ; bad_mic:trace_rpcgss_svc_mic (rqstp, maj_stat); - goto out; +return -EINVAL ; } static inline int
@@ -1023,15 +1041,6 @@ unwrap_priv_data(struct svc_rqst *rqstp, struct xdr_buf *buf, u32 seq, struct gsreturn -EINVAL ; } -struct gss_svc_data { -/* decoded gss client cred: */ -struct rpc_gss_wire_cred clcred; -/* save a pointer to the beginning of the encoded verifier, -* for use in encryption/checksumming in svcauth_gss_release: */ -__be32 *verf_start; -struct rsc *rsci; -}; -static int svcauth_gss_set_client (struct svc_rqst *rqstp) {
Signature · 1 line
2.53.0