[PATCH v3] net: caif: fix stack out-of-bounds write in cfctrl_link_setup()

Kangzheng Gu posted 1 patch 3 days, 16 hours ago
There is a newer version of this series
net/caif/cfctrl.c | 10 +++++++++-
1 file changed, 9 insertions(+), 1 deletion(-)
[PATCH v3] net: caif: fix stack out-of-bounds write in cfctrl_link_setup()
Posted by Kangzheng Gu 3 days, 16 hours ago
cfctrl_link_setup() copies the RFM volume name from a received control
packet into linkparam.u.rfm.volume until a '\0' is found. A malformed
packet can omit the terminator and make the copy run past the 20-byte
stack buffer.

Stop copying once the buffer is full and mark the frame as failed by
setting CFCTRL_ERR_BIT so the link setup is rejected.

Fixes: b482cd2053e3 ("net-caif: add CAIF core protocol stack")
Cc: stable@vger.kernel.org
Signed-off-by: Kangzheng Gu <xiaoguai0992@gmail.com>
---
 v3:
 - remove the Reported-by.
 - print a warn message and reject link setup by setting CFCTRL_ERR_BIT.

 net/caif/cfctrl.c | 10 +++++++++-
 1 file changed, 9 insertions(+), 1 deletion(-)

diff --git a/net/caif/cfctrl.c b/net/caif/cfctrl.c
index c6cc2bfed65d..373ab1dc67a7 100644
--- a/net/caif/cfctrl.c
+++ b/net/caif/cfctrl.c
@@ -416,8 +416,16 @@ static int cfctrl_link_setup(struct cfctrl *cfctrl, struct cfpkt *pkt, u8 cmdrsp
 		cp = (u8 *) linkparam.u.rfm.volume;
 		for (tmp = cfpkt_extr_head_u8(pkt);
 		     cfpkt_more(pkt) && tmp != '\0';
-		     tmp = cfpkt_extr_head_u8(pkt))
+		     tmp = cfpkt_extr_head_u8(pkt)) {
+			if (cp >= (u8 *)linkparam.u.rfm.volume +
+			    sizeof(linkparam.u.rfm.volume) - 1) {
+				pr_warn("Request reject, volume name length exceeds %lu\n",
+					sizeof(linkparam.u.rfm.volume));
+				cmdrsp |= CFCTRL_ERR_BIT;
+				break;
+			}
 			*cp++ = tmp;
+		}
 		*cp = '\0';
 
 		if (CFCTRL_ERR_BIT & cmdrsp)
-- 
2.50.1
Re: [PATCH v3] net: caif: fix stack out-of-bounds write in cfctrl_link_setup()
Posted by kernel test robot 2 days, 20 hours ago
Hi Kangzheng,

kernel test robot noticed the following build warnings:

[auto build test WARNING on net-next/main]
[also build test WARNING on net/main soc/for-next linus/master v7.0-rc6 next-20260327]
[If your patch is applied to the wrong git tree, kindly drop us a note.
And when submitting patch, we suggest to use '--base' as documented in
https://git-scm.com/docs/git-format-patch#_base_tree_information]

url:    https://github.com/intel-lab-lkp/linux/commits/Kangzheng-Gu/net-caif-fix-stack-out-of-bounds-write-in-cfctrl_link_setup/20260330-163130
base:   net-next/main
patch link:    https://lore.kernel.org/r/20260329190350.19065-1-xiaoguai0992%40gmail.com
patch subject: [PATCH v3] net: caif: fix stack out-of-bounds write in cfctrl_link_setup()
config: um-randconfig-r073-20260330 (https://download.01.org/0day-ci/archive/20260330/202603302327.ZnK21mik-lkp@intel.com/config)
compiler: clang version 17.0.6 (https://github.com/llvm/llvm-project 6009708b4367171ccdbf4b5905cb6a803753fe18)
smatch: v0.5.0-9004-gb810ac53
reproduce (this is a W=1 build): (https://download.01.org/0day-ci/archive/20260330/202603302327.ZnK21mik-lkp@intel.com/reproduce)

If you fix the issue in a separate patch/commit (i.e. not just a new version of
the same patch/commit), kindly add following tags
| Reported-by: kernel test robot <lkp@intel.com>
| Closes: https://lore.kernel.org/oe-kbuild-all/202603302327.ZnK21mik-lkp@intel.com/

All warnings (new ones prefixed by >>):

>> net/caif/cfctrl.c:423:6: warning: format specifies type 'unsigned long' but the argument has type 'unsigned int' [-Wformat]
     422 |                                 pr_warn("Request reject, volume name length exceeds %lu\n",
         |                                                                                     ~~~
         |                                                                                     %u
     423 |                                         sizeof(linkparam.u.rfm.volume));
         |                                         ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
   include/linux/printk.h:564:37: note: expanded from macro 'pr_warn'
     564 |         printk(KERN_WARNING pr_fmt(fmt), ##__VA_ARGS__)
         |                                    ~~~     ^~~~~~~~~~~
   include/linux/printk.h:511:60: note: expanded from macro 'printk'
     511 | #define printk(fmt, ...) printk_index_wrap(_printk, fmt, ##__VA_ARGS__)
         |                                                     ~~~    ^~~~~~~~~~~
   include/linux/printk.h:483:19: note: expanded from macro 'printk_index_wrap'
     483 |                 _p_func(_fmt, ##__VA_ARGS__);                           \
         |                         ~~~~    ^~~~~~~~~~~
   1 warning generated.


vim +423 net/caif/cfctrl.c

   351	
   352	static int cfctrl_link_setup(struct cfctrl *cfctrl, struct cfpkt *pkt, u8 cmdrsp)
   353	{
   354		u8 len;
   355		u8 linkid = 0;
   356		enum cfctrl_srv serv;
   357		enum cfctrl_srv servtype;
   358		u8 endpoint;
   359		u8 physlinkid;
   360		u8 prio;
   361		u8 tmp;
   362		u8 *cp;
   363		int i;
   364		struct cfctrl_link_param linkparam;
   365		struct cfctrl_request_info rsp, *req;
   366	
   367		memset(&linkparam, 0, sizeof(linkparam));
   368	
   369		tmp = cfpkt_extr_head_u8(pkt);
   370	
   371		serv = tmp & CFCTRL_SRV_MASK;
   372		linkparam.linktype = serv;
   373	
   374		servtype = tmp >> 4;
   375		linkparam.chtype = servtype;
   376	
   377		tmp = cfpkt_extr_head_u8(pkt);
   378		physlinkid = tmp & 0x07;
   379		prio = tmp >> 3;
   380	
   381		linkparam.priority = prio;
   382		linkparam.phyid = physlinkid;
   383		endpoint = cfpkt_extr_head_u8(pkt);
   384		linkparam.endpoint = endpoint & 0x03;
   385	
   386		switch (serv) {
   387		case CFCTRL_SRV_VEI:
   388		case CFCTRL_SRV_DBG:
   389			if (CFCTRL_ERR_BIT & cmdrsp)
   390				break;
   391			/* Link ID */
   392			linkid = cfpkt_extr_head_u8(pkt);
   393			break;
   394		case CFCTRL_SRV_VIDEO:
   395			tmp = cfpkt_extr_head_u8(pkt);
   396			linkparam.u.video.connid = tmp;
   397			if (CFCTRL_ERR_BIT & cmdrsp)
   398				break;
   399			/* Link ID */
   400			linkid = cfpkt_extr_head_u8(pkt);
   401			break;
   402	
   403		case CFCTRL_SRV_DATAGRAM:
   404			linkparam.u.datagram.connid = cfpkt_extr_head_u32(pkt);
   405			if (CFCTRL_ERR_BIT & cmdrsp)
   406				break;
   407			/* Link ID */
   408			linkid = cfpkt_extr_head_u8(pkt);
   409			break;
   410		case CFCTRL_SRV_RFM:
   411			/* Construct a frame, convert
   412			 * DatagramConnectionID
   413			 * to network format long and copy it out...
   414			 */
   415			linkparam.u.rfm.connid = cfpkt_extr_head_u32(pkt);
   416			cp = (u8 *) linkparam.u.rfm.volume;
   417			for (tmp = cfpkt_extr_head_u8(pkt);
   418			     cfpkt_more(pkt) && tmp != '\0';
   419			     tmp = cfpkt_extr_head_u8(pkt)) {
   420				if (cp >= (u8 *)linkparam.u.rfm.volume +
   421				    sizeof(linkparam.u.rfm.volume) - 1) {
   422					pr_warn("Request reject, volume name length exceeds %lu\n",
 > 423						sizeof(linkparam.u.rfm.volume));
   424					cmdrsp |= CFCTRL_ERR_BIT;
   425					break;
   426				}
   427				*cp++ = tmp;
   428			}
   429			*cp = '\0';
   430	
   431			if (CFCTRL_ERR_BIT & cmdrsp)
   432				break;
   433			/* Link ID */
   434			linkid = cfpkt_extr_head_u8(pkt);
   435	
   436			break;
   437		case CFCTRL_SRV_UTIL:
   438			/* Construct a frame, convert
   439			 * DatagramConnectionID
   440			 * to network format long and copy it out...
   441			 */
   442			/* Fifosize KB */
   443			linkparam.u.utility.fifosize_kb = cfpkt_extr_head_u16(pkt);
   444			/* Fifosize bufs */
   445			linkparam.u.utility.fifosize_bufs = cfpkt_extr_head_u16(pkt);
   446			/* name */
   447			cp = (u8 *) linkparam.u.utility.name;
   448			caif_assert(sizeof(linkparam.u.utility.name)
   449				     >= UTILITY_NAME_LENGTH);
   450			for (i = 0; i < UTILITY_NAME_LENGTH && cfpkt_more(pkt); i++) {
   451				tmp = cfpkt_extr_head_u8(pkt);
   452				*cp++ = tmp;
   453			}
   454			/* Length */
   455			len = cfpkt_extr_head_u8(pkt);
   456			linkparam.u.utility.paramlen = len;
   457			/* Param Data */
   458			cp = linkparam.u.utility.params;
   459			while (cfpkt_more(pkt) && len--) {
   460				tmp = cfpkt_extr_head_u8(pkt);
   461				*cp++ = tmp;
   462			}
   463			if (CFCTRL_ERR_BIT & cmdrsp)
   464				break;
   465			/* Link ID */
   466			linkid = cfpkt_extr_head_u8(pkt);
   467			/* Length */
   468			len = cfpkt_extr_head_u8(pkt);
   469			/* Param Data */
   470			cfpkt_extr_head(pkt, NULL, len);
   471			break;
   472		default:
   473			pr_warn("Request setup, invalid type (%d)\n", serv);
   474			return -1;
   475		}
   476	
   477		rsp.cmd = CFCTRL_CMD_LINK_SETUP;
   478		rsp.param = linkparam;
   479		spin_lock_bh(&cfctrl->info_list_lock);
   480		req = cfctrl_remove_req(cfctrl, &rsp);
   481	
   482		if (CFCTRL_ERR_BIT == (CFCTRL_ERR_BIT & cmdrsp) ||
   483			cfpkt_erroneous(pkt)) {
   484			pr_err("Invalid O/E bit or parse error "
   485					"on CAIF control channel\n");
   486			cfctrl->res.reject_rsp(cfctrl->serv.layer.up, 0,
   487					       req ? req->client_layer : NULL);
   488		} else {
   489			cfctrl->res.linksetup_rsp(cfctrl->serv.layer.up, linkid,
   490						  serv, physlinkid,
   491						  req ?  req->client_layer : NULL);
   492		}
   493	
   494		kfree(req);
   495	
   496		spin_unlock_bh(&cfctrl->info_list_lock);
   497	
   498		return 0;
   499	}
   500	

-- 
0-DAY CI Kernel Test Service
https://github.com/intel/lkp-tests/wiki
Re: [PATCH v3] net: caif: fix stack out-of-bounds write in cfctrl_link_setup()
Posted by kernel test robot 2 days, 21 hours ago
Hi Kangzheng,

kernel test robot noticed the following build warnings:

[auto build test WARNING on net-next/main]
[also build test WARNING on net/main soc/for-next linus/master v7.0-rc6 next-20260327]
[If your patch is applied to the wrong git tree, kindly drop us a note.
And when submitting patch, we suggest to use '--base' as documented in
https://git-scm.com/docs/git-format-patch#_base_tree_information]

url:    https://github.com/intel-lab-lkp/linux/commits/Kangzheng-Gu/net-caif-fix-stack-out-of-bounds-write-in-cfctrl_link_setup/20260330-163130
base:   net-next/main
patch link:    https://lore.kernel.org/r/20260329190350.19065-1-xiaoguai0992%40gmail.com
patch subject: [PATCH v3] net: caif: fix stack out-of-bounds write in cfctrl_link_setup()
config: hexagon-randconfig-001-20260330 (https://download.01.org/0day-ci/archive/20260330/202603302217.BEd0DrgM-lkp@intel.com/config)
compiler: clang version 23.0.0git (https://github.com/llvm/llvm-project 2cd67b8b69f78e3f95918204320c3075a74ba16c)
reproduce (this is a W=1 build): (https://download.01.org/0day-ci/archive/20260330/202603302217.BEd0DrgM-lkp@intel.com/reproduce)

If you fix the issue in a separate patch/commit (i.e. not just a new version of
the same patch/commit), kindly add following tags
| Reported-by: kernel test robot <lkp@intel.com>
| Closes: https://lore.kernel.org/oe-kbuild-all/202603302217.BEd0DrgM-lkp@intel.com/

All warnings (new ones prefixed by >>):

>> net/caif/cfctrl.c:423:6: warning: format specifies type 'unsigned long' but the argument has type '__size_t' (aka 'unsigned int') [-Wformat]
     422 |                                 pr_warn("Request reject, volume name length exceeds %lu\n",
         |                                                                                     ~~~
         |                                                                                     %zu
     423 |                                         sizeof(linkparam.u.rfm.volume));
         |                                         ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
   include/linux/printk.h:564:37: note: expanded from macro 'pr_warn'
     564 |         printk(KERN_WARNING pr_fmt(fmt), ##__VA_ARGS__)
         |                                    ~~~     ^~~~~~~~~~~
   include/linux/printk.h:511:60: note: expanded from macro 'printk'
     511 | #define printk(fmt, ...) printk_index_wrap(_printk, fmt, ##__VA_ARGS__)
         |                                                     ~~~    ^~~~~~~~~~~
   include/linux/printk.h:483:19: note: expanded from macro 'printk_index_wrap'
     483 |                 _p_func(_fmt, ##__VA_ARGS__);                           \
         |                         ~~~~    ^~~~~~~~~~~
   1 warning generated.


vim +423 net/caif/cfctrl.c

   351	
   352	static int cfctrl_link_setup(struct cfctrl *cfctrl, struct cfpkt *pkt, u8 cmdrsp)
   353	{
   354		u8 len;
   355		u8 linkid = 0;
   356		enum cfctrl_srv serv;
   357		enum cfctrl_srv servtype;
   358		u8 endpoint;
   359		u8 physlinkid;
   360		u8 prio;
   361		u8 tmp;
   362		u8 *cp;
   363		int i;
   364		struct cfctrl_link_param linkparam;
   365		struct cfctrl_request_info rsp, *req;
   366	
   367		memset(&linkparam, 0, sizeof(linkparam));
   368	
   369		tmp = cfpkt_extr_head_u8(pkt);
   370	
   371		serv = tmp & CFCTRL_SRV_MASK;
   372		linkparam.linktype = serv;
   373	
   374		servtype = tmp >> 4;
   375		linkparam.chtype = servtype;
   376	
   377		tmp = cfpkt_extr_head_u8(pkt);
   378		physlinkid = tmp & 0x07;
   379		prio = tmp >> 3;
   380	
   381		linkparam.priority = prio;
   382		linkparam.phyid = physlinkid;
   383		endpoint = cfpkt_extr_head_u8(pkt);
   384		linkparam.endpoint = endpoint & 0x03;
   385	
   386		switch (serv) {
   387		case CFCTRL_SRV_VEI:
   388		case CFCTRL_SRV_DBG:
   389			if (CFCTRL_ERR_BIT & cmdrsp)
   390				break;
   391			/* Link ID */
   392			linkid = cfpkt_extr_head_u8(pkt);
   393			break;
   394		case CFCTRL_SRV_VIDEO:
   395			tmp = cfpkt_extr_head_u8(pkt);
   396			linkparam.u.video.connid = tmp;
   397			if (CFCTRL_ERR_BIT & cmdrsp)
   398				break;
   399			/* Link ID */
   400			linkid = cfpkt_extr_head_u8(pkt);
   401			break;
   402	
   403		case CFCTRL_SRV_DATAGRAM:
   404			linkparam.u.datagram.connid = cfpkt_extr_head_u32(pkt);
   405			if (CFCTRL_ERR_BIT & cmdrsp)
   406				break;
   407			/* Link ID */
   408			linkid = cfpkt_extr_head_u8(pkt);
   409			break;
   410		case CFCTRL_SRV_RFM:
   411			/* Construct a frame, convert
   412			 * DatagramConnectionID
   413			 * to network format long and copy it out...
   414			 */
   415			linkparam.u.rfm.connid = cfpkt_extr_head_u32(pkt);
   416			cp = (u8 *) linkparam.u.rfm.volume;
   417			for (tmp = cfpkt_extr_head_u8(pkt);
   418			     cfpkt_more(pkt) && tmp != '\0';
   419			     tmp = cfpkt_extr_head_u8(pkt)) {
   420				if (cp >= (u8 *)linkparam.u.rfm.volume +
   421				    sizeof(linkparam.u.rfm.volume) - 1) {
   422					pr_warn("Request reject, volume name length exceeds %lu\n",
 > 423						sizeof(linkparam.u.rfm.volume));
   424					cmdrsp |= CFCTRL_ERR_BIT;
   425					break;
   426				}
   427				*cp++ = tmp;
   428			}
   429			*cp = '\0';
   430	
   431			if (CFCTRL_ERR_BIT & cmdrsp)
   432				break;
   433			/* Link ID */
   434			linkid = cfpkt_extr_head_u8(pkt);
   435	
   436			break;
   437		case CFCTRL_SRV_UTIL:
   438			/* Construct a frame, convert
   439			 * DatagramConnectionID
   440			 * to network format long and copy it out...
   441			 */
   442			/* Fifosize KB */
   443			linkparam.u.utility.fifosize_kb = cfpkt_extr_head_u16(pkt);
   444			/* Fifosize bufs */
   445			linkparam.u.utility.fifosize_bufs = cfpkt_extr_head_u16(pkt);
   446			/* name */
   447			cp = (u8 *) linkparam.u.utility.name;
   448			caif_assert(sizeof(linkparam.u.utility.name)
   449				     >= UTILITY_NAME_LENGTH);
   450			for (i = 0; i < UTILITY_NAME_LENGTH && cfpkt_more(pkt); i++) {
   451				tmp = cfpkt_extr_head_u8(pkt);
   452				*cp++ = tmp;
   453			}
   454			/* Length */
   455			len = cfpkt_extr_head_u8(pkt);
   456			linkparam.u.utility.paramlen = len;
   457			/* Param Data */
   458			cp = linkparam.u.utility.params;
   459			while (cfpkt_more(pkt) && len--) {
   460				tmp = cfpkt_extr_head_u8(pkt);
   461				*cp++ = tmp;
   462			}
   463			if (CFCTRL_ERR_BIT & cmdrsp)
   464				break;
   465			/* Link ID */
   466			linkid = cfpkt_extr_head_u8(pkt);
   467			/* Length */
   468			len = cfpkt_extr_head_u8(pkt);
   469			/* Param Data */
   470			cfpkt_extr_head(pkt, NULL, len);
   471			break;
   472		default:
   473			pr_warn("Request setup, invalid type (%d)\n", serv);
   474			return -1;
   475		}
   476	
   477		rsp.cmd = CFCTRL_CMD_LINK_SETUP;
   478		rsp.param = linkparam;
   479		spin_lock_bh(&cfctrl->info_list_lock);
   480		req = cfctrl_remove_req(cfctrl, &rsp);
   481	
   482		if (CFCTRL_ERR_BIT == (CFCTRL_ERR_BIT & cmdrsp) ||
   483			cfpkt_erroneous(pkt)) {
   484			pr_err("Invalid O/E bit or parse error "
   485					"on CAIF control channel\n");
   486			cfctrl->res.reject_rsp(cfctrl->serv.layer.up, 0,
   487					       req ? req->client_layer : NULL);
   488		} else {
   489			cfctrl->res.linksetup_rsp(cfctrl->serv.layer.up, linkid,
   490						  serv, physlinkid,
   491						  req ?  req->client_layer : NULL);
   492		}
   493	
   494		kfree(req);
   495	
   496		spin_unlock_bh(&cfctrl->info_list_lock);
   497	
   498		return 0;
   499	}
   500	

-- 
0-DAY CI Kernel Test Service
https://github.com/intel/lkp-tests/wiki
[PATCH v4] net: caif: fix stack out-of-bounds write in cfctrl_link_setup()
Posted by Kangzheng Gu 3 days, 5 hours ago
cfctrl_link_setup() copies the RFM volume name from a received control
packet into linkparam.u.rfm.volume until a '\0' is found. A malformed
packet can omit the terminator and make the copy run past the 20-byte
stack buffer.

Stop copying once the buffer is full and mark the frame as failed by
setting CFCTRL_ERR_BIT so the link setup is rejected.

Fixes: b482cd2053e3 ("net-caif: add CAIF core protocol stack")
Cc: stable@vger.kernel.org
Signed-off-by: Kangzheng Gu <xiaoguai0992@gmail.com>
---
 v4:
 - remove the Reported-by.
 - print a warn message and reject link setup by setting CFCTRL_ERR_BIT.
 - using %zu to adapt the compilation of 32-bit kernel.

 net/caif/cfctrl.c | 10 +++++++++-
 1 file changed, 9 insertions(+), 1 deletion(-)

diff --git a/net/caif/cfctrl.c b/net/caif/cfctrl.c
index c6cc2bfed65d..373ab1dc67a7 100644
--- a/net/caif/cfctrl.c
+++ b/net/caif/cfctrl.c
@@ -416,8 +416,16 @@ static int cfctrl_link_setup(struct cfctrl *cfctrl, struct cfpkt *pkt, u8 cmdrsp
 		cp = (u8 *) linkparam.u.rfm.volume;
 		for (tmp = cfpkt_extr_head_u8(pkt);
 		     cfpkt_more(pkt) && tmp != '\0';
-		     tmp = cfpkt_extr_head_u8(pkt))
+		     tmp = cfpkt_extr_head_u8(pkt)) {
+			if (cp >= (u8 *)linkparam.u.rfm.volume +
+			    sizeof(linkparam.u.rfm.volume) - 1) {
+				pr_warn("Request reject, volume name length exceeds %zu\n",
+					sizeof(linkparam.u.rfm.volume));
+				cmdrsp |= CFCTRL_ERR_BIT;
+				break;
+			}
 			*cp++ = tmp;
+		}
 		*cp = '\0';
 
 		if (CFCTRL_ERR_BIT & cmdrsp)
-- 
2.50.1
Re: [PATCH v4] net: caif: fix stack out-of-bounds write in cfctrl_link_setup()
Posted by Paolo Abeni 2 hours ago
On 3/30/26 8:53 AM, Kangzheng Gu wrote:
> diff --git a/net/caif/cfctrl.c b/net/caif/cfctrl.c
> index c6cc2bfed65d..373ab1dc67a7 100644
> --- a/net/caif/cfctrl.c
> +++ b/net/caif/cfctrl.c
> @@ -416,8 +416,16 @@ static int cfctrl_link_setup(struct cfctrl *cfctrl, struct cfpkt *pkt, u8 cmdrsp
>  		cp = (u8 *) linkparam.u.rfm.volume;
>  		for (tmp = cfpkt_extr_head_u8(pkt);
>  		     cfpkt_more(pkt) && tmp != '\0';
> -		     tmp = cfpkt_extr_head_u8(pkt))
> +		     tmp = cfpkt_extr_head_u8(pkt)) {
> +			if (cp >= (u8 *)linkparam.u.rfm.volume +
> +			    sizeof(linkparam.u.rfm.volume) - 1) {
> +				pr_warn("Request reject, volume name length exceeds %zu\n",
> +					sizeof(linkparam.u.rfm.volume));

It looks like this printk is remotely triggerable from each incoming
(malformed) packet. It should be rate-limited.

Thanks,

Paolo