6.6.145-rc1 review
Subsystems (7)
Greg Kroah-Hartman
maintainerPATCH 702/1266 apparmor: aa_getprocattr free procattr leak on format failure
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Zygmunt Krynicki <[email protected]>
[ Upstream commit fea23bf73f0cae8ccb1d0684e4a3003874771f41 ]
aa_getprocattr() allocates the output string before rendering the label into it. If the second aa_label_snxprint() call fails, the function returned without freeing that allocation.
Free and clear the output pointer on the uncommon formatting failure path before dropping the namespace reference.
--- security/apparmor/procattr.c | 2 ++ 1 file changed, 2 insertions(+)
security/apparmor/procattr.c +2 -0
@@ -53,6 +53,8 @@ int aa_getprocattr(struct aa_label *label, char **string)FLAG_SHOW_MODE |FLAG_VIEW_SUBNS | FLAG_HIDDEN_UNCONFINED);if (len <0 ) { +kfree (*string); + *string =NULL ;aa_put_ns (current_ns);return len; }
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 703/1266 apparmor: put secmark label after secid lookup
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Zygmunt Krynicki <[email protected]>
[ Upstream commit 340372688bb87da45ff8d4e2f82ccfd1b64c65ff ]
apparmor_secmark_init() parses a configured secmark label to obtain its secid. aa_label_strn_parse() returns a refcounted label, but the success path kept that reference after copying the secid.
--- security/apparmor/net.c | 1 + 1 file changed, 1 insertion(+)
security/apparmor/net.c +1 -0
@@ -217,6 +217,7 @@ static int apparmor_secmark_init(struct aa_secmark *secmark)return PTR_ERR (label); secmark->secid = label->secid; +aa_put_label (label);return 0 ; }
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 704/1266 i3c: master: Prevent reuse of dynamic address on device add failure
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Adrian Hunter <[email protected]>
[ Upstream commit b3ba8383da4d0cff15810e32ea785eceb0a80813 ]
i3c_master_add_i3c_dev_locked() is called after a device has already been assigned a dynamic address. If the function fails, the address remains marked as free and may be reallocated to another device, leading to address conflicts on the bus.
Ensure the address is not marked as free on failure, by updating the address slot state to prevent the address from being re-used.
Emit an error message to inform of the failure.
Opportunistically remove the !master check because it is impossible.
Note, directly resetting the device's dynamic address is no longer an option, since Direct RSTDAA was deprecated from I3C starting from version 1.1 and v1.1 (or later) target devices are meant to NACK it.
--- drivers/i3c/master.c | 19 ++++++++++++++----- 1 file changed, 14 insertions(+), 5 deletions(-)
drivers/i3c/master.c +14 -5
@@ -2014,12 +2014,11 @@ int i3c_master_add_i3c_dev_locked(struct i3c_master_controller *master,bool enable_ibi = false;int ret; -if (!master) -return -EINVAL ; - newdev =i3c_master_alloc_i3c_dev (master, &info); -if (IS_ERR (newdev)) -return PTR_ERR (newdev); +if (IS_ERR (newdev)) { + ret =PTR_ERR (newdev); + goto err_prevent_addr_reuse; + } ret =i3c_master_attach_i3c_dev (master, newdev);if (ret)
@@ -2141,6 +2140,16 @@ int i3c_master_add_i3c_dev_locked(struct i3c_master_controller *master, err_free_dev:i3c_master_free_i3c_dev (newdev); +err_prevent_addr_reuse: +/* +* Although the device has not been added, the address has been +* assigned. Prevent the address from being used again. +*/ +if (i3c_bus_get_addr_slot_status (&master->bus, addr) ==I3C_ADDR_SLOT_FREE ) +i3c_bus_set_addr_slot_status (&master->bus, addr,I3C_ADDR_SLOT_I3C_DEV ); + +dev_err (&master->dev,"Failed to add I3C device at address %u, error %d\n" , addr, ret); +return ret; }EXPORT_SYMBOL_GPL (i3c_master_add_i3c_dev_locked);
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 705/1266 apparmor: fix label can not be immediately before a declaration
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: John Johansen <[email protected]>
[ Upstream commit 1ed40bd525c00d22af666016af9aef7167f8085f ]
Fix error reported by kernel test robot
security/apparmor/policy.c:1381:2: error: a label can only be part of a statement and a declaration is not a statement
All errors (new ones prefixed by >>):
security/apparmor/policy.c: In function 'aa_replace_profiles':
Quoted 1 line
Quoted 1 line
security/apparmor/policy.c:1381:2: error: a label can only be part
of a statement and a declaration is not a statement
ssize_t udata_sz = udata->size;
^~~~~--- security/apparmor/policy.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-)
security/apparmor/policy.c +2 -1
@@ -1324,9 +1324,10 @@ ssize_t aa_replace_profiles(struct aa_ns *policy_ns, struct aa_label *label,mutex_unlock (&ns->lock); out: +aa_put_ns (ns); +ssize_t udata_sz = udata->size; -aa_put_ns (ns);aa_put_profile_loaddata (udata);kfree (ns_name);
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 706/1266 sparc: led: avoid trimming a newline from empty writes
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Pengpeng Hou <[email protected]>
[ Upstream commit 7eb475e8a738ee6fd1260aa59ddccb610fdd4300 ]
led_proc_write() duplicates up to LED_MAX_LENGTH bytes with memdup_user_nul() and then unconditionally inspects buf[count - 1] to strip a trailing newline. A zero-length write therefore reads one byte before the duplicated buffer.
The previous version rejected empty writes, but empty input already falls through to the existing default case and turns the LED off like any other unrecognized string. Preserve that behavior and only skip the newline trim when there is no input byte to inspect.
--- arch/sparc/kernel/led.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
arch/sparc/kernel/led.c +1 -1
@@ -78,7 +78,7 @@ static ssize_t led_proc_write(struct file *file, const char __user *buffer,return PTR_ERR (buf);/* work around \n when echo'ing into proc */ -if (buf[count -1 ] =='\n' ) +if (count >0 && buf[count -1 ] =='\n' ) buf[count -1 ] ='\0' ;/* before we change anything we want to stop any running timers,
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 707/1266 perf symbols: Break infinite loop on zero-filled notes in sysfs__read_build_id()
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Arnaldo Carvalho de Melo <[email protected]>
[ Upstream commit 063c647b24f640657d6d9e2e90d620ea3ee19ae6 ]
sysfs__read_build_id() iterates ELF note headers from sysfs files in a while(1) loop. If the file contains a zero-filled note header (both n_namesz and n_descsz are 0), the code computes n = namesz + descsz = 0 and calls read(fd, bf, 0). read() with count 0 returns 0, which matches the expected (ssize_t)n value, so the error check passes and the loop repeats — reading the same zero bytes and spinning forever.
This can happen with corrupted or zero-padded sysfs pseudo-files.
Add a check for n == 0 before the read, since no valid ELF note has both name and description of zero length.
--- tools/perf/util/symbol-elf.c | 3 +++ 1 file changed, 3 insertions(+)
tools/perf/util/symbol-elf.c +3 -0
@@ -1091,6 +1091,9 @@ int sysfs__read_build_id(const char *filename, struct build_id *bid) }else { n = namesz + descsz; } +/* no valid note has both namesz and descsz zero */ +if (n ==0 ) +break ;if (read (fd, bf, n) != (ssize_t )n)break ; }
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 708/1266 perf tools: Use snprintf() for root_dir path construction
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Arnaldo Carvalho de Melo <[email protected]>
[ Upstream commit 7b0df6f4d498b1608afccfd6dffb264e6da91693 ]
get_kernel_version() in machine.c and dso__load_guest_kernel_sym() in symbol.c use sprintf() to construct paths by prepending root_dir to "/proc/version" and "/proc/kallsyms" respectively. Both write into PATH_MAX stack buffers, but root_dir comes from --guestmount or KVM configuration and is not length-checked. A root_dir at or near PATH_MAX causes a stack buffer overflow.
Switch to snprintf() with sizeof(path) to prevent overflow.
--- tools/perf/util/machine.c | 2 +- tools/perf/util/symbol.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-)
tools/perf/util/machine.c +1 -1
@@ -1495,7 +1495,7 @@ static char *get_kernel_version(const char *root_dir)char *name, *tmp;const char *prefix ="Linux version " ; -sprintf (version,"%s/proc/version" , root_dir); +snprintf (version,sizeof (version),"%s/proc/version" , root_dir); file =fopen (version,"r" );if (!file)return NULL ;
tools/perf/util/symbol.c +1 -1
@@ -2215,7 +2215,7 @@ static int dso__load_guest_kernel_sym(struct dso *dso, struct map *map)if (!kallsyms_filename)return -1 ; }else { -sprintf (path,"%s/proc/kallsyms" , machine->root_dir); +snprintf (path,sizeof (path),"%s/proc/kallsyms" , machine->root_dir); kallsyms_filename = path; }
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 709/1266 perf bpf: Validate func_info_rec_size and sub_id in synthesize_bpf_prog_name()
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Arnaldo Carvalho de Melo <[email protected]>
[ Upstream commit 10b3c3d63ecc17c6acb855bac5f40367f1115765 ]
synthesize_bpf_prog_name() computes a pointer into the func_info array using sub_id * info->func_info_rec_size without validating either value. Both come from perf.data and are untrusted:
- A func_info_rec_size smaller than sizeof(struct bpf_func_info) means the finfo pointer would reference a truncated entry, reading past it into adjacent data.
- A sub_id >= nr_func_info computes an offset past the func_info buffer, causing an out-of-bounds read.
Add bounds checks for both values before computing the pointer offset. When validation fails, fall through to the non-BTF name path instead of reading garbage.
--- tools/perf/util/bpf-event.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-)
tools/perf/util/bpf-event.c +3 -1
@@ -134,7 +134,9 @@ static int synthesize_bpf_prog_name(char *buf, int size, name_len =scnprintf (buf, size,"bpf_prog_" ); name_len +=snprintf_hex (buf + name_len, size - name_len, prog_tags[sub_id],BPF_TAG_SIZE ); -if (btf) { +if (btf && + info->func_info_rec_size >=sizeof (*finfo) && + sub_id < info->nr_func_info) { finfo = func_infos + sub_id * info->func_info_rec_size; t =btf__type_by_id (btf, finfo->type_id);if (t)
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 710/1266 perf bpf: Bounds-check array offsets in bpil_offs_to_addr()
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Arnaldo Carvalho de Melo <[email protected]>
[ Upstream commit 033e85edfbf271f92979d2a39aeaf40f8472a795 ]
bpil_offs_to_addr() converts offsets stored in perf.data's bpf_prog_info_linear structure into heap pointers by adding the offset to the data allocation base. The offsets come from untrusted file input and are not validated against data_len.
If an offset exceeds data_len, the computed address points outside the allocated data buffer. Callers like synthesize_bpf_prog_name() then dereference prog_tags[sub_id] or func_info pointers, reading arbitrary heap memory.
Add a bounds check: when an offset exceeds data_len, zero the field and skip the conversion. This prevents out-of-bounds pointer construction from crafted perf.data files.
--- tools/perf/util/bpf-utils.c | 16 ++++++++++++++++ 1 file changed, 16 insertions(+)
tools/perf/util/bpf-utils.c +16 -0
@@ -246,6 +246,7 @@ void bpil_offs_to_addr(struct perf_bpil *info_linear)for (i =PERF_BPIL_FIRST_ARRAY ; i <PERF_BPIL_LAST_ARRAY ; ++i) {struct bpil_array_desc *desc;__u64 addr, offs; +__u32 count, size;if ((info_linear->arrays & (1UL << i)) ==0 )continue ;
@@ -253,6 +254,21 @@ void bpil_offs_to_addr(struct perf_bpil *info_linear) desc = bpil_array_desc + i; offs =bpf_prog_info_read_offset_u64 (&info_linear->info, desc->array_offset); + count =bpf_prog_info_read_offset_u32 (&info_linear->info, + desc->count_offset); + size =bpf_prog_info_read_offset_u32 (&info_linear->info, + desc->size_offset); +/* offset and extent from perf.data are untrusted — keep within data[] */ +if (offs >= info_linear->data_len || + (u64 )count * size > info_linear->data_len - offs) { +bpf_prog_info_set_offset_u64 (&info_linear->info, + desc->array_offset,0 ); +bpf_prog_info_set_offset_u32 (&info_linear->info, + desc->count_offset,0 ); +/* clear the bit so bpil_addr_to_offs() won't reverse a zeroed address */ + info_linear->arrays &= ~(1UL << i); +continue ; + } addr = offs +ptr_to_u64 (info_linear->data);bpf_prog_info_set_offset_u64 (&info_linear->info, desc->array_offset, addr);
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 711/1266 gpio: mlxbf3: fail probe if gpiochip registration fails
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Pengpeng Hou <[email protected]>
[ Upstream commit 0482862a90169f4daaba0ed31a85d8304bf51e04 ]
mlxbf3_gpio_probe() logs a devm_gpiochip_add_data() failure but still returns success. That leaves the platform device bound even though the GPIO chip was not registered.
Return the registration error so probe failure matches the missing gpiochip state.
--- drivers/gpio/gpio-mlxbf3.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-)
drivers/gpio/gpio-mlxbf3.c +2 -1
@@ -252,7 +252,8 @@ static int mlxbf3_gpio_probe(struct platform_device *pdev) ret =devm_gpiochip_add_data (dev, &gs->gc, gs);if (ret) -dev_err_probe (dev, ret,"Failed adding memory mapped gpiochip\n" ); +return dev_err_probe (dev, ret, +"Failed adding memory mapped gpiochip\n" );return 0 ; }
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 712/1266 spi: dw: fix wrong BAUDR setting after resume
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Jisheng Zhang <[email protected]>
[ Upstream commit 66b6605bcea7af7aca3d1d858b9c5f14903f9f9a ]
After resuming from suspend to ram, spi transfer stops working. Further debugging shows that the BAUDR register isn't correctly set, this is due to dws->current_freq doesn't match the HW BAUDR setting, specifically, the dws->current_freq equals to speed_hz, but BAUDR is 0. so the dw_spi_set_clk() in below code won't be called:
if (dws->current_freq != speed_hz) {
dw_spi_set_clk(dws, clk_div);
dws->current_freq = speed_hz;
}The mismatch comes from dw_spi_shutdown_chip() when suspending. Fix this mismatch by setting dws->current_freq to 0 as well when clearing BAUDR reg in dw_spi_shutdown_chip().
--- drivers/spi/spi-dw.h | 1 + 1 file changed, 1 insertion(+)
drivers/spi/spi-dw.h +1 -0
@@ -282,6 +282,7 @@ static inline void dw_spi_shutdown_chip(struct dw_spi *dws) {dw_spi_enable_chip (dws,0 );dw_spi_set_clk (dws,0 ); + dws->current_freq =0 ; }extern void dw_spi_set_cs (struct spi_device *spi,bool enable);
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 713/1266 xfrm: Use the XFRM_GRO to indicate a GRO call on input
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Steffen Klassert <[email protected]>
[ Upstream commit b439475a0dba2b50fb39a6356069969780e45fd4 ]
This is needed to support GRO for ESP in UDP encapsulation.
Stable-dep-of: 68de007d5ac9 ("xfrm: annotate data-races around xfrm_policy_count[] and xfrm_policy_default[]")
--- net/ipv4/esp4_offload.c | 2 +- net/ipv6/esp6_offload.c | 2 +- net/xfrm/xfrm_input.c | 6 ++---- 3 files changed, 4 insertions(+), 6 deletions(-)
net/ipv4/esp4_offload.c +1 -1
@@ -77,7 +77,7 @@ static struct sk_buff *esp4_gro_receive(struct list_head *head,/* We don't need to handle errors from xfrm_input, it does all * the error handling and frees the resources on error. */ -xfrm_input (skb,IPPROTO_ESP , spi,-2 ); +xfrm_input (skb,IPPROTO_ESP , spi,0 );return ERR_PTR (-EINPROGRESS ); out_reset:
net/ipv6/esp6_offload.c +1 -1
@@ -104,7 +104,7 @@ static struct sk_buff *esp6_gro_receive(struct list_head *head,/* We don't need to handle errors from xfrm_input, it does all * the error handling and frees the resources on error. */ -xfrm_input (skb,IPPROTO_ESP , spi,-2 ); +xfrm_input (skb,IPPROTO_ESP , spi,0 );return ERR_PTR (-EINPROGRESS ); out_reset:
net/xfrm/xfrm_input.c +2 -4
@@ -470,7 +470,7 @@ int xfrm_input(struct sk_buff *skb, int nexthdr, __be32 spi, int encap_type)struct xfrm_offload *xo =xfrm_offload (skb);struct sec_path *sp; -if (encap_type <0 ) { +if (encap_type <0 || (xo && xo->flags &XFRM_GRO )) { x =xfrm_input_state (skb);if (unlikely (x->km.state !=XFRM_STATE_VALID )) {
@@ -493,9 +493,7 @@ int xfrm_input(struct sk_buff *skb, int nexthdr, __be32 spi, int encap_type) seq =XFRM_SKB_CB (skb)->seq.input.low; goto resume; } - -/* encap_type < -1 indicates a GRO call. */ - encap_type =0 ; +/* GRO call */ seq =XFRM_SPI_SKB_CB (skb)->seq;if (xo && (xo->flags &CRYPTO_DONE )) {
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 714/1266 xfrm: Support crypto offload for inbound IPv6 ESP packets not in GRO path
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Mike Yu <[email protected]>
[ Upstream commit f7e8542d71e908706855a9f3e9e7844fea1feea0 ]
IPsec crypt offload supports outbound IPv6 ESP packets, but it doesn't support inbound IPv6 ESP packets.
This change enables the crypto offload for inbound IPv6 ESP packets that are not handled through GRO code path. If HW drivers add the offload information to the skb, the packet will be handled in the crypto offload rx code path.
Apart from the change in crypto offload rx code path, the change in xfrm_policy_check is also needed.
Exampe of RX data path:
+-----------+ +-------+
| HW Driver |-->| wlan0 |--------+
+-----------+ +-------+ |
v
+---------------+ +------+
+------>| Network Stack |-->| Apps |
| +---------------+ +------+
| |
| v
+--------+ +------------+
| ipsec1 |<--| XFRM Stack |
+--------+ +------------+Test: Enabled both in/out IPsec crypto offload, and verified IPv6
ESP packets on Android device on both wifi/cellular network
Stable-dep-of: 68de007d5ac9 ("xfrm: annotate data-races around xfrm_policy_count[] and xfrm_policy_default[]")
--- net/xfrm/xfrm_input.c | 2 +- net/xfrm/xfrm_policy.c | 5 ++++- 2 files changed, 5 insertions(+), 2 deletions(-)
net/xfrm/xfrm_input.c +1 -1
@@ -470,7 +470,7 @@ int xfrm_input(struct sk_buff *skb, int nexthdr, __be32 spi, int encap_type)struct xfrm_offload *xo =xfrm_offload (skb);struct sec_path *sp; -if (encap_type <0 || (xo && xo->flags &XFRM_GRO )) { +if (encap_type <0 || (xo && (xo->flags &XFRM_GRO || encap_type ==0 ))) { x =xfrm_input_state (skb);if (unlikely (x->km.state !=XFRM_STATE_VALID )) {
net/xfrm/xfrm_policy.c +4 -1
@@ -3683,12 +3683,15 @@ int __xfrm_policy_check(struct sock *sk, int dir, struct sk_buff *skb, }if (!pol) { +const bool is_crypto_offload = sp && + (xfrm_input_state (skb)->xso.type ==XFRM_DEV_OFFLOAD_CRYPTO ); +if (net->xfrm.policy_default[dir] ==XFRM_USERPOLICY_BLOCK ) {XFRM_INC_STATS (net,LINUX_MIB_XFRMINNOPOLS );return 0 ; } -if (sp &&secpath_has_nontransport (sp,0 , &xerr_idx)) { +if (sp &&secpath_has_nontransport (sp,0 , &xerr_idx) && !is_crypto_offload) {xfrm_secpath_reject (xerr_idx, skb, &fl);XFRM_INC_STATS (net,LINUX_MIB_XFRMINNOPOLS );return 0 ;
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 715/1266 xfrm: annotate data-races around xfrm_policy_count[] and xfrm_policy_default[]
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Eric Dumazet <[email protected]>
[ Upstream commit 68de007d5ac9df0e3f4f187a179c5c842bb5a2be ]
KCSAN reported a data race involving net->xfrm.policy_count access.
Add missing READ_ONCE()/WRITE_ONCE() annotations on xfrm_policy_count and xfrm_policy_default.
--- include/net/xfrm.h | 8 ++++---- net/xfrm/xfrm_policy.c | 24 ++++++++++++------------ net/xfrm/xfrm_user.c | 18 +++++++++--------- 3 files changed, 25 insertions(+), 25 deletions(-)
include/net/xfrm.h +4 -4
@@ -1143,8 +1143,8 @@ int __xfrm_policy_check(struct sock *, int dir, struct sk_buff *skb,static inline bool __xfrm_check_nopolicy (struct net *net,struct sk_buff *skb,int dir) { -if (!net->xfrm.policy_count[dir] && !secpath_exists (skb)) -return net->xfrm.policy_default[dir] ==XFRM_USERPOLICY_ACCEPT ; +if (!READ_ONCE (net->xfrm.policy_count[dir]) && !secpath_exists (skb)) +return READ_ONCE (net->xfrm.policy_default[dir]) ==XFRM_USERPOLICY_ACCEPT ;return false; }
@@ -1244,8 +1244,8 @@ static inline int xfrm_route_forward(struct sk_buff *skb, unsigned short family) {struct net *net =dev_net (skb->dev); -if (!net->xfrm.policy_count[XFRM_POLICY_OUT ] && - net->xfrm.policy_default[XFRM_POLICY_OUT ] ==XFRM_USERPOLICY_ACCEPT ) +if (!READ_ONCE (net->xfrm.policy_count[XFRM_POLICY_OUT ]) && +READ_ONCE (net->xfrm.policy_default[XFRM_POLICY_OUT ]) ==XFRM_USERPOLICY_ACCEPT )return true; return (skb_dst(skb)->flags & DST_NOXFRM) ||
net/xfrm/xfrm_policy.c +12 -12
@@ -656,7 +656,7 @@ static void xfrm_byidx_resize(struct net *net)static inline int xfrm_bydst_should_resize (struct net *net,int dir,int *total) { -unsigned int cnt = net->xfrm.policy_count[dir]; +unsigned int cnt =READ_ONCE (net->xfrm.policy_count[dir]);unsigned int hmask = net->xfrm.policy_bydst[dir].hmask;if (total)
@@ -682,12 +682,12 @@ static inline int xfrm_byidx_should_resize(struct net *net, int total)void xfrm_spd_getinfo (struct net *net,struct xfrmk_spdinfo *si) { - si->incnt = net->xfrm.policy_count[XFRM_POLICY_IN ]; - si->outcnt = net->xfrm.policy_count[XFRM_POLICY_OUT ]; - si->fwdcnt = net->xfrm.policy_count[XFRM_POLICY_FWD ]; - si->inscnt = net->xfrm.policy_count[XFRM_POLICY_IN +XFRM_POLICY_MAX ]; - si->outscnt = net->xfrm.policy_count[XFRM_POLICY_OUT +XFRM_POLICY_MAX ]; - si->fwdscnt = net->xfrm.policy_count[XFRM_POLICY_FWD +XFRM_POLICY_MAX ]; + si->incnt =READ_ONCE (net->xfrm.policy_count[XFRM_POLICY_IN ]); + si->outcnt =READ_ONCE (net->xfrm.policy_count[XFRM_POLICY_OUT ]); + si->fwdcnt =READ_ONCE (net->xfrm.policy_count[XFRM_POLICY_FWD ]); + si->inscnt =READ_ONCE (net->xfrm.policy_count[XFRM_POLICY_IN +XFRM_POLICY_MAX ]); + si->outscnt =READ_ONCE (net->xfrm.policy_count[XFRM_POLICY_OUT +XFRM_POLICY_MAX ]); + si->fwdscnt =READ_ONCE (net->xfrm.policy_count[XFRM_POLICY_FWD +XFRM_POLICY_MAX ]); si->spdhcnt = net->xfrm.policy_idx_hmask; si->spdhmcnt = xfrm_policy_hashmax; }
@@ -2298,7 +2298,7 @@ static void __xfrm_policy_link(struct xfrm_policy *pol, int dir)struct net *net =xp_net (pol);list_add (&pol->walk.all, &net->xfrm.policy_all); - net->xfrm.policy_count[dir]++; +WRITE_ONCE (net->xfrm.policy_count[dir], net->xfrm.policy_count[dir] +1 );xfrm_pol_hold (pol); }
@@ -2318,7 +2318,7 @@ static struct xfrm_policy *__xfrm_policy_unlink(struct xfrm_policy *pol, }list_del_init (&pol->walk.all); - net->xfrm.policy_count[dir]--; +WRITE_ONCE (net->xfrm.policy_count[dir], net->xfrm.policy_count[dir] -1 );return pol; }
@@ -3192,7 +3192,7 @@ struct dst_entry *xfrm_lookup_with_ifid(struct net *net,/* To accelerate a bit... */ if (!if_id && ((dst_orig->flags &DST_NOXFRM ) || - !net->xfrm.policy_count[XFRM_POLICY_OUT ])) + !READ_ONCE (net->xfrm.policy_count[XFRM_POLICY_OUT ]))) goto nopol; xdst =xfrm_bundle_lookup (net, fl, family, dir, &xflo, if_id);
@@ -3264,7 +3264,7 @@ struct dst_entry *xfrm_lookup_with_ifid(struct net *net, nopol:if ((!dst_orig->dev || !(dst_orig->dev->flags &IFF_LOOPBACK )) && - net->xfrm.policy_default[dir] ==XFRM_USERPOLICY_BLOCK ) { +READ_ONCE (net->xfrm.policy_default[dir]) ==XFRM_USERPOLICY_BLOCK ) { err = -EPERM ; goto error; }
@@ -3686,7 +3686,7 @@ int __xfrm_policy_check(struct sock *sk, int dir, struct sk_buff *skb,const bool is_crypto_offload = sp && (xfrm_input_state (skb)->xso.type ==XFRM_DEV_OFFLOAD_CRYPTO ); -if (net->xfrm.policy_default[dir] ==XFRM_USERPOLICY_BLOCK ) { +if (READ_ONCE (net->xfrm.policy_default[dir]) ==XFRM_USERPOLICY_BLOCK ) {XFRM_INC_STATS (net,LINUX_MIB_XFRMINNOPOLS );return 0 ; }
net/xfrm/xfrm_user.c +9 -9
@@ -2217,9 +2217,9 @@ static int xfrm_notify_userpolicy(struct net *net) } up =nlmsg_data (nlh); - up->in = net->xfrm.policy_default[XFRM_POLICY_IN ]; - up->fwd = net->xfrm.policy_default[XFRM_POLICY_FWD ]; - up->out = net->xfrm.policy_default[XFRM_POLICY_OUT ]; + up->in =READ_ONCE (net->xfrm.policy_default[XFRM_POLICY_IN ]); + up->fwd =READ_ONCE (net->xfrm.policy_default[XFRM_POLICY_FWD ]); + up->out =READ_ONCE (net->xfrm.policy_default[XFRM_POLICY_OUT ]);nlmsg_end (skb, nlh);
@@ -2243,13 +2243,13 @@ static int xfrm_set_default(struct sk_buff *skb, struct nlmsghdr *nlh,struct xfrm_userpolicy_default *up =nlmsg_data (nlh);if (xfrm_userpolicy_is_valid (up->in)) - net->xfrm.policy_default[XFRM_POLICY_IN ] = up->in; +WRITE_ONCE (net->xfrm.policy_default[XFRM_POLICY_IN ], up->in);if (xfrm_userpolicy_is_valid (up->fwd)) - net->xfrm.policy_default[XFRM_POLICY_FWD ] = up->fwd; +WRITE_ONCE (net->xfrm.policy_default[XFRM_POLICY_FWD ], up->fwd);if (xfrm_userpolicy_is_valid (up->out)) - net->xfrm.policy_default[XFRM_POLICY_OUT ] = up->out; +WRITE_ONCE (net->xfrm.policy_default[XFRM_POLICY_OUT ], up->out);rt_genid_bump_all (net);
@@ -2279,9 +2279,9 @@ static int xfrm_get_default(struct sk_buff *skb, struct nlmsghdr *nlh, } r_up =nlmsg_data (r_nlh); - r_up->in = net->xfrm.policy_default[XFRM_POLICY_IN ]; - r_up->fwd = net->xfrm.policy_default[XFRM_POLICY_FWD ]; - r_up->out = net->xfrm.policy_default[XFRM_POLICY_OUT ]; + r_up->in =READ_ONCE (net->xfrm.policy_default[XFRM_POLICY_IN ]); + r_up->fwd =READ_ONCE (net->xfrm.policy_default[XFRM_POLICY_FWD ]); + r_up->out =READ_ONCE (net->xfrm.policy_default[XFRM_POLICY_OUT ]);nlmsg_end (r_skb, r_nlh);return nlmsg_unicast (net->xfrm.nlsk, r_skb, portid);
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 716/1266 xfrm: validate selector family and prefixlen during match
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Eric Dumazet <[email protected]>
[ Upstream commit 40f0b1047918539f0b0f795ac65e35336b4c2c78 ]
syzbot reported a shift-out-of-bounds in xfrm_selector_match() due to AF_UNSPEC selector with large prefixlen (e.g. 128) matched against IPv4 flow (when XFRM_STATE_AF_UNSPEC is set).
Fix this by:
- Rejecting mismatched families in xfrm_selector_match.
- Returning false in addr4_match if prefixlen > 32.
- Returning false in addr_match if prefixlen > 128 (prevents overflow).
--- include/net/xfrm.h | 7 +++++++ net/xfrm/xfrm_policy.c | 3 +++ 2 files changed, 10 insertions(+)
include/net/xfrm.h +7 -0
@@ -836,6 +836,9 @@ static inline bool addr_match(const void *token1, const void *token2,unsigned int pdw;unsigned int pbi; +if (prefixlen >128 ) +return false; + pdw = prefixlen >>5 ;/* num of whole u32 in prefix */ pbi = prefixlen &0x1f ;/* num of bits in incomplete u32 in prefix */
@@ -860,6 +863,10 @@ static inline bool addr4_match(__be32 a1, __be32 a2, u8 prefixlen)/* C99 6.5.7 (3): u32 << 32 is undefined behaviour */ if (sizeof (long ) ==4 && prefixlen ==0 )return true; + +if (prefixlen >32 ) +return false; +return !((a1 ^ a2) &htonl (~0UL << (32 - prefixlen))); }
net/xfrm/xfrm_policy.c +3 -0
@@ -223,6 +223,9 @@ __xfrm6_selector_match(const struct xfrm_selector *sel, const struct flowi *fl)bool xfrm_selector_match (const struct xfrm_selector *sel,const struct flowi *fl,unsigned short family) { +if (family != sel->family && sel->family !=AF_UNSPEC ) +return false; +switch (family) {case AF_INET :return __xfrm4_selector_match (sel, fl);
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 717/1266 perf machine: Use snprintf() for guestmount path construction
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Arnaldo Carvalho de Melo <[email protected]>
[ Upstream commit fe63d3bca288c5bb983304efd5fc3a5ff3183403 ]
machines__findnew() and machines__create_guest_kernel_maps() use sprintf() to build paths by prepending symbol_conf.guestmount. Both write into PATH_MAX stack buffers, but guestmount comes from user configuration and is not length-checked. A guestmount path at or near PATH_MAX causes a stack buffer overflow.
Switch to snprintf() with sizeof() to prevent overflow. The subsequent access()/fopen() calls will fail on a truncated path.
--- tools/perf/util/machine.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-)
tools/perf/util/machine.c +4 -4
@@ -369,7 +369,7 @@ struct machine *machines__findnew(struct machines *machines, pid_t pid)if ((pid !=HOST_KERNEL_ID ) && (pid !=DEFAULT_GUEST_KERNEL_ID ) && (symbol_conf.guestmount)) { -sprintf (path,"%s/%d" , symbol_conf.guestmount, pid); +snprintf (path,sizeof (path),"%s/%d" , symbol_conf.guestmount, pid);if (access (path,R_OK )) {static struct strlist *seen;
@@ -1415,9 +1415,9 @@ int machines__create_guest_kernel_maps(struct machines *machines) namelist[i]->d_name);continue ; } -sprintf (path,"%s/%s/proc/kallsyms" , - symbol_conf.guestmount, - namelist[i]->d_name); +snprintf (path,sizeof (path),"%s/%s/proc/kallsyms" , + symbol_conf.guestmount, + namelist[i]->d_name); ret =access (path,R_OK );if (ret) {pr_debug ("Can't access file %s\n" , path);
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 718/1266 perf cs-etm: Validate num_cpu before metadata allocation
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Arnaldo Carvalho de Melo <[email protected]>
[ Upstream commit 312d91329b8fc6989a916a3f9a12d0674167b7e4 ]
cs_etm__process_auxtrace_info_full() reads num_cpu from untrusted perf.data and uses it to allocate the metadata pointer array:
metadata = zalloc(sizeof(*metadata) * num_cpu);
On 32-bit, sizeof(*metadata) is 4, so num_cpu = 0x40000000 overflows the multiplication to 0, causing zalloc(0) to return a valid zero-sized allocation followed by out-of-bounds writes in the population loop.
Fix by computing priv_size early and using it to bound num_cpu: each CPU needs at least one u64 metadata entry, so num_cpu cannot exceed the total number of u64 entries in the event's private data area.
--- tools/perf/util/cs-etm.c | 12 ++++++++++++ 1 file changed, 12 insertions(+)
tools/perf/util/cs-etm.c +12 -0
@@ -3355,6 +3355,18 @@ int cs_etm__process_auxtrace_info_full(union perf_event *event,/* First the global part */ ptr = (u64 *) auxtrace_info->priv; num_cpu = ptr[CS_PMU_TYPE_CPUS ] &0xffffffff ; + +/* +* Bound num_cpu by the event size: the global header consumes +* CS_ETM_HEADER_SIZE bytes, and each CPU needs at least one u64 +* metadata entry after that. +*/ + priv_size = total_size - event_header_size -INFO_HEADER_SIZE - +CS_ETM_HEADER_SIZE ; +if (num_cpu <=0 || priv_size <=0 || + num_cpu > priv_size / (int )sizeof (u64)) +return -EINVAL ; + metadata =zalloc (sizeof (*metadata) * num_cpu);if (!metadata) { err = -ENOMEM ;
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 719/1266 perf cs-etm: Require full global header in auxtrace_info size check
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Arnaldo Carvalho de Melo <[email protected]>
[ Upstream commit 78d8ba680126f3545e8d0fba667e12d79fd4353b ]
cs_etm__process_auxtrace_info() checks that header.size covers event_header_size + INFO_HEADER_SIZE (16 bytes total), but then accesses ptr[CS_PMU_TYPE_CPUS] at offset 24 from the start of the event. A crafted 16-byte auxtrace_info event passes the size check but reads out-of-bounds.
Include CS_ETM_HEADER_SIZE in the minimum size check so that the global header entries (version, pmu_type_cpus, snapshot) are guaranteed to fit within the event.
--- tools/perf/util/cs-etm-base.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-)
tools/perf/util/cs-etm-base.c +3 -1
@@ -170,7 +170,9 @@ int cs_etm__process_auxtrace_info(union perf_event *event,u64 *ptr =NULL ;u64 hdr_version; -if (auxtrace_info->header.size < (event_header_size +INFO_HEADER_SIZE )) +/* Ensure priv[] is large enough for the global header entries */ +if (auxtrace_info->header.size < (event_header_size +INFO_HEADER_SIZE + +CS_ETM_HEADER_SIZE ))return -EINVAL ;/* First the global part */
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 720/1266 ASoC: tlv320aic3x: restrict CLKDIV bypass Q values in dual-rate mode
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Sen Wang <[email protected]>
[ Upstream commit fdf043f5f3bae150b678feae3d7bb1beed87ec14 ]
The datasheet documents that when the PLL is disabled and dual-rate mode is enabled, only Q values {4, 8, 9, 12, 16} are valid for the CLKDIV bypass path; all other Q values produce invalid bitclock output.
The existing loop iterates Q from 2 to 17 without this restriction, causing silent audio failure when an out-of-spec Q is picked.
Restrict the Q search to the allowed set in dual-rate mode.
--- sound/soc/codecs/tlv320aic3x.c | 25 +++++++++++++++++++------ 1 file changed, 19 insertions(+), 6 deletions(-)
sound/soc/codecs/tlv320aic3x.c +19 -6
@@ -1049,11 +1049,13 @@ static int aic3x_hw_params(struct snd_pcm_substream *substream,struct snd_pcm_hw_params *params, struct snd_soc_dai *dai) { + static const u8 dual_rate_q[] = {4, 8, 9, 12, 16};struct snd_soc_component *component = dai->component;struct aic3x_priv *aic3x =snd_soc_component_get_drvdata (component);int codec_clk =0 , bypass_pll =0 , fsref, last_clk =0 ;u8 data, j, r, p, pll_q, pll_p =1 , pll_r =1 , pll_j =1 ;u16 d, pll_d =1 ; +bool dual_rate;int clk;int width = aic3x->slot_width;
@@ -1079,14 +1081,25 @@ static int aic3x_hw_params(struct snd_pcm_substream *substream,/* Fsref can be 44100 or 48000 */ fsref = (params_rate (params) %11025 ==0 ) ?44100 :48000 ; + dual_rate =params_rate (params) >=64000 ;/* Try to find a value for Q which allows us to bypass the PLL and * generate CODEC_CLK directly. */ -for (pll_q =2 ; pll_q <18 ; pll_q++) -if (aic3x->sysclk / (128 * pll_q) == fsref) { - bypass_pll =1 ; -break ; +if (dual_rate) { +for (int i =0 ; i <ARRAY_SIZE (dual_rate_q); i++) { + pll_q = dual_rate_q[i]; +if (aic3x->sysclk / (128 * pll_q) == fsref) { + bypass_pll =1 ; +break ; + } } + }else { +for (pll_q =2 ; pll_q <18 ; pll_q++) +if (aic3x->sysclk / (128 * pll_q) == fsref) { + bypass_pll =1 ; +break ; + } + }if (bypass_pll) { pll_q &=0xf ;
@@ -1106,13 +1119,13 @@ static int aic3x_hw_params(struct snd_pcm_substream *substream,* right DAC to right channel input */ data = (LDAC2LCH |RDAC2RCH ); data |= (fsref ==44100 ) ?FSREF_44100 :FSREF_48000 ; -if (params_rate (params) >=64000 ) +if (dual_rate) data |=DUAL_RATE_MODE ;snd_soc_component_write (component,AIC3X_CODEC_DATAPATH_REG , data);/* codec sample rate select */ data = (fsref *20 ) /params_rate (params); -if (params_rate (params) <64000 ) +if (!dual_rate) data /=2 ; data /=5 ; data -=2 ;
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 721/1266 drm/amdkfd: Avoid double-unpin of DOORBELL/MMIO BOs on free
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Yunxiang Li <[email protected]>
[ Upstream commit 3f0cc1735273a57c5116710cf0202e12152f59cc ]
amdgpu_amdkfd_gpuvm_free_memory_of_gpu() unpinned DOORBELL and MMIO remap BOs (which are pinned at allocation time) before checking whether the BO is still mapped to the GPU. When the BO is still mapped, the function returns -EBUSY and leaves the BO alive, but it has already been unpinned. The BO is then unpinned again when it is finally freed during process teardown, triggering a ttm_bo_unpin() underflow warning:
WARNING: CPU: 18 PID: 15066 at ttm/ttm_bo.c:650 amdttm_bo_unpin+0x6d/0x80 [amdttm] Workqueue: kfd_process_wq kfd_process_wq_release [amdgpu] RIP: 0010:amdttm_bo_unpin+0x6d/0x80 [amdttm] Call Trace: amdgpu_bo_unpin+0x1a/0x90 [amdgpu] amdgpu_amdkfd_gpuvm_unpin_bo+0x31/0xb0 [amdgpu] amdgpu_amdkfd_gpuvm_free_memory_of_gpu+0x3bf/0x460 [amdgpu] kfd_process_free_outstanding_kfd_bos+0xd4/0x170 [amdgpu] kfd_process_wq_release+0x109/0x1b0 [amdgpu] process_one_work+0x1e2/0x3b0 worker_thread+0x50/0x3a0 kthread+0xdd/0x100 ret_from_fork+0x29/0x50
Move the unpin after the mapped_to_gpu_memory check so it only happens once we are committed to freeing the BO.
--- drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_gpuvm.c | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-)
drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_gpuvm.c +9 -7
@@ -1823,13 +1823,6 @@ int amdgpu_amdkfd_gpuvm_free_memory_of_gpu(mutex_lock (&mem->lock); -/* Unpin MMIO/DOORBELL BO's that were pinned during allocation */ -if (mem->alloc_flags & - (KFD_IOC_ALLOC_MEM_FLAGS_DOORBELL | -KFD_IOC_ALLOC_MEM_FLAGS_MMIO_REMAP )) { -amdgpu_amdkfd_gpuvm_unpin_bo (mem->bo); - } - mapped_to_gpu_memory = mem->mapped_to_gpu_memory; is_imported = mem->is_imported;mutex_unlock (&mem->lock);
@@ -1843,6 +1836,15 @@ int amdgpu_amdkfd_gpuvm_free_memory_of_gpu(return -EBUSY ; } +/* At this point the BO is guaranteed to be freed, so unpin the +* MMIO/DOORBELL BOs that were pinned during allocation. +*/ +if (mem->alloc_flags & + (KFD_IOC_ALLOC_MEM_FLAGS_DOORBELL | +KFD_IOC_ALLOC_MEM_FLAGS_MMIO_REMAP )) { +amdgpu_amdkfd_gpuvm_unpin_bo (mem->bo); + } +/* Make sure restore workers don't access the BO any more */ mutex_lock (&process_info->lock);list_del (&mem->validate_list);
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 722/1266 drm/amdkfd: fix list_del corruption in kfd_criu_resume_svm
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Mario Limonciello <[email protected]>
[ Upstream commit 8fa5655da368d0306c03e9dc9cda8ae2a7840926 ]
The cleanup tail of kfd_criu_resume_svm() walks svms->criu_svm_metadata_list and kfree()s each struct criu_svm_metadata without removing it from the list. The list head is left pointing at freed kmalloc-96 objects.
A second AMDKFD_IOC_CRIU_OP from the same process re-enters: list_empty() reads the dangling ->next (use-after-free), the loop walks freed entries, and each is kfree()'d again (double-free). This is reachable by an unprivileged render-group user via /dev/kfd with no capabilities required.
Add list_del() before the kfree() so the list is properly emptied. The list_for_each_entry_safe() iterator already caches the next pointer, so unlinking during the walk is safe.
--- drivers/gpu/drm/amd/amdkfd/kfd_svm.c | 1 + 1 file changed, 1 insertion(+)
drivers/gpu/drm/amd/amdkfd/kfd_svm.c +1 -0
@@ -3935,6 +3935,7 @@ int kfd_criu_resume_svm(struct kfd_process *p)list_for_each_entry_safe (criu_svm_md, next, &svms->criu_svm_metadata_list, list) {pr_debug ("freeing criu_svm_md[]\n\tstart: 0x%llx\n" , criu_svm_md->data.start_addr); +list_del (&criu_svm_md->list);kfree (criu_svm_md); }
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 723/1266 drm/amdgpu: initialize irq.lock spinlock earlier
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Thadeu Lima de Souza Cascardo <[email protected]>
[ Upstream commit a2b270c0ecf6d95bcd14ef4c20d0301a88143ff5 ]
If there is an early failure during amdgpu probe, like missing firmware, it will end up calling amdgpu_irq_disable_all, which takes irq.lock spinlock without it being initialized.
Initializing irq.lock earlier at amdgpu_device_init fixes the issue.
[ 79.334079] INFO: trying to register non-static key. [ 79.334081] The code is fine but needs lockdep annotation, or maybe [ 79.334083] you didn't initialize this object before use? [ 79.334084] turning off the locking correctness validator. [ 79.334088] CPU: 2 UID: 0 PID: 1819 Comm: bash Not tainted 7.1.0-rc5-gfd06300b2348 #96 PREEMPT 8e8f461221633dae3c832d6689eaf0546c0ed4cd [ 79.334092] Hardware name: Valve Jupiter/Jupiter, BIOS F7A0133 08/05/2024 [ 79.334094] Call Trace: [ 79.334095] <TASK> [ 79.334097] dump_stack_lvl+0x5d/0x80 [ 79.334103] register_lock_class+0x7af/0x7c0 [ 79.334109] __lock_acquire+0x416/0x2610 [ 79.334114] lock_acquire+0xcf/0x310 [ 79.334117] ? amdgpu_irq_disable_all+0x3b/0xf0 [amdgpu c88bab43d391d519ad0d5c8e5a099b4aceefa180] [ 79.334503] ? _raw_spin_lock_irqsave+0x53/0x60 [ 79.334508] _raw_spin_lock_irqsave+0x3f/0x60 [ 79.334510] ? amdgpu_irq_disable_all+0x3b/0xf0 [amdgpu c88bab43d391d519ad0d5c8e5a099b4aceefa180] [ 79.334881] amdgpu_irq_disable_all+0x3b/0xf0 [amdgpu c88bab43d391d519ad0d5c8e5a099b4aceefa180] [ 79.335240] amdgpu_device_fini_hw+0x90/0x32c [amdgpu c88bab43d391d519ad0d5c8e5a099b4aceefa180] [ 79.335704] amdgpu_driver_load_kms.cold+0x22/0x44 [amdgpu c88bab43d391d519ad0d5c8e5a099b4aceefa180] [ 79.336159] amdgpu_pci_probe+0x204/0x440 [amdgpu c88bab43d391d519ad0d5c8e5a099b4aceefa180] [ 79.336494] local_pci_probe+0x3c/0x80 [ 79.336500] pci_call_probe+0x55/0x2e0 [ 79.336505] ? _raw_spin_unlock+0x2d/0x50 [ 79.336508] ? pci_match_device+0x157/0x180 [ 79.336512] pci_device_probe+0x9b/0x170 [ 79.336516] really_probe+0xd5/0x370 [ 79.336521] __driver_probe_device+0x84/0x150 [ 79.336525] device_driver_attach+0x47/0xb0 [ 79.336528] bind_store+0x73/0xc0 [ 79.336531] kernfs_fop_write_iter+0x176/0x250 [ 79.336536] vfs_write+0x24d/0x560 [ 79.336542] ksys_write+0x71/0xe0 [ 79.336546] do_syscall_64+0x122/0x710 [ 79.336550] ? do_syscall_64+0xd1/0x710 [ 79.336553] entry_SYSCALL_64_after_hwframe+0x4b/0x53 [ 79.336557] RIP: 0033:0x7f92fd675006 [ 79.336561] Code: 5d e8 41 8b 93 08 03 00 00 59 5e 48 83 f8 fc 75 19 83 e2 39 83 fa 08 75 11 e8 26 ff ff ff 66 0f 1f 44 00 00 48 8b 45 10 0f 05 <48> 8b 5d f8 c9 c3 0f 1f 40 00 f3 0f 1e fa 55 48 89 e5 48 83 ec 08 [ 79.336562] RSP: 002b:00007ffe4fa867a0 EFLAGS: 00000202 ORIG_RAX: 0000000000000001 [ 79.336565] RAX: ffffffffffffffda RBX: 000000000000000d RCX: 00007f92fd675006 [ 79.336567] RDX: 000000000000000d RSI: 000055b2dfce59b0 RDI: 0000000000000001 [ 79.336568] RBP: 00007ffe4fa867c0 R08: 0000000000000000 R09: 0000000000000000 [ 79.336569] R10: 0000000000000000 R11: 0000000000000202 R12: 000000000000000d [ 79.336570] R13: 000055b2dfce59b0 R14: 00007f92fd7ca5c0 R15: 000055b2dfdbaf70 [ 79.336574] </TASK>
--- drivers/gpu/drm/amd/amdgpu/amdgpu_device.c | 2 ++ drivers/gpu/drm/amd/amdgpu/amdgpu_irq.c | 2 -- 2 files changed, 2 insertions(+), 2 deletions(-)
drivers/gpu/drm/amd/amdgpu/amdgpu_device.c +2 -0
@@ -3590,6 +3590,8 @@ int amdgpu_device_init(struct amdgpu_device *adev,mutex_init (&adev->pm.stable_pstate_ctx_lock);mutex_init (&adev->benchmark_mutex); +spin_lock_init (&adev->irq.lock); +amdgpu_device_init_apu_flags (adev); r =amdgpu_device_check_arguments (adev);
drivers/gpu/drm/amd/amdgpu/amdgpu_irq.c +0 -2
@@ -273,8 +273,6 @@ int amdgpu_irq_init(struct amdgpu_device *adev)int r =0 ;unsigned int irq; -spin_lock_init (&adev->irq.lock); -/* Enable MSI if not disabled by module parameter */ adev->irq.msi_enabled = false;
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 724/1266 octeontx2-pf: Fix leak of SQ timestamp buffer on teardown
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Ratheesh Kannoth <[email protected]>
[ Upstream commit a056db30de92945ff8ee6033096678bfbae878e3 ]
The send-queue timestamp ring is allocated with qmem_alloc() when timestamping is used, but otx2_free_sq_res() never freed sq->timestamps, leaking that memory across ifdown and device removal. Add the missing qmem_free() alongside the other SQ companion buffers.
--- drivers/net/ethernet/marvell/octeontx2/nic/otx2_pf.c | 1 + 1 file changed, 1 insertion(+)
drivers/net/ethernet/marvell/octeontx2/nic/otx2_pf.c +1 -0
@@ -1448,6 +1448,7 @@ static void otx2_free_sq_res(struct otx2_nic *pf)continue ;qmem_free (pf->dev, sq->sqe);qmem_free (pf->dev, sq->tso_hdrs); +qmem_free (pf->dev, sq->timestamps);kfree (sq->sg);kfree (sq->sqb_ptrs); }
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 725/1266 net: psample: fix info leak in PSAMPLE_ATTR_DATA
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Jakub Kicinski <[email protected]>
[ Upstream commit aedd02af1f8b0bceb7f42f5a21c41634ca9ed390 ]
psample open codes nla_put() presumably to avoid wiping the data with 0s just to override it with packet data. This open coding is missing clearing the pad, however, each netlink attr is padded to 4B and data_len may not be divisible by 4B.
--- net/psample/psample.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-)
net/psample/psample.c +4 -2
@@ -465,15 +465,17 @@ void psample_sample_packet(struct psample_group *group, struct sk_buff *skb, goto error;if (data_len) { -int nla_len =nla_total_size (data_len); +int nla_len =nla_attr_size (data_len);struct nlattr *nla; nla =skb_put (nl_skb, nla_len); nla->nla_type =PSAMPLE_ATTR_DATA ; - nla->nla_len =nla_attr_size (data_len); + nla->nla_len = nla_len;if (skb_copy_bits (skb,0 ,nla_data (nla), data_len)) goto error; + +skb_put_zero (nl_skb,nla_padlen (data_len)); }#ifdef CONFIG_INET
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 726/1266 sctp: hold socket lock when dumping endpoints in sctp_diag
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Xin Long <[email protected]>
[ Upstream commit 7d8297e26b4e20b5d1c3c3fe51fe81a1c7fbc823 ]
SCTP_DIAG endpoint dumping was traversing endpoint address lists without holding lock_sock(), while those lists could change concurrently via socket operations (e.g., bindx changes). This creates a race where nla_reserve() counts addresses under RCU protection, but the subsequent copy may see fewer entries, potentially leaking uninitialized memory to userspace.
Fix this by:
- Taking a reference on each endpoint during hash traversal
- Moving socket operations (lock_sock()) outside read_lock_bh()
- Serializing address list access during dump
- Reworking sctp_for_each_endpoint() to support restart-based traversal with (net, pos) tracking
Also:
- Add WARN_ON_ONCE() for inconsistent address counts
- Fix idiag_states filtering for LISTEN vs association cases
- Skip dumping endpoints being freed (ep->base.dead)
- Move dump position tracking into iterator, removing cb->args[4] and its comment for sctp_ep_dump().,
- Update the comment for cb->args[4] and remove the comment for unused cb->args[5] for sctp_sock_dump().
Note: traversal is restart-based and may re-scan buckets multiple times, but this is acceptable due to small bucket sizes and required to support sleeping-safe callbacks.
This issue was reported by Nico Yip (@_cyeaa_) working with TrendAI Zero Day Initiative.
--- include/net/sctp/sctp.h | 3 +- net/sctp/diag.c | 67 ++++++++++++++++++++--------------------- net/sctp/socket.c | 29 +++++++++++++----- 3 files changed, 56 insertions(+), 43 deletions(-)
include/net/sctp/sctp.h +2 -1
@@ -112,7 +112,8 @@ int sctp_transport_lookup_process(sctp_callback_t cb, struct net *net, const union sctp_addr *paddr, void *p, int dif);int sctp_transport_traverse_process (sctp_callback_t cb,sctp_callback_t cb_done,struct net *net,int *pos,void *p); -int sctp_for_each_endpoint (int (*cb)(struct sctp_endpoint *,void *),void *p); +int sctp_for_each_endpoint (int (*cb)(struct sctp_endpoint *,void *), +struct net *net,int *pos,void *p);int sctp_get_sctp_info (struct sock *sk,struct sctp_association *asoc,struct sctp_info *info);
net/sctp/diag.c +32 -35
121 lines not on this page · raw message
net/sctp/socket.c +22 -7
@@ -5317,24 +5317,39 @@ struct sctp_transport *sctp_transport_get_idx(struct net *net, }int sctp_for_each_endpoint (int (*cb)(struct sctp_endpoint *,void *), -void *p) { -int err =0 ; -int hash =0 ; -struct sctp_endpoint *ep; +struct net *net,int *pos,void *p) { +int err, hash =0 , idx =0 , start;struct sctp_hashbucket *head; +struct sctp_endpoint *ep;for (head = sctp_ep_hashtable; hash < sctp_ep_hashsize; hash++, head++) { + start = idx; +again:read_lock_bh (&head->lock);sctp_for_each_hentry (ep, &head->chain) { - err =cb (ep, p); -if (err) +if (sock_net (ep->base.sk) != net) +continue ; +if (idx++ >= *pos) { +sctp_endpoint_hold (ep);break ; + } }read_unlock_bh (&head->lock); + +if (ep) { + err =cb (ep, p); +sctp_endpoint_put (ep); +if (err) +return err; + (*pos)++; + + idx = start; + goto again; + } } -return err; +return 0 ; }EXPORT_SYMBOL_GPL (sctp_for_each_endpoint);
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 727/1266 PCI: iproc: Restore .map_irq() for the platform bus driver
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Mark Tomlinson <[email protected]>
[ Upstream commit 3c2e6cc6affa8acdb99a580be1f8f297edf54204 ]
Commit b64aa11eb2dd ("PCI: Set bridge map_irq and swizzle_irq to default functions") moved the assignment of default .map_irq() callback to devm_of_pci_bridge_init() and removed the initialization of 'iproc_pcie::map_irq' in platform bus driver. This led to the callback getting assigned the NULL pointer for platform bus driver, thereby breaking the INTx functionality, since 'iproc_pcie::map_irq' overrides the 'pci_host_bridge::map_irq' callback in iproc_pcie_setup().
This issue only affected the iproc platform bus driver as this driver relies on the default callback for non-PAXC controllers. iproc-brcm driver was already providing the custom mapping function, so it was unaffected.
Restore the original (and intended) behaviour to use the default map_irq function by removing the local 'iproc_pcie::map_irq' pointer and directly assigning the 'pci_host_bridge::map_irq' callback in iproc-bcma driver. This ensures that the default 'map_irq' callback is used for platform bus driver and only iproc-brcm driver overrides it with a custom one.
--- drivers/pci/controller/pcie-iproc-bcma.c | 2 +- drivers/pci/controller/pcie-iproc-platform.c | 2 +- drivers/pci/controller/pcie-iproc.c | 1 - drivers/pci/controller/pcie-iproc.h | 2 -- 4 files changed, 2 insertions(+), 5 deletions(-)
drivers/pci/controller/pcie-iproc-bcma.c +1 -1
@@ -64,7 +64,7 @@ static int iproc_bcma_pcie_probe(struct bcma_device *bdev)if (ret)return ret; - pcie->map_irq = iproc_bcma_pcie_map_irq; + bridge->map_irq = iproc_bcma_pcie_map_irq;bcma_set_drvdata (bdev, pcie);
drivers/pci/controller/pcie-iproc-platform.c +1 -1
@@ -98,7 +98,7 @@ static int iproc_pltfm_pcie_probe(struct platform_device *pdev)switch (pcie->type) {case IPROC_PCIE_PAXC :case IPROC_PCIE_PAXC_V2 : - pcie->map_irq =NULL ; + bridge->map_irq =NULL ;break ;default :break ;
drivers/pci/controller/pcie-iproc.c +0 -1
@@ -1514,7 +1514,6 @@ int iproc_pcie_setup(struct iproc_pcie *pcie, struct list_head *res) host->ops = &iproc_pcie_ops; host->sysdata = pcie; - host->map_irq = pcie->map_irq; ret =pci_host_probe (host);if (ret <0 ) {
drivers/pci/controller/pcie-iproc.h +0 -2
@@ -61,7 +61,6 @@ struct iproc_msi;* @base_addr: PCIe host controller register base physical address * @mem: host bridge memory window resource * @phy: optional PHY device that controls the Serdes -* @map_irq: function callback to map interrupts * @ep_is_internal: indicates an internal emulated endpoint device is connected * @iproc_cfg_read: indicates the iProc config read function should be used * @rej_unconfig_pf: indicates the root complex needs to detect and reject
@@ -91,7 +90,6 @@ struct iproc_pcie {phys_addr_t base_addr;struct resource mem;struct phy *phy; -int (*map_irq)(const struct pci_dev *,u8 ,u8 );bool ep_is_internal;bool iproc_cfg_read;bool rej_unconfig_pf;
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 728/1266 spi: rpc-if: Use correct device for hardware reinitialization on resume
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Quang Nguyen <[email protected]>
[ Upstream commit 7b25dbafa2fce50b1a48c1d057adb35da3563f9b ]
rpcif_spi_resume() currently passes the SPI controller device to rpcif_hw_init(), but the function should be called with the RPC interface device.
Retrieve the rpcif private data from the SPI controller and pass rpc->dev instead. Also propagate the return value of rpcif_hw_init() so that a failure during resume is properly reported rather than silently ignored.
--- drivers/spi/spi-rpc-if.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-)
drivers/spi/spi-rpc-if.c +5 -1
@@ -192,8 +192,12 @@ static int __maybe_unused rpcif_spi_suspend(struct device *dev)static int __maybe_unused rpcif_spi_resume (struct device *dev) {struct spi_controller *ctlr =dev_get_drvdata (dev); +struct rpcif *rpc =spi_controller_get_devdata (ctlr); +int ret; -rpcif_hw_init (dev, false); + ret =rpcif_hw_init (rpc->dev, false); +if (ret) +return ret;return spi_controller_resume (ctlr); }
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 729/1266 virtio-net: fix len check in receive_big()
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Xiang Mei <[email protected]>
[ Upstream commit 9e5ad06ea826322ce8c58b4a68442a96f600c3c4 ]
receive_big() bounds the device-announced length by (big_packets_num_skbfrags + 1) * PAGE_SIZE. That is still too loose:add_recvbuf_big() sets sg[1] to start at offset sizeof(struct padded_vnet_hdr) into the first page, so the chain actually carries hdr_len + (PAGE_SIZE - sizeof(padded_vnet_hdr)) + big_packets_num_skbfrags * PAGE_SIZE bytes -- 20 bytes less than the check allows for the common hdr_len == 12 case.
A malicious virtio backend can announce a len in that gap. page_to_skb() then walks one frag past the page chain, storing a NULL page->private into skb_shinfo()->frags[MAX_SKB_FRAGS], which is both an out-of-bounds write past the static frag array and a NULL frag handed up the rx path.
Bound len by the size add_recvbuf_big() actually advertised.
--- drivers/net/virtio_net.c | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-)
drivers/net/virtio_net.c +6 -3
@@ -1334,15 +1334,18 @@ static struct sk_buff *receive_big(struct net_device *dev, struct virtnet_rq_stats *stats) {struct page *page = buf; +unsigned long max_len;struct sk_buff *skb; + max_len = (vi->big_packets_num_skbfrags +1 ) *PAGE_SIZE - +sizeof (struct padded_vnet_hdr ) + vi->hdr_len; +/* Make sure that len does not exceed the size allocated in * add_recvbuf_big. */ -if (unlikely (len > (vi->big_packets_num_skbfrags +1 ) *PAGE_SIZE )) { +if (unlikely (len > max_len)) {pr_debug ("%s: rx error: len %u exceeds allocated size %lu\n" , - dev->name, len, - (vi->big_packets_num_skbfrags +1 ) *PAGE_SIZE ); + dev->name, len, max_len); goto err; }
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 730/1266 dpaa2-switch: fix VLAN upper check not rejecting bridge join
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Ioana Ciornei <[email protected]>
[ Upstream commit ed2294f94e34e97342850c40b320833d881c3819 ]
The blamed commit refactored the prechangeupper event handling but failed to actually return an error in case dpaa2_switch_prevent_bridging_with_8021q_upper() detected a 802.1q upper on a port which tries to join a bridge. Fix this by returning err instead of 0.
--- drivers/net/ethernet/freescale/dpaa2/dpaa2-switch.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
drivers/net/ethernet/freescale/dpaa2/dpaa2-switch.c +1 -1
@@ -2180,7 +2180,7 @@ dpaa2_switch_prechangeupper_sanity_checks(struct net_device *netdev,if (err) {NL_SET_ERR_MSG_MOD (extack,"Cannot join a bridge while VLAN uppers are present" ); -return 0 ; +return err; }return 0 ;
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 731/1266 devlink: Fix parent ref leak in devl_rate_node_create()
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Cosmin Ratiu <[email protected]>
[ Upstream commit ba45106342bbdd905651cb9fcefb8c11871d4c25 ]
In the original commit the function bails out on kstrdup failure, forgetting to decrement the refcnt of the parent.
Fix that by moving the parent refcnt setting after kstrdup.
--- net/devlink/rate.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-)
net/devlink/rate.c +5 -5
@@ -598,11 +598,6 @@ devl_rate_node_create(struct devlink *devlink, void *priv, char *node_name,if (!rate_node)return ERR_PTR (-ENOMEM ); -if (parent) { - rate_node->parent = parent; -refcount_inc (&rate_node->parent->refcnt); - } - rate_node->type =DEVLINK_RATE_TYPE_NODE ; rate_node->devlink = devlink; rate_node->priv = priv;
@@ -613,6 +608,11 @@ devl_rate_node_create(struct devlink *devlink, void *priv, char *node_name,return ERR_PTR (-ENOMEM ); } +if (parent) { + rate_node->parent = parent; +refcount_inc (&rate_node->parent->refcnt); + } +refcount_set (&rate_node->refcnt,1 );list_add (&rate_node->list, &devlink->rate_list);devlink_rate_notify (rate_node,DEVLINK_CMD_RATE_NEW );
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 732/1266 flow_dissector: check device type before reading ETH_ADDRS
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Yun Zhou <[email protected]>
[ Upstream commit bf6e8af2c8be77489bedeae9f8a9654cb710e500 ]
__skb_flow_dissect() unconditionally reads 12 bytes from eth_hdr(skb) when FLOW_DISSECTOR_KEY_ETH_ADDRS is requested. This assumes the skb has a valid Ethernet header at mac_header, which is not always the case.
The problem can be triggered by:
1. Creating a TUN device in L3 mode (IFF_TUN, hard_header_len=0)
2. Attaching a multiq qdisc with a flower filter matching on eth_src
3. Sending a packet through AF_PACKET
Since TUN in L3 mode has no link-layer header, mac_header points to the L3 data area. The flow dissector reads 12 bytes of uninitialized skb memory, which then propagates through fl_set_masked_key() and is used as a rhashtable lookup key in __fl_lookup(), as reported by KMSAN.
Rejecting the filter in the control path (at tc filter add time) is not feasible because TC filter blocks can be shared between arbitrary devices -- a filter installed on an Ethernet device may later classify packets on a headerless device through a shared block. The device association is not fixed at filter creation time.
Fix this by gating the memcpy on dev->type == ARPHRD_ETHER, which ensures only true Ethernet-framed packets have their addresses read. This is more precise than the previous hard_header_len >= 12 check, which would incorrectly pass for non-Ethernet link types like IPoIB (ARPHRD_INFINIBAND, hard_header_len=24) and FDDI (hard_header_len=21) whose L2 headers are not in Ethernet format. Additionally check skb_mac_header_was_set() to guard against the pathological case where mac_header is the unset sentinel (~0U), which would cause eth_hdr() to return a wild pointer.
For the act_mirred redirect case (Ethernet packet redirected to a non-Ethernet device sharing a TC block), zeroing the key is the correct
behavior: the packet is now being classified on the target device, where Ethernet address matching is not semantically meaningful.
Note: on non-Ethernet devices, the zeroed key will match a filter configured with all-zero MAC addresses. This is an improvement over the previous behavior where uninitialized memory could randomly match any filter.
--- net/core/flow_dissector.c | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-)
net/core/flow_dissector.c +10 -2
@@ -1149,13 +1149,21 @@ bool __skb_flow_dissect(const struct net *net,if (dissector_uses_key (flow_dissector,FLOW_DISSECTOR_KEY_ETH_ADDRS )) { -struct ethhdr *eth =eth_hdr (skb);struct flow_dissector_key_eth_addrs *key_eth_addrs; key_eth_addrs =skb_flow_dissector_target (flow_dissector,FLOW_DISSECTOR_KEY_ETH_ADDRS , target_container); -memcpy (key_eth_addrs, eth,sizeof (*key_eth_addrs)); +/* TC filter blocks can be shared across devices with +* different link types, so we cannot validate this +* when the filter is installed -- check at dissect time. +*/ +if (skb && skb->dev && + skb->dev->type ==ARPHRD_ETHER && +skb_mac_header_was_set (skb)) +memcpy (key_eth_addrs,eth_hdr (skb),sizeof (*key_eth_addrs)); +else +memset (key_eth_addrs,0 ,sizeof (*key_eth_addrs)); } if (dissector_uses_key(flow_dissector,
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 733/1266 ALSA: usb-audio: Kill MIDI 2.0 URBs before freeing endpoints
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Cen Zhang <[email protected]>
[ Upstream commit f199c8a8bdd54296d3458777e70fe82a78bd9817 ]
MIDI 2.0 input URBs are started during snd_usb_midi_v2_create(). A later setup failure can still jump to snd_usb_midi_v2_free(), which currently frees each endpoint and its coherent URB buffers without first stopping the submitted URBs. A completion can then dereference the embedded URB context and endpoint state after they have been freed, or try to resubmit from the stale endpoint.
This was observed as a KASAN slab-use-after-free in input_urb_complete().
The buggy scenario involves two paths, with each column showing the order within that path:
probe error path: USB completion path:
1. start_input_streams() submits 1. The HCD still owns a
input URBs. submitted input URB.
2. A later setup helper returns 2. input_urb_complete() runs
an error. with urb->context in ep.
3. snd_usb_midi_v2_free() frees 3. The completion reads ep
endpoint storage and URB buffers. state and can requeue URBs.
Make the endpoint destructor follow the same teardown ordering used for disconnect when the endpoint has not already been disconnected: publish ep->disconnected, kill the URBs synchronously, and drain the endpoint before freeing URB buffers and endpoint storage. The guard avoids repeating the stop sequence after the normal snd_usb_midi_v2_disconnect_all() path, while still synchronizing the direct MIDI 2.0 create-error free path.
Validation reproduced this kernel report:
BUG: KASAN: slab-use-after-free in input_urb_complete+0x37/0x1b0 Workqueue: usb_hub_wq hub_event RIP: 0010:_raw_spin_unlock_irq+0x2e/0x50 Read of size 8 Call trace: dump_stack_lvl+0x77/0xb0 print_report+0xce/0x5f0 input_urb_complete+0x37/0x1b0 (sound/usb/midi2.c:186) srso_alias_return_thunk+0x5/0xfbef5 __virt_addr_valid+0x19f/0x330 kasan_report+0xe0/0x110 __usb_hcd_giveback_urb+0x112/0x1d0 dummy_timer+0xaaa/0x19a0 lock_is_held_type+0x9a/0x110 __lock_acquire+0x467/0x28b0 mark_held_locks+0x40/0x70 _raw_spin_unlock_irqrestore+0x44/0x60 lockdep_hardirqs_on_prepare+0xbb/0x1a0 __hrtimer_run_queues+0x101/0x520 hrtimer_run_softirq+0xd0/0x130 handle_softirqs+0x15b/0x670 __irq_exit_rcu+0xd0/0x170 irq_exit_rcu+0xe/0x20 sysvec_apic_timer_interrupt+0x6c/0x80 asm_sysvec_apic_timer_interrupt+0x1a/0x20
--- sound/usb/midi2.c | 5 +++++ 1 file changed, 5 insertions(+)
sound/usb/midi2.c +5 -0
@@ -478,6 +478,11 @@ static int create_midi2_endpoint(struct snd_usb_midi2_interface *umidi,static void free_midi2_endpoint (struct snd_usb_midi2_endpoint *ep) {list_del (&ep->list); +if (!ep->disconnected) { + ep->disconnected =1 ; +kill_midi_urbs (ep, false); +drain_urb_queue (ep); + }free_midi_urbs (ep);kfree (ep); }
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 734/1266 arm64/hw_breakpoint: reject unaligned watchpoints that would truncate BAS
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Breno Leitao <[email protected]>
[ Upstream commit 4cc70f75853bebac022334b6a86b953348072f74 ]
hw_breakpoint_arch_parse() positions the BAS bit pattern in hw->ctrl.len with
offset = hw->address & alignment_mask; /* 0..7 */ hw->ctrl.len <<= offset;
ctrl.len is an 8-bit bitfield (struct arch_hw_breakpoint_ctrl::len is u32 :8), so the shift silently drops any bits past bit 7. For non-compat AArch64 watchpoints the offset is unbounded relative to ctrl.len: a perf_event_open(PERF_TYPE_BREAKPOINT) caller asking for HW_BREAKPOINT_W with bp_addr=page+1 and bp_len=HW_BREAKPOINT_LEN_8 ends up with 0xff << 1 = 0x1fe, stored as 0xfe. The kernel programs WCR.BAS=0xfe and the hardware watches bytes [1..7] instead of the requested [1..8] -- the eighth byte is silently dropped. The syscall still returns success, leaving userspace to discover the gap by empirical probing.
The same class affects HW_BREAKPOINT_LEN_{2,4} when offset pushes the high BAS bit past bit 7 (e.g. LEN_4 with offset=5 yields 0xe0 instead of 0x1e0). No memory-safety impact -- the value is masked into 8 bits before encoding -- but debuggers and perf users observe missed events on bytes they thought they were watching.
The AArch32 branch immediately above already rejects unrepresentable (offset, len) combinations via an explicit switch. Mirror that for the non-compat branch by checking that the shifted pattern fits in the BAS field, returning -EINVAL when it does not.
GDB and similar debuggers are unaffected by the stricter check. aarch64_linux_set_debug_regs() already treats EINVAL on NT_ARM_HW_WATCH as a downgrade signal: it clears kernel_supports_any_contiguous_range, calls aarch64_downgrade_regs() to round the BAS up to a legacy 0x01/03/0f/ff mask with an aligned base, and retries -- the same fallback path that PR-20207 introduced. The new -EINVAL is therefore reachable only from a raw perf_event_open() that pairs an unaligned base with an oversized bp_len, which is precisely the bug.
Reproducer:
struct perf_event_attr a = {
.type = PERF_TYPE_BREAKPOINT, .size = sizeof(a),
.bp_type = HW_BREAKPOINT_W,
.bp_addr = (uintptr_t)(buf + 1),
.bp_len = HW_BREAKPOINT_LEN_8,
.exclude_kernel = 1, .exclude_hv = 1, };
int fd = perf_event_open(&a, 0, -1, -1, 0);
/* before this fix: succeeds, watches 7 bytes (buf+1..buf+7) */
/* after this fix: fails with EINVAL */
--- arch/arm64/kernel/hw_breakpoint.c | 9 +++++++++ 1 file changed, 9 insertions(+)
arch/arm64/kernel/hw_breakpoint.c +9 -0
@@ -557,6 +557,15 @@ int hw_breakpoint_arch_parse(struct perf_event *bp,else alignment_mask =0x7 ; offset = hw->address & alignment_mask; + +/* +* BAS is an 8-bit field in WCR/BCR; the shift below would +* silently drop the high bits of ctrl.len when offset + len +* exceeds 8, programming hardware to watch fewer bytes than +* the user requested. +*/ +if (((u32 )hw->ctrl.len << offset) >ARM_BREAKPOINT_LEN_8 ) +return -EINVAL ; } hw->address &= ~alignment_mask;
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 735/1266 thermal: intel: Fix dangling resources on thermal_throttle_online() failure
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Ricardo Neri <[email protected]>
[ Upstream commit b91d287fa7a1ba0727eed5823c6ee4924ee5fa31 ]
The function thermal_throttle_add_dev() may fail and abort a CPU hotplug online operation. Since the failure occurs within the online callback, thermal_throttle_online(), the CPU hotplug framework does not invoke the corresponding offline callback. As a result, the hardware and software resources set up during the failed operation are not torn down.
Since only thermal_throttle_add_dev() can fail, call it before setting up the rest of the resources.
--- drivers/thermal/intel/therm_throt.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-)
drivers/thermal/intel/therm_throt.c +6 -1
@@ -528,8 +528,13 @@ static int thermal_throttle_online(unsigned int cpu) {struct thermal_state *state = &per_cpu (thermal_state, cpu);struct device *dev =get_cpu_device (cpu); +int err;u32 l; + err =thermal_throttle_add_dev (dev, cpu); +if (err) +return err; + state->package_throttle.level =PACKAGE_LEVEL ; state->core_throttle.level =CORE_LEVEL ;
@@ -547,7 +552,7 @@ static int thermal_throttle_online(unsigned int cpu) l =apic_read (APIC_LVTTHMR );apic_write (APIC_LVTTHMR , l & ~APIC_LVT_MASKED ); -return thermal_throttle_add_dev (dev, cpu); +return err; }static int thermal_throttle_offline (unsigned int cpu)
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 736/1266 ACPI: resource: Amend kernel-doc style
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Andy Shevchenko <[email protected]>
[ Upstream commit 78ad5c7722b7bed9d35ffc5b45eb0f12e2c22fee ]
The functions are referred as func() in the kernel-doc. The % (percent) character makes the rendering for constants as described in the respective documentation. Amend all these.
--- drivers/acpi/resource.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-)
drivers/acpi/resource.c +3 -3
@@ -839,7 +839,7 @@ bool acpi_dev_resource_interrupt(struct acpi_resource *ares, int index,EXPORT_SYMBOL_GPL (acpi_dev_resource_interrupt);/** -* acpi_dev_free_resource_list - Free resource from %acpi_dev_get_resources(). +* acpi_dev_free_resource_list - Free resource from acpi_dev_get_resources(). * @list: The head of the resource list to free. */ void acpi_dev_free_resource_list (struct list_head *list)
@@ -959,7 +959,7 @@ static int __acpi_dev_get_resources(struct acpi_device *adev,* * The resultant struct resource objects are put on the list pointed to by * @list, that must be empty initially, as members of struct resource_entry -* objects. Callers of this routine should use %acpi_dev_free_resource_list() to +* objects. Callers of this routine should use acpi_dev_free_resource_list() to * free that list. * * The number of resources in the output list is returned on success, an error
@@ -1000,7 +1000,7 @@ static int is_memory(struct acpi_resource *ares, void *not_used)* The resultant struct resource objects are put on the list pointed to * by @list, that must be empty initially, as members of struct * resource_entry objects. Callers of this routine should use -* %acpi_dev_free_resource_list() to free that list. +* acpi_dev_free_resource_list() to free that list. * * The number of resources in the output list is returned on success, * an error code reflecting the error condition is returned otherwise.
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 737/1266 ACPI: IPMI: Fix inverted interface check in ipmi_bmc_gone()
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Xu Rao <[email protected]>
[ Upstream commit 71b57aca295d61276a60e131d8f62b0cc7cf1a35 ]
Before commit a1a69b297e47 ("ACPI / IPMI: Fix race caused by the unprotected ACPI IPMI user"), ipmi_bmc_gone() skipped entries whose interface number did not match the SMI being removed, then killed the matching entry:
if (ipmi_device->ipmi_ifnum != iface) continue; __ipmi_dev_kill(ipmi_device);
That commit folded the removal block into the existing non-match test while converting the object lifetime handling, but left the comparison unchanged. The old != meant "continue past this entry"; after the refactor it meant "kill this entry".
As a result, a single ACPI IPMI interface is never removed when its SMI disappears. If multiple interfaces are tracked, the first interface whose number differs from iface is removed instead, while the interface that actually disappeared remains on driver_data.ipmi_devices. The stale entry is not marked dead and can continue to be selected for ACPI IPMI transactions. It can also prevent the same ACPI handle from being registered again.
Change the comparison to == so ipmi_bmc_gone() removes exactly the interface reported as gone by the SMI watcher. This restores the pre-a1a69b297e47 behavior and is the correct interface matching logic.
--- drivers/acpi/acpi_ipmi.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
drivers/acpi/acpi_ipmi.c +1 -1
@@ -485,7 +485,7 @@ static void ipmi_bmc_gone(int iface)mutex_lock (&driver_data.ipmi_lock);list_for_each_entry_safe (iter, temp, &driver_data.ipmi_devices, head) { -if (iter->ipmi_ifnum != iface) { +if (iter->ipmi_ifnum == iface) { ipmi_device = iter;__ipmi_dev_kill (iter);break ;
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 738/1266 ieee802154: Remove WARN_ON() in cfg802154_pernet_exit()
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Ivan Abramov <[email protected]>
[ Upstream commit e69ed6fc9fb3b386b5fcdb9f51623f122cee2ebd ]
There's no need to call WARN_ON() in cfg802154_pernet_exit(), since every point of failure in cfg802154_switch_netns() is covered with WARN_ON(), so remove it.
Found by Linux Verification Center (linuxtesting.org) with Syzkaller.
--- net/ieee802154/core.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
net/ieee802154/core.c +1 -1
@@ -327,7 +327,7 @@ static void __net_exit cfg802154_pernet_exit(struct net *net)rtnl_lock ();list_for_each_entry (rdev, &cfg802154_rdev_list, list) {if (net_eq (wpan_phy_net (&rdev->wpan_phy), net)) -WARN_ON (cfg802154_switch_netns (rdev, &init_net)); +cfg802154_switch_netns (rdev, &init_net); }rtnl_unlock (); }
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 739/1266 ieee802154: fix kernel-infoleak in dgram_recvmsg()
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Aleksandr Nogikh <[email protected]>
[ Upstream commit 4db86f8ab11b5a41bfc36680be837e6ac1375ec6 ]
KMSAN reported a kernel-infoleak in move_addr_to_user():
BUG: KMSAN: kernel-infoleak in instrument_copy_to_user include/linux/instrumented.h:131 [inline] BUG: KMSAN: kernel-infoleak in _inline_copy_to_user include/linux/uaccess.h:205 [inline] BUG: KMSAN: kernel-infoleak in _copy_to_user+0xcc/0x120 lib/usercopy.c:26 instrument_copy_to_user include/linux/instrumented.h:131 [inline] _inline_copy_to_user include/linux/uaccess.h:205 [inline] _copy_to_user+0xcc/0x120 lib/usercopy.c:26 copy_to_user include/linux/uaccess.h:236 [inline] move_addr_to_user+0x2e7/0x440 net/socket.c:302 ____sys_recvmsg+0x232/0x610 net/socket.c:2925 ... Uninit was stored to memory at: ieee802154_addr_to_sa include/net/ieee802154_netdev.h:369 [inline] dgram_recvmsg+0xa09/0xbe0 net/ieee802154/socket.c:739
The issue occurs because the pan_id field of struct ieee802154_addr is left uninitialized when the address mode is IEEE802154_ADDR_NONE. The execution flow is as follows:
1. __ieee802154_rx_handle_packet() declares a local struct ieee802154_hdr hdr on the stack.
2. ieee802154_hdr_pull() calls ieee802154_hdr_get_addr() to parse the source and destination addresses into this structure.
3. If the address mode is IEEE802154_ADDR_NONE, ieee802154_hdr_get_addr() previously only set the mode field, leaving the pan_id field containing uninitialized stack memory.
4. This uninitialized pan_id is later copied into a struct sockaddr_ieee802154 in dgram_recvmsg() via ieee802154_addr_to_sa().
5. Finally, move_addr_to_user() copies the socket address structure to user space, leaking the uninitialized bytes.
Fix this by using memset to zero out the address structure in ieee802154_hdr_get_addr() when the mode is IEEE802154_ADDR_NONE.
--- net/ieee802154/header_ops.c | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-)
net/ieee802154/header_ops.c +6 -3
@@ -173,10 +173,13 @@ ieee802154_hdr_get_addr(const u8 *buf, int mode, bool omit_pan, {int pos =0 ; - addr->mode = mode; - -if (mode ==IEEE802154_ADDR_NONE ) +if (mode ==IEEE802154_ADDR_NONE ) { +memset (addr,0 ,sizeof (*addr)); + addr->mode =IEEE802154_ADDR_NONE ;return 0 ; + } + + addr->mode = mode;if (!omit_pan) {memcpy (&addr->pan_id, buf + pos,2 );
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 740/1266 md/raid1: free r1_bio when REQ_NOWAIT is set and read would block on retry
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Abd-Alrhman Masalkhi <[email protected]>
[ Upstream commit 69ad6ce47f9bf2b9fe0ed69b042db993d33bbf12 ]
When a read is retried, raid1_read_request() may be called with a pre-allocated r1_bio. If wait_read_barrier() fails for a REQ_NOWAIT read, the bio is completed and the function returns immediately. In this case the existing r1_bio is leaked.
This fixes a leak of pre-allocated r1_bio structures for retried reads.
--- drivers/md/raid1.c | 6 ++++++ 1 file changed, 6 insertions(+)
drivers/md/raid1.c +6 -0
@@ -1245,6 +1245,12 @@ static void raid1_read_request(struct mddev *mddev, struct bio *bio,if (!wait_read_barrier (conf, bio->bi_iter.bi_sector, bio->bi_opf &REQ_NOWAIT )) {bio_wouldblock_error (bio); + +if (r1bio_existed) { +set_bit (R1BIO_Returned, &r1_bio->state); +raid_end_bio_io (r1_bio); + } +return ; }
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 741/1266 netfilter: ipset: Fix data race between add and dump in all hash types
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Jozsef Kadlecsik <[email protected]>
[ Upstream commit 2358f7427ccd6ec8867a48205d8fcec973683a3f ]
When adding a new entry to the next position in the existing hash bucket, the position index was incremented too early and parallel dump could read it before the entry was populated with the value. Move the setting of the position index after populating the entry.
v2: Position counting fixed, noticed by Florian Westphal.
Stable-dep-of: e4b4984e28c1 ("netfilter: ipset: Don't use test_bit() in lockless RCU readers in hash types")
--- net/netfilter/ipset/ip_set_hash_gen.h | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-)
net/netfilter/ipset/ip_set_hash_gen.h +5 -2
@@ -843,7 +843,7 @@ mtype_add(struct ip_set *set, void *value, const struct ip_set_ext *ext,const struct mtype_elem *d = value;struct mtype_elem *data;struct hbucket *n, *old =ERR_PTR (-ENOENT ); -int i, j =-1 , ret; +int i, j =-1 , npos =0 , ret;bool flag_exist = flags &IPSET_FLAG_EXIST ;bool deleted = false, forceadd = false, reuse = false;u32 r, key, multi =0 , elements, maxelem;
@@ -888,6 +888,7 @@ mtype_add(struct ip_set *set, void *value, const struct ip_set_ext *ext,ext_size (AHASH_INIT_SIZE , set->dsize); goto copy_elem; } + npos = n->pos;for (i =0 ; i < n->pos; i++) {if (!test_bit (i, n->used)) {/* Reuse first deleted entry */
@@ -961,7 +962,8 @@ mtype_add(struct ip_set *set, void *value, const struct ip_set_ext *ext, } copy_elem: - j = n->pos++; + j = npos; + npos = n->pos +1 ; data =ahash_data (n, j, set->dsize); copy_data: t->hregion[r].elements++;
@@ -984,6 +986,7 @@ mtype_add(struct ip_set *set, void *value, const struct ip_set_ext *ext,if (SET_WITH_TIMEOUT (set))ip_set_timeout_set (ext_timeout (data, set), ext->timeout);smp_mb__before_atomic (); + n->pos = npos;set_bit (j, n->used);if (old !=ERR_PTR (-ENOENT )) {rcu_assign_pointer (hbucket (t, key), n);
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 742/1266 netfilter: ipset: annotate "pos" for concurrent readers/writers
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Jozsef Kadlecsik <[email protected]>
[ Upstream commit 7f7445840b7771338618930e45ee641104b38ed8 ]
The "pos" structure member of struct hbucket stores the first free slot in the hash bucket of a hash type of set and there are concurrent readers/writers. Annotate accesses properly.
Stable-dep-of: e4b4984e28c1 ("netfilter: ipset: Don't use test_bit() in lockless RCU readers in hash types")
--- net/netfilter/ipset/ip_set_hash_gen.h | 62 ++++++++++++++++----------- 1 file changed, 38 insertions(+), 24 deletions(-)
net/netfilter/ipset/ip_set_hash_gen.h +38 -24
@@ -385,8 +385,9 @@ static void mtype_ext_cleanup(struct ip_set *set, struct hbucket *n) { int i; +u8 pos =smp_load_acquire (&n->pos); -for (i =0 ; i < n->pos; i++) +for (i =0 ; i < pos; i++)if (test_bit (i, n->used))ip_set_ext_destroy (set,ahash_data (n, i, set->dsize)); }
@@ -489,7 +490,7 @@ mtype_gc_do(struct ip_set *set, struct htype *h, struct htable *t, u32 r)#ifdef IP_SET_HASH_WITH_NETS u8 k;#endif -u8 htable_bits = t->htable_bits; +u8 pos, htable_bits = t->htable_bits;spin_lock_bh (&t->hregion[r].lock); for (i = ahash_bucket_start(r, htable_bits);
@@ -497,7 +498,8 @@ mtype_gc_do(struct ip_set *set, struct htype *h, struct htable *t, u32 r) n =__ipset_dereference (hbucket (t, i));if (!n)continue ; -for (j =0 , d =0 ; j < n->pos; j++) { + pos =smp_load_acquire (&n->pos); +for (j =0 , d =0 ; j < pos; j++) {if (!test_bit (j, n->used)) { d++;continue ;
@@ -533,7 +535,7 @@ mtype_gc_do(struct ip_set *set, struct htype *h, struct htable *t, u32 r)/* Still try to delete expired elements. */ continue ; tmp->size = n->size -AHASH_INIT_SIZE ; -for (j =0 , d =0 ; j < n->pos; j++) { +for (j =0 , d =0 ; j < pos; j++) {if (!test_bit (j, n->used))continue ; data =ahash_data (n, j, dsize);
@@ -622,7 +624,7 @@ mtype_resize(struct ip_set *set, bool retried) {struct htype *h = set->data;struct htable *t, *orig; -u8 htable_bits; +u8 pos, htable_bits;size_t hsize, dsize = set->dsize;#ifdef IP_SET_HASH_WITH_NETS u8 flags;
@@ -684,7 +686,8 @@ mtype_resize(struct ip_set *set, bool retried) n =__ipset_dereference (hbucket (orig, i));if (!n)continue ; -for (j =0 ; j < n->pos; j++) { + pos =smp_load_acquire (&n->pos); +for (j =0 ; j < pos; j++) {if (!test_bit (j, n->used))continue ; data =ahash_data (n, j, dsize);
@@ -808,9 +811,10 @@ mtype_ext_size(struct ip_set *set, u32 *elements, size_t *ext_size) {struct htype *h = set->data;const struct htable *t; -u32 i, j, r;struct hbucket *n;struct mtype_elem *data; +u32 i, j, r; +u8 pos; t =rcu_dereference_bh (h->table);for (r =0 ; r <ahash_numof_locks (t->htable_bits); r++) {
@@ -819,7 +823,8 @@ mtype_ext_size(struct ip_set *set, u32 *elements, size_t *ext_size) n =rcu_dereference_bh (hbucket (t, i));if (!n)continue ; -for (j =0 ; j < n->pos; j++) { + pos =smp_load_acquire (&n->pos); +for (j =0 ; j < pos; j++) {if (!test_bit (j, n->used))continue ; data =ahash_data (n, j, set->dsize);
@@ -843,10 +848,11 @@ mtype_add(struct ip_set *set, void *value, const struct ip_set_ext *ext,const struct mtype_elem *d = value;struct mtype_elem *data;struct hbucket *n, *old =ERR_PTR (-ENOENT ); -int i, j =-1 , npos =0 , ret; +int i, j =-1 , ret;bool flag_exist = flags &IPSET_FLAG_EXIST ;bool deleted = false, forceadd = false, reuse = false;u32 r, key, multi =0 , elements, maxelem; +u8 npos =0 ;rcu_read_lock_bh (); t =rcu_dereference_bh (h->table);
@@ -888,8 +894,8 @@ mtype_add(struct ip_set *set, void *value, const struct ip_set_ext *ext,ext_size (AHASH_INIT_SIZE , set->dsize); goto copy_elem; } - npos = n->pos; -for (i =0 ; i < n->pos; i++) { + npos =smp_load_acquire (&n->pos); +for (i =0 ; i < npos; i++) {if (!test_bit (i, n->used)) {/* Reuse first deleted entry */ if (j ==-1 ) {
@@ -933,7 +939,7 @@ mtype_add(struct ip_set *set, void *value, const struct ip_set_ext *ext,if (elements >= maxelem) goto set_full;/* Create a new slot */ -if (n->pos >= n->size) { +if (npos >= n->size) {#ifdef IP_SET_HASH_WITH_MULTI if (h->bucketsize >=AHASH_MAX_TUNED ) goto set_full;
@@ -962,8 +968,7 @@ mtype_add(struct ip_set *set, void *value, const struct ip_set_ext *ext, } copy_elem: - j = npos; - npos = n->pos +1 ; + j = npos++; data =ahash_data (n, j, set->dsize); copy_data: t->hregion[r].elements++;
@@ -986,7 +991,8 @@ mtype_add(struct ip_set *set, void *value, const struct ip_set_ext *ext,if (SET_WITH_TIMEOUT (set))ip_set_timeout_set (ext_timeout (data, set), ext->timeout);smp_mb__before_atomic (); - n->pos = npos; +/* Ensure all data writes are visible before updating position */ +smp_store_release (&n->pos, npos);set_bit (j, n->used);if (old !=ERR_PTR (-ENOENT )) {rcu_assign_pointer (hbucket (t, key), n);
@@ -1045,6 +1051,7 @@ mtype_del(struct ip_set *set, void *value, const struct ip_set_ext *ext,int i, j, k, r, ret = -IPSET_ERR_EXIST ;u32 key, multi =0 ;size_t dsize = set->dsize; +u8 pos;/* Userspace add and resize is excluded by the mutex. * Kernespace add does not trigger resize.
@@ -1060,7 +1067,8 @@ mtype_del(struct ip_set *set, void *value, const struct ip_set_ext *ext, n =rcu_dereference_bh (hbucket (t, key));if (!n) goto out; -for (i =0 , k =0 ; i < n->pos; i++) { + pos =smp_load_acquire (&n->pos); +for (i =0 , k =0 ; i < pos; i++) {if (!test_bit (i, n->used)) { k++;continue ;
@@ -1074,8 +1082,8 @@ mtype_del(struct ip_set *set, void *value, const struct ip_set_ext *ext, ret =0 ;clear_bit (i, n->used);smp_mb__after_atomic (); -if (i +1 == n->pos) - n->pos--; +if (i +1 == pos) +smp_store_release (&n->pos, --pos); t->hregion[r].elements--;#ifdef IP_SET_HASH_WITH_NETS for (j =0 ; j <IPSET_NET_COUNT ; j++)
@@ -1097,11 +1105,11 @@ mtype_del(struct ip_set *set, void *value, const struct ip_set_ext *ext, x->flags = flags; } } -for (; i < n->pos; i++) { +for (; i < pos; i++) {if (!test_bit (i, n->used)) k++; } -if (k == n->pos) { +if (k == pos) { t->hregion[r].ext_size -=ext_size (n->size, dsize);rcu_assign_pointer (hbucket (t, key),NULL );kfree_rcu (n, rcu);
@@ -1112,7 +1120,7 @@ mtype_del(struct ip_set *set, void *value, const struct ip_set_ext *ext,if (!tmp) goto out; tmp->size = n->size -AHASH_INIT_SIZE ; -for (j =0 , k =0 ; j < n->pos; j++) { +for (j =0 , k =0 ; j < pos; j++) {if (!test_bit (j, n->used))continue ; data =ahash_data (n, j, dsize);
@@ -1173,6 +1181,7 @@ mtype_test_cidrs(struct ip_set *set, struct mtype_elem *d,int ret, i, j =0 ;#endif u32 key, multi =0 ; +u8 pos;pr_debug ("test by nets\n" );for (; j <NLEN && h->nets[j].cidr[0 ] && !multi; j++) {
@@ -1190,7 +1199,8 @@ mtype_test_cidrs(struct ip_set *set, struct mtype_elem *d, n =rcu_dereference_bh (hbucket (t, key));if (!n)continue ; -for (i =0 ; i < n->pos; i++) { + pos =smp_load_acquire (&n->pos); +for (i =0 ; i < pos; i++) {if (!test_bit (i, n->used))continue ; data =ahash_data (n, i, set->dsize);
@@ -1224,6 +1234,7 @@ mtype_test(struct ip_set *set, void *value, const struct ip_set_ext *ext,struct mtype_elem *data;int i, ret =0 ;u32 key, multi =0 ; +u8 pos;rcu_read_lock_bh (); t =rcu_dereference_bh (h->table);
@@ -1246,7 +1257,8 @@ mtype_test(struct ip_set *set, void *value, const struct ip_set_ext *ext, ret =0 ; goto out; } -for (i =0 ; i < n->pos; i++) { + pos =smp_load_acquire (&n->pos); +for (i =0 ; i < pos; i++) {if (!test_bit (i, n->used))continue ; data =ahash_data (n, i, set->dsize);
@@ -1363,6 +1375,7 @@ mtype_list(const struct ip_set *set,/* We assume that one hash bucket fills into one page */ void *incomplete;int i, ret =0 ; +u8 pos; atd =nla_nest_start (skb,IPSET_ATTR_ADT );if (!atd)
@@ -1381,7 +1394,8 @@ mtype_list(const struct ip_set *set, cb->args[IPSET_CB_ARG0], t, n);if (!n)continue ; -for (i =0 ; i < n->pos; i++) { + pos =smp_load_acquire (&n->pos); +for (i =0 ; i < pos; i++) {if (!test_bit (i, n->used))continue ; e =ahash_data (n, i, set->dsize);
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 743/1266 netfilter: ipset: Dont use test_bit() in lockless RCU readers in hash types
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Jozsef Kadlecsik <[email protected]>
[ Upstream commit e4b4984e28c16406ecb318444dea4a8bf47def3e ]
Sashiko pointed out that there are a few lockless RCU readers using test_bit() which is a relaxed atomic operation and provides no memory barrier guarantees. Use test_bit_acquire() instead where the operation may run parallel with add/del/gc, i.e. is not one from the next cases
- protected by region lock
- in a set destroy phase
- in a new/temporary set creation phase
--- net/netfilter/ipset/ip_set_hash_gen.h | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-)
net/netfilter/ipset/ip_set_hash_gen.h +5 -5
@@ -688,7 +688,7 @@ mtype_resize(struct ip_set *set, bool retried)continue ; pos =smp_load_acquire (&n->pos);for (j =0 ; j < pos; j++) { -if (!test_bit (j, n->used)) +if (!test_bit_acquire (j, n->used))continue ; data =ahash_data (n, j, dsize);if (SET_ELEM_EXPIRED (set, data))
@@ -825,7 +825,7 @@ mtype_ext_size(struct ip_set *set, u32 *elements, size_t *ext_size)continue ; pos =smp_load_acquire (&n->pos);for (j =0 ; j < pos; j++) { -if (!test_bit (j, n->used)) +if (!test_bit_acquire (j, n->used))continue ; data =ahash_data (n, j, set->dsize);if (!SET_ELEM_EXPIRED (set, data))
@@ -1201,7 +1201,7 @@ mtype_test_cidrs(struct ip_set *set, struct mtype_elem *d,continue ; pos =smp_load_acquire (&n->pos);for (i =0 ; i < pos; i++) { -if (!test_bit (i, n->used)) +if (!test_bit_acquire (i, n->used))continue ; data =ahash_data (n, i, set->dsize);if (!mtype_data_equal (data, d, &multi))
@@ -1259,7 +1259,7 @@ mtype_test(struct ip_set *set, void *value, const struct ip_set_ext *ext, } pos =smp_load_acquire (&n->pos);for (i =0 ; i < pos; i++) { -if (!test_bit (i, n->used)) +if (!test_bit_acquire (i, n->used))continue ; data =ahash_data (n, i, set->dsize);if (!mtype_data_equal (data, d, &multi))
@@ -1396,7 +1396,7 @@ mtype_list(const struct ip_set *set,continue ; pos =smp_load_acquire (&n->pos);for (i =0 ; i < pos; i++) { -if (!test_bit (i, n->used)) +if (!test_bit_acquire (i, n->used))continue ; e =ahash_data (n, i, set->dsize);if (SET_ELEM_EXPIRED (set, e))
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 744/1266 netfilter: ipset: fix order of kfree_rcu() and rcu_assign_pointer()
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Jozsef Kadlecsik <[email protected]>
[ Upstream commit 3ca9982a8882470aa0ac4e8bb9a552b181d1efcd ]
Sashiko pointed out that kfree_rcu() was called before rcu_assign_pointer() in handling the comment extension. Fix the order so that rcu_assign_pointer() called first.
--- net/netfilter/ipset/ip_set_core.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-)
net/netfilter/ipset/ip_set_core.c +2 -2
@@ -351,8 +351,8 @@ ip_set_init_comment(struct ip_set *set, struct ip_set_comment *comment,if (unlikely (c)) { set->ext_size -=sizeof (*c) +strlen (c->str) +1 ; -kfree_rcu (c, rcu);rcu_assign_pointer (comment->c,NULL ); +kfree_rcu (c, rcu); }if (!len)return ;
@@ -393,8 +393,8 @@ ip_set_comment_free(struct ip_set *set, void *ptr)if (unlikely (!c))return ; set->ext_size -=sizeof (*c) +strlen (c->str) +1 ; -kfree_rcu (c, rcu);rcu_assign_pointer (comment->c,NULL ); +kfree_rcu (c, rcu); }typedef void (*destroyer )(struct ip_set *,void *);
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 745/1266 netfilter: nf_reject: skip iphdr options when looking for icmp header
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Florian Westphal <[email protected]>
[ Upstream commit af8d6ae09c0a5f8b8a0d5680203c74b3c1daa85b ]
Not a big deal but this hould have used the real ip header length and not the base header size. As-is, if there are options then nf_skb_is_icmp_unreach() result will be random.
--- net/ipv4/netfilter/nf_reject_ipv4.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
net/ipv4/netfilter/nf_reject_ipv4.c +1 -1
@@ -80,7 +80,7 @@ static bool nf_skb_is_icmp_unreach(const struct sk_buff *skb)if (iph->protocol !=IPPROTO_ICMP )return false; - thoff =skb_network_offset (skb) +sizeof (*iph); + thoff =skb_network_offset (skb) +ip_hdrlen (skb); tp = skb_header_pointer(skb, thoff + offsetof(struct icmphdr, type),
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 746/1266 netfilter: nft_meta_bridge: fix NFT_META_BRI_IIFPVID stack leak
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Florian Westphal <[email protected]>
[ Upstream commit 27dd2997746d54ebc079bb13161cc1bdd401d4a6 ]
This needs to test for nonzero retval.
--- net/bridge/netfilter/nft_meta_bridge.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-)
net/bridge/netfilter/nft_meta_bridge.c +3 -1
@@ -44,7 +44,9 @@ static void nft_meta_bridge_get_eval(const struct nft_expr *expr,if (!br_dev || !br_vlan_enabled (br_dev)) goto err; -br_vlan_get_pvid_rcu (in, &p_pvid); +if (br_vlan_get_pvid_rcu (in, &p_pvid)) + goto err; +nft_reg_store16 (dest, p_pvid);return ; }
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 747/1266 irqchip/crossbar: Fix parent domain resource leak
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Bhargav Joshi <[email protected]>
[ Upstream commit a1074dd62faa6572921d387e8a21589ccea00efc ]
irq_domain_alloc_irqs_parent() is called in allocate_gic_irq() but irq_domain_free_irqs_parent() is never called which causes a resource leak.
Fix this by calling irq_domain_free_irqs_parent() in crossbar_domain_free().
--- drivers/irqchip/irq-crossbar.c | 1 + 1 file changed, 1 insertion(+)
drivers/irqchip/irq-crossbar.c +1 -0
@@ -163,6 +163,7 @@ static void crossbar_domain_free(struct irq_domain *domain, unsigned int virq, cb->write (d->hwirq, cb->safe_map); }raw_spin_unlock (&cb->lock); +irq_domain_free_irqs_parent (domain, virq, nr_irqs); } static int crossbar_domain_translate(struct irq_domain *d,
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 748/1266 selftests/mm: clarify alternate unmapping in compaction_test
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Sayali Patil <[email protected]>
[ Upstream commit 69ba1d76d93ab818245333cf400928477ba72053 ]
Add a comment explaining that every other entry in the list is unmapped to intentionally create fragmentation with locked pages before invoking check_compaction().
--- tools/testing/selftests/mm/compaction_test.c | 3 +++ 1 file changed, 3 insertions(+)
tools/testing/selftests/mm/compaction_test.c +3 -0
@@ -234,6 +234,9 @@ int main(int argc, char **argv) mem_fragmentable_MB -=MAP_SIZE_MB ; } +/* Unmap every other entry in the list to create fragmentation with +* locked pages before invoking check_compaction(). +*/ for (entry = list; entry !=NULL ; entry = entry->next) {munmap (entry->map,MAP_SIZE );if (!entry->next)
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 749/1266 selftests/mm: allow PUD-level entries in compound testcase of hmm tests
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Sayali Patil <[email protected]>
[ Upstream commit 224ed0e019b122d08580362abe57574a78f2b5fa ]
Patch series "selftests/mm: assorted fixes for hmm-tests", v3.
This series fixes a few issues in hmm-tests that show up when page-size and huge-page configuration differ from the hardcoded assumptions the tests were written for (PMD/THP sizing, default hugepage size, and related cases).
It also includes a fix to exclusive_cow: the test ignored the return value of fork(), so both parent and child ran the same teardown path.
This patch (of 3):
The HMM compound testcase currently assumes only PMD-level mappings and fails on systems where default_hugepagesz=1G is set, because the region is then reported by the device at PUD level.
Determine the mapping level (PMD or PUD) the device reports for the first page of the range and require every page to match that level exactly via ASSERT_EQ(). This accepts PUD-level mappings while preserving the expected/observed protection values printed on failure, and rejects a fragmented mapping that mixes PMD- and PUD-level entries within the same range (which a per-page OR check would have let pass).
--- tools/testing/selftests/mm/hmm-tests.c | 32 +++++++++++++++++++------- 1 file changed, 24 insertions(+), 8 deletions(-)
tools/testing/selftests/mm/hmm-tests.c +24 -8
@@ -1612,8 +1612,8 @@ TEST_F(hmm2, snapshot) }/* -* Test the hmm_range_fault() HMM_PFN_PMD flag for large pages that -* should be mapped by a large page table entry. +* Test the hmm_range_fault() handling of large pages (PMD or PUD) +* that should be mapped by a large page table entry. */ TEST_F(hmm, compound) {
@@ -1623,6 +1623,7 @@ TEST_F(hmm, compound)unsigned long default_hsize;int *ptr;unsigned char *m; +unsigned char prot;int ret;unsigned long i;
@@ -1661,11 +1662,20 @@ TEST_F(hmm, compound)ASSERT_EQ (ret,0 );ASSERT_EQ (buffer->cpages, npages); -/* Check what the device saw. */ +/* +* Check what the device saw. The region is backed by a single huge +* page that the device reports either at PMD or at PUD level depending +* on the configured default hugepage size. Determine that level from +* the first page and require every page in the range to match it +* exactly, so that a fragmented mapping mixing levels (or a missing +* large-page bit) is still caught and reported with its actual value. +*/ m = buffer->mirror; + prot =HMM_DMIRROR_PROT_WRITE | + ((m[0 ] &HMM_DMIRROR_PROT_PUD ) ?HMM_DMIRROR_PROT_PUD : +HMM_DMIRROR_PROT_PMD );for (i =0 ; i < npages; ++i) -ASSERT_EQ (m[i],HMM_DMIRROR_PROT_WRITE | -HMM_DMIRROR_PROT_PMD ); +ASSERT_EQ (m[i], prot);/* Make the region read-only. */ ret =mprotect (buffer->ptr, size,PROT_READ );
@@ -1676,11 +1686,17 @@ TEST_F(hmm, compound)ASSERT_EQ (ret,0 );ASSERT_EQ (buffer->cpages, npages); -/* Check what the device saw. */ +/* +* Check what the device saw after mprotect(PROT_READ). Same +* approach as above: determine the mapping level from the first +* page and require every page to match it exactly. +*/ m = buffer->mirror; + prot =HMM_DMIRROR_PROT_READ | + ((m[0 ] &HMM_DMIRROR_PROT_PUD ) ?HMM_DMIRROR_PROT_PUD : +HMM_DMIRROR_PROT_PMD );for (i =0 ; i < npages; ++i) -ASSERT_EQ (m[i],HMM_DMIRROR_PROT_READ | -HMM_DMIRROR_PROT_PMD ); +ASSERT_EQ (m[i], prot);munmap (buffer->ptr, buffer->size); buffer->ptr =NULL ;
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 750/1266 selftests/mm: fix exclusive_cow test fork() handling
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Aboorva Devarajan <[email protected]>
[ Upstream commit cea5702144615878600d3a39b5d8b3cc34719012 ]
The test ignores the return value of fork(), so both the parent and the (newly created) child run the COW verification loops and then call hmm_buffer_free() before returning into the kselftest harness, which _exit()s each side. This duplicated teardown sequence has been observed to manifest as a SIGSEGV in the test child, e.g.:
hmm-tests[360141]: segfault (11) at 0 nip 10006964 lr 1000ac3c code 1 in hmm-tests[6964,10000000+30000]
Fix this by adopting the same fork()-then-wait pattern already used by the nearby anon_write_child / anon_write_child_shared tests in this file: the child performs the COW verification and then _exit(0)s so it does not run the test teardown, while the parent independently verifies COW, waits for the child, and only then frees the buffer.
--- tools/testing/selftests/mm/hmm-tests.c | 31 +++++++++++++++++++++++--- 1 file changed, 28 insertions(+), 3 deletions(-)
tools/testing/selftests/mm/hmm-tests.c +28 -3
@@ -1896,6 +1896,8 @@ TEST_F(hmm, exclusive_cow)unsigned long i;int *ptr;int ret; +pid_t pid; +int status; npages =ALIGN (HMM_BUFFER_SIZE , self->page_size) >> self->page_shift;ASSERT_NE (npages,0 );
@@ -1924,14 +1926,37 @@ TEST_F(hmm, exclusive_cow)ASSERT_EQ (ret,0 );ASSERT_EQ (buffer->cpages, npages); -fork (); + pid =fork (); +if (pid ==-1 ) +ASSERT_EQ (pid,0 ); -/* Fault pages back to system memory and check them. */ +if (pid ==0 ) { +/* +* Child verifies COW independently, then _exit(0)s so it does +* not run the test teardown. A failed ASSERT_* here makes the +* harness abort() the child, so the parent sees +* !WIFEXITED(status) below and fails in turn. +*/ +for (i =0 , ptr = buffer->ptr; i < size /sizeof (*ptr); ++i) +ASSERT_EQ (ptr[i]++, i); + +for (i =0 , ptr = buffer->ptr; i < size /sizeof (*ptr); ++i) +ASSERT_EQ (ptr[i], i +1 ); + +_exit (0 ); + } + +/* Parent: also increment to verify COW works for both processes. */ for (i =0 , ptr = buffer->ptr; i < size /sizeof (*ptr); ++i)ASSERT_EQ (ptr[i]++, i);for (i =0 , ptr = buffer->ptr; i < size /sizeof (*ptr); ++i) -ASSERT_EQ (ptr[i], i+1 ); +ASSERT_EQ (ptr[i], i +1 ); + +/* Parent: wait for child and then free the buffer. */ +ASSERT_EQ (waitpid (pid, &status,0 ), pid); +ASSERT_TRUE (WIFEXITED (status)); +ASSERT_EQ (WEXITSTATUS (status),0 );hmm_buffer_free (buffer); }
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 751/1266 net: marvell: prestera: initialize err in prestera_port_sfp_bind
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Ruoyu Wang <[email protected]>
[ Upstream commit 62b01f72d93c7bc8fde3b2e5b5f783eca5f53324 ]
prestera_port_sfp_bind() returns err after walking the ports node. If no child node matches the port's front-panel id, err is never assigned.
Initialize err to 0 because absence of a matching optional port device tree node is not an error. In that case no phylink is created and port creation should continue with port->phy_link left NULL. Errors from malformed matched nodes and phylink_create() still propagate.
--- drivers/net/ethernet/marvell/prestera/prestera_main.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
drivers/net/ethernet/marvell/prestera/prestera_main.c +1 -1
@@ -372,7 +372,7 @@ static int prestera_port_sfp_bind(struct prestera_port *port)struct device_node *ports, *node;struct fwnode_handle *fwnode;struct phylink *phy_link; -int err; +int err =0 ;if (!sw->np)return 0 ;
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 752/1266 tipc: fix use-after-free of the discoverer in tipc_disc_rcv()
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Weiming Shi <[email protected]>
[ Upstream commit 1579342d71133da7f00daa02c75cebec7372097b ]
bearer_disable() frees b->disc with tipc_disc_delete()'s plain kfree(), but tipc_disc_rcv() still dereferences b->disc in RX softirq under rcu_read_lock() (tipc_udp_recv -> tipc_rcv -> tipc_disc_rcv).
L2 bearers are safe thanks to the synchronize_net() in tipc_disable_l2_media(), but the UDP bearer defers that call to the cleanup_bearer() workqueue, so the discoverer is freed with no grace period:
BUG: KASAN: slab-use-after-free in tipc_disc_rcv (net/tipc/discover.c:149) Read of size 8 at addr ffff88802348b728 by task poc_tipc/184 <IRQ> tipc_disc_rcv (net/tipc/discover.c:149) tipc_rcv (net/tipc/node.c:2126) tipc_udp_recv (net/tipc/udp_media.c:391) udp_rcv (net/ipv4/udp.c:2643) ip_local_deliver_finish (net/ipv4/ip_input.c:241) </IRQ> Freed by task 181: kfree (mm/slub.c:6565) bearer_disable (net/tipc/bearer.c:418) tipc_nl_bearer_disable (net/tipc/bearer.c:1001)
The bearer is freed with kfree_rcu(); free the discoverer the same way. Add an rcu_head to struct tipc_discoverer and free it and its skb from an RCU callback.
Because the RCU callback (tipc_disc_free_rcu) lives in module text, a call_rcu() that is still pending when the tipc module is unloaded would invoke a freed function. Add an rcu_barrier() to tipc_exit() after the bearer subsystem has been torn down, so all pending discoverer callbacks have run before the module text goes away.
Reachable from an unprivileged user namespace: the TIPCv2 genl family is netnsok and its bearer commands have no GENL_ADMIN_PERM. Needs CONFIG_TIPC and CONFIG_TIPC_MEDIA_UDP.
--- net/tipc/core.c | 5 +++++ net/tipc/discover.c | 14 ++++++++++++-- 2 files changed, 17 insertions(+), 2 deletions(-)
net/tipc/core.c +5 -0
@@ -218,6 +218,11 @@ static void __exit tipc_exit(void)unregister_pernet_device (&tipc_net_ops);tipc_unregister_sysctl (); +/* TODO: Wait for all timers that called call_rcu() to finish before +* calling rcu_barrier(). +*/ +rcu_barrier (); +pr_info ("Deactivated\n" ); }
net/tipc/discover.c +12 -2
@@ -58,6 +58,7 @@* @skb: request message to be (repeatedly) sent * @timer: timer governing period between requests * @timer_intv: current interval between requests (in ms) +* @rcu: RCU head for deferred freeing */ struct tipc_discoverer {u32 bearer_id;
@@ -69,6 +70,7 @@ struct tipc_discoverer {struct sk_buff *skb;struct timer_list timer;unsigned long timer_intv; +struct rcu_head rcu; };/**
@@ -382,6 +384,15 @@ int tipc_disc_create(struct net *net, struct tipc_bearer *b,return 0 ; } +static void tipc_disc_free_rcu (struct rcu_head *rp) +{ + struct tipc_discoverer *d = container_of(rp, struct tipc_discoverer, + rcu); + +kfree_skb (d->skb); +kfree (d); +} +/** * tipc_disc_delete - destroy object sending periodic link setup requests * @d: ptr to link dest structure
@@ -389,8 +400,7 @@ int tipc_disc_create(struct net *net, struct tipc_bearer *b,void tipc_disc_delete (struct tipc_discoverer *d) {timer_shutdown_sync (&d->timer); -kfree_skb (d->skb); -kfree (d); +call_rcu (&d->rcu, tipc_disc_free_rcu); }/**
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 753/1266 net: ethernet: mtk_ppe: Fix rhashtable leak in mtk_ppe_init error paths
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Wayen Yan <[email protected]>
[ Upstream commit 41782770be567abc6509169d0ffdada31c783a66 ]
In mtk_ppe_init(), when accounting is enabled, the error paths for dmam_alloc_coherent(mib) and devm_kzalloc(acct) failures return NULL directly, bypassing the err_free_l2_flows label that destroys the rhashtable initialized earlier.
While this leak only occurs during probe (not runtime) and the leaked memory is minimal (an empty rhash table), fixing it ensures proper error path cleanup consistency.
Fix by changing the two return NULL statements to goto err_free_l2_flows.
--- drivers/net/ethernet/mediatek/mtk_ppe.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-)
drivers/net/ethernet/mediatek/mtk_ppe.c +2 -2
@@ -916,7 +916,7 @@ struct mtk_ppe *mtk_ppe_init(struct mtk_eth *eth, void __iomem *base, int index) mib =dmam_alloc_coherent (ppe->dev,MTK_PPE_ENTRIES *sizeof (*mib), &ppe->mib_phys,GFP_KERNEL );if (!mib) -return NULL ; + goto err_free_l2_flows; ppe->mib_table = mib;
@@ -924,7 +924,7 @@ struct mtk_ppe *mtk_ppe_init(struct mtk_eth *eth, void __iomem *base, int index) GFP_KERNEL);if (!acct) -return NULL ; + goto err_free_l2_flows; ppe->acct_table = acct; }
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 754/1266 octeontx2-af: mcs: Fix unsupported secy stats read
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Geetha sowjanya <[email protected]>
[ Upstream commit d4b7440f7316e76f013f57d8b6da069a1b9c34e7 ]
Secy control stats counter doesn't exist for CNF10KB platform. Skip reading this respective register for CNF10KB silicon while fetching secy stats.
--- drivers/net/ethernet/marvell/octeontx2/af/mcs.c | 6 +++--- drivers/net/ethernet/marvell/octeontx2/af/rvu_debugfs.c | 3 ++- 2 files changed, 5 insertions(+), 4 deletions(-)
drivers/net/ethernet/marvell/octeontx2/af/mcs.c +3 -3
@@ -120,13 +120,13 @@ void mcs_get_rx_secy_stats(struct mcs *mcs, struct mcs_secy_stats *stats, int id reg =MCSX_CSE_RX_MEM_SLAVE_INPKTSSECYUNTAGGEDX (id); stats->pkt_untaged_cnt =mcs_reg_read (mcs, reg); - reg =MCSX_CSE_RX_MEM_SLAVE_INPKTSSECYCTLX (id); - stats->pkt_ctl_cnt =mcs_reg_read (mcs, reg); -if (mcs->hw->mcs_blks >1 ) { reg =MCSX_CSE_RX_MEM_SLAVE_INPKTSSECYNOTAGX (id); stats->pkt_notag_cnt =mcs_reg_read (mcs, reg); +return ; } + reg =MCSX_CSE_RX_MEM_SLAVE_INPKTSSECYCTLX (id); + stats->pkt_ctl_cnt =mcs_reg_read (mcs, reg); } void mcs_get_flowid_stats(struct mcs *mcs, struct mcs_flowid_stats *stats,
drivers/net/ethernet/marvell/octeontx2/af/rvu_debugfs.c +2 -1
@@ -505,10 +505,11 @@ static int rvu_dbg_mcs_rx_secy_stats_display(struct seq_file *filp, void *unusedseq_printf (filp,"secy%d: Tagged ctrl pkts: %lld\n" , secy_id, stats.pkt_tagged_ctl_cnt);seq_printf (filp,"secy%d: Untaged pkts: %lld\n" , secy_id, stats.pkt_untaged_cnt); -seq_printf (filp,"secy%d: Ctrl pkts: %lld\n" , secy_id, stats.pkt_ctl_cnt);if (mcs->hw->mcs_blks >1 )seq_printf (filp,"secy%d: pkts notag: %lld\n" , secy_id, stats.pkt_notag_cnt); +else +seq_printf (filp,"secy%d: Ctrl pkts: %lld\n" , secy_id, stats.pkt_ctl_cnt); }mutex_unlock (&mcs->stats_lock);return 0 ;
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 755/1266 octeontx2-pf: Clear stats of all resources when freeing resources
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Subbaraya Sundeep <[email protected]>
[ Upstream commit fd4460721fb4062ef470ecdfdaedadfe7e415c09 ]
When all MCS resources mapped to a PF are being freed then clear stats of all those resources too.
--- drivers/net/ethernet/marvell/octeontx2/nic/cn10k_macsec.c | 1 + 1 file changed, 1 insertion(+)
drivers/net/ethernet/marvell/octeontx2/nic/cn10k_macsec.c +1 -0
@@ -213,6 +213,7 @@ static void cn10k_mcs_free_rsrc(struct otx2_nic *pfvf, enum mcs_direction dir, clear_req->id = hw_rsrc_id; clear_req->type = type; clear_req->dir = dir; + clear_req->all = all; req =otx2_mbox_alloc_msg_mcs_free_resources (mbox);if (!req)
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 756/1266 octeontx2-pf: mcs: Fix mcs resources free on PF shutdown
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Geetha sowjanya <[email protected]>
[ Upstream commit 450d0e90b10393bd9f50c127875a9fdd4cc81c30 ]
On PF shutdown, the current driver free mcs hardware resources though mcs resources are not allocated to it. This patch checks the mcs resources status and if resources are allocated then only sends mailbox message to free them.
--- .../net/ethernet/marvell/octeontx2/nic/cn10k_macsec.c | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-)
drivers/net/ethernet/marvell/octeontx2/nic/cn10k_macsec.c +7 -2
@@ -1808,11 +1808,16 @@ int cn10k_mcs_init(struct otx2_nic *pfvf)void cn10k_mcs_free (struct otx2_nic *pfvf) { +struct cn10k_mcs_cfg *cfg = pfvf->macsec_cfg; +if (!test_bit (CN10K_HW_MACSEC , &pfvf->hw.cap_flag))return ; -cn10k_mcs_free_rsrc (pfvf,MCS_TX ,MCS_RSRC_TYPE_SECY ,0 , true); -cn10k_mcs_free_rsrc (pfvf,MCS_RX ,MCS_RSRC_TYPE_SECY ,0 , true); +if (!list_empty (&cfg->txsc_list)) { +cn10k_mcs_free_rsrc (pfvf,MCS_TX ,MCS_RSRC_TYPE_SECY ,0 , true); +cn10k_mcs_free_rsrc (pfvf,MCS_RX ,MCS_RSRC_TYPE_SECY ,0 , true); + } +kfree (pfvf->macsec_cfg); pfvf->macsec_cfg =NULL ; }
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 757/1266 rtc: abx80x: fix the RTC_VL_CLR clearing all status flags
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Antoni Pokusinski <[email protected]>
[ Upstream commit 419719c514252a2dbb2e2976f564c83417dd6d0a ]
The RTC_VL_CLR ioctl intends to clear only the battery low flag (BLF), however the current implementation writes 0 to the status register, clearing all status bits.
Fix this by writing back the masked status value so that only BLF is cleared, preserving other status flags.
--- drivers/rtc/rtc-abx80x.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-)
drivers/rtc/rtc-abx80x.c +2 -1
@@ -545,7 +545,8 @@ static int abx80x_ioctl(struct device *dev, unsigned int cmd, unsigned long arg) status &= ~ABX8XX_STATUS_BLF ; - tmp =i2c_smbus_write_byte_data (client,ABX8XX_REG_STATUS ,0 ); + tmp =i2c_smbus_write_byte_data (client,ABX8XX_REG_STATUS , + status);if (tmp <0 )return tmp;
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 758/1266 rtc: ds1307: handle oscillator stop flag for ds1337/ds1339/ds3231
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Ronan Dalton <[email protected]>
[ Upstream commit a091e1ba3b68cabc9caedafc6f81d9fe9b3b2200 ]
Prior to commit 48458654659c ("rtc: ds1307: remove clear of oscillator stop flag (OSF) in probe"), the oscillator stop flag (OSF) bit was checked during device probe for the ds1337, ds1339, ds1341, and ds3231 chips; if it was set, it would be cleared and a warning would be logged saying "SET TIME!". Since that commit, the OSF bit is no longer cleared, but the warning is still printed.
Directly following that commit, there was no way to get rid of this warning because nothing cleared the OSF bit on these chips.
The commit associated with the previous commit, 523923cfd5d6 ("rtc:
ds1307: handle oscillator stop flag (OSF) for ds1341"), made proper use of the OSF when getting and setting the time in the RTC. However, the other RTC variants ds1337, ds1339 and ds3231 didn't have a corresponding change made.
Given that the OSF bit is no longer cleared at probe time when it is set, the remaining three chips should have the same handling as the ds1341 chip has for the OSF bit.
Fix the issue on the ds1337, ds1339 and ds3231 chips by applying the same logic as the ds1341 has to these chips.
Note that any devices brought up between the first referenced commit and this one may begin mistrusting the time reported by the RTC until it is set again, if the bit was never explicitly cleared.
Note that only the ds1339 was tested with this change, but the datasheets for the other chips contain essentially identical descriptions of the OSF bit so the same change should work.
--- drivers/rtc/rtc-ds1307.c | 28 +++++++++++++++++----------- 1 file changed, 17 insertions(+), 11 deletions(-)
drivers/rtc/rtc-ds1307.c +17 -11
@@ -264,6 +264,16 @@ static int ds1307_get_time(struct device *dev, struct rtc_time *t)if (tmp &DS1338_BIT_OSF )return -EINVAL ;break ; +case ds_1337: +case ds_1339: +case ds_1341: +case ds_3231: + ret =regmap_read (ds1307->regmap,DS1337_REG_STATUS , &tmp); +if (ret) +return ret; +if (tmp &DS1337_BIT_OSF ) +return -EINVAL ; +break ;case ds_1340:if (tmp & DS1340_BIT_nEOSC)return -EINVAL ;
@@ -274,13 +284,6 @@ static int ds1307_get_time(struct device *dev, struct rtc_time *t)if (tmp &DS1340_BIT_OSF )return -EINVAL ;break ; -case ds_1341: - ret =regmap_read (ds1307->regmap,DS1337_REG_STATUS , &tmp); -if (ret) -return ret; -if (tmp &DS1337_BIT_OSF ) -return -EINVAL ; -break ;case ds_1388: ret =regmap_read (ds1307->regmap,DS1388_REG_FLAG , &tmp);if (ret)
@@ -375,14 +378,17 @@ static int ds1307_set_time(struct device *dev, struct rtc_time *t)regmap_update_bits (ds1307->regmap,DS1307_REG_CONTROL ,DS1338_BIT_OSF ,0 );break ; -case ds_1340: -regmap_update_bits (ds1307->regmap,DS1340_REG_FLAG , -DS1340_BIT_OSF ,0 ); -break ; +case ds_1337: +case ds_1339:case ds_1341: +case ds_3231:regmap_update_bits (ds1307->regmap,DS1337_REG_STATUS ,DS1337_BIT_OSF ,0 );break ; +case ds_1340: +regmap_update_bits (ds1307->regmap,DS1340_REG_FLAG , +DS1340_BIT_OSF ,0 ); +break ;case ds_1388:regmap_update_bits (ds1307->regmap,DS1388_REG_FLAG ,DS1388_BIT_OSF ,0 );
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 759/1266 bpf: Fix stack slot index in nospec checks
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Nuoqi Gui <[email protected]>
[ Upstream commit d1d53aa30ab3b5ae89161c9cc840b3f7489ad386 ]
check_stack_write_fixed_off() computes the byte slot for a fixed-offset stack write as -off - 1, and records each written byte in slot_type[] with (slot - i) % BPF_REG_SIZE.
The Spectre v4 sanitization pre-check uses slot_type[i] instead. For a 4-byte write at fp-8 after the lower half of fp-8 has been zeroed, the pre-check scans bytes 0..3 and sees STACK_ZERO while the actual write updates bytes 7..4. That can leave the second half-slot write without nospec_result even though the bytes being overwritten still require sanitization.
Use the same slot index in the sanitization pre-check that the write path uses when updating slot_type[].
--- kernel/bpf/verifier.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-)
kernel/bpf/verifier.c +2 -1
@@ -4672,7 +4672,8 @@ static int check_stack_write_fixed_off(struct bpf_verifier_env *env,bool sanitize = reg &&is_spillable_regtype (reg->type);for (i =0 ; i < size; i++) { -u8 type = state->stack[spi].slot_type[i]; +u8 type = state->stack[spi].slot_type[(slot - i) % +BPF_REG_SIZE ];if (type !=STACK_MISC && type !=STACK_ZERO ) { sanitize = true;
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 760/1266 bpf: zero-initialize the fib lookup flow struct
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Avinash Duduskar <[email protected]>
[ Upstream commit 0dfcb68a6a5ac517b22dff6a1f01cb4f126dfc57 ]
bpf_ipv4_fib_lookup() and bpf_ipv6_fib_lookup() build the flow key on the stack with a bare "struct flowi4 fl4;" / "struct flowi6 fl6;" and fill it field by field, but never set flowi4_l3mdev / flowi6_l3mdev.
On the non-DIRECT path the lookup goes through the fib rules whenever the netns has custom rules, which a VRF installs:
bpf_ipv4_fib_lookup() -> fib_lookup() -> __fib_lookup() -> l3mdev_update_flow() reads !fl->flowi_l3mdev -> fib_rules_lookup() -> fib_rule_match() -> l3mdev_fib_rule_match() uses fl->flowi_l3mdev
l3mdev_update_flow() resolves the l3mdev master from the ingress device only while the field is still zero. Left at a nonzero stack value the resolution is skipped, and l3mdev_fib_rule_match() then tests that value as an ifindex, so the VRF master is not resolved and the rule fails to
match: an ingress enslaved to a VRF can fail to select its table. FIB rules matching on an L3 master device (l3mdev_fib_rule_iif_match()/ _oif_match()) read the same value, so an "ip rule iif/oif <vrf>" mismatches the same way.
Zero-initialize the whole flow struct rather than adding one more field assignment, so any flowi field added later is covered too. ip_route_input_slow() likewise zeroes the field before its input lookup.
CONFIG_INIT_STACK_ALL_ZERO masks this by default, but it depends on compiler support (CC_HAS_AUTO_VAR_INIT_ZERO), so INIT_STACK_NONE builds, including older toolchains that fall back to it, are exposed. Built with INIT_STACK_ALL_PATTERN, a plain bpf_fib_lookup (no VLAN, no DIRECT) over a VRF slave whose destination is routed only in the VRF table returns BPF_FIB_LKUP_RET_NOT_FWDED, and resolves with this patch. On the default config the lookup succeeds either way, so ordinary testing does not catch the bug.
--- net/core/filter.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-)
net/core/filter.c +2 -2
@@ -5955,7 +5955,7 @@ static int bpf_ipv4_fib_lookup(struct net *net, struct bpf_fib_lookup *params,struct neighbour *neigh;struct net_device *dev;struct fib_result res; -struct flowi4 fl4; +struct flowi4 fl4 = {};u32 mtu =0 ;int err;
@@ -6092,7 +6092,7 @@ static int bpf_ipv6_fib_lookup(struct net *net, struct bpf_fib_lookup *params,struct neighbour *neigh;struct net_device *dev;struct inet6_dev *idev; -struct flowi6 fl6; +struct flowi6 fl6 = {};int strict =0 ;int oif, err;u32 mtu =0 ;
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 761/1266 bpf: Fix effective prog array index with BPF_F_PREORDER
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Amery Hung <[email protected]>
[ Upstream commit f08aaee3152d0dfc578b3f2586932d82062701dd ]
replace_effective_prog() and purge_effective_progs() located the slot in the effective array by walking the program hlist and counting entries linearly. That count does not match the array layout: compute_effective_ progs() places BPF_F_PREORDER programs at the front (ancestor cgroup first, attach order within a cgroup) and the rest after them (descendant cgroup first). So when a preorder program is present, the linear hlist position no longer equals the program's index in the effective array.
For replace_effective_prog() (bpf_link_update()) this overwrote the wrong slot, corrupting the effective order. For purge_effective_progs(), it could dummy out a slot belonging to a different program and leave the detached program in the array while bpf_prog_put() drops its reference, i.e. a use-after-free.
Fix both by replaying compute_effective_progs()'s placement (including the per-cgroup preorder reversal) in a shared effective_prog_pos() helper. Identify the entry by its struct bpf_prog_list pointer rather than by (prog, link) value, so the lookup resolves to exactly the attachment the syscall selected even when the same bpf_prog is attached to several cgroups in the hierarchy.
--- kernel/bpf/cgroup.c | 108 +++++++++++++++++++++++++------------------- 1 file changed, 62 insertions(+), 46 deletions(-)
kernel/bpf/cgroup.c +62 -46
@@ -769,19 +769,65 @@ static int cgroup_bpf_attach(struct cgroup *cgrp,return ret; } +static int effective_prog_pos (struct cgroup *cgrp, +enum cgroup_bpf_attach_type atype, +struct bpf_prog_list *target_pl) +{ +int cnt =0 , preorder_cnt =0 , fstart, bstart, init_bstart, pos =-1 ; +struct bpf_prog_list *pl; +struct cgroup *p = cgrp; + +/* count effective programs to find where the preorder region ends */ +do { +if (cnt ==0 || (p->bpf.flags[atype] &BPF_F_ALLOW_MULTI )) + cnt +=prog_list_length (&p->bpf.progs[atype], &preorder_cnt); + p =cgroup_parent (p); + }while (p); + +/* replay compute_effective_progs() placement and record target's slot */ + cnt =0 ; + p = cgrp; + fstart = preorder_cnt; + bstart = preorder_cnt -1 ; +do { +if (cnt >0 && !(p->bpf.flags[atype] &BPF_F_ALLOW_MULTI )) +continue ; + + init_bstart = bstart; +hlist_for_each_entry (pl, &p->bpf.progs[atype], node) { +if (!prog_list_prog (pl)) +continue ; + +if (pl->flags &BPF_F_PREORDER ) { +if (pl == target_pl) + pos = bstart; + bstart--; + }else { +if (pl == target_pl) + pos = fstart; + fstart++; + } + cnt++; + } + +/* reverse pre-ordering progs at this cgroup level */ +if (pos >= bstart +1 && pos <= init_bstart) + pos = bstart +1 + init_bstart - pos; + }while ((p =cgroup_parent (p))); + +return pos; +} +/* Swap updated BPF program for given link in effective program arrays across * all descendant cgroups. This function is guaranteed to succeed. */ static void replace_effective_prog (struct cgroup *cgrp,enum cgroup_bpf_attach_type atype, -struct bpf_cgroup_link *link) +struct bpf_prog_list *pl) {struct bpf_prog_array_item *item;struct cgroup_subsys_state *css;struct bpf_prog_array *progs; -struct bpf_prog_list *pl; -struct hlist_head *head; -struct cgroup *cg;int pos;css_for_each_descendant_pre (css, &cgrp->self) {
@@ -790,27 +836,15 @@ static void replace_effective_prog(struct cgroup *cgrp,if (percpu_ref_is_zero (&desc->bpf.refcnt))continue ; -/* find position of link in effective progs array */ -for (pos =0 , cg = desc; cg; cg =cgroup_parent (cg)) { -if (pos && !(cg->bpf.flags[atype] &BPF_F_ALLOW_MULTI )) -continue ; + pos =effective_prog_pos (desc, atype, pl); +if (WARN_ON_ONCE (pos <0 )) +continue ; - head = &cg->bpf.progs[atype]; -hlist_for_each_entry (pl, head, node) { -if (!prog_list_prog (pl)) -continue ; -if (pl->link == link) - goto found; - pos++; - } - } -found: -BUG_ON (!cg); progs =rcu_dereference_protected ( desc->bpf.effective[atype],lockdep_is_held (&cgroup_mutex)); item = &progs->items[pos]; -WRITE_ONCE (item->prog, link->link.prog); +WRITE_ONCE (item->prog, pl->link->link.prog); } }
@@ -853,7 +887,7 @@ static int __cgroup_bpf_replace(struct cgroup *cgrp,return -ENOENT ; old_prog =xchg (&link->link.prog, new_prog); -replace_effective_prog (cgrp, atype, link); +replace_effective_prog (cgrp, atype, pl);bpf_prog_put (old_prog);return 0 ; }
@@ -920,19 +954,14 @@ static struct bpf_prog_list *find_detach_entry(struct hlist_head *progs,* recomputing the array in place. * * @cgrp: The cgroup which descendants to travers -* @prog: A program to detach or NULL -* @link: A link to detach or NULL +* @pl: The prog_list entry being detached * @atype: Type of detach operation */ -static void purge_effective_progs (struct cgroup *cgrp,struct bpf_prog *prog, -struct bpf_cgroup_link *link, +static void purge_effective_progs (struct cgroup *cgrp,struct bpf_prog_list *pl,enum cgroup_bpf_attach_type atype) {struct cgroup_subsys_state *css;struct bpf_prog_array *progs; -struct bpf_prog_list *pl; -struct hlist_head *head; -struct cgroup *cg;int pos;/* recompute effective prog array in place */
@@ -942,24 +971,11 @@ static void purge_effective_progs(struct cgroup *cgrp, struct bpf_prog *prog,if (percpu_ref_is_zero (&desc->bpf.refcnt))continue ; -/* find position of link or prog in effective progs array */ -for (pos =0 , cg = desc; cg; cg =cgroup_parent (cg)) { -if (pos && !(cg->bpf.flags[atype] &BPF_F_ALLOW_MULTI )) -continue ; - - head = &cg->bpf.progs[atype]; -hlist_for_each_entry (pl, head, node) { -if (!prog_list_prog (pl)) -continue ; -if (pl->prog == prog && pl->link == link) - goto found; - pos++; - } - } - + pos =effective_prog_pos (desc, atype, pl);/* no link or prog match, skip the cgroup of this layer */ -continue ; -found: +if (pos <0 ) +continue ; + progs =rcu_dereference_protected ( desc->bpf.effective[atype],lockdep_is_held (&cgroup_mutex));
@@ -1020,7 +1036,7 @@ static int __cgroup_bpf_detach(struct cgroup *cgrp, struct bpf_prog *prog,/* if update effective array failed replace the prog with a dummy prog*/ pl->prog = old_prog; pl->link = link; -purge_effective_progs (cgrp, old_prog, link, atype); +purge_effective_progs (cgrp, pl, atype); }/* now can actually delete it from this cgroup list */
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 762/1266 drm/edid: fix OOB read in drm_parse_tiled_block()
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Xiang Mei <[email protected]>
[ Upstream commit faaa1e1155833e7d4ce7e3cfaf64c0d636b190db ]
drm_parse_tiled_block() casts the DisplayID block to a struct displayid_tiled_block and reads the full fixed layout up to tile->topology_id[7] without checking block->num_bytes. The DisplayID iterator only validates the declared payload length, so a crafted EDID can advertise a tiled-display block (tag DATA_BLOCK_TILED_DISPLAY, or DATA_BLOCK_2_TILED_DISPLAY_TOPOLOGY for v2.0) with a small num_bytes at the end of a DisplayID extension. The read then runs past the end of the exact-sized kmemdup()'d EDID allocation, a heap out-of-bounds read.
Reject blocks shorter than the spec's 22-byte tiled payload before reading the fixed struct, as drm_parse_vesa_mso_data() already does.
BUG: KASAN: slab-out-of-bounds in drm_edid_connector_update Read of size 2 at addr ffff888010077700 by task exploit/147 dump_stack_lvl (lib/dump_stack.c:94 ...) print_report (mm/kasan/report.c:378 ...) kasan_report (mm/kasan/report.c:595) drm_edid_connector_update (drivers/gpu/drm/drm_edid.c:7581) bochs_connector_helper_get_modes (drivers/gpu/drm/tiny/bochs.c:574) drm_helper_probe_single_connector_modes (drivers/gpu/drm/drm_probe_helper.c:426) status_store (drivers/gpu/drm/drm_sysfs.c:219) ... vfs_write (fs/read_write.c:595 fs/read_write.c:688) ksys_write (fs/read_write.c:740)
--- drivers/gpu/drm/drm_edid.c | 8 ++++++++ 1 file changed, 8 insertions(+)
drivers/gpu/drm/drm_edid.c +8 -0
@@ -7279,6 +7279,14 @@ static void drm_parse_tiled_block(struct drm_connector *connector,u8 num_v_tile, num_h_tile;struct drm_tile_group *tg; +/* tiled block payload per spec: cap 1 + topo 3 + size 4 + bezel 5 + id 9 = 22 */ +if (block->num_bytes <22 ) { +drm_dbg_kms (connector->dev, +"[CONNECTOR:%d:%s] Unexpected tiled block size %u\n" , + connector->base.id, connector->name, block->num_bytes); +return ; + } + w = tile->tile_size[0 ] | tile->tile_size[1 ] <<8 ; h = tile->tile_size[2 ] | tile->tile_size[3 ] <<8 ;
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 763/1266 PCI: endpoint: pci-epf-vntb: Add check to detect db_count value of 0
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Manivannan Sadhasivam <[email protected]>
[ Upstream commit 33bd1ea748bc897c4d13437284e08c658e8d1340 ]
epf_ntb->db_count value should be within 1 to MAX_DB_COUNT. Current code only checks for the upper bound, while the lower bound is unchecked. This can cause a lot of issues in the driver if the user passes 'db_count' as 0.
Add a check for 0 also. While at it, remove the redundant 'db_count' assignment.
--- drivers/pci/endpoint/functions/pci-epf-vntb.c | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-)
drivers/pci/endpoint/functions/pci-epf-vntb.c +3 -6
@@ -484,7 +484,6 @@ static int epf_ntb_configure_interrupt(struct epf_ntb *ntb) {const struct pci_epc_features *epc_features;struct device *dev; -u32 db_count;int ret; dev = &ntb->epf->dev;
@@ -496,14 +495,12 @@ static int epf_ntb_configure_interrupt(struct epf_ntb *ntb)return -EINVAL ; } - db_count = ntb->db_count; -if (db_count >MAX_DB_COUNT ) { -dev_err (dev,"DB count cannot be more than %d\n" ,MAX_DB_COUNT ); +if (!ntb->db_count || ntb->db_count >MAX_DB_COUNT ) { +dev_err (dev,"DB count %d out of range (1 - %d)\n" , + ntb->db_count,MAX_DB_COUNT );return -EINVAL ; } - ntb->db_count = db_count; -if (epc_features->msi_capable) { ret = pci_epc_set_msi(ntb->epf->epc, ntb->epf->func_no,
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 764/1266 PCI: endpoint: pci-epf-ntb: Add check to detect db_count value of 0
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Manivannan Sadhasivam <[email protected]>
[ Upstream commit d1db6d7c2485ee475a04d8354fbb5b26ea10d978 ]
epf_ntb->db_count value should be within 1 to MAX_DB_COUNT. Current code only checks for the upper bound, while the lower bound is unchecked. This can cause a lot of issues in the driver if the user passes 'db_count' as 0.
Add a check for 0 also. While at it, remove the redundant 'db_count' variable from epf_ntb_configure_interrupt().
--- drivers/pci/endpoint/functions/pci-epf-ntb.c | 21 ++++++++++---------- 1 file changed, 11 insertions(+), 10 deletions(-)
drivers/pci/endpoint/functions/pci-epf-ntb.c +11 -10
@@ -559,12 +559,15 @@ static int epf_ntb_configure_db(struct epf_ntb *ntb,struct pci_epc *epc;int ret; -if (db_count >MAX_DB_COUNT ) -return -EINVAL ; - ntb_epc = ntb->epc[type]; epc = ntb_epc->epc; +if (!db_count || db_count >MAX_DB_COUNT ) { +dev_err (&epc->dev,"DB count %d out of range (1 - %d)\n" , + db_count,MAX_DB_COUNT ); +return -EINVAL ; + } +if (msix) ret =epf_ntb_configure_msix (ntb, type, db_count);else
@@ -1278,7 +1281,6 @@ static int epf_ntb_configure_interrupt(struct epf_ntb *ntb,u8 func_no, vfunc_no;struct pci_epc *epc;struct device *dev; -u32 db_count;int ret; ntb_epc = ntb->epc[type];
@@ -1296,17 +1298,16 @@ static int epf_ntb_configure_interrupt(struct epf_ntb *ntb, func_no = ntb_epc->func_no; vfunc_no = ntb_epc->vfunc_no; - db_count = ntb->db_count; -if (db_count >MAX_DB_COUNT ) { -dev_err (dev,"DB count cannot be more than %d\n" ,MAX_DB_COUNT ); +if (!ntb->db_count || ntb->db_count >MAX_DB_COUNT ) { +dev_err (dev,"DB count %d out of range (1 - %d)\n" , + ntb->db_count,MAX_DB_COUNT );return -EINVAL ; } - ntb->db_count = db_count; epc = ntb_epc->epc;if (msi_capable) { - ret =pci_epc_set_msi (epc, func_no, vfunc_no, db_count); + ret =pci_epc_set_msi (epc, func_no, vfunc_no, ntb->db_count);if (ret) {dev_err (dev,"%s intf: MSI configuration failed\n" ,pci_epc_interface_string (type));
@@ -1315,7 +1316,7 @@ static int epf_ntb_configure_interrupt(struct epf_ntb *ntb, }if (msix_capable) { - ret =pci_epc_set_msix (epc, func_no, vfunc_no, db_count, + ret =pci_epc_set_msix (epc, func_no, vfunc_no, ntb->db_count, ntb_epc->msix_bar, ntb_epc->msix_table_offset);if (ret) {
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 765/1266 ice: fix FDIR CTRL VSI resource leak in ice_reset_all_vfs()
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Dawid Osuchowski <[email protected]>
[ Upstream commit ebbe8868cf473f698e0fbaf436d2618b2bcda806 ]
Resetting all VFs causes resource leak on VFs with FDIR filters enabled as CTRL VSIs are only invalidated and not freed. Fix by using ice_vf_ctrl_vsi_release() instead of ice_vf_ctrl_invalidate_vsi() which aligns behavior with the ice_reset_vf() function.
Reproduction:
echo 1 > /sys/class/net/$pf/device/sriov_numvfs ethtool -N $vf flow-type ether proto 0x9000 action 0 echo 1 > /sys/class/net/$pf/device/reset
--- drivers/net/ethernet/intel/ice/ice_vf_lib.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
drivers/net/ethernet/intel/ice/ice_vf_lib.c +1 -1
@@ -784,7 +784,7 @@ void ice_reset_all_vfs(struct ice_pf *pf)* setup only when VF creates its first FDIR rule. */ if (vf->ctrl_vsi_idx !=ICE_NO_VSI ) -ice_vf_ctrl_invalidate_vsi (vf); +ice_vf_ctrl_vsi_release (vf);ice_vf_pre_vsi_rebuild (vf);if (ice_vf_rebuild_vsi (vf)) {
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 766/1266 ice: fix AQ error code comparison in ice_set_pauseparam()
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Lukasz Czapnik <[email protected]>
[ Upstream commit 2bf7744bc3221a63b95c76c94eab1dad832fa401 ]
Fix unreachable code: the conditionals in ice_set_pauseparam() used the bitwise-AND operator suggesting aq_failures is a bitmap, but it is actually an enum, making the third condition logically unreachable.
Replace the if-else ladder with a switch statement. Also move the aq_failures initialization to the variable declaration and remove the redundant zeroing from ice_set_fc().
--- drivers/net/ethernet/intel/ice/ice_common.c | 1 - drivers/net/ethernet/intel/ice/ice_ethtool.c | 12 ++++++++---- 2 files changed, 8 insertions(+), 5 deletions(-)
drivers/net/ethernet/intel/ice/ice_common.c +0 -1
@@ -3454,7 +3454,6 @@ ice_set_fc(struct ice_port_info *pi, u8 *aq_failures, bool ena_auto_link_update)if (!pi || !aq_failures)return -EINVAL ; - *aq_failures =0 ; hw = pi->hw; pcaps =devm_kzalloc (ice_hw_to_dev (hw),sizeof (*pcaps),GFP_KERNEL );
drivers/net/ethernet/intel/ice/ice_ethtool.c +8 -4
@@ -3015,7 +3015,7 @@ ice_set_pauseparam(struct net_device *netdev, struct ethtool_pauseparam *pause)struct ice_vsi *vsi = np->vsi;struct ice_hw *hw = &pf->hw;struct ice_port_info *pi; -u8 aq_failures; +u8 aq_failures =0 ;bool link_up;u32 is_an;int err;
@@ -3086,18 +3086,22 @@ ice_set_pauseparam(struct net_device *netdev, struct ethtool_pauseparam *pause)/* Set the FC mode and only restart AN if link is up */ err =ice_set_fc (pi, &aq_failures, link_up); -if (aq_failures &ICE_SET_FC_AQ_FAIL_GET ) { +switch (aq_failures) { +case ICE_SET_FC_AQ_FAIL_GET :netdev_info (netdev,"Set fc failed on the get_phy_capabilities call with err %d aq_err %s\n" , err,ice_aq_str (hw->adminq.sq_last_status)); err = -EAGAIN ; - }else if (aq_failures &ICE_SET_FC_AQ_FAIL_SET ) { +break ; +case ICE_SET_FC_AQ_FAIL_SET :netdev_info (netdev,"Set fc failed on the set_phy_config call with err %d aq_err %s\n" , err,ice_aq_str (hw->adminq.sq_last_status)); err = -EAGAIN ; - }else if (aq_failures &ICE_SET_FC_AQ_FAIL_UPDATE ) { +break ; +case ICE_SET_FC_AQ_FAIL_UPDATE :netdev_info (netdev,"Set fc failed on the get_link_info call with err %d aq_err %s\n" , err,ice_aq_str (hw->adminq.sq_last_status)); err = -EAGAIN ; +break ; }return err;
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 767/1266 i40e: Fix i40e_debug() to use struct i40e_hw argument
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Mohamed Khalfella <[email protected]>
[ Upstream commit 798f94603eb0737033861efd320a9159f382a7c5 ]
i40e_debug() macro takes struct i40e_hw *h as first argument. But the macro body uses hw instead of h. This has been working so far because hw happens to be the name of the variable in the context where the macro is expanded. Fix the macro to use the passed argument.
--- drivers/net/ethernet/intel/i40e/i40e_debug.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
drivers/net/ethernet/intel/i40e/i40e_debug.h +1 -1
@@ -41,7 +41,7 @@ struct device *i40e_hw_to_dev(struct i40e_hw *hw);#define i40e_debug (h, m, s, ...) \ do { \ if (((m) & (h)->debug_mask)) \ - dev_info(i40e_hw_to_dev(hw), s, ##__VA_ARGS__); \ + dev_info(i40e_hw_to_dev(h), s, ##__VA_ARGS__); \ } while (0)#endif /* _I40E_DEBUG_H_ */
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 768/1266 rtc: msc313: fix NULL deref in shared IRQ handler at probe
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Stepan Ionichev <[email protected]>
[ Upstream commit a369f48be8de426a7d2bca18dbd46c2ad1138803 ]
msc313_rtc_probe() calls devm_request_irq() with IRQF_SHARED and &pdev->dev as the cookie, but platform_set_drvdata() is only called later after the clock setup. With a shared IRQ line, another device on the same line can trigger the handler in that window. The handler does dev_get_drvdata() on the cookie, gets NULL, and dereferences priv->rtc_base in interrupt context.
Pass priv as the cookie directly so the handler reads it from dev_id without the lookup, removing the dependency on probe order.
--- drivers/rtc/rtc-msc313.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-)
drivers/rtc/rtc-msc313.c +2 -2
@@ -160,7 +160,7 @@ static const struct rtc_class_ops msc313_rtc_ops = {static irqreturn_t msc313_rtc_interrupt (s32 irq,void *dev_id) { -struct msc313_rtc *priv =dev_get_drvdata (dev_id); +struct msc313_rtc *priv = dev_id;u16 reg; reg =readw (priv->rtc_base +REG_RTC_STATUS_INT );
@@ -206,7 +206,7 @@ static int msc313_rtc_probe(struct platform_device *pdev) priv->rtc_dev->range_max =U32_MAX ; ret =devm_request_irq (dev, irq, msc313_rtc_interrupt,IRQF_SHARED , -dev_name (&pdev->dev), &pdev->dev); +dev_name (&pdev->dev), priv);if (ret) {dev_err (dev,"Could not request IRQ\n" );return ret;
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 769/1266 ksmbd: fix use-after-free of conn->preauth_info in concurrent SMB2 NEGOTIATE
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Gil Portnoy <[email protected]>
[ Upstream commit 0c054227479ed7e36ebccb3a558bc0ef698264f6 ]
conn->preauth_info is shared connection state (struct preauth_integrity_info, kmalloc-96) that is allocated and freed by the SMB2 NEGOTIATE handler and read by the response send path.
smb2_handle_negotiate() allocates conn->preauth_info, and on a deassemble_neg_contexts() failure kfrees it and sets it to NULL. Both the allocation and the free/NULL happen under ksmbd_conn_lock(conn) (the connection srv_mutex), which is held across the whole handler body.
The response send path smb3_preauth_hash_rsp(), called from the send:
block of __handle_ksmbd_work(), reads conn->preauth_info and dereferences conn->preauth_info->Preauth_HashValue (via ksmbd_gen_preauth_integrity_hash()) without taking conn_lock. When a client drives two SMB2 NEGOTIATE requests on the same connection, one worker can free conn->preauth_info on the failing-negotiate path while a concurrent send-path worker is reading it, producing a slab use-after-free read (KASAN-confirmed).
The send-path read tested conn->preauth_info for NULL but raced with the free that occurs between the NULL check and the dereference, so the NULL guard alone does not close the window.
Serialize the NEGOTIATE-branch read in smb3_preauth_hash_rsp() under ksmbd_conn_lock(conn) and re-check conn->preauth_info inside the lock. Because the negotiate handler holds conn_lock across its kfree + NULL assignment, a reader that also takes conn_lock either runs fully before the allocation or fully after the NULL store, and can never observe the freed-but-not-yet-NULLed pointer. ksmbd_gen_preauth_integrity_hash() takes no locks itself (it only computes a SHA-512 over the buffer), so no lock-ordering inversion is introduced, and conn_lock is a sleepable mutex which is safe on this send path (it already performs network I/O).
--- fs/smb/server/smb2pdu.c | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-)
fs/smb/server/smb2pdu.c +7 -4
@@ -9132,10 +9132,13 @@ void smb3_preauth_hash_rsp(struct ksmbd_work *work)WORK_BUFFERS (work, req, rsp); -if (le16_to_cpu (req->Command) ==SMB2_NEGOTIATE_HE && - conn->preauth_info) -ksmbd_gen_preauth_integrity_hash (conn, work->response_buf, - conn->preauth_info->Preauth_HashValue); +if (le16_to_cpu (req->Command) ==SMB2_NEGOTIATE_HE ) { +ksmbd_conn_lock (conn); +if (conn->preauth_info) +ksmbd_gen_preauth_integrity_hash (conn, work->response_buf, + conn->preauth_info->Preauth_HashValue); +ksmbd_conn_unlock (conn); + }if (le16_to_cpu (rsp->Command) ==SMB2_SESSION_SETUP_HE && sess) {__u8 *hash_value;
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 770/1266 ipv6: Fix null-ptr-deref in fib6_nh_mtu_change().
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Xiang Mei <[email protected]>
[ Upstream commit 46c3b8191aad3d032776bf3bebf03efdf5f4b905 ]
fib6_nh_mtu_change() re-fetches idev via __in6_dev_get(arg->dev) and dereferences idev->cnf.mtu6 without a NULL check. addrconf_ifdown() clears dev->ip6_ptr with RCU_INIT_POINTER() after rt6_disable_ip() has released tb6_lock, so the RA-driven MTU walk can observe a NULL idev and oops. The caller rt6_mtu_change_route() guards its own __in6_dev_get(), but this re-fetch is unguarded; nexthop-backed routes survive addrconf_ifdown()'s flush, so the walk still reaches it after ip6_ptr is nulled.
Return 0 when idev is NULL, matching rt6_mtu_change_route() and the fib6_mtu() fix in commit 5ad509c1fdad ("ipv6: Fix null-ptr-deref in fib6_mtu().").
Oops: general protection fault, ... KASAN: null-ptr-deref in range
[0x00000000000002a8-0x00000000000002af]
RIP: 0010:fib6_nh_mtu_change+0x203/0x990
rt6_mtu_change_route+0x141/0x1d0
__fib6_clean_all+0xd0/0x160
rt6_mtu_change+0xb4/0x100
ndisc_router_discovery+0x24b5/0x2cb0
icmpv6_rcv+0x12e9/0x1710
ipv6_rcv+0x39b/0x410--- net/ipv6/route.c | 3 +++ 1 file changed, 3 insertions(+)
net/ipv6/route.c +3 -0
@@ -4980,6 +4980,9 @@ static int fib6_nh_mtu_change(struct fib6_nh *nh, void *_arg)struct inet6_dev *idev =__in6_dev_get (arg->dev);u32 mtu = f6i->fib6_pmtu; +if (!idev) +return 0 ; +if (mtu >= arg->mtu || (mtu < arg->mtu && mtu == idev->cnf.mtu6))fib6_metric_set (f6i,RTAX_MTU , arg->mtu);
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 771/1266 ipv4: fib: Dont ignore error route in local/main tables.
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Kuniyuki Iwashima <[email protected]>
[ Upstream commit b72f0db64205d9ce462038ba995d5d31eff32dc1 ]
When CONFIG_IP_MULTIPLE_TABLES is enabled but no rule is added, fib_lookup() performs route lookup directly on two tables.
Since the first lookup does not properly bail out, the result of an error route in the merged local/main table could be overwritten by another route in the default table:
# unshare -n
# ip link set lo up
# ip route add 192.168.0.0/24 dev lo table 253
# ip route add unreachable 192.168.0.0/24
# ip route get 192.168.0.1
192.168.0.1 dev lo table default uid 0
cache <local>Once a random rule is added, the error route is respected:
# ip rule add table 0 # ip rule del table 0 # ip route get 192.168.0.1 RTNETLINK answers: No route to host
Let's fix the inconsistent behaviour.
--- include/net/ip_fib.h | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-)
include/net/ip_fib.h +3 -4
@@ -370,7 +370,7 @@ static inline int fib_lookup(struct net *net, struct flowi4 *flp, struct fib_result *res, unsigned int flags) {struct fib_table *tb; -int err = -ENETUNREACH ; +int err = -EAGAIN ; flags |=FIB_LOOKUP_NOREF ;if (net->ipv4.fib_has_custom_rules)
@@ -384,17 +384,16 @@ static inline int fib_lookup(struct net *net, struct flowi4 *flp,if (tb) err =fib_table_lookup (tb, flp, res, flags); -if (!err) +if (err != -EAGAIN ) goto out; tb =rcu_dereference_rtnl (net->ipv4.fib_default);if (tb) err =fib_table_lookup (tb, flp, res, flags); -out:if (err == -EAGAIN ) err = -ENETUNREACH ; - +out:rcu_read_unlock ();return err;
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 772/1266 bpf, lsm: Add disabled BPF LSM hook list
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Xu Kuohai <[email protected]>
[ Upstream commit 21c7063f6d08ab9afa088584939791bee0c177e5 ]
Add a disabled hooks list for BPF LSM. progs being attached to the listed hooks will be rejected by the verifier.
Stable-dep-of: 12091470c6b4 ("bpf: Disable xfrm_decode_session hook attachment")
--- kernel/bpf/bpf_lsm.c | 31 +++++++++++++++++++++++++++++-- 1 file changed, 29 insertions(+), 2 deletions(-)
kernel/bpf/bpf_lsm.c +29 -2
@@ -36,6 +36,24 @@ BTF_SET_START(bpf_lsm_hooks)#undef LSM_HOOK BTF_SET_END(bpf_lsm_hooks) +BTF_SET_START(bpf_lsm_disabled_hooks) +BTF_ID(func, bpf_lsm_vm_enough_memory) +BTF_ID(func, bpf_lsm_inode_need_killpriv) +BTF_ID(func, bpf_lsm_inode_getsecurity) +BTF_ID(func, bpf_lsm_inode_listsecurity) +BTF_ID(func, bpf_lsm_inode_copy_up_xattr) +BTF_ID(func, bpf_lsm_getselfattr) +BTF_ID(func, bpf_lsm_getprocattr) +BTF_ID(func, bpf_lsm_setprocattr) +#ifdef CONFIG_KEYS +BTF_ID(func, bpf_lsm_key_getsecurity) +#endif +#ifdef CONFIG_AUDIT +BTF_ID(func, bpf_lsm_audit_rule_match) +#endif +BTF_ID(func, bpf_lsm_ismaclabel) +BTF_SET_END(bpf_lsm_disabled_hooks) +/* List of LSM hooks that should operate on 'current' cgroup regardless * of function signature. */
@@ -97,15 +115,24 @@ void bpf_lsm_find_cgroup_shim(const struct bpf_prog *prog,int bpf_lsm_verify_prog (struct bpf_verifier_log *vlog,const struct bpf_prog *prog) { +u32 btf_id = prog->aux->attach_btf_id; +const char *func_name = prog->aux->attach_func_name; +if (!prog->gpl_compatible) {bpf_log (vlog,"LSM programs must have a GPL compatible license\n" );return -EINVAL ; } -if (!btf_id_set_contains (&bpf_lsm_hooks, prog->aux->attach_btf_id)) { +if (btf_id_set_contains (&bpf_lsm_disabled_hooks, btf_id)) { +bpf_log (vlog,"attach_btf_id %u points to disabled hook %s\n" , + btf_id, func_name); +return -EINVAL ; + } + +if (!btf_id_set_contains (&bpf_lsm_hooks, btf_id)) {bpf_log (vlog,"attach_btf_id %u points to wrong type name %s\n" , - prog->aux->attach_btf_id, prog->aux->attach_func_name); + btf_id, func_name);return -EINVAL ; }
Signature · 1 line
2.53.0
Re: [PATCH 6.6 0772/1266] bpf, lsm: Add disabled BPF LSM hook list
Hello All,
backport ("bpf, lsm: Add disabled BPF LSM hook list") for v6.6.y bring the new build warning for us, let your know that.
and the lsm_getselfattr from a04a1198088a1378d0389c250cc684f649bcc91e commit ("LSM: syscalls for current process attributes"), I suggest that use a not upstream commit to just drop 'BTF_ID(func, bpf_lsm_getselfattr)' from 6.6.y. Maybe 6.1.y has the problem too.
BRs
Wentao Guan
Log:
WARN: resolve_btfids: unresolved symbol bpf_lsm_getselfattr
Sasha Levin
maintainerRe: [PATCH 6.6 0772/1266] bpf, lsm: Add disabled BPF LSM hook list
Quoted 7 lines
backport ("bpf, lsm: Add disabled BPF LSM hook list") for v6.6.y bring the new build warning for us, let your know that.
and the
lsm_getselfattrfroma04a1198088a1378d0389c250cc684f649bcc91ecommit ("LSM: syscalls for current process attributes"), I suggest that use a not upstream commit to just drop 'BTF_ID(func, bpf_lsm_getselfattr)' from 6.6.y. Maybe 6.1.y has the problem too.
Thanks for the report, I agree with the analysis.
Quoted 1 line
Maybe 6.1.y has the problem too.
Yes, 6.1.y is affected as well - the same backport of 21c7063f6d08 ("bpf, lsm: Add disabled BPF LSM hook list") is in v6.1.178.
The impact is build noise only: resolve_btfids only prints the WARN and carries on, the unresolved entry is patched as BTF ID 0, and 0 never matches a real prog->aux->attach_btf_id, so the enforcement for the other disabled hooks keeps working. I do not want to revert the pair, since 21c7063f6d08 came in as a dependency of 12091470c6b4 ("bpf: Disable xfrm_decode_session hook attachment"), which prevents a reachable BUG_ON() and does belong on these trees.
Could you post a formal patch for this please?
Signature · 2 lines
Thanks, Sasha
PATCH 1/1 bpf: drop bpf_lsm_getselfattr from hook list
Backport ("bpf, lsm: Add disabled BPF LSM hook list") for v6.6.y bring the warning "WARN: resolve_btfids: unresolved symbol bpf_lsm_getselfattr".
The lsm_getselfattr from commit a04a1198088a
("LSM: syscalls for current process attributes"), no need to backport the huge patch, simply drop the entry to fix the noise.
This is a fix for stable v6.6.145 backport commit, so no upstream commit.
--- kernel/bpf/bpf_lsm.c | 1 - 1 file changed, 1 deletion(-)
kernel/bpf/bpf_lsm.c +0 -1
@@ -42,7 +42,6 @@ BTF_ID(func, bpf_lsm_inode_need_killpriv) BTF_ID(func, bpf_lsm_inode_getsecurity) BTF_ID(func, bpf_lsm_inode_listsecurity) BTF_ID(func, bpf_lsm_inode_copy_up_xattr) -BTF_ID(func, bpf_lsm_getselfattr) BTF_ID(func, bpf_lsm_getprocattr) BTF_ID(func, bpf_lsm_setprocattr)#ifdef CONFIG_KEYS
Signature · 1 line
2.30.2
Re: [PATCH 6.6.y] bpf: drop bpf_lsm_getselfattr from hook list
Quoted 1 line
[PATCH 6.6.y] bpf: drop
bpf_lsm_getselfattrfrom hook list
Queued for 6.6, thanks.
Signature · 2 lines
Thanks, Sasha
PATCH 1/1 bpf: drop bpf_lsm_getselfattr from hook list
In reply to Sasha LevinBackport ("bpf, lsm: Add disabled BPF LSM hook list") for v6.1.y bring the warning "WARN: resolve_btfids: unresolved symbol bpf_lsm_getselfattr".
The lsm_getselfattr from commit a04a1198088a
("LSM: syscalls for current process attributes"), no need to backport the huge patch, simply drop the entry to fix the noise.
This is a fix for stable v6.1.178 backport commit, so no upstream commit.
--- kernel/bpf/bpf_lsm.c | 1 - 1 file changed, 1 deletion(-)
kernel/bpf/bpf_lsm.c +0 -1
@@ -42,7 +42,6 @@ BTF_ID(func, bpf_lsm_inode_need_killpriv) BTF_ID(func, bpf_lsm_inode_getsecurity) BTF_ID(func, bpf_lsm_inode_listsecurity) BTF_ID(func, bpf_lsm_inode_copy_up_xattr) -BTF_ID(func, bpf_lsm_getselfattr) BTF_ID(func, bpf_lsm_getprocattr) BTF_ID(func, bpf_lsm_setprocattr)#ifdef CONFIG_KEYS
Signature · 1 line
2.30.2
Re: [PATCH 6.1.y] bpf: drop bpf_lsm_getselfattr from hook list
Quoted 1 line
[PATCH 6.1.y] bpf: drop
bpf_lsm_getselfattrfrom hook list
Queued for 6.1, thanks.
Signature · 2 lines
Thanks, Sasha
Greg Kroah-Hartman
maintainerPATCH 773/1266 bpf: Disable xfrm_decode_session hook attachment
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Bradley Morgan <[email protected]>
[ Upstream commit 12091470c6b4c1c14b2de12dcbae2ada6cb6d20b ]
BPF LSM programs can currently attach to xfrm_decode_session(). That hook may return an error, but security_skb_classify_flow() calls it from a void path and triggers BUG_ON() if an error is returned.
Disable BPF attachment to the hook to prevent a BPF LSM program from turning packet classification into a full panic.
--- kernel/bpf/bpf_lsm.c | 3 +++ 1 file changed, 3 insertions(+)
kernel/bpf/bpf_lsm.c +3 -0
@@ -51,6 +51,9 @@ BTF_ID(func, bpf_lsm_key_getsecurity)#ifdef CONFIG_AUDIT BTF_ID(func, bpf_lsm_audit_rule_match)#endif +#ifdef CONFIG_SECURITY_NETWORK_XFRM +BTF_ID(func, bpf_lsm_xfrm_decode_session) +#endif BTF_ID(func, bpf_lsm_ismaclabel)BTF_SET_END (bpf_lsm_disabled_hooks)
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 774/1266 netfilter: nf_nat: avoid invalid nat_net pointer use on failed nf_nat_init()
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Mathias Krause <[email protected]>
[ Upstream commit 069cfe3de2a5e16069485893cd04665ab769c1d8 ]
We ran into below KASAN splat, which is mostly uninteresting, beside for having nf_nat_register_fn() in the call chain as a cause for the offending access:
==================================================================
BUG: KASAN: slab-out-of-bounds in nf_nat_register_fn+0x5f9/0x640 Read of size 8 at addr ffff890031e54c20 by task iptables/9510 CPU: 0 UID: 0 PID: 9510 Comm: iptables Not tainted 6.18.18-grsec-full-20260320181326 #1 PREEMPT(voluntary) Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS 1.16.3-debian-1.16.3-2 04/01/2014 Call Trace: <TASK> […] dump_stack_lvl+0xee/0x160 ffff88004117eeb8 […] print_report+0x6e/0x640 ffff88004117eee0 […] ? __phys_addr+0x8e/0x140 ffff88004117eef0 […] ? kasan_addr_to_slab+0x51/0xe0 ffff88004117ef08 […] ? complete_report_info+0xec/0x1c0 ffff88004117ef20 […] ? nf_nat_register_fn+0x5f9/0x640 ffff88004117ef48 […] kasan_report+0xbc/0x140 ffff88004117ef50 […] ? nf_nat_register_fn+0x5f9/0x640 ffff88004117ef90 […] nf_nat_register_fn+0x5f9/0x640 ffff88004117eff8 […] ? nf_nat_icmp_reply_translation+0x6e0/0x6e0 ffff88004117f070 […] nf_tables_register_hook.part.0+0xa0/0x220 ffff88004117f080 […] nf_tables_addchain.constprop.0+0x1054/0x1fc0 ffff88004117f0b8 […] ? nft_chain_lookup.part.0+0x4ce/0xac0 ffff88004117f130 […] ? nf_tables_abort+0x3d80/0x3d80 ffff88004117f190 […] ? nf_tables_dumpreset_obj+0x100/0x100 ffff88004117f1c8 […] ? nft_table_lookup.part.0+0x255/0x300 ffff88004117f310 […] ? nf_tables_newchain+0x21a4/0x2fa0 ffff88004117f358 […] nf_tables_newchain+0x21a4/0x2fa0 ffff88004117f360 […] ? nf_tables_addchain.constprop.0+0x1fc0/0x1fc0 ffff88004117f458 […] ? nla_get_range_signed+0x4a0/0x4a0 ffff88004117f488 […] ? lock_acquire+0x16f/0x320 ffff88004117f490 […] ? find_held_lock+0x3b/0xe0 ffff88004117f4b0 […] ? __nla_parse+0x45/0x80 ffff88004117f500 […] nfnetlink_rcv_batch+0xbca/0x19a0 ffff88004117f550 […] ? nfnetlink_net_exit_batch+0x120/0x120 ffff88004117f618 […] ? __sanitizer_cov_trace_switch+0x63/0xe0 ffff88004117f720 […] ? gr_acl_handle_mmap+0x1c4/0x320 ffff88004117f7c0 […] ? nla_get_range_signed+0x4a0/0x4a0 ffff88004117f7e8 […] ? gr_is_capable+0x6f/0xe0 ffff88004117f830 […] ? __nla_parse+0x45/0x80 ffff88004117f860 […] ? skb_pull+0x103/0x1a0 ffff88004117f880 […] nfnetlink_rcv+0x3db/0x4a0 ffff88004117f8b0 […] ? nfnetlink_rcv_batch+0x19a0/0x19a0 ffff88004117f8d8 […] ? netlink_lookup+0xe2/0x240 ffff88004117f900 […] netlink_unicast+0x74b/0xb00 ffff88004117f930 […] ? netlink_attachskb+0xb20/0xb20 ffff88004117f980 […] ? __check_object_size+0x3e/0xaa0 ffff88004117f998 […] ? security_netlink_send+0x51/0x160 ffff88004117f9c8 […] netlink_sendmsg+0xa03/0x1200 ffff88004117f9f8 […] ? netlink_unicast+0xb00/0xb00 ffff88004117fa70 […] ? netlink_unicast+0xb00/0xb00 ffff88004117fac8 […] ? ____sys_sendmsg+0xe2a/0x1040 ffff88004117faf8 […] ____sys_sendmsg+0xe2a/0x1040 ffff88004117fb00 […] ? kernel_recvmsg+0x300/0x300 ffff88004117fb60 […] ? reacquire_held_locks+0xe9/0x260 ffff88004117fbc8 […] ___sys_sendmsg+0x138/0x200 ffff88004117fbf8 […] ? do_recvmmsg+0x7e0/0x7e0 ffff88004117fc30 […] ? lockdep_hardirqs_on_prepare+0x101/0x1e0 ffff88004117fc50 […] ? lock_acquire+0x16f/0x320 ffff88004117fd20 […] ? lock_acquire+0x16f/0x320 ffff88004117fd58 […] ? find_held_lock+0x3b/0xe0 ffff88004117fd70 […] __sys_sendmsg+0x17a/0x260 ffff88004117fdc8 […] ? __sys_sendmsg_sock+0x80/0x80 ffff88004117fdf0 […] ? syscall_trace_enter+0x15e/0x2c0 ffff88004117fe98 […] do_syscall_64+0x7d/0x400 ffff88004117fec8 […] entry_SYSCALL_64_safe_stack+0x4a/0x60 ffff88004117fef8 </TASK> ==================================================================
The out-of-bounds report, though, is a red herring as it is for an access that shouldn't have happened in the first place.
When nf_nat_init() fails to register its BPF kfuncs, it'll unwind and, among others, call unregister_pernet_subsys() to deregister its per-net ops. This makes the previously allocated net id available for reuse by the next caller of register_pernet_subsys(), in our case, synproxy. However, 'nat_net_id' will still hold the previously allocated value.
If nf_nat.o gets build as a module, all this doesn't matter. A failed initialization routine makes the module fail to load and any dependent module won't be able to load either. However, if nf_nat.o is built-in, a failing init won't /completely/ make its functionality unavailable to dependent modules, namely the code and static data is still there, free to be called by modules like nft_chain_nat.ko.
Case in point, nft_chain_nat registers hooks that'll call into nf_nat which, in our case, failed to initialize and therefore won't have a valid net id nor related net_nat object any more.
Code in nf_nat, namely nf_nat_register_fn() and nf_nat_unregister_fn(), still making use of the reallocated net id, lead to a type confusion as the call to net_generic() will no longer return memory belonging to an object suited to fit 'struct nat_net' but 'struct synproxy_net' instead. The latter is only 24 bytes on 64-bit systems, much smaller than struct nat_net which is 176 bytes, perfectly explaining the OOB KASAN report.
Detect and handle a failed nf_nat_init() by testing the 'nf_nat_hook' pointer which will be reset to NULL on initialization errors to prevent the usage of an invalid nat_net pointer.
As this check is only needed when nf_nat.o is built-in, guard it by '#ifndef MODULE...'.
--- net/netfilter/nf_nat_core.c | 10 ++++++++++ 1 file changed, 10 insertions(+)
net/netfilter/nf_nat_core.c +10 -0
@@ -1204,6 +1204,16 @@ int nf_nat_register_fn(struct net *net, u8 pf, const struct nf_hook_ops *ops,struct nf_hook_ops *nat_ops;int i, ret; +#ifndef MODULE +/* If nf_nat_core is built-in and nf_nat_init() fails, dependent +* modules like nft_chain_nat.ko may still call this function. +* However, nat_net would be invalid, likely pointing to some other +* per-net structure. +*/ +if (WARN_ON_ONCE (!nf_nat_hook)) +return -EOPNOTSUPP ; +#endif +if (WARN_ON_ONCE (pf >=ARRAY_SIZE (nat_net->nat_proto_net)))return -EINVAL ;
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 775/1266 netfilter: nf_conncount: prevent connlimit drops for early confirmed ct
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Fernando Fernandez Mancera <[email protected]>
[ Upstream commit c8b6f36f766991e3ebebec6596daee4b04dcbc49 ]
Commit 69894e5b4c5e ("netfilter: nft_connlimit: update the count if add was skipped") introduced a regression where packets for valid connections are dropped when using connlimit for soft-limiting scenarios.
The issue occurs when a new connection reuses a socket currently in the TIME_WAIT state. In this scenario, the connection tracking entry is evaluated as already confirmed. Previously, __nf_conncount_add() assumed that if a connection was confirmed and did not originate from the loopback interface, it should skip the addition and return -EEXIST.
Skipping the addition triggers a garbage collection run that cleans up the TIME_WAIT connection. Consequently, the active connection count drops to 0, which xt_connlimit mishandles, leading to the false rejection of the perfectly valid new connection.
Fix this by replacing the interface check with protocol-agnostic state checks. We now skip the tree insertion and preserve the lockless garbage collection optimization only if the connection is IPS_ASSURED. This allows early-confirmed setup packets (such as reused TIME_WAIT sockets or locally generated SYN-ACKs) to be properly evaluated and counted without falsely dropping. The goto check_connections path is maintained to ensure these setup packets are deduplicated correctly.
This has been tested with slowhttptest and HTTP server configured locally to ensure we are not breaking soft-limiting scenarios for local or external connections. In addition, it was tested with a OVS zone limit too.
--- net/netfilter/nf_conncount.c | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-)
net/netfilter/nf_conncount.c +5 -6
@@ -179,17 +179,16 @@ static int __nf_conncount_add(struct net *net,return -ENOENT ;if (ct &&nf_ct_is_confirmed (ct)) { -/* local connections are confirmed in postrouting so confirmation -* might have happened before hitting connlimit +/* Connection is confirmed but might still be in the setup phase. +* Only skip the tracking if it is fully assured. This guarantees +* that setup packets or retransmissions are properly counted and +* deduplicated. */ -if (skb->skb_iif !=LOOPBACK_IFINDEX ) { +if (test_bit (IPS_ASSURED_BIT , &ct->status)) { err = -EEXIST ; goto out_put; } -/* this is likely a local connection, skip optimization to avoid -* adding duplicates from a 'packet train' -*/ goto check_connections; }
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 776/1266 netfilter: nft_synproxy: stop bypassing the priv->info snapshot
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Runyu Xiao <[email protected]>
[ Upstream commit 11d4bc4e26fb66040a5b5d95e9abf37deac2b1fc ]
nft_synproxy_eval_v4() and nft_synproxy_eval_v6() already take a whole-object READ_ONCE() snapshot of the shared priv->info state before building the SYNACK reply, but nft_synproxy_tcp_options() still masks opts->options with priv->info.options from the live shared object.
When a named synproxy object is updated concurrently with SYN traffic, the eval path can then mix mss and timestamp handling from the local snapshot with an options mask taken from a newer configuration, so one SYNACK no longer reflects a coherent synproxy configuration.
Use info->options so nft_synproxy_tcp_options() stays on the same local snapshot that the eval path already copied from priv->info.
--- net/netfilter/nft_synproxy.c | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-)
net/netfilter/nft_synproxy.c +4 -5
@@ -23,14 +23,13 @@ static const struct nla_policy nft_synproxy_policy[NFTA_SYNPROXY_MAX + 1] = {static void nft_synproxy_tcp_options (struct synproxy_options *opts,const struct tcphdr *tcp,struct synproxy_net *snet, -struct nf_synproxy_info *info, -const struct nft_synproxy *priv) +struct nf_synproxy_info *info) {this_cpu_inc (snet->stats->syn_received);if (tcp->ece && tcp->cwr) opts->options |=NF_SYNPROXY_OPT_ECN ; - opts->options &= priv->info.options; + opts->options &= info->options; opts->mss_encode = opts->mss_option; opts->mss_option = info->mss;if (opts->options &NF_SYNPROXY_OPT_TIMESTAMP )
@@ -55,7 +54,7 @@ static void nft_synproxy_eval_v4(const struct nft_synproxy *priv,if (tcp->syn) {/* Initial SYN from client */ -nft_synproxy_tcp_options (opts, tcp, snet, &info, priv); +nft_synproxy_tcp_options (opts, tcp, snet, &info);synproxy_send_client_synack (net, skb, tcp, opts);consume_skb (skb); regs->verdict.code =NF_STOLEN ;
@@ -86,7 +85,7 @@ static void nft_synproxy_eval_v6(const struct nft_synproxy *priv,if (tcp->syn) {/* Initial SYN from client */ -nft_synproxy_tcp_options (opts, tcp, snet, &info, priv); +nft_synproxy_tcp_options (opts, tcp, snet, &info);synproxy_send_client_synack_ipv6 (net, skb, tcp, opts);consume_skb (skb); regs->verdict.code =NF_STOLEN ;
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 777/1266 netfilter: nft_compat: ebtables emulation must reject non-bridge targets
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Florian Westphal <[email protected]>
[ Upstream commit 9dbba7e694ec045f21ede2f892fb42b81b4e1692 ]
xtables targets return netfilter verdicts: NF_ACCEPT, NF_DROP, and so on. ebtables targets return incompatible verdicts: EBT_ACCEPT,EBT_DROP, ... We cannot allow fallback to NFPROTO_UNSPEC.
ebtables doesn't permit this since11ff7288beb2 ("netfilter: ebtables: reject non-bridge targets") but that commit missed the nft_compat layer.
--- net/netfilter/nft_compat.c | 24 +++++++++++++++++++++--- 1 file changed, 21 insertions(+), 3 deletions(-)
net/netfilter/nft_compat.c +21 -3
@@ -389,6 +389,22 @@ static int nft_target_validate(const struct nft_ctx *ctx,return 0 ; } +static int nft_target_bridge_validate (const struct nft_ctx *ctx, +const struct nft_expr *expr) +{ +struct xt_target *target = expr->ops->data; + +/* Do not allow UNSPEC to stand-in for NFPROTO_BRIDGE +* targets: they are incompatible. ebtables targets return +* EBT_ACCEPT, DROP and so on which are not compatible with +* NF_ACCEPT, NF_DROP and so on. +*/ +if (target->family !=NFPROTO_BRIDGE ) +return -ENOENT ; + +return nft_target_validate (ctx, expr); +} + static void __nft_match_eval(const struct nft_expr *expr, struct nft_regs *regs, const struct nft_pktinfo *pkt,
@@ -916,14 +932,16 @@ nft_target_select_ops(const struct nft_ctx *ctx, ops->init = nft_target_init; ops->destroy = nft_target_destroy; ops->dump = nft_target_dump; - ops->validate = nft_target_validate; ops->data = target; ops->reduce =NFT_REDUCE_READONLY ; -if (family ==NFPROTO_BRIDGE ) +if (family ==NFPROTO_BRIDGE ) { ops->eval = nft_target_eval_bridge; -else + ops->validate = nft_target_bridge_validate; + }else { ops->eval = nft_target_eval_xt; + ops->validate = nft_target_validate; + }return ops; err:
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 778/1266 NTB: epf: Make db_valid_mask cover only real doorbell bits
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Koichiro Den <[email protected]>
[ Upstream commit 6eb7e28f1f24a28234add38755687a7ed8bc2654 ]
ndev->db_count includes an unused doorbell slot due to the legacy extra offset in the peer doorbell path. db_valid_mask must cover only the real doorbell bits and exclude the unused slot.
Set db_valid_mask to BIT_ULL(db_count - 1) - 1.
--- drivers/ntb/hw/epf/ntb_hw_epf.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-)
drivers/ntb/hw/epf/ntb_hw_epf.c +5 -1
@@ -560,7 +560,11 @@ static int ntb_epf_init_dev(struct ntb_epf_dev *ndev)return ret; } - ndev->db_valid_mask =BIT_ULL (ndev->db_count) -1 ; +/* +* ndev->db_count includes an extra skipped slot due to the legacy +* doorbell layout, hence -1. +*/ + ndev->db_valid_mask =BIT_ULL (ndev->db_count -1 ) -1 ; ndev->mw_count =readl (ndev->ctrl_reg +NTB_EPF_MW_COUNT ); ndev->spad_count =readl (ndev->ctrl_reg +NTB_EPF_SPAD_COUNT );
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 779/1266 NTB: epf: Report 0-based doorbell vector via ntb_db_event()
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Koichiro Den <[email protected]>
[ Upstream commit 3147f0964cecca15e349cbfbdd6a28eb6d50379d ]
ntb_db_event() expects the vector number to be relative to the first doorbell vector starting at 0.
Vector 0 is reserved for link events in the EPF driver, so doorbells start at vector 1. However, both supported peers (ntb_hw_epf with pci-epf-ntb, and pci-epf-vntb) have historically skipped vector 1 and started doorbells at vector 2.
Pass (irq_no - 2) to ntb_db_event() so doorbells are reported as 0..N-1. If irq_no == 1 is ever observed, warn and ignore it, since the slot is reserved in the legacy layout and reporting it as DB#0 would collide with the real DB#0 slot.
--- drivers/ntb/hw/epf/ntb_hw_epf.c | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-)
drivers/ntb/hw/epf/ntb_hw_epf.c +13 -3
@@ -69,6 +69,12 @@ enum epf_ntb_bar { NTB_BAR_NUM, }; +enum epf_irq_slot { +EPF_IRQ_LINK =0 , +EPF_IRQ_RESERVED_DB ,/* Historically skipped slot */ +EPF_IRQ_DB_START , +}; +#define NTB_EPF_MAX_MW_COUNT (NTB_BAR_NUM - BAR_MW1)struct ntb_epf_dev {
@@ -322,10 +328,14 @@ static irqreturn_t ntb_epf_vec_isr(int irq, void *dev) irq_no = irq - ndev->irq_base; ndev->db_val = irq_no +1 ; -if (irq_no ==0 ) +if (irq_no ==EPF_IRQ_LINK ) {ntb_link_event (&ndev->ntb); -else -ntb_db_event (&ndev->ntb, irq_no); + }else if (irq_no ==EPF_IRQ_RESERVED_DB ) { +dev_warn_ratelimited (ndev->dev, +"Unexpected reserved doorbell slot IRQ received\n" ); + }else { +ntb_db_event (&ndev->ntb, irq_no -EPF_IRQ_DB_START ); + }return IRQ_HANDLED ; }
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 780/1266 NTB: epf: Fix doorbell bitmask and IRQ vector handling
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Koichiro Den <[email protected]>
[ Upstream commit 4fdea8dbb62d746429498e07385a3ba0b0f6d1ab ]
The EPF driver currently stores the incoming doorbell as a vector number (irq_no + 1) in db_val and db_clear() clears all bits unconditionally. This breaks db_read()/db_clear() semantics when multiple doorbells are used.
Store doorbells as a bitmask (BIT_ULL(vector)) and make db_clear(db_bits) clear only the specified bits. Use atomic64 operations as db_val is updated from interrupt context.
Once db_val is stored as a bitmask, the ISR's doorbell vector is used not only for ntb_db_event(), but also as the bit index for BIT_ULL(). The existing ISR derives that vector by subtracting pci_irq_vector(pdev,
0) from the Linux IRQ number passed to the handler, but Linux IRQ numbers are not guaranteed to be contiguous.
Pass per-vector context as request_irq() dev_id instead, so the ISR gets the device vector directly.
Validate the doorbell vector before updating db_val or calling ntb_db_event(), so an unexpected vector cannot create an invalid shift or be reported to NTB clients.
While at it, read and validate mw_count before requesting interrupt vectors. An unsupported memory-window count does not need IRQs, and failing before ntb_epf_init_isr() keeps the probe error path simple.
--- drivers/ntb/hw/epf/ntb_hw_epf.c | 61 +++++++++++++++++++++------------ 1 file changed, 39 insertions(+), 22 deletions(-)
drivers/ntb/hw/epf/ntb_hw_epf.c +39 -22
@@ -6,6 +6,7 @@* Author: Kishon Vijay Abraham I <[email protected]> */ +#include <linux/atomic.h> #include <linux/delay.h> #include <linux/module.h> #include <linux/pci.h>
@@ -77,6 +78,13 @@ enum epf_irq_slot {#define NTB_EPF_MAX_MW_COUNT (NTB_BAR_NUM - BAR_MW1) +struct ntb_epf_dev ; + +struct ntb_epf_irq_ctx { +struct ntb_epf_dev *ndev; +unsigned int irq_no; +}; +struct ntb_epf_dev {struct ntb_dev ntb;struct device *dev;
@@ -96,9 +104,9 @@ struct ntb_epf_dev {unsigned int self_spad;unsigned int peer_spad; -int db_val; +atomic64_t db_val;u64 db_valid_mask; -int irq_base; +struct ntb_epf_irq_ctx irq_ctx[NTB_EPF_MAX_DB_COUNT +1 ]; };#define ntb_ndev (__ntb) container_of(__ntb, struct ntb_epf_dev, ntb)
@@ -322,11 +330,10 @@ static int ntb_epf_link_disable(struct ntb_dev *ntb)static irqreturn_t ntb_epf_vec_isr (int irq,void *dev) { -struct ntb_epf_dev *ndev = dev; -int irq_no; - - irq_no = irq - ndev->irq_base; - ndev->db_val = irq_no +1 ; +struct ntb_epf_irq_ctx *ctx = dev; +struct ntb_epf_dev *ndev = ctx->ndev; +unsigned int db_vector; +unsigned int irq_no = ctx->irq_no;if (irq_no ==EPF_IRQ_LINK ) {ntb_link_event (&ndev->ntb);
@@ -334,7 +341,17 @@ static irqreturn_t ntb_epf_vec_isr(int irq, void *dev)dev_warn_ratelimited (ndev->dev,"Unexpected reserved doorbell slot IRQ received\n" ); }else { -ntb_db_event (&ndev->ntb, irq_no -EPF_IRQ_DB_START ); + db_vector = irq_no -EPF_IRQ_DB_START ; +if (ndev->db_count <NTB_EPF_MIN_DB_COUNT || + db_vector >= ndev->db_count -1 ) { +dev_warn_ratelimited (ndev->dev, +"Unexpected doorbell vector %u (db_count %u)\n" , + db_vector, ndev->db_count); +return IRQ_HANDLED ; + } + +atomic64_or (BIT_ULL (db_vector), &ndev->db_val); +ntb_db_event (&ndev->ntb, db_vector); }return IRQ_HANDLED ;
@@ -361,18 +378,18 @@ static int ntb_epf_init_isr(struct ntb_epf_dev *ndev, int msi_min, int msi_max) argument &= ~MSIX_ENABLE ; } - ndev->irq_base =pci_irq_vector (pdev,0 ); + ndev->db_count = irq -1 ;for (i =0 ; i < irq; i++) { + ndev->irq_ctx[i].ndev = ndev; + ndev->irq_ctx[i].irq_no = i; ret =request_irq (pci_irq_vector (pdev, i), ntb_epf_vec_isr, -0 ,"ntb_epf" , ndev); +0 ,"ntb_epf" , &ndev->irq_ctx[i]);if (ret) {dev_err (dev,"Failed to request irq\n" ); goto err_free_irq; } } - ndev->db_count = irq -1 ; - ret =ntb_epf_send_command (ndev,CMD_CONFIGURE_DOORBELL , argument | irq);if (ret) {
@@ -384,7 +401,7 @@ static int ntb_epf_init_isr(struct ntb_epf_dev *ndev, int msi_min, int msi_max) err_free_irq:while (i--) -free_irq (pci_irq_vector (pdev, i), ndev); +free_irq (pci_irq_vector (pdev, i), &ndev->irq_ctx[i]);pci_free_irq_vectors (pdev);return ret;
@@ -509,7 +526,7 @@ static u64 ntb_epf_db_read(struct ntb_dev *ntb) {struct ntb_epf_dev *ndev =ntb_ndev (ntb); -return ndev->db_val; +return atomic64_read (&ndev->db_val); }static int ntb_epf_db_clear_mask (struct ntb_dev *ntb,u64 db_bits)
@@ -521,7 +538,7 @@ static int ntb_epf_db_clear(struct ntb_dev *ntb, u64 db_bits) {struct ntb_epf_dev *ndev =ntb_ndev (ntb); - ndev->db_val =0 ; +atomic64_and (~db_bits, &ndev->db_val);return 0 ; }
@@ -562,6 +579,12 @@ static int ntb_epf_init_dev(struct ntb_epf_dev *ndev)struct device *dev = ndev->dev;int ret; + ndev->mw_count =readl (ndev->ctrl_reg +NTB_EPF_MW_COUNT ); +if (ndev->mw_count >NTB_EPF_MAX_MW_COUNT ) { +dev_err (dev,"Unsupported MW count: %u\n" , ndev->mw_count); +return -EINVAL ; + } +/* One Link interrupt and rest doorbell interrupt */ ret =ntb_epf_init_isr (ndev,NTB_EPF_MIN_DB_COUNT +1 ,NTB_EPF_MAX_DB_COUNT +1 );
@@ -575,14 +598,8 @@ static int ntb_epf_init_dev(struct ntb_epf_dev *ndev)* doorbell layout, hence -1. */ ndev->db_valid_mask =BIT_ULL (ndev->db_count -1 ) -1 ; - ndev->mw_count =readl (ndev->ctrl_reg +NTB_EPF_MW_COUNT ); ndev->spad_count =readl (ndev->ctrl_reg +NTB_EPF_SPAD_COUNT ); -if (ndev->mw_count >NTB_EPF_MAX_MW_COUNT ) { -dev_err (dev,"Unsupported MW count: %u\n" , ndev->mw_count); -return -EINVAL ; - } -return 0 ; }
@@ -677,7 +694,7 @@ static void ntb_epf_cleanup_isr(struct ntb_epf_dev *ndev)ntb_epf_send_command (ndev,CMD_TEARDOWN_DOORBELL , ndev->db_count +1 );for (i =0 ; i < ndev->db_count +1 ; i++) -free_irq (pci_irq_vector (pdev, i), ndev); +free_irq (pci_irq_vector (pdev, i), &ndev->irq_ctx[i]);pci_free_irq_vectors (pdev); }
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 781/1266 alpha/PCI: Add security_locked_down() check to pci_mmap_resource()
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Krzysztof Wilczyński <[email protected]>
[ Upstream commit 78a228f0aa0e9eba31955950c8a40a9945e2c8bb ]
Currently, Alpha's pci_mmap_resource() does not check security_locked_down(LOCKDOWN_PCI_ACCESS) before allowing userspace to mmap PCI BARs.
The generic version has had this check since commit eb627e17727e ("PCI:
Lock down BAR access when the kernel is locked down") to prevent DMA attacks when the kernel is locked down.
Add the same check to Alpha's pci_mmap_resource().
--- arch/alpha/kernel/pci-sysfs.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-)
arch/alpha/kernel/pci-sysfs.c +6 -1
@@ -11,6 +11,7 @@*/ #include <linux/sched.h> +#include <linux/security.h> #include <linux/stat.h> #include <linux/slab.h> #include <linux/pci.h>
@@ -71,7 +72,11 @@ static int pci_mmap_resource(struct kobject *kobj,struct resource *res = attr->private;enum pci_mmap_state mmap_type;struct pci_bus_region bar; -int i; +int i, ret; + + ret =security_locked_down (LOCKDOWN_PCI_ACCESS ); +if (ret) +return ret;for (i =0 ; i <PCI_STD_NUM_BARS ; i++)if (res == &pdev->resource[i])
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 782/1266 alpha/PCI: Fix __pci_mmap_fits() overflow for zero-length BARs
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Krzysztof Wilczyński <[email protected]>
[ Upstream commit 802a3b3f470b9bc1148f26e01fc9cbfeb4dfcb57 ]
Currently, __pci_mmap_fits() computes the BAR size using "pci_resource_len() - 1", which wraps to a large value when the BAR length is zero, causing the bounds check to incorrectly succeed.
Add an early return for empty resources.
--- arch/alpha/kernel/pci-sysfs.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-)
arch/alpha/kernel/pci-sysfs.c +5 -1
@@ -37,12 +37,16 @@ static int hose_mmap_page_range(struct pci_controller *hose,static int __pci_mmap_fits (struct pci_dev *pdev,int num,struct vm_area_struct *vma,int sparse) { +resource_size_t len =pci_resource_len (pdev, num);unsigned long nr, start, size;int shift = sparse ?5 :0 ; +if (!len) +return 0 ; + nr =vma_pages (vma); start = vma->vm_pgoff; - size = ((pci_resource_len (pdev, num) -1 ) >> (PAGE_SHIFT - shift)) +1 ; + size = ((len -1 ) >> (PAGE_SHIFT - shift)) +1 ;if (start < size && size - start >= nr)return 1 ;
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 783/1266 net, bpf: check master for NULL in xdp_master_redirect()
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Xiang Mei <[email protected]>
[ Upstream commit e82d8cc4321c373dc46e741cd2dfdaa7921fddb7 ]
xdp_master_redirect() dereferences the result of netdev_master_upper_dev_get_rcu() without a NULL check, but that helper returns NULL when the receiving device has no upper-master adjacency.
The reach guard only checks netif_is_bond_slave(). On bond slave release bond_upper_dev_unlink() drops the upper-master adjacency before clearing IFF_SLAVE, so an XDP_TX reaching xdp_master_redirect() in that window still passes netif_is_bond_slave() while master is already NULL, and faults on master->flags at offset 0xb0:
BUG: kernel NULL pointer dereference, address: 00000000000000b0 RIP: 0010:xdp_master_redirect (net/core/filter.c:4432) Call Trace: xdp_master_redirect (net/core/filter.c:4432) bpf_prog_run_generic_xdp (include/net/xdp.h:700) do_xdp_generic (net/core/dev.c:5608) __netif_receive_skb_one_core (net/core/dev.c:6204) process_backlog (net/core/dev.c:6319) __napi_poll (net/core/dev.c:7729) net_rx_action (net/core/dev.c:7792) handle_softirqs (kernel/softirq.c:622) __dev_queue_xmit (include/linux/bottom_half.h:33) packet_sendmsg (net/packet/af_packet.c:3082) __sys_sendto (net/socket.c:2252) Kernel panic - not syncing: Fatal exception in interrupt
The missing check dates back to the original code; commit 1921f91298d1 ("net, bpf: fix null-ptr-deref in xdp_master_redirect() for down master") later added the master->flags read where the fault now lands but kept the unconditional deref. Check master for NULL before use; a NULL master is treated the same as one that is not up.
--- net/core/filter.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
net/core/filter.c +1 -1
@@ -4393,7 +4393,7 @@ u32 xdp_master_redirect(struct xdp_buff *xdp)struct bpf_redirect_info *ri =this_cpu_ptr (&bpf_redirect_info); master =netdev_master_upper_dev_get_rcu (xdp->rxq->dev); -if (unlikely (!(master->flags &IFF_UP ))) +if (unlikely (!master || !(master->flags &IFF_UP )))return XDP_ABORTED ; slave = master->netdev_ops->ndo_xdp_get_xmit_slave (master, xdp);if (slave && slave != xdp->rxq->dev) {
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 784/1266 net: dsa: sja1105: round up PTP perout pin duration
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Aleksandrova Alyona <[email protected]>
[ Upstream commit aee5836273b07b439fb245fb43930664d8b78518 ]
pin_duration is converted from the user-provided period to SJA1105 clock ticks and is later passed as the cycle_time argument to future_base_time().
Very small period values may become zero after the conversion, which can lead to a division by zero in future_base_time().
Round zero pin_duration up to 1 tick so that the smallest unsupported periods use the minimum non-zero hardware duration instead of passing zero to future_base_time().
--- drivers/net/dsa/sja1105/sja1105_ptp.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
drivers/net/dsa/sja1105/sja1105_ptp.c +1 -1
@@ -755,7 +755,7 @@ static int sja1105_per_out_enable(struct sja1105_private *priv,* 2 edges on PTP_CLK. So check for truncation which happens * at periods larger than around 68.7 seconds. */ - pin_duration =ns_to_sja1105_ticks (pin_duration /2 ); + pin_duration =max_t (u64,ns_to_sja1105_ticks (pin_duration /2 ),1 );if (pin_duration >U32_MAX ) { rc = -ERANGE ; goto out;
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 785/1266 veth: fix NAPI leak in XDP enable error path
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Eric Dumazet <[email protected]>
[ Upstream commit 6739027cb72da26890edd424c77080d187b2a92e ]
During XDP enablement in veth, if xdp_rxq_info_reg() or xdp_rxq_info_reg_mem_model() fails, the driver rolls back the changes.
However, the rollback loop:
for (i--; i >= start; i--) {decrements the loop index 'i' before the first iteration. This correctly skips unregistering the rxq for the failed index 'i' (as registration failed or was already cleaned up), but it also erroneously skips calling netif_napi_deli() for rq[i].xdp_napi.
Since netif_napi_add() was already called for index 'i', this leaves a dangling napi_struct in the device's napi_list. When the veth device is later destroyed, the freed queue memory (which contains the leaked NAPI structure) can be reused.
The subsequent device teardown iterates the NAPI list and corrupts the reallocated memory, leading to UAF.
Fix this by explicitly deleting the NAPI association for the failed index 'i' before rolling back the successfully configured queues.
--- drivers/net/veth.c | 2 ++ 1 file changed, 2 insertions(+)
drivers/net/veth.c +2 -0
@@ -1159,6 +1159,8 @@ static int veth_enable_xdp_range(struct net_device *dev, int start, int end, err_reg_mem:xdp_rxq_info_unreg (&priv->rq[i].xdp_rxq); err_rxq_reg: +if (!napi_already_on) +netif_napi_del (&priv->rq[i].xdp_napi);for (i--; i >= start; i--) {struct veth_rq *rq = &priv->rq[i];
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 786/1266 net/sched: cls_api: Handle TC_ACT_CONSUMED in tcf_qevent_handle
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Jamal Hadi Salim <[email protected]>
[ Upstream commit a8a02897f2b479127db261de05cbf0c28b98d159 ]
tcf_classify() can return TC_ACT_CONSUMED while the skb is held by the defragmentation engine (e.g. act_ct on out-of-order fragments). When that happens the skb is no longer owned by the caller and must not be touched again.
tcf_qevent_handle() did not handle TC_ACT_CONSUMED: it fell through the switch and returned the skb to the caller as if classification had passed. The only qdisc that wires up qevents today is RED, via three call sites (qe_mark on RED_PROB_MARK/HARD_MARK, qe_early_drop on congestion_drop) red_enqueue() was continuing to operate on an skb it no longer owns in this case -- enqueueing it, dropping it, or updating statistics. Resulting in a UAF.
tc qdisc add dev eth0 root handle 1: red ... qevent early_drop block 10 tc filter add block 10 ... action ct
(with ct defrag enabled and traffic that produces out-of-order fragments, e.g. a fragmented UDP stream)
Handle TC_ACT_CONSUMED in tcf_qevent_handle() the same way the ingress and egress fast paths do: treat it as stolen and return NULL without touching the skb. Unlike the TC_ACT_STOLEN case, the skb must not be dropped/freed here, as it is no longer owned by us.
--- net/sched/cls_api.c | 3 +++ 1 file changed, 3 insertions(+)
net/sched/cls_api.c +3 -0
@@ -3971,6 +3971,9 @@ struct sk_buff *tcf_qevent_handle(struct tcf_qevent *qe, struct Qdisc *sch, struskb_do_redirect (skb); *ret = __NET_XMIT_STOLEN;return NULL ; +case TC_ACT_CONSUMED : + *ret = __NET_XMIT_STOLEN; +return NULL ; }return skb;
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 787/1266 ipv6: fix error handling in disable_ipv6 sysctl
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Fernando Fernandez Mancera <[email protected]>
[ Upstream commit c779441e5070e2268bdfe77f6e2e0de926c431e3 ]
When writing to the disable_ipv6 sysctl, if proc_dointvec() fails to parse the input, it returns a negative error code. The current implementation is overwriting that error for write operations.
This results in a silent failure, it returns a successful write although the configuration was not modified at all. When modifying the "all" variant it can also modify the configuration of existing interfaces to the wrong value.
Fix this by checking the return value of proc_dointvec() and returning early on failure.
--- net/ipv6/addrconf.c | 2 ++ 1 file changed, 2 insertions(+)
net/ipv6/addrconf.c +2 -0
@@ -6441,6 +6441,8 @@ static int addrconf_sysctl_disable(struct ctl_table *ctl, int write, lctl.data = &val; ret =proc_dointvec (&lctl, write, buffer, lenp, ppos); +if (ret) +return ret;if (write) ret =addrconf_disable_ipv6 (ctl, valp, val);
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 788/1266 ipv6: fix error handling in ignore_routes_with_linkdown sysctl
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Fernando Fernandez Mancera <[email protected]>
[ Upstream commit cf4f2b14401f29ccac56393ca9e4b42a2505f540 ]
When writing to the ignore_routes_with_linkdown sysctl, if proc_dointvec() fails to parse the input, it returns a negative error code. The current implementation is overwriting that error for write operations.
This results in a silent failure, it returns a successful write although the configuration was not modified at all. When modifying the "all" variant it can also modify the configuration of existing interfaces to the wrong value.
Fix this by checking the return value of proc_dointvec() and returning early on failure.
--- net/ipv6/addrconf.c | 2 ++ 1 file changed, 2 insertions(+)
net/ipv6/addrconf.c +2 -0
@@ -6639,6 +6639,8 @@ int addrconf_sysctl_ignore_routes_with_linkdown(struct ctl_table *ctl, lctl.data = &val; ret =proc_dointvec (&lctl, write, buffer, lenp, ppos); +if (ret) +return ret;if (write) ret =addrconf_fixup_linkdown (ctl, valp, val);
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 789/1266 ipv6: fix error handling in forwarding sysctl
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Fernando Fernandez Mancera <[email protected]>
[ Upstream commit 058b9b19f9639fe1e1225a17c540f61b65bee6ad ]
When writing to the forwarding sysctl, if proc_dointvec() fails to parse the input, it returns a negative error code. The current implementation is overwriting that error for write operations.
This results in a silent failure, it returns a successful write although the configuration was not modified at all. When modifying the "all" variant it can also modify the configuration of existing interfaces to the wrong value.
Fix this by checking the return value of proc_dointvec() and returning early on failure. In addition, adjust return code of addrconf_fixup_forwarding() for successful operation.
--- net/ipv6/addrconf.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-)
net/ipv6/addrconf.c +3 -1
@@ -916,7 +916,7 @@ static int addrconf_fixup_forwarding(struct ctl_table *table, int *p, int newf)if (newf)rt6_purge_dflt_routers (net); -return 1 ; +return 0 ; }static void addrconf_linkdown_change (struct net *net,__s32 newf)
@@ -6344,6 +6344,8 @@ static int addrconf_sysctl_forward(struct ctl_table *ctl, int write, lctl.data = &val; ret =proc_dointvec (&lctl, write, buffer, lenp, ppos); +if (ret) +return ret;if (write) ret =addrconf_fixup_forwarding (ctl, valp, val);
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 790/1266 ipv6: fix error handling in disable_policy sysctl
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Fernando Fernandez Mancera <[email protected]>
[ Upstream commit 3e0e51c0ee1d08cc9d48dc17f3248d5b31cf8066 ]
When writing to the disable_policy sysctl, if proc_dointvec() fails to parse the input, it returns a negative error code. The current implementation is resetting the position argument even if an error occurred during proc_dointvec() and not only during sysctl restart.
Fix this by checking the return value of proc_dointvec() and returning early on failure.
--- net/ipv6/addrconf.c | 2 ++ 1 file changed, 2 insertions(+)
net/ipv6/addrconf.c +2 -0
@@ -6738,6 +6738,8 @@ static int addrconf_sysctl_disable_policy(struct ctl_table *ctl, int write, lctl = *ctl; lctl.data = &val; ret =proc_dointvec (&lctl, write, buffer, lenp, ppos); +if (ret) +return ret;if (write && (*valp != val)) ret =addrconf_disable_policy (ctl, valp, val);
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 791/1266 smb/client: preserve errors from smb2_set_sparse()
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Huiwen He <[email protected]>
[ Upstream commit 2a4b3d2db5c6fcdba889baf7b2ae5661b0beac89 ]
smb2_set_sparse() converts every FSCTL_SET_SPARSE failure to false and marks sparse support as broken for the share. Callers therefore report EOPNOTSUPP even for errors such as ENOSPC or EACCES, and later sparse operations remain disabled until the share is unmounted.
Return the SMB2 ioctl error directly. Set broken_sparse_sup only for EOPNOTSUPP, which indicates that the server does not support the request.
Update smb3_punch_hole() to propagate the error returned by smb2_set_sparse().
--- fs/smb/client/smb2ops.c | 30 +++++++++++++++--------------- 1 file changed, 15 insertions(+), 15 deletions(-)
fs/smb/client/smb2ops.c +15 -15
@@ -1967,8 +1967,9 @@ smb2_sync_write(const unsigned int xid, struct cifs_fid *pfid, }/* Set or clear the SPARSE_FILE attribute based on value passed in setsparse */ -static bool smb2_set_sparse (const unsigned int xid,struct cifs_tcon *tcon, -struct cifsFileInfo *cfile,struct inode *inode,__u8 setsparse) +static int smb2_set_sparse (const unsigned int xid,struct cifs_tcon *tcon, +struct cifsFileInfo *cfile,struct inode *inode, +__u8 setsparse) {struct cifsInodeInfo *cifsi;int rc;
@@ -1977,31 +1978,31 @@ static bool smb2_set_sparse(const unsigned int xid, struct cifs_tcon *tcon,/* if file already sparse don't bother setting sparse again */ if ((cifsi->cifsAttrs &FILE_ATTRIBUTE_SPARSE_FILE ) && setsparse) -return true;/* already sparse */ +return 0 ;/* already sparse */ if (!(cifsi->cifsAttrs &FILE_ATTRIBUTE_SPARSE_FILE ) && !setsparse) -return true;/* already not sparse */ +return 0 ;/* already not sparse */ /* * Can't check for sparse support on share the usual way via the * FS attribute info (FILE_SUPPORTS_SPARSE_FILES) on the share * since Samba server doesn't set the flag on the share, yet * supports the set sparse FSCTL and returns sparse correctly -* in the file attributes. If we fail setting sparse though we -* mark that server does not support sparse files for this share -* to avoid repeatedly sending the unsupported fsctl to server -* if the file is repeatedly extended. +* in the file attributes. If the server returns EOPNOTSUPP, mark +* that sparse files are not supported on this share to avoid +* repeatedly sending the unsupported FSCTL. */ if (tcon->broken_sparse_sup) -return false; +return -EOPNOTSUPP ; rc =SMB2_ioctl (xid, tcon, cfile->fid.persistent_fid, cfile->fid.volatile_fid,FSCTL_SET_SPARSE , &setsparse,1 , CIFSMaxBufSize,NULL ,NULL );if (rc) { - tcon->broken_sparse_sup = true; +if (rc == -EOPNOTSUPP ) + tcon->broken_sparse_sup = true;cifs_dbg (FYI ,"set sparse rc = %d\n" , rc); -return false; +return rc; }if (setsparse)
@@ -2009,7 +2010,7 @@ static bool smb2_set_sparse(const unsigned int xid, struct cifs_tcon *tcon,else cifsi->cifsAttrs &= (~FILE_ATTRIBUTE_SPARSE_FILE ); -return true; +return 0 ; } static int
@@ -3322,10 +3323,9 @@ static long smb3_punch_hole(struct file *file, struct cifs_tcon *tcon,inode_lock (inode);/* Need to make file sparse, if not already, before freeing range. */ /* Consider adding equivalent for compressed since it could also work */ -if (!smb2_set_sparse (xid, tcon, cfile, inode, set_sparse)) { - rc = -EOPNOTSUPP ; + rc =smb2_set_sparse (xid, tcon, cfile, inode, set_sparse); +if (rc) goto out; - }filemap_invalidate_lock (inode->i_mapping);/*
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 792/1266 rtc: ds1307: Fix off-by-one issue with wday for rx8130
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Fredrik M Olsson <[email protected]>
[ Upstream commit 6882aab3c66112b33b251be95c09c8ead3e8d580 ]
The RTC represent each weekday with a individual bit set in the WDAY register, where the 0th bit represent the first day of the week and the 6th bit represents the last day of the week. For each passed day the chip performs a rotary-left-shift by one to advance the weekday by one.
The tm_wday field represent weekdays by a value in the range of 0-6.
The fls() function return the bit index of the last bit set. To handle when there are no bits set it will return 0, and if the 0th bit is set it will return 1, and if the 1st bit is set it will return 2, and so on.
In order to make the result of the fls() function fall into the expected range of 0-6 (instead of 1-7) this patch subtracts one from the result (which matches how the value is written in ds1307_set_time()).
--- drivers/rtc/rtc-ds1307.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
drivers/rtc/rtc-ds1307.c +1 -1
@@ -306,7 +306,7 @@ static int ds1307_get_time(struct device *dev, struct rtc_time *t) t->tm_hour =bcd2bin (tmp);/* rx8130 is bit position, not BCD */ if (ds1307->type == rx_8130) - t->tm_wday =fls (regs[DS1307_REG_WDAY ] &0x7f ); + t->tm_wday =fls (regs[DS1307_REG_WDAY ] &0x7f ) -1 ;else t->tm_wday =bcd2bin (regs[DS1307_REG_WDAY ] &0x07 ) -1 ; t->tm_mday =bcd2bin (regs[DS1307_REG_MDAY ] &0x3f );
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 793/1266 rtc: cmos: unregister HPET IRQ handler on probe failure
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Haoxiang Li <[email protected]>
[ Upstream commit a5bb580df018b5d1c5668f05f7979044fb19e23a ]
cmos_do_probe() registers cmos_interrupt() as the HPET RTC IRQ handler before requesting the RTC IRQ and registering the RTC device. If either request_irq() or devm_rtc_register_device() fails afterwards, the error path leaves the HPET RTC IRQ handler installed. This leaves a stale handler behind and make a later hpet_register_irq_handler() fail with -EBUSY.
Track whether the HPET handler was registered successfully and undo the registration on the probe error path. Also mask the HPET RTC IRQ bits to match the normal shutdown cleanup.
--- drivers/rtc/rtc-cmos.c | 6 ++++++ 1 file changed, 6 insertions(+)
drivers/rtc/rtc-cmos.c +6 -0
@@ -932,6 +932,7 @@ cmos_do_probe(struct device *dev, struct resource *ports, int rtc_irq)unsigned char rtc_control;unsigned address_space;u32 flags =0 ; +bool hpet_registered = false;struct nvmem_config nvmem_cfg = { .name ="cmos_nvram" , .word_size =1 ,
@@ -1089,6 +1090,7 @@ cmos_do_probe(struct device *dev, struct resource *ports, int rtc_irq) " failed in rtc_init()."); goto cleanup1; } + hpet_registered = true; }else rtc_cmos_int_handler = cmos_interrupt;
@@ -1138,6 +1140,10 @@ cmos_do_probe(struct device *dev, struct resource *ports, int rtc_irq)if (is_valid_irq (rtc_irq))free_irq (rtc_irq, cmos_rtc.rtc); cleanup1: +if (hpet_registered) { +hpet_mask_rtc_irq_bit (RTC_IRQMASK ); +hpet_unregister_irq_handler (cmos_interrupt); + } cmos_rtc.dev =NULL ; cleanup0:if (RTC_IOMAPPED )
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 794/1266 net: mvneta: re-enable percpu interrupt on resume
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Yun Zhou <[email protected]>
[ Upstream commit fd398d6480987e4c84fff0aaab6b9d6642a93343 ]
On Marvell MPIC platforms (Armada 370/XP/38x), mvneta uses a percpu IRQ disable/enable scheme for NAPI: the ISR (mvneta_percpu_isr) calls disable_percpu_irq() to mask the MPIC per-CPU interrupt and schedules NAPI poll, which calls enable_percpu_irq() on completion to unmask.
If suspend occurs while NAPI poll is pending (between disable_percpu_irq in the ISR and enable_percpu_irq in poll completion), the interrupt is never re-enabled:
1. mvneta_percpu_isr: disable_percpu_irq() + napi_schedule() => MPIC masked, percpu_enabled cpumask bit cleared
2. NAPI poll does not complete before suspend proceeds (on PREEMPT_RT this is highly likely since softirqs run in ksoftirqd which gets frozen; on non-RT it can happen when softirq processing is deferred to ksoftirqd)
3. mvneta_stop_dev => napi_disable(): cancels the pending poll without executing the completion path
4. suspend_device_irqs => IRQCHIP_MASK_ON_SUSPEND: masks MPIC (already masked, but records IRQS_SUSPENDED)
5. Resume: mpic_resume checks irq_percpu_is_enabled() => false (bit was cleared in step 1) => skips unmask
6. mvneta_start_dev only restores device-level INTR_NEW_MASK, does not touch the MPIC per-CPU mask
Result: MPIC per-CPU interrupt stays masked permanently. The NIC generates interrupts (INTR_NEW_CAUSE != 0) but the CPU never receives them, causing complete loss of network connectivity.
Fix by calling on_each_cpu(mvneta_percpu_enable) in the resume path to unconditionally unmask the MPIC per-CPU interrupt regardless of pre-suspend state.
--- drivers/net/ethernet/marvell/mvneta.c | 3 +++ 1 file changed, 3 insertions(+)
drivers/net/ethernet/marvell/mvneta.c +3 -0
@@ -5866,6 +5866,9 @@ static int mvneta_resume(struct device *device)rtnl_unlock ();mvneta_set_rx_mode (dev); +if (!pp->neta_armada3700) +on_each_cpu (mvneta_percpu_enable, pp, true); + return 0; }#endif
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 795/1266 net: sungem: fix probe error cleanup
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Ruoyu Wang <[email protected]>
[ Upstream commit 36dea2f639249460d13f6ca66b2a9064187cd34d ]
gem_init_one() calls gem_remove_one() when register_netdev() fails. gem_remove_one() unregisters and frees resources owned by the net_device, including the DMA block, MMIO mapping, PCI regions, and the net_device itself. gem_init_one() then falls through to its own cleanup labels and frees the same resources again.
Keep the register_netdev() error path in gem_init_one(): clear drvdata so PM/remove paths do not see a half-registered device, remove the NAPI instance added during probe, and let the existing cleanup labels release the resources once.
The issue was found by a local static-analysis checker for probe error paths. The reported path was manually inspected before sending this fix.
Compile-tested with CONFIG_SUNGEM=y. Runtime testing was not performed because no sungem hardware is available.
--- drivers/net/ethernet/sun/sungem.c | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-)
drivers/net/ethernet/sun/sungem.c +9 -4
@@ -2986,10 +2986,10 @@ static int gem_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) dev->max_mtu =GEM_MAX_MTU ;/* Register with kernel */ -if (register_netdev (dev)) { + err =register_netdev (dev); +if (err) {pr_err ("Cannot register net device, aborting\n" ); - err = -ENOMEM ; - goto err_out_free_consistent; + goto err_out_clear_drvdata; }/* Undo the get_cell with appropriate locking (we could use
@@ -3003,8 +3003,13 @@ static int gem_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) dev->dev_addr);return 0 ; +err_out_clear_drvdata: +pci_set_drvdata (pdev,NULL ); +netif_napi_del (&gp->napi); + err_out_free_consistent: -gem_remove_one (pdev); +dma_free_coherent (&pdev->dev,sizeof (struct gem_init_block ), + gp->init_block, gp->gblock_dvma); err_out_iounmap:gem_put_cell (gp);iounmap (gp->regs);
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 796/1266 net: ethernet: sunplus: spl2sw: fix phy_node refcount leak in remove
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Shitalkumar Gandhi <[email protected]>
[ Upstream commit a9e29dcd8a84081177f693439d663ca9e216c9fa ]
mac->phy_node is acquired via of_parse_phandle() in spl2sw_probe() and stored in the mac private data, transferring ownership of the device_node reference to mac. On driver removal, spl2sw_phy_remove() disconnects the PHY but never drops that reference, so each probe-then-remove cycle leaks one of_node refcount per port permanently.
Drop the reference after phy_disconnect(). While at it, remove the redundant inner "if (ndev)" check; comm->ndev[i] was just verified non-NULL on the line above.
Compile-tested only; no SP7021 hardware available.
--- drivers/net/ethernet/sunplus/spl2sw_phy.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-)
drivers/net/ethernet/sunplus/spl2sw_phy.c +4 -2
@@ -79,12 +79,14 @@ int spl2sw_phy_connect(struct spl2sw_common *comm)void spl2sw_phy_remove (struct spl2sw_common *comm) {struct net_device *ndev; +struct spl2sw_mac *mac;int i;for (i =0 ; i <MAX_NETDEV_NUM ; i++)if (comm->ndev[i]) { ndev = comm->ndev[i]; -if (ndev) -phy_disconnect (ndev->phydev); + mac =netdev_priv (ndev); +phy_disconnect (ndev->phydev); +of_node_put (mac->phy_node); } }
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 797/1266 ASoC: fsl_asrc_dma: fix eDMA maxburst misalignment with channel count
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Shengjiu Wang <[email protected]>
[ Upstream commit cf6f56990ea21172e085f0588e5bbf2089ce8f58 ]
The back-end consumes data in units of the number of channels. When the maxburst value is not evenly divisible by the channel count, the DMA transfer length does not align with the FIFO frame boundary, causing wrong data to be copied and audible noise at the end of the stream.
This is specific to eDMA: eDMA only responds to DMA requests from the back-end, whereas SDMA handles requests from both the front-end and the back-end and is not affected.
For eDMA, when the back-end maxburst is not evenly divisible by the channel count, align it to the nearest valid boundary:
- If maxburst >= channel count, override to the channel count so each transfer corresponds to exactly one audio frame.
- If maxburst < channel count, override to 1 to avoid partial-frame transfers.
Retain the original maxburst for SDMA or when it already aligns with the channel count.
--- sound/soc/fsl/fsl_asrc_dma.c | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+)
sound/soc/fsl/fsl_asrc_dma.c +20 -0
@@ -275,6 +275,26 @@ static int fsl_asrc_dma_hw_params(struct snd_soc_component *component, config_be.dst_addr_width = buswidth; config_be.dst_maxburst = dma_params_be->maxburst; +/* +* For eDMA, the back-end may report a maxburst size that is not evenly +* divisible by the channel count. This causes the DMA transfer length +* to misalign with the FIFO boundary, resulting in wrong data and +* audible noise. Align maxburst to the nearest valid boundary: +* - If maxburst >= channel count, override to the channel count so +* each transfer equals exactly one audio frame. +* - If maxburst < channel count, override to 1 to avoid partial-frame +* transfers. +*/ +if (asrc->use_edma && (dma_params_be->maxburst %params_channels (params))) { +if (dma_params_be->maxburst >=params_channels (params)) { + config_be.src_maxburst =params_channels (params); + config_be.dst_maxburst =params_channels (params); + }else { + config_be.src_maxburst =1 ; + config_be.dst_maxburst =1 ; + } + } +memset (&audio_config,0 ,sizeof (audio_config)); config_be.peripheral_config = &audio_config; config_be.peripheral_size =sizeof (audio_config);
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 798/1266 dt-bindings: net: renesas,ether: Drop example "ethernet-phy-ieee802.3-c22" fallback
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Rob Herring (Arm) <[email protected]>
[ Upstream commit 14eb1d2c03b38ce3427f299967f7a4d97ebff4c2 ]
Fix the Micrel PHY in the example which shouldn't have the fallback "ethernet-phy-ieee802.3-c22" compatible:
Documentation/devicetree/bindings/net/renesas,ether.example.dtb: ethernet-phy@1 \
(ethernet-phy-id0022.1537): compatible: ['ethernet-phy-id0022.1537', 'ethernet-phy-ieee802.3-c22'] is too long
from schema $id: http://devicetree.org/schemas/net/micrel.yaml
--- Documentation/devicetree/bindings/net/renesas,ether.yaml | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-)
Documentation/devicetree/bindings/net/renesas,ether.yaml +1 -2
@@ -119,8 +119,7 @@ examples: #size-cells = <0>; phy1: ethernet-phy@1 { - compatible = "ethernet-phy-id0022.1537", - "ethernet-phy-ieee802.3-c22"; + compatible = "ethernet-phy-id0022.1537"; reg = <1>; interrupt-parent = <&irqc0>; interrupts = <0 IRQ_TYPE_LEVEL_LOW>;
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 799/1266 tracing: probes: fix typo in a log message
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Martin Kaiser <[email protected]>
[ Upstream commit 72c8646956ffc8050bb8be5988a0f28fc37e1ac4 ]
Fix a typo ("Invalid $-variable") in a log message.
--- kernel/trace/trace_probe.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
kernel/trace/trace_probe.h +1 -1
@@ -496,7 +496,7 @@ extern int traceprobe_define_arg_fields(struct trace_event_call *event_call,C (NO_RETVAL ,"This function returns 'void' type" ), \C (BAD_STACK_NUM ,"Invalid stack number" ), \C (BAD_ARG_NUM ,"Invalid argument number" ), \ -C (BAD_VAR ,"Invalid $-valiable specified" ), \ +C (BAD_VAR ,"Invalid $-variable specified" ), \C (BAD_REG_NAME ,"Invalid register name" ), \C (BAD_MEM_ADDR ,"Invalid memory address" ), \ C(BAD_IMM, "Invalid immediate value"), \
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 800/1266 spi: sh-msiof: abort transfers when reset times out
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Pengpeng Hou <[email protected]>
[ Upstream commit 6dbaa4d288432c697cea47028480481b8b29bd6a ]
sh_msiof_spi_reset_regs() asserts TX/RX reset and polls until the reset bits clear, but the poll result is ignored. sh_msiof_transfer_one() can therefore continue programming a transfer after the controller did not leave reset.
Return the reset poll result from the helper and abort the transfer on timeout, matching the existing transfer path's error-return style.
--- drivers/spi/spi-sh-msiof.c | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-)
drivers/spi/spi-sh-msiof.c +6 -4
@@ -242,7 +242,7 @@ static irqreturn_t sh_msiof_spi_irq(int irq, void *data)return IRQ_HANDLED ; } -static void sh_msiof_spi_reset_regs (struct sh_msiof_spi_priv *p) +static int sh_msiof_spi_reset_regs (struct sh_msiof_spi_priv *p) {u32 mask =SICTR_TXRST |SICTR_RXRST ;u32 data;
@@ -251,8 +251,8 @@ static void sh_msiof_spi_reset_regs(struct sh_msiof_spi_priv *p) data |= mask;sh_msiof_write (p,SICTR , data); -readl_poll_timeout_atomic (p->mapbase +SICTR , data, !(data & mask),1 , -100 ); +return readl_poll_timeout_atomic (p->mapbase +SICTR , data, + !(data & mask),1 ,100 ); }static const u32 sh_msiof_spi_div_array[] = {
@@ -926,7 +926,9 @@ static int sh_msiof_transfer_one(struct spi_controller *ctlr,int ret;/* reset registers */ -sh_msiof_spi_reset_regs (p); + ret =sh_msiof_spi_reset_regs (p); +if (ret) +return ret;/* setup clocks (clock already enabled in chipselect()) */ if (!spi_controller_is_target (p->ctlr))
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 801/1266 gpio: mvebu: fail probe if gpiochip registration fails
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Pengpeng Hou <[email protected]>
[ Upstream commit 479e91fc92416a4d54d2b3150aa1e4550d9cc759 ]
mvebu_gpio_probe() registers the GPIO chip with devm_gpiochip_add_data() but ignores the return value. If registration fails, probe continues and leaves later code operating on a GPIO chip that was never published to gpiolib.
Return the registration error so the device fails probe cleanly.
--- drivers/gpio/gpio-mvebu.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-)
drivers/gpio/gpio-mvebu.c +4 -1
@@ -1232,7 +1232,10 @@ static int mvebu_gpio_probe(struct platform_device *pdev)BUG (); } -devm_gpiochip_add_data (&pdev->dev, &mvchip->chip, mvchip); + err =devm_gpiochip_add_data (&pdev->dev, &mvchip->chip, mvchip); +if (err) +return dev_err_probe (&pdev->dev, err, +"failed to register gpiochip\n" );/* Some MVEBU SoCs have simple PWM support for GPIO lines */ if (IS_REACHABLE (CONFIG_PWM )) {
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 802/1266 gpio: htc-egpio: use managed gpiochip registration
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Pengpeng Hou <[email protected]>
[ Upstream commit 17326db5f0ab4ec1901e75d052b5ebef486b467f ]
egpio_probe() registers each nested gpio_chip with gpiochip_add_data() but ignores the return value. If one registration fails, probe still returns success even though one of the chips was not published to gpiolib.
Use devm_gpiochip_add_data() and fail probe if any chip registration fails. This lets devres unwind already registered chips and prevents the driver from publishing a partially initialized device.
--- drivers/gpio/gpio-htc-egpio.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-)
drivers/gpio/gpio-htc-egpio.c +5 -1
@@ -268,6 +268,7 @@ static int __init egpio_probe(struct platform_device *pdev)struct gpio_chip *chip;unsigned int irq, irq_end;int i; +int ret;/* Initialize ei data structure. */ ei =devm_kzalloc (&pdev->dev,sizeof (*ei),GFP_KERNEL );
@@ -331,7 +332,10 @@ static int __init egpio_probe(struct platform_device *pdev) chip->base = pdata->chip[i].gpio_base; chip->ngpio = pdata->chip[i].num_gpios; -gpiochip_add_data (chip, &ei->chip[i]); + ret =devm_gpiochip_add_data (&pdev->dev, chip, &ei->chip[i]); +if (ret) +return dev_err_probe (&pdev->dev, ret, +"failed to register gpiochip %d\n" , i); }/* Set initial pin values */
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 803/1266 seg6: validate SRH length before reading fixed fields
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Nuoqi Gui <[email protected]>
[ Upstream commit a75d99f46bf21b45965ce39c5cfb3b8bb5ffb1aa ]
seg6_validate_srh() reads fixed SRH fields such as srh->type and srh->hdrlen before checking that the supplied length covers the fixed struct ipv6_sr_hdr fields.
The BPF SEG6 encap path reaches this with a BPF program-supplied pointer and length: bpf_lwt_push_encap() and the SEG6 local BPF END_B6 and END_B6_ENCAP actions call bpf_push_seg6_encap(), which forwards the length to seg6_validate_srh() with no minimum-size guard. A 2-byte SEG6 encap header can therefore make the validator read srh->type at offset 2 beyond the caller-supplied buffer.
Reject lengths shorter than the fixed SRH at the top of seg6_validate_srh(), before any field is read. This fixes the BPF helper path and keeps the common validator robust.
--- net/ipv6/seg6.c | 3 +++ 1 file changed, 3 insertions(+)
net/ipv6/seg6.c +3 -0
@@ -31,6 +31,9 @@ bool seg6_validate_srh(struct ipv6_sr_hdr *srh, int len, bool reduced)int max_last_entry;int trailing; +if (len <sizeof (*srh)) +return false; +if (srh->type !=IPV6_SRCRT_TYPE_4 )return false;
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 804/1266 qede: fix out-of-bounds check for cqe->len_list[]
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Matvey Kovalev <[email protected]>
[ Upstream commit f9ba47fce5932c15891c89c60e76dfaca919cb8d ]
Move index check before element access.
--- drivers/net/ethernet/qlogic/qede/qede_fp.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-)
drivers/net/ethernet/qlogic/qede/qede_fp.c +2 -2
@@ -961,7 +961,7 @@ static inline void qede_tpa_cont(struct qede_dev *edev, {int i; -for (i =0 ; cqe->len_list[i] && i <ARRAY_SIZE (cqe->len_list); i++) +for (i =0 ; i <ARRAY_SIZE (cqe->len_list) && cqe->len_list[i]; i++)qede_fill_frag_skb (edev, rxq, cqe->tpa_agg_index,le16_to_cpu (cqe->len_list[i]));
@@ -986,7 +986,7 @@ static int qede_tpa_end(struct qede_dev *edev,dma_unmap_page (rxq->dev, tpa_info->buffer.mapping,PAGE_SIZE , rxq->data_direction); -for (i =0 ; cqe->len_list[i] && i <ARRAY_SIZE (cqe->len_list); i++) +for (i =0 ; i <ARRAY_SIZE (cqe->len_list) && cqe->len_list[i]; i++)qede_fill_frag_skb (edev, rxq, cqe->tpa_agg_index,le16_to_cpu (cqe->len_list[i]));if (unlikely (i >1 ))
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 805/1266 net: enetc: check the number of BDs needed for xdp_frame
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Wei Fang <[email protected]>
[ Upstream commit 555c5475e787802eeae0d2b91c2f66c330db2767 ]
The size of xdp_redirect_arr array is ENETC_MAX_SKB_FRAGS. However, the number of fragments contained in xdp_frame may be greater than or equal to ENETC_MAX_SKB_FRAGS, which will cause the access to xdp_redirect_arr to be out of bounds.
--- drivers/net/ethernet/freescale/enetc/enetc.c | 7 +++++++ 1 file changed, 7 insertions(+)
drivers/net/ethernet/freescale/enetc/enetc.c +7 -0
@@ -1425,6 +1425,7 @@ int enetc_xdp_xmit(struct net_device *ndev, int num_frames, {struct enetc_tx_swbd xdp_redirect_arr[ENETC_MAX_SKB_FRAGS ] = {0 };struct enetc_ndev_priv *priv =netdev_priv (ndev); +struct skb_shared_info *shinfo;struct enetc_bdr *tx_ring;int xdp_tx_bd_cnt, i, k;int xdp_tx_frm_cnt =0 ;
@@ -1440,6 +1441,12 @@ int enetc_xdp_xmit(struct net_device *ndev, int num_frames,prefetchw (ENETC_TXBD (*tx_ring, tx_ring->next_to_use));for (k =0 ; k < num_frames; k++) { +if (xdp_frame_has_frags (frames[k])) { + shinfo =xdp_get_shared_info_from_frame (frames[k]); +if (unlikely ((shinfo->nr_frags +1 ) >ENETC_MAX_SKB_FRAGS )) +break ; + } + xdp_tx_bd_cnt =enetc_xdp_frame_to_xdp_tx_swbd (tx_ring, xdp_redirect_arr, frames[k]);
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 806/1266 sctp: fix SCTP_RESET_STREAMS stream list length limit
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Yousef Alhouseen <[email protected]>
[ Upstream commit 2b9f5ef534184bd81b8a4772780626c40eed1fd5 ]
SCTP_RESET_STREAMS carries a flexible array of u16 stream IDs, but the optlen clamps treat USHRT_MAX as a byte count and then multiply sizeof(__u16) by the fixed header size.
That caps the copied and validated option buffer at about 64 KiB, which rejects valid requests containing more than about half of the u16 stream ID range.
Use struct_size_t() for the maximum struct sctp_reset_streams layout instead, so the bound matches the flexible array described by srs_number_streams.
--- net/sctp/socket.c | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-)
net/sctp/socket.c +5 -4
@@ -4110,8 +4110,9 @@ static int sctp_setsockopt_reset_streams(struct sock *sk,if (optlen <sizeof (*params))return -EINVAL ;/* srs_number_streams is u16, so optlen can't be bigger than this. */ - optlen = min_t(unsigned int, optlen, USHRT_MAX + -sizeof (__u16) *sizeof (*params)); + optlen = min_t(unsigned int, optlen, + struct_size_t(struct sctp_reset_streams, srs_stream_list, +USHRT_MAX ));if (params->srs_number_streams *sizeof (__u16) > optlen -sizeof (*params))
@@ -4597,8 +4598,8 @@ static int sctp_setsockopt(struct sock *sk, int level, int optname,if (optlen >0 ) {/* Trim it to the biggest size sctp sockopt may need if necessary */ optlen = min_t(unsigned int, optlen, -PAGE_ALIGN (USHRT_MAX + -sizeof (__u16) *sizeof (struct sctp_reset_streams ))); + PAGE_ALIGN(struct_size_t(struct sctp_reset_streams, + srs_stream_list,USHRT_MAX ))); kopt =memdup_sockptr (optval, optlen);if (IS_ERR (kopt))return PTR_ERR (kopt);
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 807/1266 MIPS: DEC: Ensure RTC platform device deregistration upon failure
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Maciej W. Rozycki <[email protected]>
[ Upstream commit eacaf5ae747f7dead6cc268de17a7382d79031fc ]
Switch RTC platform device registration from platform_device_register() to platform_add_devices() so as to make sure any failure will result in automatic device unregistration.
--- arch/mips/dec/platform.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-)
arch/mips/dec/platform.c +5 -1
@@ -38,6 +38,10 @@ static struct platform_device dec_rtc_device = { .num_resources = ARRAY_SIZE(dec_rtc_resources), }; +static struct platform_device *dec_rtc_devices[]__initdata = { + &dec_rtc_device, +}; +static struct resource dec_dz_resources[] = { { .name ="dz" , .flags =IORESOURCE_MEM , }, { .name ="dz" , .flags =IORESOURCE_IRQ , },
@@ -137,7 +141,7 @@ static int __init dec_add_devices(void) } num_zs = i; - ret1 =platform_device_register (&dec_rtc_device); + ret1 =platform_add_devices (dec_rtc_devices,1 ); ret2 =IS_ENABLED (CONFIG_32BIT ) ?platform_add_devices (dec_dz_devices, num_dz) :0 ; ret3 =platform_add_devices (dec_zs_devices, num_zs);
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 808/1266 hwmon: adm1275: Prevent reading uninitialized stack
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Matti Vaittinen <[email protected]>
[ Upstream commit 553f9517813912a5ab661af5504485d96824a61c ]
While adding support for the ROHM BD127X0 hot-swap controllers, sashiko reported an error in device-name comparison, which can lead to reading uninitialized stack memory.
Quoting Sashiko:
This is a pre-existing issue, but I noticed that just before this block in adm1275_probe(), there might be an out-of-bounds stack read:
ret = i2c_smbus_read_block_data(client, PMBUS_MFR_MODEL, block_buffer);
if (ret < 0) { ... }
for (mid = adm1275_id; mid->name[0]; mid++) {
if (!strncasecmp(mid->name, block_buffer, strlen(mid->name)))
break;
}Since i2c_smbus_read_block_data() reads up to 32 bytes into the uninitialized stack array block_buffer without appending a null terminator, strncasecmp() could read past the valid bytes returned in ret.
For example, if the device returns a shorter string like "adm12", checking it against "adm1275" up to the length of "adm1275" will continue reading into uninitialized stack bounds.
Prevent reading uninitialized memory by zeroing the stack array.
--- drivers/hwmon/pmbus/adm1275.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
drivers/hwmon/pmbus/adm1275.c +1 -1
@@ -508,7 +508,7 @@ static int adm1275_enable_vout_temp(struct adm1275_data *data,static int adm1275_probe (struct i2c_client *client) {s32 (*config_read_fn)(const struct i2c_client *client,u8 reg); -u8 block_buffer[I2C_SMBUS_BLOCK_MAX +1 ]; +u8 block_buffer[I2C_SMBUS_BLOCK_MAX +1 ] = {0 };int config, device_config;int ret;struct pmbus_driver_info *info;
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 809/1266 hwmon: (pmbus) Fix passing events to regulator core
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Guenter Roeck <[email protected]>
[ Upstream commit 9ef7dacd44216bf5ea05c8aef49eba4d145f4047 ]
Sashiko reports:
Commit 754bd2b4a084 ("hwmon: (pmbus/core) Protect regulator operations with mutex") introduced a worker to batch regulator events over time using atomic_or(). The delayed worker then passes the combined bitmask unmodified to regulator_notifier_call_chain().
The core regulator subsystem's regulator_handle_critical() function evaluates the event parameter using a strict switch statement. If multiple distinct faults occur before the worker runs (e.g., REGULATOR_EVENT_UNDER_VOLTAGE | REGULATOR_EVENT_OVER_CURRENT), the combined bitmask fails to match any case. This leaves the reason as NULL and completely bypasses the critical hw_protection_trigger().
Fix the problem by passing events bit by bit to the regulator event handler.
--- drivers/hwmon/pmbus/pmbus_core.c | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-)
drivers/hwmon/pmbus/pmbus_core.c +9 -4
@@ -3190,18 +3190,23 @@ static void pmbus_regulator_notify_worker(struct work_struct *work)int i, j;for (i =0 ; i < data->info->pages; i++) { -int event; +unsigned int event; event =atomic_xchg (&data->regulator_events[i],0 );if (!event)continue ;for (j =0 ; j < data->info->num_regulators; j++) { -if (i ==rdev_get_id (data->rdevs[j])) { +if (i !=rdev_get_id (data->rdevs[j])) +continue ; +while (event) { +unsigned int _event =BIT (__ffs (event)); +regulator_notifier_call_chain (data->rdevs[j], - event,NULL ); -break ; + _event,NULL ); + event &= ~_event; } +break ; } } }
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 810/1266 usbnet: gl620a: fix out-of-bounds read in genelink_rx_fixup()
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Xiang Mei <[email protected]>
[ Upstream commit 8ff7f2a6da4fccaa5cc9be7251a24e71e29fbd1a ]
genelink_rx_fixup() splits an aggregated RX frame into its individual packets, using a per-packet length taken from device-supplied data. That length is only bounded by GL_MAX_PACKET_LEN (1514); it is never compared against how many bytes were actually received.
A malicious GeneLink (GL620A) device can therefore send a short URB whose header claims packet_count > 1 and a first packet of up to 1514 bytes.
skb_put_data(gl_skb, packet->packet_data, size);
then copies past the end of the receive buffer and hands the adjacent slab contents up the network stack, an out-of-bounds read that leaks kernel heap. No privilege is required: the path runs in the usbnet RX softirq as soon as the interface is up.
BUG: KASAN: slab-out-of-bounds in genelink_rx_fixup (drivers/net/usb/gl620a.c:112)
Read of size 1514 at addr ffff888011309708 by task ksoftirqd/0/14
Call Trace:
...
__asan_memcpy (mm/kasan/shadow.c:105)
genelink_rx_fixup (include/linux/skbuff.h:2814 drivers/net/usb/gl620a.c:112)
usbnet_bh (drivers/net/usb/usbnet.c:572 drivers/net/usb/usbnet.c:1589)
process_one_work (kernel/workqueue.c:3322)
bh_worker (kernel/workqueue.c:3405)
tasklet_action (kernel/softirq.c:965)
handle_softirqs (kernel/softirq.c:622)
run_ksoftirqd (kernel/softirq.c:1076)
...skb_pull() already verifies that the requested length fits the buffer and returns NULL otherwise. Move it ahead of the copy and check its result, so a packet that overruns the received data is rejected before it is read. Well-formed frames, whose packets are fully present, are unaffected.
--- drivers/net/usb/gl620a.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-)
drivers/net/usb/gl620a.c +3 -3
@@ -104,6 +104,9 @@ static int genelink_rx_fixup(struct usbnet *dev, struct sk_buff *skb)return 0 ; } +if (!skb_pull (skb, size +4 )) +return 0 ; +// allocate the skb for the individual packet gl_skb =alloc_skb (size,GFP_ATOMIC );if (gl_skb) {
@@ -116,9 +119,6 @@ static int genelink_rx_fixup(struct usbnet *dev, struct sk_buff *skb)// advance to the next packet packet = (struct gl_packet *)&packet->packet_data[size]; count--; - -// shift the data pointer to the next gl_packet -skb_pull (skb, size +4 ); }// skip the packet length field 4 bytes
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 811/1266 net: phy: sfp: free mii_bus in sfp_i2c_mdiobus_destroy
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Petr Wozniak <[email protected]>
[ Upstream commit 8f31efff9206f9f0adb853cad6916086aac4d5ef ]
sfp_i2c_mdiobus_create() allocates the I2C MDIO bus with mdio_i2c_alloc(), a plain (non-devm) allocation, and registers it. sfp_i2c_mdiobus_destroy() only unregisters the bus and clears sfp->i2c_mii without calling mdiobus_free(). As the only reference to the bus is then cleared, the struct mii_bus is leaked.
This is hit whenever a copper/RollBall SFP module that instantiated an MDIO bus is removed: sfp_sm_main() takes the global teardown path and calls sfp_i2c_mdiobus_destroy(). sfp_cleanup(), on driver unbind, frees sfp->i2c_mii directly, which is why the leak only triggered on module hot-removal and not on unbind.
Free the bus in sfp_i2c_mdiobus_destroy() to match the allocation done in sfp_i2c_mdiobus_create().
--- drivers/net/phy/sfp.c | 1 + 1 file changed, 1 insertion(+)
drivers/net/phy/sfp.c +1 -0
@@ -747,6 +747,7 @@ static int sfp_i2c_mdiobus_create(struct sfp *sfp)static void sfp_i2c_mdiobus_destroy (struct sfp *sfp) {mdiobus_unregister (sfp->i2c_mii); +mdiobus_free (sfp->i2c_mii); sfp->i2c_mii =NULL ; }
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 812/1266 net: gianfar: dispose irq mappings on probe failure and device removal
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Rosen Penev <[email protected]>
[ Upstream commit dbf803bc4a8b0522c9a12560c20905a5952d1cb9 ]
irq_of_parse_and_map() creates irqdomain mappings that should be balanced with irq_dispose_mapping(). The driver never called irq_dispose_mapping(), leaking mappings on probe failure and device removal.
Fix by adding irq_dispose_mapping() in free_gfar_dev() and expanding its loop from priv->num_grps to MAXGROUPS so the error path also catches partially-initialized groups. All irqinfo pointers are pre-initialized to NULL in gfar_of_init(), making the NULL-guarded walk in free_gfar_dev() safe for every scenario.
gfar_parse_group() itself is left as a simple parse function with no resource management; cleanup is centralized in the caller's error path.
--- drivers/net/ethernet/freescale/gianfar.c | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-)
drivers/net/ethernet/freescale/gianfar.c +11 -5
@@ -470,10 +470,13 @@ static void free_gfar_dev(struct gfar_private *priv) {int i, j; -for (i =0 ; i < priv->num_grps; i++) +for (i =0 ; i <MAXGROUPS ; i++)for (j =0 ; j <GFAR_NUM_IRQS ; j++) { -kfree (priv->gfargrp[i].irqinfo[j]); - priv->gfargrp[i].irqinfo[j] =NULL ; +if (priv->gfargrp[i].irqinfo[j]) { +irq_dispose_mapping (priv->gfargrp[i].irqinfo[j]->irq); +kfree (priv->gfargrp[i].irqinfo[j]); + priv->gfargrp[i].irqinfo[j] =NULL ; + } }free_netdev (priv->ndev);
@@ -630,7 +633,7 @@ static phy_interface_t gfar_get_interface(struct net_device *dev)static int gfar_of_init (struct platform_device *ofdev,struct net_device **pdev) {const char *model; -int err =0 , i; +int err =0 , i, j;phy_interface_t interface;struct net_device *dev =NULL ;struct gfar_private *priv =NULL ;
@@ -714,8 +717,11 @@ static int gfar_of_init(struct platform_device *ofdev, struct net_device **pdev) priv->rx_list.count =0 ;mutex_init (&priv->rx_queue_access); -for (i =0 ; i <MAXGROUPS ; i++) +for (i =0 ; i <MAXGROUPS ; i++) { priv->gfargrp[i].regs =NULL ; +for (j =0 ; j <GFAR_NUM_IRQS ; j++) + priv->gfargrp[i].irqinfo[j] =NULL ; + }/* Parse and initialize group specific information */ if (priv->mode ==MQ_MG_MODE ) {
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 813/1266 net/sched: sch_teql: Introduce slaves_lock to avoid race condition and UAF
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Jamal Hadi Salim <[email protected]>
[ Upstream commit e5b811fe793166aecc59b085c1b7c31262ef2316 ]
The teql master->slaves singly linked list is not protected against multiple writes. It can be mod'ed concurently from teql_master_xmit(), teql_dequeue(), teql_init() and teql_destroy() without holding any list lock or RCU protection.
[email protected] has demonstrated that the qdisc is freed after an RCU grace period, but teql_master_xmit() running on another CPU can still hold a stale pointer into the list, resulting in a slab-use-after-free:
BUG: KASAN: slab-use-after-free in teql_master_xmit+0xf0f/0x16b0 Read of size 8 at addr ffff888013fb0440 by task poc/332
Freed 512-byte region [ffff888013fb0400, ffff888013fb0600) (kmalloc-512)
The fix?
Add a per-master slaves_lock spinlock that serializes all mutations of master->slaves and the NEXT_SLAVE() links in teql_destroy() and teql_qdisc_init(). teql_master_xmit() also takes the same slaves_lock around those updates.
Annotate master->slaves and the per-slave ->next pointer with __rcu and use the appropriate RCU accessors everywhere they are touched:rcu_assign_pointer() on the writer side (under slaves_lock), rcu_dereference_protected() for the writer-side loads (also under slaves_lock), rcu_dereference_bh() for the loads in teql_master_xmit() and rtnl_dereference() for the loads in teql_master_open()/teql_master_mtu(), which run under RTNL.
Pair this with rcu_read_lock_bh()/rcu_read_unlock_bh() around the list traversal in teql_master_xmit(), so that readers either observe a fully linked list or are deferred until the in-flight mutation completes. The two early-return paths in teql_master_xmit() are updated to release the RCU-bh read-side critical section before returning, since leaving it held would disable BH on that CPU for good.
--- net/sched/sch_teql.c | 125 +++++++++++++++++++++++++++++-------------- 1 file changed, 86 insertions(+), 39 deletions(-)
net/sched/sch_teql.c +86 -39
@@ -52,7 +52,8 @@struct teql_master {struct Qdisc_ops qops;struct net_device *dev; -struct Qdisc *slaves; +struct Qdisc __rcu *slaves; +spinlock_t slaves_lock;/* serializes writes to ->slaves */ struct list_head master_list;unsigned long tx_bytes;unsigned long tx_packets;
@@ -61,7 +62,7 @@ struct teql_master { };struct teql_sched_data { -struct Qdisc *next; +struct Qdisc __rcu *next;struct teql_master *m;struct sk_buff_head q; };
@@ -101,7 +102,9 @@ teql_dequeue(struct Qdisc *sch)if (skb ==NULL ) {struct net_device *m =qdisc_dev (q);if (m) { - dat->m->slaves = sch; +spin_lock_bh (&dat->m->slaves_lock); +rcu_assign_pointer (dat->m->slaves, sch); +spin_unlock_bh (&dat->m->slaves_lock);netif_wake_queue (m); } }else {
@@ -132,34 +135,49 @@ teql_destroy(struct Qdisc *sch)struct Qdisc *q, *prev;struct teql_sched_data *dat =qdisc_priv (sch);struct teql_master *master = dat->m; +struct netdev_queue *txq =NULL ; +bool reset_master_queue = false;if (!master)return ; - prev = master->slaves; +spin_lock_bh (&master->slaves_lock); + prev =rcu_dereference_protected (master->slaves, +lockdep_is_held (&master->slaves_lock));if (prev) {do { - q =NEXT_SLAVE (prev); -if (q == sch) { -NEXT_SLAVE (prev) =NEXT_SLAVE (q); -if (q == master->slaves) { - master->slaves =NEXT_SLAVE (q); -if (q == master->slaves) { -struct netdev_queue *txq; - - txq =netdev_get_tx_queue (master->dev,0 ); - master->slaves =NULL ; - -dev_reset_queue (master->dev, - txq,NULL ); - } - } -skb_queue_purge (&dat->q); -break ; +struct Qdisc *head, *next; + + q =rcu_dereference_protected (NEXT_SLAVE (prev), +lockdep_is_held (&master->slaves_lock)); +if (q != sch) { + prev = q; +continue ; } - }while ((prev = q) != master->slaves); + next =rcu_dereference_protected (NEXT_SLAVE (q), +lockdep_is_held (&master->slaves_lock)); +rcu_assign_pointer (NEXT_SLAVE (prev), next); + + head =rcu_dereference_protected (master->slaves, +lockdep_is_held (&master->slaves_lock)); +if (q == head) { +rcu_assign_pointer (master->slaves, next); +if (q == next) { + txq =netdev_get_tx_queue (master->dev,0 ); +rcu_assign_pointer (master->slaves,NULL ); + reset_master_queue = true; + } + } +skb_queue_purge (&dat->q); +break ; + }while (prev !=rcu_dereference_protected (master->slaves, +lockdep_is_held (&master->slaves_lock))); } +spin_unlock_bh (&master->slaves_lock); + +if (reset_master_queue) +dev_reset_queue (master->dev, txq,NULL ); } static int teql_qdisc_init(struct Qdisc *sch, struct nlattr *opt,
@@ -168,6 +186,7 @@ static int teql_qdisc_init(struct Qdisc *sch, struct nlattr *opt,struct net_device *dev =qdisc_dev (sch);struct teql_master *m = (struct teql_master *)sch->ops;struct teql_sched_data *q =qdisc_priv (sch); +struct Qdisc *first;if (dev->hard_header_len > m->dev->hard_header_len)return -EINVAL ;
@@ -184,7 +203,9 @@ static int teql_qdisc_init(struct Qdisc *sch, struct nlattr *opt,skb_queue_head_init (&q->q); -if (m->slaves) { +spin_lock_bh (&m->slaves_lock); + first =rcu_dereference_protected (m->slaves,lockdep_is_held (&m->slaves_lock)); +if (first) {if (m->dev->flags &IFF_UP ) { if ((m->dev->flags & IFF_POINTOPOINT && !(dev->flags & IFF_POINTOPOINT)) ||
@@ -192,8 +213,10 @@ static int teql_qdisc_init(struct Qdisc *sch, struct nlattr *opt, !(dev->flags & IFF_BROADCAST)) || (m->dev->flags & IFF_MULTICAST && !(dev->flags & IFF_MULTICAST)) || - dev->mtu < m->dev->mtu) + dev->mtu < m->dev->mtu) { +spin_unlock_bh (&m->slaves_lock);return -EINVAL ; + } }else {if (!(dev->flags&IFF_POINTOPOINT )) m->dev->flags &= ~IFF_POINTOPOINT ;
@@ -204,14 +227,17 @@ static int teql_qdisc_init(struct Qdisc *sch, struct nlattr *opt,if (dev->mtu < m->dev->mtu) m->dev->mtu = dev->mtu; } - q->next =NEXT_SLAVE (m->slaves); -NEXT_SLAVE (m->slaves) = sch; +rcu_assign_pointer (q->next, +rcu_dereference_protected (NEXT_SLAVE (first), +lockdep_is_held (&m->slaves_lock))); +rcu_assign_pointer (NEXT_SLAVE (first), sch); }else { - q->next = sch; - m->slaves = sch; +rcu_assign_pointer (q->next, sch); +rcu_assign_pointer (m->slaves, sch); m->dev->mtu = dev->mtu; m->dev->flags = (m->dev->flags&~FMASK )|(dev->flags&FMASK ); } +spin_unlock_bh (&m->slaves_lock);return 0 ; }
@@ -285,7 +311,9 @@ static netdev_tx_t teql_master_xmit(struct sk_buff *skb, struct net_device *dev)int subq =skb_get_queue_mapping (skb);struct sk_buff *skb_res =NULL ; - start = master->slaves; +rcu_read_lock_bh (); + + start =rcu_dereference_bh (master->slaves); restart: nores =0 ;
@@ -317,10 +345,17 @@ static netdev_tx_t teql_master_xmit(struct sk_buff *skb, struct net_device *dev) netdev_start_xmit(skb, slave, slave_txq, false) == NETDEV_TX_OK) {__netif_tx_unlock (slave_txq); - master->slaves =NEXT_SLAVE (q); +spin_lock_bh (&master->slaves_lock); +if (rcu_dereference_protected (master->slaves, +lockdep_is_held (&master->slaves_lock)) == q) +rcu_assign_pointer (master->slaves, +rcu_dereference_protected (NEXT_SLAVE (q), +lockdep_is_held (&master->slaves_lock))); +spin_unlock_bh (&master->slaves_lock);netif_wake_queue (dev); master->tx_packets++; master->tx_bytes += length; +rcu_read_unlock_bh ();return NETDEV_TX_OK ; }__netif_tx_unlock (slave_txq);
@@ -329,14 +364,21 @@ static netdev_tx_t teql_master_xmit(struct sk_buff *skb, struct net_device *dev) busy =1 ;break ;case 1 : - master->slaves =NEXT_SLAVE (q); +spin_lock_bh (&master->slaves_lock); +if (rcu_dereference_protected (master->slaves, +lockdep_is_held (&master->slaves_lock)) == q) +rcu_assign_pointer (master->slaves, +rcu_dereference_protected (NEXT_SLAVE (q), +lockdep_is_held (&master->slaves_lock))); +spin_unlock_bh (&master->slaves_lock); +rcu_read_unlock_bh ();return NETDEV_TX_OK ;default : nores =1 ;break ; }__skb_pull (skb,skb_network_offset (skb)); - }while ((q =NEXT_SLAVE (q)) != start); + }while ((q =rcu_dereference_bh (NEXT_SLAVE (q))) != start);if (nores && skb_res ==NULL ) { skb_res = skb;
@@ -345,29 +387,32 @@ static netdev_tx_t teql_master_xmit(struct sk_buff *skb, struct net_device *dev)if (busy) {netif_stop_queue (dev); +rcu_read_unlock_bh ();return NETDEV_TX_BUSY ; } master->tx_errors++; drop: master->tx_dropped++; +rcu_read_unlock_bh ();dev_kfree_skb (skb);return NETDEV_TX_OK ; }static int teql_master_open (struct net_device *dev) { -struct Qdisc *q; +struct Qdisc *q, *first;struct teql_master *m =netdev_priv (dev);int mtu =0xFFFE ;unsigned int flags =IFF_NOARP |IFF_MULTICAST ; -if (m->slaves ==NULL ) + first =rtnl_dereference (m->slaves); +if (!first)return -EUNATCH ; flags =FMASK ; - q = m->slaves; + q = first; do { struct net_device *slave = qdisc_dev(q);
@@ -389,7 +434,7 @@ static int teql_master_open(struct net_device *dev) flags &= ~IFF_BROADCAST ;if (!(slave->flags&IFF_MULTICAST )) flags &= ~IFF_MULTICAST ; - }while ((q =NEXT_SLAVE (q)) != m->slaves); + }while ((q =rtnl_dereference (NEXT_SLAVE (q))) != first); m->dev->mtu = mtu; m->dev->flags = (m->dev->flags&~FMASK ) | flags;
@@ -417,14 +462,15 @@ static void teql_master_stats64(struct net_device *dev,static int teql_master_mtu (struct net_device *dev,int new_mtu) {struct teql_master *m =netdev_priv (dev); -struct Qdisc *q; +struct Qdisc *q, *first; - q = m->slaves; + first =rtnl_dereference (m->slaves); + q = first;if (q) {do {if (new_mtu >qdisc_dev (q)->mtu)return -EINVAL ; - }while ((q =NEXT_SLAVE (q)) != m->slaves); + }while ((q =rtnl_dereference (NEXT_SLAVE (q))) != first); } dev->mtu = new_mtu;
@@ -444,6 +490,7 @@ static __init void teql_master_setup(struct net_device *dev)struct teql_master *master =netdev_priv (dev);struct Qdisc_ops *ops = &master->qops; +spin_lock_init (&master->slaves_lock); master->dev = dev; ops->priv_size =sizeof (struct teql_sched_data );
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 814/1266 bridge: stp: Fix a potential use-after-free when deleting a bridge
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Ido Schimmel <[email protected]>
[ Upstream commit 2a00517db8de4be7df3d483b215c5544fb30a191 ]
The three STP timers are not supposed to be armed while the bridge is administratively down. They are synchronously deactivated when the bridge is put administratively down and the various call sites check for 'IFF_UP' before arming them.
This check is missing from br_topology_change_detection() and it is possible to engineer a situation in which the topology change timer is armed while the bridge is administratively down, resulting in a use-after-free [1] when the bridge is deleted.
Fix by adding the missing check and for good measures synchronously shutdown the three timers when the bridge is deleted.
[1]
ODEBUG: free active (active state 0) object: ffff88811662b9b0 object type: timer_list hint: br_topology_change_timer_expired (net/bridge/br_stp_timer.c:120)
WARNING: lib/debugobjects.c:629 at debug_print_object+0x1bc/0x450, CPU#9: ip/359
--- net/bridge/br_if.c | 3 +++ net/bridge/br_stp.c | 3 ++- 2 files changed, 5 insertions(+), 1 deletion(-)
net/bridge/br_if.c +3 -0
@@ -391,6 +391,9 @@ void br_dev_delete(struct net_device *dev, struct list_head *head)br_fdb_delete_by_port (br,NULL ,0 ,1 ); +timer_shutdown_sync (&br->hello_timer); +timer_shutdown_sync (&br->topology_change_timer); +timer_shutdown_sync (&br->tcn_timer);cancel_delayed_work_sync (&br->gc_work);br_sysfs_delbr (br->dev);
net/bridge/br_stp.c +2 -1
@@ -371,7 +371,8 @@ void br_topology_change_detection(struct net_bridge *br) {int isroot =br_is_root_bridge (br); -if (br->stp_enabled !=BR_KERNEL_STP ) +if (br->stp_enabled !=BR_KERNEL_STP || + !(br->dev->flags &IFF_UP ))return ; br_info(br, "topology change detected, %s\n",
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 815/1266 tracing/events: Fix to check the simple_tsk_fn creation
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Masami Hiramatsu (Google) <[email protected]>
[ Upstream commit cda1fbfc5313bb90daa271d45eea4a8d317a8544 ]
Sashiko pointed that this sample code does not correctly handle the failure of thread creation because kthread_run() can return -errno.
Check the simple_tsk_fn is correctly initialized (created) or not.
--- samples/trace_events/trace-events-sample.c | 4 ++++ 1 file changed, 4 insertions(+)
samples/trace_events/trace-events-sample.c +4 -0
@@ -107,6 +107,10 @@ int foo_bar_reg(void)* for consistency sake, we still take the thread_mutex. */ simple_tsk_fn =kthread_run (simple_thread_fn,NULL ,"event-sample-fn" ); +if (IS_ERR_OR_NULL (simple_tsk_fn)) { +pr_err ("Failed to create simple_thread_fn\n" ); + simple_tsk_fn =NULL ; + } out:mutex_unlock (&thread_mutex);return 0 ;
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 816/1266 tracing: eprobe: read the complete FILTER_PTR_STRING pointer
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Martin Kaiser <[email protected]>
[ Upstream commit 206b25c09080cc20fd4c2bea12d59df4b7ba2121 ]
For a char * element in an event, the FILTER_PTR_STRING filter type is used. When the event occurs, a pointer is stored in the ringbuffer.
If an eprobe references such a char * element of a "base event", the stored pointer is truncated when it's read from the ringbuffer.
$ cd /sys/kernel/tracing $ echo 'e rcu.rcu_utilization $s:x64 $s:string' > dynamic_events $ echo 1 > tracing_on $ echo 1 > events/eprobes/enable $ sleep 1 $ echo 0 > events/eprobes/enable $ cat trace <idle>-0 ...: (rcu.rcu_utilization) arg1=0x4f arg2=(fault) <idle>-0 ...: (rcu.rcu_utilization) arg1=0x2 arg2=(fault)
The problem is in get_event_field
val = (unsigned long)(*(char *)addr);
addr points to the position in the ringbuffer where the pointer was stored. The assignment reads only the lowest byte of the pointer.
Fix the cast to read the whole pointer. The output of the test above is now
<idle>-0 ... arg1=0xffffffff81c7d3f3 arg2="Start scheduler-tick" <idle>-0 ... arg1=0xffffffff81c57340 arg2="End scheduler-tick"
--- kernel/trace/trace_eprobe.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
kernel/trace/trace_eprobe.c +1 -1
@@ -314,7 +314,7 @@ get_event_field(struct fetch_insn *code, void *rec) val = (unsigned long )addr;break ;case FILTER_PTR_STRING : - val = (unsigned long )(*(char *)addr); + val = *(unsigned long *)addr;break ;default :WARN_ON_ONCE (1 );
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 817/1266 irqchip/gic-v3-its: Fix OF node reference leak
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Yuho Choi <[email protected]>
[ Upstream commit 2e1368a9d61bdf5502ddade004f223a5831c5b8c ]
of_get_cpu_node() returns a referenced device node. In its_cpu_init_collection(), the Cavium 23144 workaround only uses the node to compare the CPU NUMA node, but the reference is never dropped.
Use the device_node cleanup helper for the CPU node reference so it is released when leaving the workaround block, including the NUMA mismatch return path.
--- drivers/irqchip/irq-gic-v3-its.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-)
drivers/irqchip/irq-gic-v3-its.c +2 -4
@@ -3218,11 +3218,9 @@ static void its_cpu_init_collection(struct its_node *its)/* avoid cross node collections and its mapping */ if (its->flags &ITS_FLAGS_WORKAROUND_CAVIUM_23144 ) { -struct device_node *cpu_node; + struct device_node *cpu_node __free(device_node) = of_get_cpu_node(cpu, NULL); - cpu_node =of_get_cpu_node (cpu,NULL ); -if (its->numa_node !=NUMA_NO_NODE && - its->numa_node !=of_node_to_nid (cpu_node)) +if (its->numa_node !=NUMA_NO_NODE && its->numa_node !=of_node_to_nid (cpu_node))return ; }
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 818/1266 irqchip/ts4800: Fix missing chained handler cleanup on remove
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Qingshuang Fu <[email protected]>
[ Upstream commit 98bf7e54cec07d514b3575c11896a8b12d50ecc4 ]
The driver installs a chained handler for the parent interrupt during probe using irq_set_chained_handler_and_data(), but the remove function does not clear this handler. This leaves a dangling handler that may be called when the parent interrupt fires after the driver has been removed, potentially accessing freed memory and causing a kernel crash.
Additionally, the parent_irq obtained via irq_of_parse_and_map() is not stored, making it inaccessible in the remove function. Moreover, interrupt mappings created during probe are not properly disposed.
Fix this by:
- Saving parent_irq in probe
- Clearing the chained handler with NULL in ts4800_ic_remove()
- Disposing all IRQ mappings before domain removal to prevent resource leaks
--- drivers/irqchip/irq-ts4800.c | 10 ++++++++++ 1 file changed, 10 insertions(+)
drivers/irqchip/irq-ts4800.c +10 -0
@@ -28,6 +28,7 @@ struct ts4800_irq_data {void __iomem *base;struct platform_device *pdev;struct irq_domain *domain; +unsigned int parent_irq; };static void ts4800_irq_mask (struct irq_data *d)
@@ -134,6 +135,7 @@ static int ts4800_ic_probe(struct platform_device *pdev)irq_set_chained_handler_and_data (parent_irq, ts4800_ic_chained_handle_irq, data); + data->parent_irq = parent_irq;platform_set_drvdata (pdev, data);return 0 ;
@@ -142,6 +144,14 @@ static int ts4800_ic_probe(struct platform_device *pdev)static int ts4800_ic_remove (struct platform_device *pdev) {struct ts4800_irq_data *data =platform_get_drvdata (pdev); +unsigned int hwirq; + +irq_set_chained_handler_and_data (data->parent_irq,NULL ,NULL ); + +for (hwirq =0 ; hwirq <8 ; hwirq++) +irq_dispose_mapping (irq_find_mapping (data->domain, hwirq)); + +irq_dispose_mapping (data->parent_irq);irq_domain_remove (data->domain);
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 819/1266 virtio_net: disable cb when NAPI is busy-polled
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Longjun Tang <[email protected]>
[ Upstream commit 1eb8fc67ca41db71c90866ff76c990d85247daef ]
When busy-poll is active, napi_schedule_prep() returns false in virtqueue_napi_schedule(), so virtqueue_disable_cb() is skipped. The device may keep firing irqs until reaches virtqueue_napi_complete(). Under load (received == budget), it will lead to a large number of spurious interrupts.
Fix it by disabling the callback at the virtnet_poll() entry. This keeps the callback off while we poll and it is re-enabled by virtqueue_napi_complete() when going idle.
--- drivers/net/virtio_net.c | 3 +++ 1 file changed, 3 insertions(+)
drivers/net/virtio_net.c +3 -0
@@ -2228,6 +2228,9 @@ static int virtnet_poll(struct napi_struct *napi, int budget)unsigned int received;unsigned int xdp_xmit =0 ; +if (budget) +virtqueue_disable_cb (rq->vq); +virtnet_poll_cleantx (rq, budget); received =virtnet_receive (rq, budget, &xdp_xmit);
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 820/1266 cxgb4: Fix decode strings dump for T6 adapters
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Gleb Markov <[email protected]>
[ Upstream commit 5d6dc22d62682d93f5f55f145ad792f2891de911 ]
Depending on the value of chip_version, the correct decode set is selected. However, the subsequent matching with the t4 encoding type in the if-else block results in a reassignment, which leads to the loss of support for t6_decode as well as reinitializing of values t4_decode and t5_decode.
The component history shows that the if-else block previously used for this purpose, as well as the execution order, was not affected by the change.
Furthermore, it is suggested by the execution order that the scenario with overwriting and loss of support will be implemented.
Delete the if-else block.
--- drivers/net/ethernet/chelsio/cxgb4/t4_hw.c | 8 -------- 1 file changed, 8 deletions(-)
drivers/net/ethernet/chelsio/cxgb4/t4_hw.c +0 -8
@@ -6737,14 +6737,6 @@ void t4_sge_decode_idma_state(struct adapter *adapter, int state)return ; } -if (is_t4 (adapter->params.chip)) { - sge_idma_decode = (const char **)t4_decode; - sge_idma_decode_nstates =ARRAY_SIZE (t4_decode); - }else { - sge_idma_decode = (const char **)t5_decode; - sge_idma_decode_nstates =ARRAY_SIZE (t5_decode); - } -if (state < sge_idma_decode_nstates)CH_WARN (adapter,"idma state %s\n" , sge_idma_decode[state]);else
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 821/1266 net/sched: act_bpf: use rcu_dereference_bh() to read the filter
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Sechang Lim <[email protected]>
[ Upstream commit adc49c7ba690c9b33b8392ec27397456b65d0893 ]
tcf_bpf_act() can run from the tc egress path, which holds only rcu_read_lock_bh(), but reads prog->filter with rcu_dereference() and trips lockdep:
WARNING: suspicious RCU usage
net/sched/act_bpf.c:47 suspicious rcu_dereference_check() usage! 1 lock held by syz.2.1588/12756:
#0: (rcu_read_lock_bh){....}-{1:3}, at: __dev_queue_xmit net/core/dev.c:4792
tcf_bpf_act+0x6ae/0x940 net/sched/act_bpf.c:47 tcf_classify+0x6e4/0x1080 net/sched/cls_api.c:1860 sch_handle_egress net/core/dev.c:4545 [inline] __dev_queue_xmit+0x2185/0x2c00 net/core/dev.c:4808 packet_sendmsg+0x3dfa/0x5120 net/packet/af_packet.c:3114
The other tc actions and cls_bpf already use rcu_dereference_bh() here. Do the same.
--- net/sched/act_bpf.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
net/sched/act_bpf.c +1 -1
@@ -44,7 +44,7 @@ TC_INDIRECT_SCOPE int tcf_bpf_act(struct sk_buff *skb,tcf_lastuse_update (&prog->tcf_tm);bstats_update (this_cpu_ptr (prog->common.cpu_bstats), skb); - filter =rcu_dereference (prog->filter); + filter =rcu_dereference_bh (prog->filter);if (at_ingress) {__skb_push (skb, skb->mac_len); filter_res =bpf_prog_run_data_pointers (filter, skb);
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 822/1266 ksmbd: reject undersized DACLs before parsing ACEs
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Haofeng Li <[email protected]>
[ Upstream commit 60908f7ebcd9b6cde74ad5711fab0f49c7970949 ]
parse_dacl() limits the attacker-controlled ACE count by comparing it with the number of minimal ACEs that fit in the DACL size. The DACL size field is 16 bits, but the expression subtracts sizeof(struct smb_acl). Because sizeof() is unsigned, a DACL size smaller than the ACL header underflows to a large size_t.
A malicious client can reach this with:
SMB2_SET_INFO (InfoType=SMB2_O_INFO_SECURITY)
-> smb2_set_info_sec()
-> set_info_sec()
-> parse_sec_desc()
-> parse_dacl()
-> init_acl_state(..., 0xffff)
-> init_acl_state(..., 0xffff)
-> kmalloc_objs(..., 0xffff)Thus a malformed security descriptor can make num_aces pass the guard and drive large temporary ACL state and pointer-array allocations.
Reject DACLs smaller than struct smb_acl before doing the subtraction, so the ACE count check cannot be bypassed by the underflow.
--- fs/smb/server/smbacl.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-)
fs/smb/server/smbacl.c +6 -1
@@ -374,6 +374,7 @@ static void parse_dacl(struct mnt_idmap *idmap, {int i, ret;u16 num_aces =0 ; +u16 dacl_size;unsigned int acl_size;char *acl_base;struct smb_ace **ppace;
@@ -403,7 +404,11 @@ static void parse_dacl(struct mnt_idmap *idmap,if (num_aces <=0 )return ; -if (num_aces > (le16_to_cpu (pdacl->size) -sizeof (struct smb_acl )) / + dacl_size =le16_to_cpu (pdacl->size); +if (dacl_size <sizeof (struct smb_acl )) +return ; + +if (num_aces > (dacl_size -sizeof (struct smb_acl )) / (offsetof(struct smb_ace , sid) + offsetof(struct smb_sid , sub_auth) +sizeof (__le16)))return ;
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 823/1266 smb: move some duplicate definitions to common/cifsglob.h
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: ZhangGuoDong <[email protected]>
[ Upstream commit d877470b59910b5c50383d634dda3782386bba51 ]
In order to maintain the code more easily, move duplicate definitions to new common header file.
Stable-dep-of: 38637163501f ("ksmbd: fix use-after-free of fp->owner.name in durable handle owner check")
--- fs/smb/client/cifsglob.h | 19 +------------------ fs/smb/common/cifsglob.h | 30 ++++++++++++++++++++++++++++++ fs/smb/server/smb_common.h | 14 +------------- 3 files changed, 32 insertions(+), 31 deletions(-) create mode 100644 fs/smb/common/cifsglob.h
fs/smb/client/cifsglob.h +1 -18
@@ -25,6 +25,7 @@#include "cifsacl.h" #include <crypto/internal/hash.h> #include <uapi/linux/cifs/cifs_mount.h> +#include "../common/cifsglob.h" #include "../common/smb2pdu.h" #include "smb2pdu.h" #include <linux/filelock.h>
@@ -669,12 +670,6 @@ get_rfc1002_length(void *buf)return be32_to_cpu (*((__be32 *)buf)) &0xffffff ; } -static inline void -inc_rfc1001_len (void *buf,int count) -{ -be32_add_cpu ((__be32 *)buf, count); -} -struct TCP_Server_Info {struct list_head tcp_ses_list;struct list_head smb_ses_list;
@@ -982,8 +977,6 @@ compare_mid(__u16 mid, const struct smb_hdr *smb)#define CIFS_MAX_RFC1002_WSIZE ((1<<17) - 1 - sizeof(WRITE_REQ) + 4)#define CIFS_MAX_RFC1002_RSIZE ((1<<17) - 1 - sizeof(READ_RSP) + 4) -#define CIFS_DEFAULT_IOSIZE (1024 * 1024) -/* * Windows only supports a max of 60kb reads and 65535 byte writes. Default to * those values when posix extensions aren't in force. In actuality here, we
@@ -2131,30 +2124,20 @@ extern mempool_t *cifs_req_poolp;extern mempool_t *cifs_mid_poolp;/* Operations for different SMB versions */ -#define SMB1_VERSION_STRING "1.0" -#define SMB20_VERSION_STRING "2.0"#ifdef CONFIG_CIFS_ALLOW_INSECURE_LEGACY extern struct smb_version_operations smb1_operations;extern struct smb_version_values smb1_values;extern struct smb_version_operations smb20_operations;extern struct smb_version_values smb20_values;#endif /* CIFS_ALLOW_INSECURE_LEGACY */ -#define SMB21_VERSION_STRING "2.1"extern struct smb_version_operations smb21_operations;extern struct smb_version_values smb21_values; -#define SMBDEFAULT_VERSION_STRING "default"extern struct smb_version_values smbdefault_values; -#define SMB3ANY_VERSION_STRING "3"extern struct smb_version_values smb3any_values; -#define SMB30_VERSION_STRING "3.0"extern struct smb_version_operations smb30_operations;extern struct smb_version_values smb30_values; -#define SMB302_VERSION_STRING "3.02" -#define ALT_SMB302_VERSION_STRING "3.0.2"/*extern struct smb_version_operations smb302_operations;*/ /* not needed yet */ extern struct smb_version_values smb302_values; -#define SMB311_VERSION_STRING "3.1.1" -#define ALT_SMB311_VERSION_STRING "3.11"extern struct smb_version_operations smb311_operations;extern struct smb_version_values smb311_values;
fs/smb/common/cifsglob.h new file +30 -0
@@ -0,0 +1,30 @@ +/* SPDX-License-Identifier: LGPL-2.1 */ +/* +* +* Copyright (C) International Business Machines Corp., 2002,2008 +* Author(s): Steve French ([email protected]) +* Jeremy Allison ([email protected]) +* +*/ +#ifndef _COMMON_CIFS_GLOB_H +#define _COMMON_CIFS_GLOB_H + +static inline void inc_rfc1001_len (void *buf,int count) +{ +be32_add_cpu ((__be32 *)buf, count); +} + +#define SMB1_VERSION_STRING "1.0" +#define SMB20_VERSION_STRING "2.0" +#define SMB21_VERSION_STRING "2.1" +#define SMBDEFAULT_VERSION_STRING "default" +#define SMB3ANY_VERSION_STRING "3" +#define SMB30_VERSION_STRING "3.0" +#define SMB302_VERSION_STRING "3.02" +#define ALT_SMB302_VERSION_STRING "3.0.2" +#define SMB311_VERSION_STRING "3.1.1" +#define ALT_SMB311_VERSION_STRING "3.11" + +#define CIFS_DEFAULT_IOSIZE (1024 * 1024) + +#endif /* _COMMON_CIFS_GLOB_H */
fs/smb/server/smb_common.h +1 -13
@@ -10,6 +10,7 @@#include "glob.h" #include "nterr.h" +#include "../common/cifsglob.h" #include "../common/smb2pdu.h" #include "smb2pdu.h"
@@ -26,16 +27,8 @@#define SMB311_PROT 6#define BAD_PROT 0xFFFF -#define SMB1_VERSION_STRING "1.0" -#define SMB20_VERSION_STRING "2.0" -#define SMB21_VERSION_STRING "2.1" -#define SMB30_VERSION_STRING "3.0" -#define SMB302_VERSION_STRING "3.02" -#define SMB311_VERSION_STRING "3.1.1" -#define SMB_ECHO_INTERVAL (60 * HZ) -#define CIFS_DEFAULT_IOSIZE (64 * 1024)#define MAX_CIFS_SMALL_BUFFER_SIZE 448/* big enough for most */ #define MAX_STREAM_PROT_LEN 0x00FFFFFF
@@ -462,9 +455,4 @@ static inline unsigned int get_rfc1002_len(void *buf) {return be32_to_cpu (*((__be32 *)buf)) &0xffffff ; } - -static inline void inc_rfc1001_len (void *buf,int count) -{ -be32_add_cpu ((__be32 *)buf, count); -}#endif /* __SMB_COMMON_H__ */
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 824/1266 ksmbd: fix use-after-free of fp->owner.name in durable handle owner check
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Gil Portnoy <[email protected]>
[ Upstream commit 38637163501fd9e2f684b8cd275d0db5d79f37c6 ]
Two concurrent SMB2 durable reconnects (DH2C/DHnC) on the same persistent_id race the fp->owner.name compare-read in ksmbd_vfs_compare_durable_owner() against the kfree() in ksmbd_reopen_durable_fd()'s reopen-success path. fp->owner.name is a standalone kstrdup() buffer whose lifetime is independent of the fp refcount, and the two sites share no lock: the compare reads the buffer while the reopen frees it, so the strcmp() can dereference freed memory.
Commit 7ce4fc40018d ("ksmbd: fix durable reconnect double-bind race in ksmbd_reopen_durable_fd") made the fp->conn claim atomic under global_ft.lock (closing the owner.name double-free and the ksmbd_file write-UAF), but the compare-read versus reopen-free pair was left unserialized.
BUG: KASAN: slab-use-after-free in strcmp+0x2c/0x80
Read of size 1 by task kworker
strcmp
ksmbd_vfs_compare_durable_owner
smb2_check_durable_oplock
smb2_open
Freed by task kworker:
kfree
ksmbd_reopen_durable_fd
smb2_open
Allocated by task kworker:
kstrdup
session_fd_check
smb2_session_logoff
The buggy address belongs to the cache kmalloc-8Serialize both sides of the race with fp->f_lock. The global durable file-table lock still protects the durable reconnect claim, but fp->owner.name is per-open state and does not need to block unrelated durable table lookups or reconnects. The teardown is left at its existing location after the reopen-success point so that an __open_id() rollback still retains owner.name for a later legitimate reconnect to verify.
--- fs/smb/server/vfs_cache.c | 29 +++++++++++++++++++++-------- 1 file changed, 21 insertions(+), 8 deletions(-)
fs/smb/server/vfs_cache.c +21 -8
@@ -986,16 +986,21 @@ void ksmbd_stop_durable_scavenger(void)static int ksmbd_vfs_copy_durable_owner (struct ksmbd_file *fp,struct ksmbd_user *user) { +char *name; +if (!user)return -EINVAL ;/* Duplicate the user name to ensure identity persistence */ - fp->owner.name =kstrdup (user->name,GFP_KERNEL ); -if (!fp->owner.name) + name =kstrdup (user->name,GFP_KERNEL ); +if (!name)return -ENOMEM ; +spin_lock (&fp->f_lock); fp->owner.uid = user->uid; fp->owner.gid = user->gid; + fp->owner.name = name; +spin_unlock (&fp->f_lock);return 0 ; }
@@ -1013,18 +1018,24 @@ static int ksmbd_vfs_copy_durable_owner(struct ksmbd_file *fp,bool ksmbd_vfs_compare_durable_owner (struct ksmbd_file *fp,struct ksmbd_user *user) { -if (!user || !fp->owner.name) +bool ret = false; + +if (!user)return false; +spin_lock (&fp->f_lock); +if (!fp->owner.name) + goto out; +/* Check if the UID and GID match first (fast path) */ if (fp->owner.uid != user->uid || fp->owner.gid != user->gid) -return false; + goto out;/* Validate the account name to ensure the same SecurityContext */ -if (strcmp (fp->owner.name, user->name)) -return false; - -return true; + ret = (strcmp (fp->owner.name, user->name) ==0 ); +out: +spin_unlock (&fp->f_lock); +return ret; } static bool session_fd_check(struct ksmbd_tree_connect *tcon,
@@ -1178,9 +1189,11 @@ int ksmbd_reopen_durable_fd(struct ksmbd_work *work, struct ksmbd_file *fp) }up_write (&ci->m_lock); +spin_lock (&fp->f_lock); fp->owner.uid = fp->owner.gid =0 ;kfree (fp->owner.name); fp->owner.name =NULL ; +spin_unlock (&fp->f_lock);return 0 ; }
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 825/1266 gpio: timberdale: Return -ENOMEM on dynamic memory allocation in probe
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Vladimir Zapolskiy <[email protected]>
[ Upstream commit 8d7e62d5e9b2d2ff146f472a9215d7e29c7e2307 ]
Out of memory situation on driver's probe is expected to be reported to the driver's framework with a proper -ENOMEM error code.
--- drivers/gpio/gpio-timberdale.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
drivers/gpio/gpio-timberdale.c +1 -1
@@ -228,7 +228,7 @@ static int timbgpio_probe(struct platform_device *pdev) tgpio =devm_kzalloc (dev,sizeof (*tgpio),GFP_KERNEL );if (!tgpio) -return -EINVAL ; +return -ENOMEM ; tgpio->irq_base = pdata->irq_base;
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 826/1266 pinctrl: meson: restore non-sleeping GPIO access
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Viacheslav Bocharov <[email protected]>
[ Upstream commit 9777530157e7b82fd994327ff878c4245dadc931 ]
Commit 28f240683871 ("pinctrl: meson: mark the GPIO controller as sleeping") set gpio_chip.can_sleep = true to work around gpio-shared-proxy holding a spinlock across a sleeping pinctrl config path. That locking bug is now fixed in the shared-proxy itself ("gpio:
shared-proxy: always serialize with a sleeping mutex"), so the controller-wide workaround is no longer needed; the meson GPIO controller does not sleep.
meson_gpio_get/set/direction_* access MMIO through regmap. The regmap_mmio bus uses fast I/O (spinlock) locking, so these value callbacks do not contain sleeping operations. Since gpio_chip.can_sleep describes the get/set value path, restore can_sleep = false.
Marking the controller sleeping also broke atomic value consumers such as w1-gpio (1-Wire bitbang): w1_io.c runs its read time slot under local_irq_save() and uses the non-cansleep gpiod_set_value() / gpiod_get_value(), which with can_sleep=true trigger WARN_ON(can_sleep) in gpiolib on every transferred bit (from w1_gpio_write_bit() / w1_gpio_read_bit() via w1_reset_bus() and w1_search()). The printk and stack dump inside the IRQs-off, microsecond-scale time slot destroy the bit timing, so reset/presence detection and ROM search fail: the bus master registers but w1_master_slave_count stays at 0 and no devices are found. Verified on an Amlogic A113X board (DS18B20 on GPIOA_14):
with can_sleep restored to false the warnings are gone and the sensor is detected and read again.
This must not be applied or backported without the shared-proxy locking fix above; otherwise the original Khadas VIM3 splat returns on boards that genuinely share a meson GPIO.
--- drivers/pinctrl/meson/pinctrl-meson.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
drivers/pinctrl/meson/pinctrl-meson.c +1 -1
@@ -618,7 +618,7 @@ static int meson_gpiolib_register(struct meson_pinctrl *pc) pc->chip.set = meson_gpio_set; pc->chip.base =-1 ; pc->chip.ngpio = pc->data->num_pins; - pc->chip.can_sleep = true; + pc->chip.can_sleep = false; ret =gpiochip_add_data (&pc->chip, pc);if (ret) {
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 827/1266 net/sched: hhf: clear heavy-hitter state on reset
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Samuel Moelius <[email protected]>
[ Upstream commit a225f8c20712713406ae47024b8df42deacddd4a ]
HHF reset does not clear the classifier state used to identify heavy hitters. Packets after reset can therefore be scheduled using flow history from before the reset.
The reset operation should return the qdisc to an empty state.
Clear the heavy-hitter classifier tables when HHF is reset.
--- net/sched/sch_hhf.c | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+)
net/sched/sch_hhf.c +27 -0
@@ -461,12 +461,39 @@ static struct sk_buff *hhf_dequeue(struct Qdisc *sch)return skb; } +static void hhf_reset_classifier (struct hhf_sched_data *q) +{ +int i; + +if (!q->hh_flows) +return ; + +for (i =0 ; i <HH_FLOWS_CNT ; i++) { +struct hh_flow_state *flow, *next; +struct list_head *head = &q->hh_flows[i]; + +list_for_each_entry_safe (flow, next, head, flowchain) { +list_del (&flow->flowchain); +kfree (flow); + } + } +WRITE_ONCE (q->hh_flows_current_cnt,0 ); + +for (i =0 ; i <HHF_ARRAYS_CNT ; i++) { +if (q->hhf_valid_bits[i]) +bitmap_zero (q->hhf_valid_bits[i],HHF_ARRAYS_LEN ); + } + q->hhf_arrays_reset_timestamp =hhf_time_stamp (); +} +static void hhf_reset (struct Qdisc *sch) { +struct hhf_sched_data *q =qdisc_priv (sch);struct sk_buff *skb;while ((skb =hhf_dequeue (sch)) !=NULL )rtnl_kfree_skbs (skb, skb); +hhf_reset_classifier (q); }static void hhf_destroy (struct Qdisc *sch)
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 828/1266 fs: refuse O_TMPFILE creation with an unmapped fsuid or fsgid
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Christian Brauner <[email protected]>
[ Upstream commit 539dce1144651f7976fa418e618b0b574bf15eeb ]
vfs_tmpfile() never checked that the caller's fsuid and fsgid map into the filesystem. On an idmapped mount whose idmapping does not cover the caller's fs{u,g}id, the ->tmpfile() instance initializes the new inode through inode_init_owner(), where mapped_fsuid()/mapped_fsgid() return INVALID_UID/INVALID_GID, and the tmpfile ends up owned by (uid_t)-1.
Every other creation path already refuses this: may_o_create() (O_CREAT) and may_create_dentry() (mkdir, mknod, symlink, link) bail out with -EOVERFLOW via fsuidgid_has_mapping() precisely so that an object cannot be created with an owner the filesystem cannot represent. An O_TMPFILE is no exception: it is created I_LINKABLE and linkat(2) can splice it into the namespace afterwards, so the same guarantee must hold.
Add the missing fsuidgid_has_mapping() check to vfs_tmpfile(). On a non-idmapped mount the caller's fs{u,g}id always map in the superblock's user namespace, so this is a no-op there and only takes effect on an idmapped mount that does not map the caller. It applies to every filesystem that sets FS_ALLOW_IDMAP and implements ->tmpfile() (tmpfs, ext4, btrfs, xfs, f2fs, ...), and to overlayfs, whose upper-layer tmpfile creation funnels through vfs_tmpfile() via backing_tmpfile_open().
--- fs/namei.c | 4 ++++ 1 file changed, 4 insertions(+)
fs/namei.c +4 -0
@@ -3676,6 +3676,10 @@ static int vfs_tmpfile(struct mnt_idmap *idmap,int error;int open_flag = file->f_flags; +/* A tmpfile is I_LINKABLE, so guard its owner like may_o_create(). */ +if (!fsuidgid_has_mapping (dir->i_sb, idmap)) +return -EOVERFLOW ; +/* we want directory to be writable */ error =inode_permission (idmap, dir,MAY_WRITE |MAY_EXEC );if (error)
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 829/1266 afs: Fix error code in afs_extract_vl_addrs()
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Dan Carpenter <[email protected]>
[ Upstream commit 4897cb71d4ab1f7e1a214adb1e4b80176702368d ]
The error codes on these paths are only set on the first iteration through the loop. Set the correct error code on every iteration.
--- fs/afs/vl_list.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-)
fs/afs/vl_list.c +3 -1
@@ -88,7 +88,7 @@ static struct afs_addr_list *afs_extract_vl_addrs(const u8 **_b, const u8 *end, {struct afs_addr_list *alist;const u8 *b = *_b; -int ret = -EINVAL ; +int ret; alist =afs_alloc_addrlist (nr_addrs,VL_SERVICE , port);if (!alist)
@@ -106,6 +106,7 @@ static struct afs_addr_list *afs_extract_vl_addrs(const u8 **_b, const u8 *end,case DNS_ADDRESS_IS_IPV4 :if (end - b <4 ) {_leave (" = -EINVAL [short inet]" ); + ret = -EINVAL ; goto error; }memcpy (x, b,4 );
@@ -116,6 +117,7 @@ static struct afs_addr_list *afs_extract_vl_addrs(const u8 **_b, const u8 *end,case DNS_ADDRESS_IS_IPV6 :if (end - b <16 ) {_leave (" = -EINVAL [short inet6]" ); + ret = -EINVAL ; goto error; }memcpy (x, b,16 );
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 830/1266 afs: use kvfree() to free memory allocated by kvcalloc()
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Zilin Guan <[email protected]>
[ Upstream commit cb39654926f8e7a08ecc1dcb3941628855275940 ]
op->more_files is allocated with kvcalloc() but released via afs_put_operation(), which uses kfree() internally. This mismach prevents the resource from being released properly and may lead to undefined behavior.
Fix this by using kvfree() to free op->more_files to match its allocation method.
--- fs/afs/fs_operation.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
fs/afs/fs_operation.c +1 -1
@@ -240,7 +240,7 @@ int afs_put_operation(struct afs_operation *op)for (i =0 ; i < op->nr_files -2 ; i++)if (op->more_files[i].put_vnode)iput (&op->more_files[i].vnode->netfs.inode); -kfree (op->more_files); +kvfree (op->more_files); }afs_end_cursor (&op->ac);
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 831/1266 afs: Fix callback service message parsers to pass through -EAGAIN
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: David Howells <[email protected]>
[ Upstream commit 0f36469d7ce98b362934113c550d08bb0c784231 ]
The AFS filesystem client uses an rxrpc server to listen for callback notifications. Each callback call type handler has a delivery function that parses the incoming request stream, and this should return -EAGAIN the last packet hasn't yet been seen, but all currently queued received data is consumed. afs_extract_data() does this, but the -EAGAIN return is switched to 0 inadvertantly
Fix callback service message parsers to pass through -EAGAIN
--- fs/afs/cmservice.c | 2 -- 1 file changed, 2 deletions(-)
fs/afs/cmservice.c +0 -2
@@ -390,7 +390,6 @@ static int afs_deliver_cb_init_call_back_state3(struct afs_call *call) ret =afs_extract_data (call, false);switch (ret) {case 0 :break ; -case -EAGAIN :return 0 ;default :return ret; }
@@ -503,7 +502,6 @@ static int afs_deliver_cb_probe_uuid(struct afs_call *call) ret =afs_extract_data (call, false);switch (ret) {case 0 :break ; -case -EAGAIN :return 0 ;default :return ret; }
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 832/1266 afs: Fix vllist leak
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: David Howells <[email protected]>
[ Upstream commit fc10c0ecf06f2981af5d04357612b00051e03e9e ]
Fix a leak of the new vllist in afs_update_cell() in the event that it is an empty list (nr_servers == 0), in which case the old list isn't displaced unless the old list is also empty.
--- fs/afs/cell.c | 2 ++ 1 file changed, 2 insertions(+)
fs/afs/cell.c +2 -0
@@ -474,6 +474,8 @@ static int afs_update_cell(struct afs_cell *cell)rcu_assign_pointer (cell->vl_servers, vllist); cell->dns_source = vllist->source; old = p; + }else { + old = vllist; }write_unlock (&cell->vl_servers_lock);afs_put_vlserverlist (cell->net, old);
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 833/1266 afs: Fix the volume AFS_VOLUME_RM_TREE is set on
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: David Howells <[email protected]>
[ Upstream commit 56b4e4b26f84411d880f968a539207b0a8889c8c ]
Fix afs_insert_volume_into_cell() to set AFS_VOLUME_RM_TREE on the volume replaced, not the new volume, as it's now removed from the cell's volume tree. This will cause the old volume to be removed from the tree twice and the new volume never to be removed.
--- fs/afs/volume.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
fs/afs/volume.c +1 -1
@@ -37,7 +37,7 @@ static struct afs_volume *afs_insert_volume_into_cell(struct afs_cell *cell, goto found; } -set_bit (AFS_VOLUME_RM_TREE , &volume->flags); +set_bit (AFS_VOLUME_RM_TREE , &p->flags);rb_replace_node_rcu (&p->cell_node, &volume->cell_node, &cell->volumes); } }
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 834/1266 afs: Fix unchecked-length string display in debug statement
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: David Howells <[email protected]>
[ Upstream commit 903d37c97228258da71e092f8b4ab260ce81497d ]
Fix afs_extract_vlserver_list() to limit the length of the displayed string in a debug statement().
--- fs/afs/vl_list.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-)
fs/afs/vl_list.c +5 -1
@@ -192,6 +192,8 @@ struct afs_vlserver_list *afs_extract_vlserver_list(struct afs_cell *cell, b +=sizeof (*hdr);while (end - b >=sizeof (bs)) { +int nlen; + bs.name_len =afs_extract_le16 (&b); bs.priority =afs_extract_le16 (&b); bs.weight =afs_extract_le16 (&b);
@@ -201,10 +203,12 @@ struct afs_vlserver_list *afs_extract_vlserver_list(struct afs_cell *cell, bs.protocol = *b++; bs.nr_addrs = *b++; + nlen =min3 (bs.name_len, end - b,255 ); +_debug ("extract %u %u %u %u %u %u %*.*s" , bs.name_len, bs.priority, bs.weight, bs.port, bs.protocol, bs.nr_addrs, - bs.name_len, bs.name_len, b); + bs.name_len, nlen, b);if (end - b < bs.name_len)break ;
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 835/1266 minix: avoid overflow in bitmap block count calculation
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Michael Bommarito <[email protected]>
[ Upstream commit fb3e566cafc38fe3ba35e6843a2d529a3748870c ]
minix_check_superblock() uses minix_blocks_needed() to verify that the on-disk imap and zmap block counts are large enough for the advertised inode and zone counts.
The helper currently performs DIV_ROUND_UP() in unsigned int arithmetic. A Minix v3 image can set s_ninodes or s_zones near UINT_MAX so the addition inside DIV_ROUND_UP() wraps to zero. That makes a zero imap/zmap block count look valid, after which minix_fill_super() can dereference s_imap[0] or s_zmap[0] even though no bitmap buffers were allocated.
Impact: mounting a crafted Minix v3 image whose s_ninodes or s_zones is near UINT_MAX makes minix_check_superblock() accept a zero bitmap-block count and minix_fill_super() dereference s_imap[0]/s_zmap[0], panicking the kernel.
The divisor is the bitmap capacity in bits, blocksize * 8, which is always a power of two: minix_fill_super() obtains the block size through sb_set_blocksize(), and blk_validate_block_size() rejects any size that is not a power of two. Use DIV_ROUND_UP_POW2(), which divides before adding the round-up term and so cannot overflow for a power-of-two divisor.
--- fs/minix/minix.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
fs/minix/minix.h +1 -1
@@ -91,7 +91,7 @@ static inline struct minix_inode_info *minix_i(struct inode *inode)static inline unsigned minix_blocks_needed (unsigned bits,unsigned blocksize) { -return DIV_ROUND_UP (bits, blocksize *8 ); +return DIV_ROUND_UP_POW2 (bits, blocksize *8 ); } #if defined(CONFIG_MINIX_FS_NATIVE_ENDIAN) && \
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 836/1266 ata: sata_gemini: unwind clocks on IDE pinctrl errors
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Myeonghun Pak <[email protected]>
[ Upstream commit c0ace4130e813acbabdfaa28d4e94a849c2ffdd7 ]
gemini_sata_bridge_init() prepares and enables both SATA PCLKs, then disables them again while keeping the clocks prepared for later bridge start and stop operations. If gemini_setup_ide_pins() fails after that, gemini_sata_probe() returns directly and skips the existing out_unprep_clk unwind path.
Route the IDE pinctrl failure through out_unprep_clk so the clocks prepared by gemini_sata_bridge_init() are unprepared before probe fails.
--- drivers/ata/sata_gemini.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
drivers/ata/sata_gemini.c +1 -1
@@ -385,7 +385,7 @@ static int gemini_sata_probe(struct platform_device *pdev)if (sg->ide_pins) { ret =gemini_setup_ide_pins (dev);if (ret) -return ret; + goto out_unprep_clk; }dev_info (dev,"set up the Gemini IDE/SATA nexus\n" );
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 837/1266 HID: picolcd: prevent NULL pointer dereference in picolcd_send_and_wait()
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Georgiy Osokin <[email protected]>
[ Upstream commit 0021eb09041f021c079be1022934a280f7f176c0 ]
In picolcd_send_and_wait(), an integer overflow of the signed loop counter 'k' can theoretically lead to a NULL pointer dereference of 'raw_data'. If the loop executes more than INT_MAX times, 'k' becomes negative, making the condition 'k < size' true even when 'size' is 0.
Change the type of 'k' to 'unsigned int' to prevent the overflow and eliminate the out-of-bounds access.
Found by Linux Verification Center (linuxtesting.org) with the Svace static analysis tool.
--- drivers/hid/hid-picolcd_core.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-)
drivers/hid/hid-picolcd_core.c +2 -1
@@ -72,7 +72,8 @@ struct picolcd_pending *picolcd_send_and_wait(struct hid_device *hdev,struct picolcd_pending *work;struct hid_report *report =picolcd_out_report (report_id, hdev);unsigned long flags; -int i, j, k; +int i, j; +unsigned int k;if (!report || !data)return NULL ;
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 838/1266 HID: core: Fix OOB read in hid_get_report for numbered reports
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Lee Jones <[email protected]>
[ Upstream commit af1a9b65ebe8a948eda805c14b78d4d0767cb1b5 ]
When a caller passes a size of 0 to hid_report_raw_event() for a numbered report, the function originally called hid_get_report() before performing any size validation.
Inside hid_get_report(), if the report is numbered (report_enum->numbered is true), it unconditionally dereferences data[0] to extract the report ID. With a size of 0, this results in an out-of-bounds read or kernel panic.
Fix this by moving the numbered report size validation check before the call to hid_get_report(), ensuring that size is at least 1 before dereferencing the data pointer.
--- drivers/hid/hid-core.c | 7 +++++++ 1 file changed, 7 insertions(+)
drivers/hid/hid-core.c +7 -0
@@ -1998,6 +1998,13 @@ int hid_report_raw_event(struct hid_device *hid, enum hid_report_type type, u8 *u8 *cdata = data;int ret =0 ; +if (report_enum->numbered && (size <1 || bufsize <1 )) { +hid_warn_ratelimited (hid, +"Event data for numbered report is too short (%d vs %zu)\n" , + size, bufsize); +return -EINVAL ; + } + report =hid_get_report (report_enum, data);if (!report)return 0 ;
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 839/1266 arm64/mm: convert READ_ONCE(*ptep) to ptep_get(ptep)
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Ryan Roberts <[email protected]>
[ Upstream commit 532736558e8ef2865eae1d84b52dda4422cac810 ]
There are a number of places in the arch code that read a pte by using the READ_ONCE() macro. Refactor these call sites to instead use the ptep_get() helper, which itself is a READ_ONCE(). Generated code should be the same.
This will benefit us when we shortly introduce the transparent contpte support. In this case, ptep_get() will become more complex so we now have all the code abstracted through it.
Stable-dep-of: ff4c5a0de1f2 ("arm64/mm: Optimize TLB flush in unmap_hotplug_[pmd|pud]_range()")
--- arch/arm64/include/asm/pgtable.h | 12 +++++++++--- arch/arm64/kernel/efi.c | 2 +- arch/arm64/mm/fault.c | 4 ++-- arch/arm64/mm/hugetlbpage.c | 6 +++--- arch/arm64/mm/kasan_init.c | 2 +- arch/arm64/mm/mmu.c | 12 ++++++------ arch/arm64/mm/pageattr.c | 4 ++-- arch/arm64/mm/trans_pgd.c | 2 +- 8 files changed, 25 insertions(+), 19 deletions(-)
arch/arm64/include/asm/pgtable.h +9 -3
@@ -281,6 +281,12 @@ static inline void set_pte(pte_t *ptep, pte_t pte) } } +#define ptep_get ptep_get +static inline pte_t ptep_get (pte_t *ptep) +{ +return READ_ONCE (*ptep); +} +extern void __sync_icache_dcache (pte_t pteval);bool pgattr_change_is_safe (u64 old,u64 new);
@@ -308,7 +314,7 @@ static inline void __check_safe_pte_update(struct mm_struct *mm, pte_t *ptep,if (!IS_ENABLED (CONFIG_DEBUG_VM ))return ; - old_pte =READ_ONCE (*ptep); + old_pte =ptep_get (ptep);if (!pte_valid (old_pte) || !pte_valid (pte))return ;
@@ -897,7 +903,7 @@ static inline int __ptep_test_and_clear_young(pte_t *ptep) {pte_t old_pte, pte; - pte =READ_ONCE (*ptep); + pte =ptep_get (ptep); do { old_pte = pte; pte = pte_mkold(pte);
@@ -979,7 +985,7 @@ static inline void ptep_set_wrprotect(struct mm_struct *mm, unsigned long addres {pte_t old_pte, pte; - pte =READ_ONCE (*ptep); + pte =ptep_get (ptep); do { old_pte = pte; pte = pte_wrprotect(pte);
arch/arm64/kernel/efi.c +1 -1
@@ -107,7 +107,7 @@ static int __init set_permissions(pte_t *ptep, unsigned long addr, void *data) {struct set_perm_data *spd = data;const efi_memory_desc_t *md = spd->md; -pte_t pte =READ_ONCE (*ptep); +pte_t pte =ptep_get (ptep);if (md->attribute &EFI_MEMORY_RO ) pte =set_pte_bit (pte,__pgprot (PTE_RDONLY ));
arch/arm64/mm/fault.c +2 -2
@@ -191,7 +191,7 @@ static void show_pte(unsigned long addr)if (!ptep)break ; - pte =READ_ONCE (*ptep); + pte =ptep_get (ptep);pr_cont (", pte=%016llx" ,pte_val (pte));pte_unmap (ptep); }while (0 );
@@ -214,7 +214,7 @@ int ptep_set_access_flags(struct vm_area_struct *vma, pte_t entry, int dirty) {pteval_t old_pteval, pteval; -pte_t pte =READ_ONCE (*ptep); +pte_t pte =ptep_get (ptep);if (pte_same (pte, entry))return 0 ;
arch/arm64/mm/hugetlbpage.c +3 -3
@@ -479,7 +479,7 @@ void huge_ptep_set_wrprotect(struct mm_struct *mm,size_t pgsize;pte_t pte; -if (!pte_cont (READ_ONCE (*ptep))) { +if (!pte_cont (ptep_get (ptep))) {ptep_set_wrprotect (mm, addr, ptep);return ; }
@@ -504,7 +504,7 @@ pte_t huge_ptep_clear_flush(struct vm_area_struct *vma,size_t pgsize;int ncontig; -if (!pte_cont (READ_ONCE (*ptep))) +if (!pte_cont (ptep_get (ptep)))return ptep_clear_flush (vma, addr, ptep); ncontig =find_num_contig (mm, addr, ptep, &pgsize);
@@ -552,7 +552,7 @@ pte_t huge_ptep_modify_prot_start(struct vm_area_struct *vma, unsigned long addr* when the permission changes from executable to non-executable * in cases where cpu is affected with errata #2645198. */ -if (pte_user_exec (READ_ONCE (*ptep))) +if (pte_user_exec (ptep_get (ptep)))return huge_ptep_clear_flush (vma, addr, ptep); }return huge_ptep_get_and_clear (vma->vm_mm, addr, ptep, psize);
arch/arm64/mm/kasan_init.c +1 -1
@@ -113,7 +113,7 @@ static void __init kasan_pte_populate(pmd_t *pmdp, unsigned long addr,memset (__va (page_phys),KASAN_SHADOW_INIT ,PAGE_SIZE ); next = addr +PAGE_SIZE ;set_pte (ptep,pfn_pte (__phys_to_pfn (page_phys),PAGE_KERNEL )); - }while (ptep++, addr = next, addr != end &&pte_none (READ_ONCE (*ptep))); + }while (ptep++, addr = next, addr != end &&pte_none (ptep_get (ptep))); } static void __init kasan_pmd_populate(pud_t *pudp, unsigned long addr,
arch/arm64/mm/mmu.c +6 -6
@@ -165,7 +165,7 @@ static void init_pte(pte_t *ptep, unsigned long addr, unsigned long end, phys_addr_t phys, pgprot_t prot) { do { - pte_t old_pte = READ_ONCE(*ptep); + pte_t old_pte = ptep_get(ptep); /* * Required barriers to make this visible to the table walker
@@ -178,7 +178,7 @@ static void init_pte(pte_t *ptep, unsigned long addr, unsigned long end,* only allow updates to the permission attributes. */ BUG_ON (!pgattr_change_is_safe (pte_val (old_pte), -READ_ONCE (pte_val (*ptep)))); +pte_val (ptep_get (ptep)))); phys +=PAGE_SIZE ; }while (ptep++, addr +=PAGE_SIZE , addr != end);
@@ -864,7 +864,7 @@ static void unmap_hotplug_pte_range(pmd_t *pmdp, unsigned long addr, do { ptep = pte_offset_kernel(pmdp, addr); - pte = READ_ONCE(*ptep); + pte = ptep_get(ptep); if (pte_none(pte)) continue;
@@ -1001,7 +1001,7 @@ static void free_empty_pte_table(pmd_t *pmdp, unsigned long addr, do { ptep = pte_offset_kernel(pmdp, addr); - pte = READ_ONCE(*ptep); + pte = ptep_get(ptep); /* * This is just a sanity check here which verifies that
@@ -1020,7 +1020,7 @@ static void free_empty_pte_table(pmd_t *pmdp, unsigned long addr,*/ ptep =pte_offset_kernel (pmdp,0UL );for (i =0 ; i <PTRS_PER_PTE ; i++) { -if (!pte_none (READ_ONCE (ptep[i]))) +if (!pte_none (ptep_get (&ptep[i])))return ; }
@@ -1495,7 +1495,7 @@ pte_t ptep_modify_prot_start(struct vm_area_struct *vma, unsigned long addr, pte* when the permission changes from executable to non-executable * in cases where cpu is affected with errata #2645198. */ -if (pte_user_exec (READ_ONCE (*ptep))) +if (pte_user_exec (ptep_get (ptep)))return ptep_clear_flush (vma, addr, ptep); }return ptep_get_and_clear (vma->vm_mm, addr, ptep);
arch/arm64/mm/pageattr.c +2 -2
@@ -36,7 +36,7 @@ bool can_set_direct_map(void)static int change_page_range (pte_t *ptep,unsigned long addr,void *data) {struct page_change_data *cdata = data; -pte_t pte =READ_ONCE (*ptep); +pte_t pte =ptep_get (ptep); pte =clear_pte_bit (pte, cdata->clear_mask); pte =set_pte_bit (pte, cdata->set_mask);
@@ -242,5 +242,5 @@ bool kernel_page_present(struct page *page)return true; ptep =pte_offset_kernel (pmdp, addr); -return pte_valid (READ_ONCE (*ptep)); +return pte_valid (ptep_get (ptep)); }
arch/arm64/mm/trans_pgd.c +1 -1
@@ -33,7 +33,7 @@ static void *trans_alloc(struct trans_pgd_info *info)static void _copy_pte (pte_t *dst_ptep,pte_t *src_ptep,unsigned long addr) { -pte_t pte =READ_ONCE (*src_ptep); +pte_t pte =ptep_get (src_ptep);if (pte_valid (pte)) {/*
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 840/1266 arm64/mm: convert set_pte_at() to set_ptes(..., 1)
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Ryan Roberts <[email protected]>
[ Upstream commit 659e193027910a5d3083e34b488ab459d2ef5082 ]
Since set_ptes() was introduced, set_pte_at() has been implemented as a generic macro around set_ptes(..., 1). So this change should continue to generate the same code. However, making this change prepares us for the transparent contpte support. It means we can reroute set_ptes() to __set_ptes(). Since set_pte_at() is a generic macro, there will be no equivalent __set_pte_at() to reroute to.
Note that a couple of calls to set_pte_at() remain in the arch code. This is intentional, since those call sites are acting on behalf of core-mm and should continue to call into the public set_ptes() rather than the arch-private __set_ptes().
Stable-dep-of: ff4c5a0de1f2 ("arm64/mm: Optimize TLB flush in unmap_hotplug_[pmd|pud]_range()")
--- arch/arm64/include/asm/pgtable.h | 2 +- arch/arm64/kernel/mte.c | 2 +- arch/arm64/kvm/guest.c | 2 +- arch/arm64/mm/fault.c | 2 +- arch/arm64/mm/hugetlbpage.c | 10 +++++----- 5 files changed, 9 insertions(+), 9 deletions(-)
arch/arm64/include/asm/pgtable.h +1 -1
@@ -1077,7 +1077,7 @@ static inline void arch_swap_restore(swp_entry_t entry, struct folio *folio)#endif /* CONFIG_ARM64_MTE */ /* -* On AArch64, the cache coherency is handled via the set_pte_at() function. +* On AArch64, the cache coherency is handled via the set_ptes() function. */ static inline void update_mmu_cache_range(struct vm_fault *vmf, struct vm_area_struct *vma, unsigned long addr, pte_t *ptep,
arch/arm64/kernel/mte.c +1 -1
@@ -67,7 +67,7 @@ int memcmp_pages(struct page *page1, struct page *page2)/* * If the page content is identical but at least one of the pages is * tagged, return non-zero to avoid KSM merging. If only one of the -* pages is tagged, set_pte_at() may zero or change the tags of the +* pages is tagged, set_ptes() may zero or change the tags of the * other page via mte_sync_tags(). */ if (page_mte_tagged (page1) ||page_mte_tagged (page2))
arch/arm64/kvm/guest.c +1 -1
@@ -1073,7 +1073,7 @@ int kvm_vm_ioctl_mte_copy_tags(struct kvm *kvm, }else {/* * Only locking to serialise with a concurrent -* set_pte_at() in the VMM but still overriding the +* set_ptes() in the VMM but still overriding the * tags, hence ignoring the return value. */ try_page_mte_tagging (page);
arch/arm64/mm/fault.c +1 -1
@@ -205,7 +205,7 @@ static void show_pte(unsigned long addr)* * It needs to cope with hardware update of the accessed/dirty state by other * agents in the system and can safely skip the __sync_icache_dcache() call as, -* like set_pte_at(), the PTE is never changed from no-exec to exec here. +* like set_ptes(), the PTE is never changed from no-exec to exec here. * * Returns whether or not the PTE actually changed. */
arch/arm64/mm/hugetlbpage.c +5 -5
@@ -246,12 +246,12 @@ void set_huge_pte_at(struct mm_struct *mm, unsigned long addr,if (!pte_present (pte)) {for (i =0 ; i < ncontig; i++, ptep++, addr += pgsize) -set_pte_at (mm, addr, ptep, pte); +set_ptes (mm, addr, ptep, pte,1 );return ; }if (!pte_cont (pte)) { -set_pte_at (mm, addr, ptep, pte); +set_ptes (mm, addr, ptep, pte,1 );return ; }
@@ -262,7 +262,7 @@ void set_huge_pte_at(struct mm_struct *mm, unsigned long addr,clear_flush (mm, addr, ptep, pgsize, ncontig);for (i =0 ; i < ncontig; i++, ptep++, addr += pgsize, pfn += dpfn) -set_pte_at (mm, addr, ptep,pfn_pte (pfn, hugeprot)); +set_ptes (mm, addr, ptep,pfn_pte (pfn, hugeprot),1 ); } pte_t *huge_pte_alloc(struct mm_struct *mm, struct vm_area_struct *vma,
@@ -465,7 +465,7 @@ int huge_ptep_set_access_flags(struct vm_area_struct *vma, hugeprot =pte_pgprot (pte);for (i =0 ; i < ncontig; i++, ptep++, addr += pgsize, pfn += dpfn) -set_pte_at (mm, addr, ptep,pfn_pte (pfn, hugeprot)); +set_ptes (mm, addr, ptep,pfn_pte (pfn, hugeprot),1 );return 1 ; }
@@ -494,7 +494,7 @@ void huge_ptep_set_wrprotect(struct mm_struct *mm, pfn =pte_pfn (pte);for (i =0 ; i < ncontig; i++, ptep++, addr += pgsize, pfn += dpfn) -set_pte_at (mm, addr, ptep,pfn_pte (pfn, hugeprot)); +set_ptes (mm, addr, ptep,pfn_pte (pfn, hugeprot),1 ); } pte_t huge_ptep_clear_flush(struct vm_area_struct *vma,
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 841/1266 arm64/mm: convert ptep_clear() to ptep_get_and_clear()
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Ryan Roberts <[email protected]>
[ Upstream commit cbb0294fdd72a5f63ec59fad5c0a98d63bd572fc ]
ptep_clear() is a generic wrapper around the arch-implemented ptep_get_and_clear(). We are about to convert ptep_get_and_clear() into a public version and private version (__ptep_get_and_clear()) to support the transparent contpte work. We won't have a private version of ptep_clear() so let's convert it to directly call ptep_get_and_clear().
Stable-dep-of: ff4c5a0de1f2 ("arm64/mm: Optimize TLB flush in unmap_hotplug_[pmd|pud]_range()")
--- arch/arm64/mm/hugetlbpage.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
arch/arm64/mm/hugetlbpage.c +1 -1
@@ -228,7 +228,7 @@ static void clear_flush(struct mm_struct *mm,unsigned long i, saddr = addr;for (i =0 ; i < ncontig; i++, addr += pgsize, ptep++) -ptep_clear (mm, addr, ptep); +ptep_get_and_clear (mm, addr, ptep);flush_tlb_range (&vma, saddr, addr); }
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 842/1266 arm64/mm: Optimize TLB flush in unmap_hotplug_[pmd|pud]_range()
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Anshuman Khandual <[email protected]>
[ Upstream commit ff4c5a0de1f2ef7737a8688a86e19301e567020d ]
Commit 48478b9f7913 ("arm64/mm: Enable batched TLB flush in unmap_hotplug_range") inadvertently introduced redundant TLB invalidation when clearing a block entry, resulting in unnecessary broadcast invalidation on CPUs without support for range-based invalidation.
Re-introduce the old behaviour, along with some expanded comments to help people working in this area next time around.
--- arch/arm64/mm/mmu.c | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-)
arch/arm64/mm/mmu.c +9 -2
@@ -901,7 +901,13 @@ static void unmap_hotplug_pmd_range(pud_t *pudp, unsigned long addr,if (free_mapped) {/* CONT blocks are not supported in the vmemmap */ WARN_ON (pmd_cont (pmd)); -flush_tlb_kernel_range (addr, addr +PMD_SIZE ); +/* +* Invalidating a block entry requires just +* a single overlapping TLB invalidation, +* so limit the range of the flush to a single +* page. +*/ +flush_tlb_kernel_range (addr, addr +PAGE_SIZE );free_hotplug_page_range (pmd_page (pmd),PMD_SIZE , altmap); }
@@ -931,7 +937,8 @@ static void unmap_hotplug_pud_range(p4d_t *p4dp, unsigned long addr,if (pud_sect (pud)) {pud_clear (pudp);if (free_mapped) { -flush_tlb_kernel_range (addr, addr +PUD_SIZE ); +/* See comment in unmap_hotplug_pmd_range(). */ +flush_tlb_kernel_range (addr, addr +PAGE_SIZE );free_hotplug_page_range (pud_page (pud),PUD_SIZE , altmap); }
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 843/1266 selftests/hid: ensure we can compile the tests on kernels pre-6.3
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Benjamin Tissoires <[email protected]>
[ Upstream commit ae7487d112cf9f310d32f27d5956f53d9f143fea ]
For the hid-bpf tests to compile, we need to have the definition of struct hid_bpf_ctx. This definition is an internal one from the kernel and it is supposed to be defined in the generated vmlinux.h.
This vmlinux.h header is generated based on the currently running kernel or if the kernel was already compiled in the tree. If you just compile the selftests without compiling the kernel beforehand and you are running on a 6.2 kernel, you'll end up with a vmlinux.h without the hid_bpf_ctx definition.
Use the clever trick from tools/testing/selftests/bpf/progs/bpf_iter.h to force the definition of that symbol in case we don't find it in the BTF and also add __attribute__((preserve_access_index)) to further support CO-RE functionality for these tests.
Stable-dep-of: eebbef7c468a ("selftests/hid: Cover hid_bpf_get_data() size overflow")
--- tools/testing/selftests/hid/progs/hid.c | 3 - .../selftests/hid/progs/hid_bpf_helpers.h | 77 +++++++++++++++++++ 2 files changed, 77 insertions(+), 3 deletions(-)
tools/testing/selftests/hid/progs/hid.c +0 -3
@@ -1,8 +1,5 @@// SPDX-License-Identifier: GPL-2.0 /* Copyright (c) 2022 Red hat */ -#include "vmlinux.h" -#include <bpf/bpf_helpers.h> -#include <bpf/bpf_tracing.h> #include "hid_bpf_helpers.h" char _license[] SEC("license") = "GPL";
tools/testing/selftests/hid/progs/hid_bpf_helpers.h +77 -0
83 lines not on this page · raw message
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 844/1266 selftests/hid: do not manually call headers_install
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Benjamin Tissoires <[email protected]>
[ Upstream commit 89d024a7ba02b6b969f89ac057442b5d3bcb4272 ]
"make headers" is a requirement before calling make on the selftests dir, so we should not have to manually install those headers
Stable-dep-of: eebbef7c468a ("selftests/hid: Cover hid_bpf_get_data() size overflow")
--- tools/testing/selftests/hid/Makefile | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-)
tools/testing/selftests/hid/Makefile +2 -6
@@ -24,7 +24,7 @@ CXX ?= $(CROSS_COMPILE)g++ HOSTPKG_CONFIG := pkg-config -CFLAGS += -g -O0 -rdynamic -Wall -Werror -I$(KHDR_INCLUDES) -I$(OUTPUT) +CFLAGS += -g -O0 -rdynamic -Wall -Werror -I$(OUTPUT) LDLIBS += -lelf -lz -lrt -lpthread # Silence some warnings when compiled with clang
@@ -68,7 +68,6 @@ BPFTOOLDIR := $(TOOLSDIR)/bpf/bpftool SCRATCH_DIR := $(OUTPUT)/tools BUILD_DIR := $(SCRATCH_DIR)/build INCLUDE_DIR := $(SCRATCH_DIR)/include -KHDR_INCLUDES := $(SCRATCH_DIR)/uapi/include BPFOBJ := $(BUILD_DIR)/libbpf/libbpf.a ifneq ($(CROSS_COMPILE),) HOST_BUILD_DIR := $(BUILD_DIR)/host
@@ -154,9 +153,6 @@ else $(Q)cp "$(VMLINUX_H)" $@ endif -$(KHDR_INCLUDES)/linux/hid.h: $(top_srcdir)/include/uapi/linux/hid.h - $(MAKE) -C $(top_srcdir) INSTALL_HDR_PATH=$(SCRATCH_DIR)/uapi headers_install - $(RESOLVE_BTFIDS): $(HOST_BPFOBJ) | $(HOST_BUILD_DIR)/resolve_btfids \ $(TOOLSDIR)/bpf/resolve_btfids/main.c \ $(TOOLSDIR)/lib/rbtree.c \
@@ -234,7 +230,7 @@ $(BPF_SKELS): %.skel.h: %.bpf.o $(BPFTOOL) | $(OUTPUT) $(Q)$(BPFTOOL) gen object $(<:.o=.linked1.o) $< $(Q)$(BPFTOOL) gen skeleton $(<:.o=.linked1.o) name $(notdir $(<:.bpf.o=)) > $@ -$(OUTPUT)/%.o: %.c $(BPF_SKELS) $(KHDR_INCLUDES)/linux/hid.h +$(OUTPUT)/%.o: %.c $(BPF_SKELS) $(call msg,CC,,$@) $(Q)$(CC) $(CFLAGS) -c $(filter %.c,$^) $(LDLIBS) -o $@
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 845/1266 selftests/hid: force using our compiled libbpf headers
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Benjamin Tissoires <[email protected]>
[ Upstream commit 91939636cac4585e5c99a15c8b9023e0dcabb4e5 ]
Turns out that we were relying on the globally installed headers, not the ones we freshly compiled.
Add a manual include in CFLAGS to sort this out.
Stable-dep-of: eebbef7c468a ("selftests/hid: Cover hid_bpf_get_data() size overflow")
--- tools/testing/selftests/hid/Makefile | 2 ++ 1 file changed, 2 insertions(+)
tools/testing/selftests/hid/Makefile +2 -0
@@ -25,6 +25,8 @@ CXX ?= $(CROSS_COMPILE)g++ HOSTPKG_CONFIG := pkg-config CFLAGS += -g -O0 -rdynamic -Wall -Werror -I$(OUTPUT) +CFLAGS += -I$(OUTPUT)/tools/include + LDLIBS += -lelf -lz -lrt -lpthread # Silence some warnings when compiled with clang
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 846/1266 selftests/hid: convert the hid_bpf selftests with struct_ops
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Benjamin Tissoires <[email protected]>
[ Upstream commit d7696738d66b4f1379fe77eef61cd1047d7f0773 ]
We drop the need for the attach() bpf syscall, but we need to set up the hid_id field before calling __load().
The .bpf.c part is mechanical: we create one struct_ops per HID-BPF program, as all the tests are for one program at a time.
Stable-dep-of: eebbef7c468a ("selftests/hid: Cover hid_bpf_get_data() size overflow")
--- tools/testing/selftests/hid/hid_bpf.c | 59 +++++++------- tools/testing/selftests/hid/progs/hid.c | 76 +++++++++++++------ .../selftests/hid/progs/hid_bpf_helpers.h | 19 +---- 3 files changed, 89 insertions(+), 65 deletions(-)
tools/testing/selftests/hid/hid_bpf.c +31 -28
@@ -444,7 +444,7 @@ FIXTURE(hid_bpf) {int hid_id;pthread_t tid;struct hid *skel; -int hid_links[3 ];/* max number of programs loaded in a single test */ +struct bpf_link *hid_links[3 ];/* max number of programs loaded in a single test */ };static void detach_bpf (FIXTURE_DATA (hid_bpf) * self) {
@@ -456,7 +456,7 @@ static void detach_bpf(FIXTURE_DATA(hid_bpf) * self)for (i =0 ; i <ARRAY_SIZE (self->hid_links); i++) {if (self->hid_links[i]) -close (self->hid_links[i]); +bpf_link__destroy (self->hid_links[i]); }hid__destroy (self->skel);
@@ -511,14 +511,7 @@ static void load_programs(const struct test_program programs[], FIXTURE_DATA(hid_bpf) * self, const FIXTURE_VARIANT(hid_bpf) * variant) { -int attach_fd, err = -EINVAL ; -struct attach_prog_args args = { - .retval =-1 , - }; -DECLARE_LIBBPF_OPTS (bpf_test_run_opts, tattr, - .ctx_in = &args, - .ctx_size_in = sizeof(args), - ); +int err = -EINVAL ; ASSERT_LE(progs_count, ARRAY_SIZE(self->hid_links))TH_LOG ("too many programs are to be loaded" );
@@ -529,35 +522,41 @@ static void load_programs(const struct test_program programs[],for (int i =0 ; i < progs_count; i++) {struct bpf_program *prog; +struct bpf_map *map; +int *ops_hid_id; prog =bpf_object__find_program_by_name (*self->skel->skeleton->obj, programs[i].name); ASSERT_OK_PTR(prog) TH_LOG("can not find program by name '%s'", programs[i].name);bpf_program__set_autoload (prog, true); + + map =bpf_object__find_map_by_name (*self->skel->skeleton->obj, + programs[i].name +4 ); + ASSERT_OK_PTR(map) TH_LOG("can not find struct_ops by name '%s'", + programs[i].name + 4); + +/* hid_id is the first field of struct hid_bpf_ops */ + ops_hid_id =bpf_map__initial_value (map,NULL ); + ASSERT_OK_PTR(ops_hid_id) TH_LOG("unable to retrieve struct_ops data"); + + *ops_hid_id = self->hid_id; } err =hid__load (self->skel); ASSERT_OK(err) TH_LOG("hid_skel_load failed: %d", err); - attach_fd =bpf_program__fd (self->skel->progs.attach_prog); - ASSERT_GE(attach_fd, 0) TH_LOG("locate attach_prog: %d", attach_fd); -for (int i =0 ; i < progs_count; i++) { -struct bpf_program *prog; +struct bpf_map *map; - prog =bpf_object__find_program_by_name (*self->skel->skeleton->obj, - programs[i].name); - ASSERT_OK_PTR(prog) TH_LOG("can not find program by name '%s'", programs[i].name); - - args.prog_fd =bpf_program__fd (prog); - args.hid = self->hid_id; - args.insert_head = programs[i].insert_head; - err =bpf_prog_test_run_opts (attach_fd, &tattr); - ASSERT_GE(args.retval, 0) -TH_LOG ("attach_hid(%s): %d" , programs[i].name, args.retval); + map =bpf_object__find_map_by_name (*self->skel->skeleton->obj, + programs[i].name +4 ); + ASSERT_OK_PTR(map) TH_LOG("can not find struct_ops by name '%s'", + programs[i].name + 4); - self->hid_links[i] = args.retval; + self->hid_links[i] =bpf_map__attach_struct_ops (map); + ASSERT_OK_PTR(self->hid_links[i]) TH_LOG("failed to attach struct ops '%s'", + programs[i].name +4 ); } self->hidraw_fd =open_hidraw (self->dev_id);
@@ -632,13 +631,17 @@ TEST_F(hid_bpf, test_attach_detach) { .name = "hid_first_event" }, { .name = "hid_second_event" }, }; +struct bpf_link *link;__u8 buf[10 ] = {0 }; -int err, link; +int err, link_fd;LOAD_PROGRAMS (progs); link = self->hid_links[0 ]; - ASSERT_GT(link, 0) TH_LOG("HID-BPF link not created"); + ASSERT_OK_PTR(link) TH_LOG("HID-BPF link not created"); + + link_fd =bpf_link__fd (link); + ASSERT_GE(link_fd, 0) TH_LOG("HID-BPF link FD not valid");/* inject one event */ buf[0 ] =1 ;
@@ -657,7 +660,7 @@ TEST_F(hid_bpf, test_attach_detach)/* pin the first program and immediately unpin it */ #define PIN_PATH "/sys/fs/bpf/hid_first_event" - err =bpf_obj_pin (link,PIN_PATH ); + err =bpf_obj_pin (link_fd,PIN_PATH ); ASSERT_OK(err) TH_LOG("error while calling bpf_obj_pin");remove (PIN_PATH );#undef PIN_PATH
tools/testing/selftests/hid/progs/hid.c +54 -22
127 lines not on this page · raw message
tools/testing/selftests/hid/progs/hid_bpf_helpers.h +4 -15
@@ -20,9 +20,6 @@#define HID_REQ_SET_REPORT HID_REQ_SET_REPORT___not_used#define HID_REQ_SET_IDLE HID_REQ_SET_IDLE___not_used#define HID_REQ_SET_PROTOCOL HID_REQ_SET_PROTOCOL___not_used -#define HID_BPF_FLAG_NONE HID_BPF_FLAG_NONE___not_used -#define HID_BPF_FLAG_INSERT_HEAD HID_BPF_FLAG_INSERT_HEAD___not_used -#define HID_BPF_FLAG_MAX HID_BPF_FLAG_MAX___not_used#include "vmlinux.h"
@@ -40,9 +37,6 @@#undef HID_REQ_SET_REPORT#undef HID_REQ_SET_IDLE#undef HID_REQ_SET_PROTOCOL -#undef HID_BPF_FLAG_NONE -#undef HID_BPF_FLAG_INSERT_HEAD -#undef HID_BPF_FLAG_MAX#include <bpf/bpf_helpers.h> #include <bpf/bpf_tracing.h>
@@ -57,10 +51,8 @@ enum hid_report_type { };struct hid_bpf_ctx { -__u32 index; -const struct hid_device *hid; +struct hid_device *hid;__u32 allocated_size; -enum hid_report_type report_type;union {__s32 retval;__s32 size;
@@ -76,17 +68,14 @@ enum hid_class_request { HID_REQ_SET_PROTOCOL = 0x0B, }; -enum hid_bpf_attach_flags { -HID_BPF_FLAG_NONE =0 , -HID_BPF_FLAG_INSERT_HEAD =_BITUL (0 ), -HID_BPF_FLAG_MAX , -}; +#ifndef BPF_F_BEFORE +#define BPF_F_BEFORE (1U << 3) +#endif /* following are kfuncs exported by HID for HID-BPF */ extern __u8 *hid_bpf_get_data (struct hid_bpf_ctx *ctx,unsigned int offset,const size_t __sz) __ksym; -extern int hid_bpf_attach_prog(unsigned int hid_id, int prog_fd, u32 flags) __ksym;extern struct hid_bpf_ctx *hid_bpf_allocate_context (unsigned int hid_id) __ksym; extern void hid_bpf_release_context(struct hid_bpf_ctx *ctx) __ksym; extern int hid_bpf_hw_request(struct hid_bpf_ctx *ctx,
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 847/1266 selftests/hid: Cover hid_bpf_get_data() size overflow
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Yiyang Chen <[email protected]>
[ Upstream commit eebbef7c468a5cb58c4772849ee5066441166cf0 ]
Add a HID-BPF regression check for hid_bpf_get_data() requests whose size would overflow when added to the offset.
The new rdesc fixup callback asks for offset 2 and size ~0ULL, then records whether the helper returns NULL. A vulnerable kernel returns a non-NULL pointer because the runtime check wraps the addition. A fixed kernel rejects the request. The callback records the helper result without dereferencing any returned pointer.
The callback reports the helper result through BSS and returns 0 intentionally. hid_rdesc_fixup return values are consumed as report descriptor fixup results, so a positive test-result value would be interpreted as a replacement report descriptor size.
Also add KHDR_INCLUDES to the HID selftest build so hid_bpf.c sees the current kernel UAPI HID definitions on systems whose installed headers do not provide enum hid_report_type.
--- tools/testing/selftests/hid/Makefile | 2 +- tools/testing/selftests/hid/hid_bpf.c | 11 +++++++++++ tools/testing/selftests/hid/progs/hid.c | 15 +++++++++++++++ 3 files changed, 27 insertions(+), 1 deletion(-)
tools/testing/selftests/hid/Makefile +1 -1
@@ -24,7 +24,7 @@ CXX ?= $(CROSS_COMPILE)g++ HOSTPKG_CONFIG := pkg-config -CFLAGS += -g -O0 -rdynamic -Wall -Werror -I$(OUTPUT) +CFLAGS += -g -O0 -rdynamic -Wall -Werror -I$(OUTPUT) $(KHDR_INCLUDES) CFLAGS += -I$(OUTPUT)/tools/include LDLIBS += -lelf -lz -lrt -lpthread
tools/testing/selftests/hid/hid_bpf.c +11 -0
@@ -842,6 +842,17 @@ TEST_F(hid_bpf, test_rdesc_fixup)ASSERT_EQ (rpt_desc.value[4 ],0x42 ); } +TEST_F(hid_bpf, test_rdesc_fixup_get_data_overflow) +{ +const struct test_program progs[] = { + { .name ="hid_rdesc_fixup_get_data_overflow" }, + }; + +LOAD_PROGRAMS (progs); + +ASSERT_EQ (self->skel->bss->get_data_overflow_check,1 ); +} +static int libbpf_print_fn (enum libbpf_print_level level,const char *format,va_list args) {
tools/testing/selftests/hid/progs/hid.c +15 -0
@@ -13,6 +13,7 @@ struct attach_prog_args {__u64 callback_check =52 ;__u64 callback2_check =52 ; +__u64 get_data_overflow_check; SEC("?struct_ops/hid_device_event")int BPF_PROG (hid_first_event ,struct hid_bpf_ctx *hid_ctx,enum hid_report_type type)
@@ -170,6 +171,20 @@ struct hid_bpf_ops rdesc_fixup = { .hid_rdesc_fixup = (void *)hid_rdesc_fixup, }; +SEC("?struct_ops.s/hid_rdesc_fixup") +int BPF_PROG (hid_rdesc_fixup_get_data_overflow ,struct hid_bpf_ctx *hid_ctx) +{ +if (!hid_bpf_get_data (hid_ctx,2 /* offset */ , ~0ULL /* size */ )) + get_data_overflow_check =1 ; + +return 0 ; +} + +SEC(".struct_ops.link") +struct hid_bpf_ops rdesc_fixup_get_data_overflow = { + .hid_rdesc_fixup = (void *)hid_rdesc_fixup_get_data_overflow, +}; + SEC("?struct_ops/hid_device_event")int BPF_PROG (hid_test_insert1 ,struct hid_bpf_ctx *hid_ctx,enum hid_report_type type) {
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 848/1266 net: usb: net1080: validate packet_len before pad-byte access in rx_fixup
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Xiang Mei <[email protected]>
[ Upstream commit 03f384bc0cb8d4a1301d4f5b0baef2d980258383 ]
For an even packet_len, net1080_rx_fixup() reads the pad byte at skb->data[packet_len] before the skb->len != packet_len check further down, and packet_len is only bounded against NC_MAX_PACKET. A malicious NetChip 1080 device can send a short frame advertising a large even packet_len (e.g. 0x4000), so the pad-byte read lands past the end of the skb:
BUG: KASAN: slab-out-of-bounds in net1080_rx_fixup Read of size 1 at addr ffff8880106c83c6 by task ksoftirqd/0/14 ... net1080_rx_fixup (drivers/net/usb/net1080.c:384) usbnet_bh (drivers/net/usb/usbnet.c:1589) process_one_work (kernel/workqueue.c:3322) bh_worker (kernel/workqueue.c:3708) tasklet_action (kernel/softirq.c:965) handle_softirqs (kernel/softirq.c:622) ...
Reject the frame when packet_len >= skb->len before reading.
--- drivers/net/usb/net1080.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
drivers/net/usb/net1080.c +1 -1
@@ -381,7 +381,7 @@ static int net1080_rx_fixup(struct usbnet *dev, struct sk_buff *skb)skb_trim (skb, skb->len -sizeof *trailer);if ((packet_len &0x01 ) ==0 ) { -if (skb->data [packet_len] !=PAD_BYTE ) { +if (packet_len >= skb->len || skb->data[packet_len] !=PAD_BYTE ) { dev->net->stats.rx_frame_errors++;netdev_dbg (dev->net,"bad pad\n" );return 0 ;
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 849/1266 gue: validate REMCSUM private option length
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Qihang <[email protected]>
[ Upstream commit d335dcc6f521571d57117b8deeebc940836e5450 ]
GUE private flags can indicate that remote checksum offload metadata is present. The private flags field itself is accounted for by guehdr_flags_len(), but guehdr_priv_flags_len() currently returns 0 even when GUE_PFLAG_REMCSUM is set.
This lets a packet with only the private flags field pass validate_gue_flags(), after which gue_remcsum() and gue_gro_remcsum() read the missing REMCSUM start/offset fields from the following bytes.
Account for GUE_PLEN_REMCSUM when GUE_PFLAG_REMCSUM is present so that malformed packets are rejected during option validation.
--- include/net/gue.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
include/net/gue.h +1 -1
@@ -80,7 +80,7 @@ static inline size_t guehdr_flags_len(__be16 flags)static inline size_t guehdr_priv_flags_len (__be32 flags) { -return 0 ; +return (flags &GUE_PFLAG_REMCSUM ) ?GUE_PLEN_REMCSUM :0 ; }/* Validate standard and private flags. Returns non-zero (meaning invalid)
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 850/1266 netfilter: xt_u32: reject invalid shift counts
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Wyatt Feng <[email protected]>
[ Upstream commit 64cdf7d30ac18e43df6c48004435febb965809a8 ]
u32_match_it() executes rule-supplied shift operands on a 32-bit value. A malformed u32 rule can provide a shift count of 32 or more, triggering an undefined shift out-of-bounds during packet evaluation.
Validate XT_U32_LEFTSH and XT_U32_RIGHTSH operands in u32_mt_checkentry() and reject malformed rules before they reach the packet path.
--- net/netfilter/xt_u32.c | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-)
net/netfilter/xt_u32.c +11 -1
@@ -100,7 +100,7 @@ static int u32_mt_checkentry(const struct xt_mtchk_param *par) {const struct xt_u32 *data = par->matchinfo;const struct xt_u32_test *ct; -unsigned int i; +unsigned int i, j;if (data->ntests >ARRAY_SIZE (data->tests))return -EINVAL ;
@@ -111,6 +111,16 @@ static int u32_mt_checkentry(const struct xt_mtchk_param *par)if (ct->nnums >ARRAY_SIZE (ct->location) || ct->nvalues >ARRAY_SIZE (ct->value))return -EINVAL ; + +for (j =1 ; j < ct->nnums; ++j) { +switch (ct->location[j].nextop) { +case XT_U32_LEFTSH : +case XT_U32_RIGHTSH : +if (ct->location[j].number >=32 ) +return -EINVAL ; +break ; + } + } }return 0 ;
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 851/1266 netfilter: xt_rateest: fix u64 truncation in xt_rateest_mt()
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Feng Wu <[email protected]>
[ Upstream commit 444853cd438201007da5359821adcc2995655ab1 ]
On links faster than ~34 Gbps, where byte rate may exceed 2^32-1 (~ 4.3 GBps), the comparison result becomes incorrect because the truncated value no longer reflects the actual estimator rate.
Fix by changing the local variables to u64.
--- net/netfilter/xt_rateest.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
net/netfilter/xt_rateest.c +1 -1
@@ -16,7 +16,7 @@ xt_rateest_mt(const struct sk_buff *skb, struct xt_action_param *par) {const struct xt_rateest_match_info *info = par->matchinfo;struct gnet_stats_rate_est64 sample = {0 }; -u_int32_t bps1, bps2, pps1, pps2; +u64 bps1, bps2, pps1, pps2;bool ret = true;gen_estimator_read (&info->est1->rate_est, &sample);
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 852/1266 netfilter: ip6tables: mark malformed IPv6 extension headers for hotdrop
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Zhixing Chen <[email protected]>
[ Upstream commit 43ccc20b5a733226417832cf16ef45322e594990 ]
The ah, hbh and rt matches check that the fixed extension header is present, then use the header length field to derive the advertised extension header length for matching.
For the ah match, add the missing advertised-length check. For hbh and rt, update the existing advertised-length checks. In all three cases, set hotdrop to true before returning false when the advertised extension header length exceeds the available skb data.
Returning false treats the packet as a rule mismatch. Set hotdrop to true and drop malformed packets so they cannot bypass rules intended to drop packets with these IPv6 extension headers.
--- net/ipv6/netfilter/ip6t_ah.c | 5 +++++ net/ipv6/netfilter/ip6t_hbh.c | 1 + net/ipv6/netfilter/ip6t_rt.c | 3 ++- 3 files changed, 8 insertions(+), 1 deletion(-)
net/ipv6/netfilter/ip6t_ah.c +5 -0
@@ -56,6 +56,11 @@ static bool ah_mt6(const struct sk_buff *skb, struct xt_action_param *par) } hdrlen =ipv6_authlen (ah); +if (skb->len - ptr < hdrlen) { +/* Packet smaller than its length field */ + par->hotdrop = true; +return false; + }pr_debug ("IPv6 AH LEN %u %u " , hdrlen, ah->hdrlen);pr_debug ("RES %04X " , ah->reserved);
net/ipv6/netfilter/ip6t_hbh.c +1 -0
@@ -75,6 +75,7 @@ hbh_mt6(const struct sk_buff *skb, struct xt_action_param *par) hdrlen =ipv6_optlen (oh);if (skb->len - ptr < hdrlen) {/* Packet smaller than it's length field */ + par->hotdrop = true;return false; }
net/ipv6/netfilter/ip6t_rt.c +2 -1
@@ -56,7 +56,8 @@ static bool rt_mt6(const struct sk_buff *skb, struct xt_action_param *par) hdrlen =ipv6_optlen (rh);if (skb->len - ptr < hdrlen) { -/* Pcket smaller than its length field */ +/* Packet smaller than its length field */ + par->hotdrop = true;return false; }
Signature · 1 line
2.53.0