diff mbox series

[net-next,v17,11/14] net: ethtool: cable-test: Target the command to the requested PHY

Message ID 20240709063039.2909536-12-maxime.chevallier@bootlin.com (mailing list archive)
State Deferred
Delegated to: Netdev Maintainers
Headers show
Series Introduce PHY listing and link_topology tracking | expand

Checks

Context Check Description
netdev/series_format success Posting correctly formatted
netdev/tree_selection success Clearly marked for net-next, async
netdev/ynl success Generated files up to date; no warnings/errors; GEN HAS DIFF 2 files changed, 911 insertions(+);
netdev/fixes_present success Fixes tag not required for -next series
netdev/header_inline success No static functions without inline keyword in header files
netdev/build_32bit success Errors and warnings before: 816 this patch: 816
netdev/build_tools success No tools touched, skip
netdev/cc_maintainers success CCed 6 of 6 maintainers
netdev/build_clang success Errors and warnings before: 821 this patch: 821
netdev/verify_signedoff success Signed-off-by tag matches author and committer
netdev/deprecated_api success None detected
netdev/check_selftest success No net selftest shell script
netdev/verify_fixes success No Fixes tag
netdev/build_allmodconfig_warn success Errors and warnings before: 821 this patch: 821
netdev/checkpatch success total: 0 errors, 0 warnings, 0 checks, 101 lines checked
netdev/build_clang_rust success No Rust files in patch. Skipping build
netdev/kdoc success Errors and warnings before: 0 this patch: 0
netdev/source_inline success Was 0 now: 0
netdev/contest success net-next-2024-07-11--18-00 (tests: 696)

Commit Message

Maxime Chevallier July 9, 2024, 6:30 a.m. UTC
Cable testing is a PHY-specific command. Instead of targeting the command
towards dev->phydev, use the request to pick the targeted PHY.

Signed-off-by: Maxime Chevallier <maxime.chevallier@bootlin.com>
---
 net/ethtool/cabletest.c | 35 ++++++++++++++++++++++-------------
 1 file changed, 22 insertions(+), 13 deletions(-)

Comments

Christophe Leroy Aug. 14, 2024, 2:32 p.m. UTC | #1
Le 09/07/2024 à 08:30, Maxime Chevallier a écrit :
> Cable testing is a PHY-specific command. Instead of targeting the command
> towards dev->phydev, use the request to pick the targeted PHY.
> 
> Signed-off-by: Maxime Chevallier <maxime.chevallier@bootlin.com>

Reviewed-by: Christophe Leroy <christophe.leroy@csgroup.eu>
Tested-by: Christophe Leroy <christophe.leroy@csgroup.eu>

> ---
>   net/ethtool/cabletest.c | 35 ++++++++++++++++++++++-------------
>   1 file changed, 22 insertions(+), 13 deletions(-)
> 
> diff --git a/net/ethtool/cabletest.c b/net/ethtool/cabletest.c
> index f6f136ec7ddf..01db8f394869 100644
> --- a/net/ethtool/cabletest.c
> +++ b/net/ethtool/cabletest.c
> @@ -13,7 +13,7 @@
>   
>   const struct nla_policy ethnl_cable_test_act_policy[] = {
>   	[ETHTOOL_A_CABLE_TEST_HEADER]		=
> -		NLA_POLICY_NESTED(ethnl_header_policy),
> +		NLA_POLICY_NESTED(ethnl_header_policy_phy),
>   };
>   
>   static int ethnl_cable_test_started(struct phy_device *phydev, u8 cmd)
> @@ -58,6 +58,7 @@ int ethnl_act_cable_test(struct sk_buff *skb, struct genl_info *info)
>   	struct ethnl_req_info req_info = {};
>   	const struct ethtool_phy_ops *ops;
>   	struct nlattr **tb = info->attrs;
> +	struct phy_device *phydev;
>   	struct net_device *dev;
>   	int ret;
>   
> @@ -69,12 +70,16 @@ int ethnl_act_cable_test(struct sk_buff *skb, struct genl_info *info)
>   		return ret;
>   
>   	dev = req_info.dev;
> -	if (!dev->phydev) {
> +
> +	rtnl_lock();
> +	phydev = ethnl_req_get_phydev(&req_info,
> +				      tb[ETHTOOL_A_CABLE_TEST_HEADER],
> +				      info->extack);
> +	if (IS_ERR_OR_NULL(phydev)) {
>   		ret = -EOPNOTSUPP;
>   		goto out_dev_put;
>   	}
>   
> -	rtnl_lock();
>   	ops = ethtool_phy_ops;
>   	if (!ops || !ops->start_cable_test) {
>   		ret = -EOPNOTSUPP;
> @@ -85,13 +90,12 @@ int ethnl_act_cable_test(struct sk_buff *skb, struct genl_info *info)
>   	if (ret < 0)
>   		goto out_rtnl;
>   
> -	ret = ops->start_cable_test(dev->phydev, info->extack);
> +	ret = ops->start_cable_test(phydev, info->extack);
>   
>   	ethnl_ops_complete(dev);
>   
>   	if (!ret)
> -		ethnl_cable_test_started(dev->phydev,
> -					 ETHTOOL_MSG_CABLE_TEST_NTF);
> +		ethnl_cable_test_started(phydev, ETHTOOL_MSG_CABLE_TEST_NTF);
>   
>   out_rtnl:
>   	rtnl_unlock();
> @@ -216,7 +220,7 @@ static const struct nla_policy cable_test_tdr_act_cfg_policy[] = {
>   
>   const struct nla_policy ethnl_cable_test_tdr_act_policy[] = {
>   	[ETHTOOL_A_CABLE_TEST_TDR_HEADER]	=
> -		NLA_POLICY_NESTED(ethnl_header_policy),
> +		NLA_POLICY_NESTED(ethnl_header_policy_phy),
>   	[ETHTOOL_A_CABLE_TEST_TDR_CFG]		= { .type = NLA_NESTED },
>   };
>   
> @@ -305,6 +309,7 @@ int ethnl_act_cable_test_tdr(struct sk_buff *skb, struct genl_info *info)
>   	struct ethnl_req_info req_info = {};
>   	const struct ethtool_phy_ops *ops;
>   	struct nlattr **tb = info->attrs;
> +	struct phy_device *phydev;
>   	struct phy_tdr_config cfg;
>   	struct net_device *dev;
>   	int ret;
> @@ -317,10 +322,6 @@ int ethnl_act_cable_test_tdr(struct sk_buff *skb, struct genl_info *info)
>   		return ret;
>   
>   	dev = req_info.dev;
> -	if (!dev->phydev) {
> -		ret = -EOPNOTSUPP;
> -		goto out_dev_put;
> -	}
>   
>   	ret = ethnl_act_cable_test_tdr_cfg(tb[ETHTOOL_A_CABLE_TEST_TDR_CFG],
>   					   info, &cfg);
> @@ -328,6 +329,14 @@ int ethnl_act_cable_test_tdr(struct sk_buff *skb, struct genl_info *info)
>   		goto out_dev_put;
>   
>   	rtnl_lock();
> +	phydev = ethnl_req_get_phydev(&req_info,
> +				      tb[ETHTOOL_A_CABLE_TEST_TDR_HEADER],
> +				      info->extack);
> +	if (!IS_ERR_OR_NULL(phydev)) {
> +		ret = -EOPNOTSUPP;
> +		goto out_dev_put;
> +	}
> +
>   	ops = ethtool_phy_ops;
>   	if (!ops || !ops->start_cable_test_tdr) {
>   		ret = -EOPNOTSUPP;
> @@ -338,12 +347,12 @@ int ethnl_act_cable_test_tdr(struct sk_buff *skb, struct genl_info *info)
>   	if (ret < 0)
>   		goto out_rtnl;
>   
> -	ret = ops->start_cable_test_tdr(dev->phydev, info->extack, &cfg);
> +	ret = ops->start_cable_test_tdr(phydev, info->extack, &cfg);
>   
>   	ethnl_ops_complete(dev);
>   
>   	if (!ret)
> -		ethnl_cable_test_started(dev->phydev,
> +		ethnl_cable_test_started(phydev,
>   					 ETHTOOL_MSG_CABLE_TEST_TDR_NTF);
>   
>   out_rtnl:
Pengfei Xu Aug. 27, 2024, 5:25 a.m. UTC | #2
Hi Maxime Chevallier,

I used syzkaller and found that: there was general protection fault in
phy_start_cable_test_tdr in Linux next:next-20240826.

Bisected and found first bad commit:
"
3688ff3077d3 net: ethtool: cable-test: Target the command to the requested PHY
"
After reverted below commit on top of next-20240826, this issue was gone.

All detailed info: https://github.com/xupengfe/syzkaller_logs/tree/main/240826_202302_phy_start_cable_test_tdr
Syzkaller repro code: https://github.com/xupengfe/syzkaller_logs/blob/main/240826_202302_phy_start_cable_test_tdr/repro.c
Syzkaller repro syscall steps: https://github.com/xupengfe/syzkaller_logs/blob/main/240826_202302_phy_start_cable_test_tdr/repro.prog
Syzkaller report: https://github.com/xupengfe/syzkaller_logs/blob/main/240826_202302_phy_start_cable_test_tdr/repro.report
Kconfig(make olddefconfig): https://github.com/xupengfe/syzkaller_logs/blob/main/240826_202302_phy_start_cable_test_tdr/kconfig_origin
Bisect info: https://github.com/xupengfe/syzkaller_logs/blob/main/240826_202302_phy_start_cable_test_tdr/bisect_info.log
bzImage: https://github.com/xupengfe/syzkaller_logs/raw/main/240826_202302_phy_start_cable_test_tdr/bzImage_1ca4237ad9ce29b0c66fe87862f1da54ac56a1e8.tar.gz
Issue dmesg: https://github.com/xupengfe/syzkaller_logs/blob/main/240826_202302_phy_start_cable_test_tdr/1ca4237ad9ce29b0c66fe87862f1da54ac56a1e8_dmesg.log

"
[   27.323262] Oops: general protection fault, probably for non-canonical address 0xdffffc00000000fe: 0000 [#1] PREEMPT SMP KASAN NOPTI
[   27.324087] KASAN: null-ptr-deref in range [0x00000000000007f0-0x00000000000007f7]
[   27.324587] CPU: 0 UID: 0 PID: 729 Comm: repro Not tainted 6.11.0-rc5-next-20240826-1ca4237ad9ce-dirty #1
[   27.325203] Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS rel-1.16.0-0-gd239552ce722-prebuilt.qemu.org 04/01/2014
[   27.325931] RIP: 0010:phy_start_cable_test_tdr+0x43/0x690
[   27.326320] Code: 48 83 ec 20 48 89 55 c0 48 89 75 c8 e8 b6 a6 1e fd 49 8d bc 24 f0 07 00 00 48 b8 00 00 00 00 00 fc ff df 48 89 fa 48 c1 ea 03 <80> 3c 02 00 0f 85 9c 05 00 00 4d 8d bc 24 e8 04 00 00 49 8b 9c 24
[   27.327485] RSP: 0018:ffff888022397370 EFLAGS: 00010202
[   27.327828] RAX: dffffc0000000000 RBX: ffff888022397560 RCX: 1ffffffff0c6423b
[   27.328291] RDX: 00000000000000fe RSI: ffffffff84482e0a RDI: 00000000000007f0
[   27.328763] RBP: ffff8880223973b8 R08: 0000000000000000 R09: ffffed1002715815
[   27.329232] R10: 0000000000000000 R11: 0000000000000005 R12: 0000000000000000
[   27.329691] R13: 0000000000000000 R14: 0000000000000000 R15: ffffffff84482de0
[   27.330155] FS:  00007ff6a8b4e740(0000) GS:ffff88806c400000(0000) knlGS:0000000000000000
[   27.330678] CS:  0010 DS: 0000 ES: 0000 CR0: 0000000080050033
[   27.331060] CR2: 00007ffc26df3eb8 CR3: 0000000020c62001 CR4: 0000000000770ef0
[   27.331529] DR0: 0000000000000000 DR1: 0000000000000000 DR2: 0000000000000000
[   27.331991] DR3: 0000000000000000 DR6: 00000000ffff07f0 DR7: 0000000000000400
[   27.332452] PKRU: 55555554
[   27.332639] Call Trace:
[   27.332808]  <TASK>
[   27.332960]  ? show_regs+0x6d/0x80
[   27.333211]  ? die_addr+0x45/0xb0
[   27.333445]  ? exc_general_protection+0x1ae/0x340
[   27.333780]  ? asm_exc_general_protection+0x2b/0x30
[   27.334120]  ? __pfx_phy_start_cable_test_tdr+0x10/0x10
[   27.334473]  ? phy_start_cable_test_tdr+0x2a/0x690
[   27.334797]  ? phy_start_cable_test_tdr+0x43/0x690
[   27.335120]  ? __sanitizer_cov_trace_const_cmp1+0x1e/0x30
[   27.335489]  ? __pfx_phy_start_cable_test_tdr+0x10/0x10
[   27.335834]  ethnl_act_cable_test_tdr+0x718/0xe70
[   27.336161]  ? __pfx_ethnl_act_cable_test_tdr+0x10/0x10
[   27.336513]  ? debug_smp_processor_id+0x20/0x30
[   27.336822]  ? __nla_parse+0x49/0x60
[   27.337087]  ? __sanitizer_cov_trace_const_cmp4+0x1a/0x20
[   27.337446]  ? genl_family_rcv_msg_attrs_parse.constprop.0+0xbc/0x2a0
[   27.337877]  genl_family_rcv_msg_doit+0x22f/0x330
[   27.338192]  ? __pfx_genl_family_rcv_msg_doit+0x10/0x10
[   27.338543]  ? cap_capable+0x1d3/0x240
[   27.338813]  ? __sanitizer_cov_trace_const_cmp4+0x1a/0x20
[   27.339173]  ? ns_capable+0xec/0x130
[   27.339425]  genl_rcv_msg+0x582/0x850
[   27.339683]  ? __pfx_genl_rcv_msg+0x10/0x10
[   27.339964]  ? __pfx_ethnl_act_cable_test_tdr+0x10/0x10
[   27.340313]  ? __this_cpu_preempt_check+0x21/0x30
[   27.340632]  ? lock_acquire.part.0+0x152/0x390
[   27.340943]  netlink_rcv_skb+0x187/0x470
[   27.341216]  ? __pfx_genl_rcv_msg+0x10/0x10
[   27.341498]  ? __pfx_netlink_rcv_skb+0x10/0x10
[   27.341809]  ? __pfx_down_read+0x10/0x10
[   27.342079]  ? netlink_deliver_tap+0x1b9/0xca0
[   27.342388]  genl_rcv+0x32/0x50
[   27.342607]  netlink_unicast+0x5a3/0x870
[   27.342878]  ? __pfx_netlink_unicast+0x10/0x10
[   27.343184]  ? __sanitizer_cov_trace_cmp8+0x1c/0x30
[   27.343514]  ? __check_object_size+0x43/0x8e0
[   27.343821]  netlink_sendmsg+0x956/0xe80
[   27.344096]  ? __pfx_netlink_sendmsg+0x10/0x10
[   27.344401]  ? __import_iovec+0x1f5/0x6c0
[   27.344686]  ? __might_fault+0xf1/0x1b0
[   27.344961]  ? __pfx_netlink_sendmsg+0x10/0x10
[   27.345268]  ____sys_sendmsg+0xaba/0xc90
[   27.345544]  ? __pfx_____sys_sendmsg+0x10/0x10
[   27.345848]  ? lock_release+0x441/0x870
[   27.346115]  ___sys_sendmsg+0x122/0x1c0
[   27.346386]  ? __pfx____sys_sendmsg+0x10/0x10
[   27.346689]  ? __pfx___lock_acquire+0x10/0x10
[   27.346987]  ? __sanitizer_cov_trace_const_cmp8+0x1c/0x30
[   27.347351]  ? put_user_ifreq+0xa5/0xc0
[   27.347614]  ? __this_cpu_preempt_check+0x21/0x30
[   27.347933]  ? __sanitizer_cov_trace_const_cmp4+0x1a/0x20
[   27.348294]  ? fdget+0x188/0x230
[   27.348531]  ? __sanitizer_cov_trace_const_cmp8+0x1c/0x30
[   27.348895]  __sys_sendmsg+0x11f/0x200
[   27.349157]  ? __pfx___sys_sendmsg+0x10/0x10
[   27.349453]  ? __this_cpu_preempt_check+0x21/0x30
[   27.349777]  ? __audit_syscall_entry+0x39c/0x500
[   27.350096]  __x64_sys_sendmsg+0x80/0xc0
[   27.350371]  ? syscall_trace_enter+0x14a/0x230
[   27.350678]  x64_sys_call+0x932/0x2140
[   27.350941]  do_syscall_64+0x6d/0x140
[   27.351199]  entry_SYSCALL_64_after_hwframe+0x76/0x7e
[   27.351543] RIP: 0033:0x7ff6a883ee5d
[   27.351791] Code: ff c3 66 2e 0f 1f 84 00 00 00 00 00 90 f3 0f 1e fa 48 89 f8 48 89 f7 48 89 d6 48 89 ca 4d 89 c2 4d 89 c8 4c 8b 4c 24 08 0f 05 <48> 3d 01 f0 ff ff 73 01 c3 48 8b 0d 93 af 1b 00 f7 d8 64 89 01 48
[   27.352965] RSP: 002b:00007ffc26df4f28 EFLAGS: 00000282 ORIG_RAX: 000000000000002e
[   27.353457] RAX: ffffffffffffffda RBX: 0000000000000000 RCX: 00007ff6a883ee5d
[   27.353916] RDX: 0000000000000000 RSI: 00000000200003c0 RDI: 0000000000000003
[   27.354429] RBP: 00007ffc26df4f40 R08: 000000000000000c R09: 000000000000000c
[   27.354874] R10: 000000000000000c R11: 0000000000000282 R12: 00007ffc26df5088
[   27.355321] R13: 000000000040257c R14: 0000000000404e08 R15: 00007ff6a8b99000
[   27.355775]  </TASK>
[   27.355923] Modules linked in:
[   27.356255] ---[ end trace 0000000000000000 ]---
"

I hope it's helpful.

---

If you don't need the following environment to reproduce the problem or if you
already have one reproduced environment, please ignore the following information.

How to reproduce:
git clone https://gitlab.com/xupengfe/repro_vm_env.git
cd repro_vm_env
tar -xvf repro_vm_env.tar.gz
cd repro_vm_env; ./start3.sh  // it needs qemu-system-x86_64 and I used v7.1.0
  // start3.sh will load bzImage_2241ab53cbb5cdb08a6b2d4688feb13971058f65 v6.2-rc5 kernel
  // You could change the bzImage_xxx as you want
  // Maybe you need to remove line "-drive if=pflash,format=raw,readonly=on,file=./OVMF_CODE.fd \" for different qemu version
You could use below command to log in, there is no password for root.
ssh -p 10023 root@localhost

After login vm(virtual machine) successfully, you could transfer reproduced
binary to the vm by below way, and reproduce the problem in vm:
gcc -pthread -o repro repro.c
scp -P 10023 repro root@localhost:/root/

Get the bzImage for target kernel:
Please use target kconfig and copy it to kernel_src/.config
make olddefconfig
make -jx bzImage           //x should equal or less than cpu num your pc has

Fill the bzImage file into above start3.sh to load the target kernel in vm.


Tips:
If you already have qemu-system-x86_64, please ignore below info.
If you want to install qemu v7.1.0 version:
git clone https://github.com/qemu/qemu.git
cd qemu
git checkout -f v7.1.0
mkdir build
cd build
yum install -y ninja-build.x86_64
yum -y install libslirp-devel.x86_64
../configure --target-list=x86_64-softmmu --enable-kvm --enable-vnc --enable-gtk --enable-sdl --enable-usb-redir --enable-slirp
make
make install

Best Regards,
Thanks!



On 2024-07-09 at 08:30:34 +0200, Maxime Chevallier wrote:
> Cable testing is a PHY-specific command. Instead of targeting the command
> towards dev->phydev, use the request to pick the targeted PHY.
> 
> Signed-off-by: Maxime Chevallier <maxime.chevallier@bootlin.com>
> ---
>  net/ethtool/cabletest.c | 35 ++++++++++++++++++++++-------------
>  1 file changed, 22 insertions(+), 13 deletions(-)
> 
> diff --git a/net/ethtool/cabletest.c b/net/ethtool/cabletest.c
> index f6f136ec7ddf..01db8f394869 100644
> --- a/net/ethtool/cabletest.c
> +++ b/net/ethtool/cabletest.c
> @@ -13,7 +13,7 @@
>  
>  const struct nla_policy ethnl_cable_test_act_policy[] = {
>  	[ETHTOOL_A_CABLE_TEST_HEADER]		=
> -		NLA_POLICY_NESTED(ethnl_header_policy),
> +		NLA_POLICY_NESTED(ethnl_header_policy_phy),
>  };
>  
>  static int ethnl_cable_test_started(struct phy_device *phydev, u8 cmd)
> @@ -58,6 +58,7 @@ int ethnl_act_cable_test(struct sk_buff *skb, struct genl_info *info)
>  	struct ethnl_req_info req_info = {};
>  	const struct ethtool_phy_ops *ops;
>  	struct nlattr **tb = info->attrs;
> +	struct phy_device *phydev;
>  	struct net_device *dev;
>  	int ret;
>  
> @@ -69,12 +70,16 @@ int ethnl_act_cable_test(struct sk_buff *skb, struct genl_info *info)
>  		return ret;
>  
>  	dev = req_info.dev;
> -	if (!dev->phydev) {
> +
> +	rtnl_lock();
> +	phydev = ethnl_req_get_phydev(&req_info,
> +				      tb[ETHTOOL_A_CABLE_TEST_HEADER],
> +				      info->extack);
> +	if (IS_ERR_OR_NULL(phydev)) {
>  		ret = -EOPNOTSUPP;
>  		goto out_dev_put;
>  	}
>  
> -	rtnl_lock();
>  	ops = ethtool_phy_ops;
>  	if (!ops || !ops->start_cable_test) {
>  		ret = -EOPNOTSUPP;
> @@ -85,13 +90,12 @@ int ethnl_act_cable_test(struct sk_buff *skb, struct genl_info *info)
>  	if (ret < 0)
>  		goto out_rtnl;
>  
> -	ret = ops->start_cable_test(dev->phydev, info->extack);
> +	ret = ops->start_cable_test(phydev, info->extack);
>  
>  	ethnl_ops_complete(dev);
>  
>  	if (!ret)
> -		ethnl_cable_test_started(dev->phydev,
> -					 ETHTOOL_MSG_CABLE_TEST_NTF);
> +		ethnl_cable_test_started(phydev, ETHTOOL_MSG_CABLE_TEST_NTF);
>  
>  out_rtnl:
>  	rtnl_unlock();
> @@ -216,7 +220,7 @@ static const struct nla_policy cable_test_tdr_act_cfg_policy[] = {
>  
>  const struct nla_policy ethnl_cable_test_tdr_act_policy[] = {
>  	[ETHTOOL_A_CABLE_TEST_TDR_HEADER]	=
> -		NLA_POLICY_NESTED(ethnl_header_policy),
> +		NLA_POLICY_NESTED(ethnl_header_policy_phy),
>  	[ETHTOOL_A_CABLE_TEST_TDR_CFG]		= { .type = NLA_NESTED },
>  };
>  
> @@ -305,6 +309,7 @@ int ethnl_act_cable_test_tdr(struct sk_buff *skb, struct genl_info *info)
>  	struct ethnl_req_info req_info = {};
>  	const struct ethtool_phy_ops *ops;
>  	struct nlattr **tb = info->attrs;
> +	struct phy_device *phydev;
>  	struct phy_tdr_config cfg;
>  	struct net_device *dev;
>  	int ret;
> @@ -317,10 +322,6 @@ int ethnl_act_cable_test_tdr(struct sk_buff *skb, struct genl_info *info)
>  		return ret;
>  
>  	dev = req_info.dev;
> -	if (!dev->phydev) {
> -		ret = -EOPNOTSUPP;
> -		goto out_dev_put;
> -	}
>  
>  	ret = ethnl_act_cable_test_tdr_cfg(tb[ETHTOOL_A_CABLE_TEST_TDR_CFG],
>  					   info, &cfg);
> @@ -328,6 +329,14 @@ int ethnl_act_cable_test_tdr(struct sk_buff *skb, struct genl_info *info)
>  		goto out_dev_put;
>  
>  	rtnl_lock();
> +	phydev = ethnl_req_get_phydev(&req_info,
> +				      tb[ETHTOOL_A_CABLE_TEST_TDR_HEADER],
> +				      info->extack);
> +	if (!IS_ERR_OR_NULL(phydev)) {
> +		ret = -EOPNOTSUPP;
> +		goto out_dev_put;
> +	}
> +
>  	ops = ethtool_phy_ops;
>  	if (!ops || !ops->start_cable_test_tdr) {
>  		ret = -EOPNOTSUPP;
> @@ -338,12 +347,12 @@ int ethnl_act_cable_test_tdr(struct sk_buff *skb, struct genl_info *info)
>  	if (ret < 0)
>  		goto out_rtnl;
>  
> -	ret = ops->start_cable_test_tdr(dev->phydev, info->extack, &cfg);
> +	ret = ops->start_cable_test_tdr(phydev, info->extack, &cfg);
>  
>  	ethnl_ops_complete(dev);
>  
>  	if (!ret)
> -		ethnl_cable_test_started(dev->phydev,
> +		ethnl_cable_test_started(phydev,
>  					 ETHTOOL_MSG_CABLE_TEST_TDR_NTF);
>  
>  out_rtnl:
> -- 
> 2.45.1
>
Maxime Chevallier Aug. 27, 2024, 5:33 a.m. UTC | #3
Hi,

On Tue, 27 Aug 2024 13:25:52 +0800
Pengfei Xu <pengfei.xu@intel.com> wrote:

> Hi Maxime Chevallier,
> 
> I used syzkaller and found that: there was general protection fault in
> phy_start_cable_test_tdr in Linux next:next-20240826.
> 
> Bisected and found first bad commit:
> "
> 3688ff3077d3 net: ethtool: cable-test: Target the command to the requested PHY
> "
> After reverted below commit on top of next-20240826, this issue was gone.
> 
> All detailed info: https://github.com/xupengfe/syzkaller_logs/tree/main/240826_202302_phy_start_cable_test_tdr
> Syzkaller repro code: https://github.com/xupengfe/syzkaller_logs/blob/main/240826_202302_phy_start_cable_test_tdr/repro.c
> Syzkaller repro syscall steps: https://github.com/xupengfe/syzkaller_logs/blob/main/240826_202302_phy_start_cable_test_tdr/repro.prog
> Syzkaller report: https://github.com/xupengfe/syzkaller_logs/blob/main/240826_202302_phy_start_cable_test_tdr/repro.report
> Kconfig(make olddefconfig): https://github.com/xupengfe/syzkaller_logs/blob/main/240826_202302_phy_start_cable_test_tdr/kconfig_origin
> Bisect info: https://github.com/xupengfe/syzkaller_logs/blob/main/240826_202302_phy_start_cable_test_tdr/bisect_info.log
> bzImage: https://github.com/xupengfe/syzkaller_logs/raw/main/240826_202302_phy_start_cable_test_tdr/bzImage_1ca4237ad9ce29b0c66fe87862f1da54ac56a1e8.tar.gz
> Issue dmesg: https://github.com/xupengfe/syzkaller_logs/blob/main/240826_202302_phy_start_cable_test_tdr/1ca4237ad9ce29b0c66fe87862f1da54ac56a1e8_dmesg.log

Thanks for the report !

This issue has indeed been detected, and is being addressed, see :

https://lore.kernel.org/netdev/20240826134656.94892-1-djahchankoike@gmail.com/

Thanks,

Maxime
Pengfei Xu Aug. 27, 2024, 6:19 a.m. UTC | #4
Hi Maxime Chevallier,

On 2024-08-27 at 07:33:59 +0200, Maxime Chevallier wrote:
> Hi,
> 
> On Tue, 27 Aug 2024 13:25:52 +0800
> Pengfei Xu <pengfei.xu@intel.com> wrote:
> 
> > Hi Maxime Chevallier,
> > 
> > I used syzkaller and found that: there was general protection fault in
> > phy_start_cable_test_tdr in Linux next:next-20240826.
> > 
> > Bisected and found first bad commit:
> > "
> > 3688ff3077d3 net: ethtool: cable-test: Target the command to the requested PHY
> > "
> > After reverted below commit on top of next-20240826, this issue was gone.
> > 
> > All detailed info: https://github.com/xupengfe/syzkaller_logs/tree/main/240826_202302_phy_start_cable_test_tdr
> > Syzkaller repro code: https://github.com/xupengfe/syzkaller_logs/blob/main/240826_202302_phy_start_cable_test_tdr/repro.c
> > Syzkaller repro syscall steps: https://github.com/xupengfe/syzkaller_logs/blob/main/240826_202302_phy_start_cable_test_tdr/repro.prog
> > Syzkaller report: https://github.com/xupengfe/syzkaller_logs/blob/main/240826_202302_phy_start_cable_test_tdr/repro.report
> > Kconfig(make olddefconfig): https://github.com/xupengfe/syzkaller_logs/blob/main/240826_202302_phy_start_cable_test_tdr/kconfig_origin
> > Bisect info: https://github.com/xupengfe/syzkaller_logs/blob/main/240826_202302_phy_start_cable_test_tdr/bisect_info.log
> > bzImage: https://github.com/xupengfe/syzkaller_logs/raw/main/240826_202302_phy_start_cable_test_tdr/bzImage_1ca4237ad9ce29b0c66fe87862f1da54ac56a1e8.tar.gz
> > Issue dmesg: https://github.com/xupengfe/syzkaller_logs/blob/main/240826_202302_phy_start_cable_test_tdr/1ca4237ad9ce29b0c66fe87862f1da54ac56a1e8_dmesg.log
> 
> Thanks for the report !
> 
> This issue has indeed been detected, and is being addressed, see :
> 
> https://lore.kernel.org/netdev/20240826134656.94892-1-djahchankoike@gmail.com/

Thanks for your sharing of the solution!

Best Regards,
Thanks!


> 
> Thanks,
> 
> Maxime
Dan Carpenter Aug. 27, 2024, 8:27 a.m. UTC | #5
On Tue, Aug 27, 2024 at 07:33:59AM +0200, Maxime Chevallier wrote:
> 
> This issue has indeed been detected, and is being addressed, see :
> 
> https://lore.kernel.org/netdev/20240826134656.94892-1-djahchankoike@gmail.com/
> 

There is a similar bug in ethnl_act_cable_test_tdr() that needs to be fixed
as well.

net/ethtool/cabletest.c
   307  int ethnl_act_cable_test_tdr(struct sk_buff *skb, struct genl_info *info)
   308  {
   309          struct ethnl_req_info req_info = {};
   310          const struct ethtool_phy_ops *ops;
   311          struct nlattr **tb = info->attrs;
   312          struct phy_device *phydev;
   313          struct phy_tdr_config cfg;
   314          struct net_device *dev;
   315          int ret;
   316  
   317          ret = ethnl_parse_header_dev_get(&req_info,
   318                                           tb[ETHTOOL_A_CABLE_TEST_TDR_HEADER],
   319                                           genl_info_net(info), info->extack,
   320                                           true);
   321          if (ret < 0)
   322                  return ret;
   323  
   324          dev = req_info.dev;
   325  
   326          ret = ethnl_act_cable_test_tdr_cfg(tb[ETHTOOL_A_CABLE_TEST_TDR_CFG],
   327                                             info, &cfg);
   328          if (ret)
   329                  goto out_dev_put;
   330  
   331          rtnl_lock();
                ^^^^^^^^^^^^

   332          phydev = ethnl_req_get_phydev(&req_info,
   333                                        tb[ETHTOOL_A_CABLE_TEST_TDR_HEADER],
   334                                        info->extack);
   335          if (!IS_ERR_OR_NULL(phydev)) {
                    ^
This test is reversed so it will lead to a crash.

Could you add some comments to ethnl_req_get_phydev() what the NULL return
means vs the error pointers?  I figured it out because the callers have comments
but it should be next to ethnl_req_get_phydev() as well.

   336                  ret = -EOPNOTSUPP;
   337                  goto out_dev_put;
   338          }
   339  
   340          ops = ethtool_phy_ops;
   341          if (!ops || !ops->start_cable_test_tdr) {
   342                  ret = -EOPNOTSUPP;
   343                  goto out_rtnl;
   344          }
   345  
   346          ret = ethnl_ops_begin(dev);
   347          if (ret < 0)
   348                  goto out_rtnl;
   349  
   350          ret = ops->start_cable_test_tdr(phydev, info->extack, &cfg);
   351  
   352          ethnl_ops_complete(dev);
   353  
   354          if (!ret)
   355                  ethnl_cable_test_started(phydev,
   356                                           ETHTOOL_MSG_CABLE_TEST_TDR_NTF);
   357  
   358  out_rtnl:
   359          rtnl_unlock();
   360  out_dev_put:
   361          ethnl_parse_header_dev_put(&req_info);
   362          return ret;
   363  }

regards,
dan carpenter
Maxime Chevallier Aug. 27, 2024, 8:37 a.m. UTC | #6
Hello Dan,

On Tue, 27 Aug 2024 11:27:48 +0300
Dan Carpenter <dan.carpenter@linaro.org> wrote:

> On Tue, Aug 27, 2024 at 07:33:59AM +0200, Maxime Chevallier wrote:
> > 
> > This issue has indeed been detected, and is being addressed, see :
> > 
> > https://lore.kernel.org/netdev/20240826134656.94892-1-djahchankoike@gmail.com/
> >   
> 
> There is a similar bug in ethnl_act_cable_test_tdr() that needs to be fixed
> as well.
> 
> net/ethtool/cabletest.c
>    307  int ethnl_act_cable_test_tdr(struct sk_buff *skb, struct genl_info *info)
>    308  {
>    309          struct ethnl_req_info req_info = {};
>    310          const struct ethtool_phy_ops *ops;
>    311          struct nlattr **tb = info->attrs;
>    312          struct phy_device *phydev;
>    313          struct phy_tdr_config cfg;
>    314          struct net_device *dev;
>    315          int ret;
>    316  
>    317          ret = ethnl_parse_header_dev_get(&req_info,
>    318                                           tb[ETHTOOL_A_CABLE_TEST_TDR_HEADER],
>    319                                           genl_info_net(info), info->extack,
>    320                                           true);
>    321          if (ret < 0)
>    322                  return ret;
>    323  
>    324          dev = req_info.dev;
>    325  
>    326          ret = ethnl_act_cable_test_tdr_cfg(tb[ETHTOOL_A_CABLE_TEST_TDR_CFG],
>    327                                             info, &cfg);
>    328          if (ret)
>    329                  goto out_dev_put;
>    330  
>    331          rtnl_lock();
>                 ^^^^^^^^^^^^
> 
>    332          phydev = ethnl_req_get_phydev(&req_info,
>    333                                        tb[ETHTOOL_A_CABLE_TEST_TDR_HEADER],
>    334                                        info->extack);
>    335          if (!IS_ERR_OR_NULL(phydev)) {
>                     ^
> This test is reversed so it will lead to a crash.
> 
> Could you add some comments to ethnl_req_get_phydev() what the NULL return
> means vs the error pointers?  I figured it out because the callers have comments
> but it should be next to ethnl_req_get_phydev() as well.

Good catch ! I'll send some followup to address this report as
well as update the doc.

Thanks,

Maxime
Maxime Chevallier Aug. 27, 2024, 8:48 a.m. UTC | #7
Hi again Dan,

On Tue, 27 Aug 2024 11:27:48 +0300
Dan Carpenter <dan.carpenter@linaro.org> wrote:


> Could you add some comments to ethnl_req_get_phydev() what the NULL return
> means vs the error pointers?  I figured it out because the callers have comments
> but it should be next to ethnl_req_get_phydev() as well.

Actually I replied a bit too fast, this is already documented :
https://git.kernel.org/pub/scm/linux/kernel/git/netdev/net-next.git/tree/net/ethtool/netlink.h#n284

Is this doc clear enough or should I still add some more explicit
comments ?

Thanks,

Maxime
Dan Carpenter Aug. 27, 2024, 9:17 a.m. UTC | #8
On Tue, Aug 27, 2024 at 10:48:25AM +0200, Maxime Chevallier wrote:
> Hi again Dan,
> 
> On Tue, 27 Aug 2024 11:27:48 +0300
> Dan Carpenter <dan.carpenter@linaro.org> wrote:
> 
> 
> > Could you add some comments to ethnl_req_get_phydev() what the NULL return
> > means vs the error pointers?  I figured it out because the callers have comments
> > but it should be next to ethnl_req_get_phydev() as well.
> 
> Actually I replied a bit too fast, this is already documented :
> https://git.kernel.org/pub/scm/linux/kernel/git/netdev/net-next.git/tree/net/ethtool/netlink.h#n284
> 
> Is this doc clear enough or should I still add some more explicit
> comments ?
> 

Ah, I didn't see that.  Thanks.

That comment is fine but we normally would have put it next to the function
implementation instead of the header file.  There are lots of comments in the
header file, sure, but those are for inline functions so it's the same rule of
thumb that the comments are next to the implementation.

regards,
dan carpenter
diff mbox series

Patch

diff --git a/net/ethtool/cabletest.c b/net/ethtool/cabletest.c
index f6f136ec7ddf..01db8f394869 100644
--- a/net/ethtool/cabletest.c
+++ b/net/ethtool/cabletest.c
@@ -13,7 +13,7 @@ 
 
 const struct nla_policy ethnl_cable_test_act_policy[] = {
 	[ETHTOOL_A_CABLE_TEST_HEADER]		=
-		NLA_POLICY_NESTED(ethnl_header_policy),
+		NLA_POLICY_NESTED(ethnl_header_policy_phy),
 };
 
 static int ethnl_cable_test_started(struct phy_device *phydev, u8 cmd)
@@ -58,6 +58,7 @@  int ethnl_act_cable_test(struct sk_buff *skb, struct genl_info *info)
 	struct ethnl_req_info req_info = {};
 	const struct ethtool_phy_ops *ops;
 	struct nlattr **tb = info->attrs;
+	struct phy_device *phydev;
 	struct net_device *dev;
 	int ret;
 
@@ -69,12 +70,16 @@  int ethnl_act_cable_test(struct sk_buff *skb, struct genl_info *info)
 		return ret;
 
 	dev = req_info.dev;
-	if (!dev->phydev) {
+
+	rtnl_lock();
+	phydev = ethnl_req_get_phydev(&req_info,
+				      tb[ETHTOOL_A_CABLE_TEST_HEADER],
+				      info->extack);
+	if (IS_ERR_OR_NULL(phydev)) {
 		ret = -EOPNOTSUPP;
 		goto out_dev_put;
 	}
 
-	rtnl_lock();
 	ops = ethtool_phy_ops;
 	if (!ops || !ops->start_cable_test) {
 		ret = -EOPNOTSUPP;
@@ -85,13 +90,12 @@  int ethnl_act_cable_test(struct sk_buff *skb, struct genl_info *info)
 	if (ret < 0)
 		goto out_rtnl;
 
-	ret = ops->start_cable_test(dev->phydev, info->extack);
+	ret = ops->start_cable_test(phydev, info->extack);
 
 	ethnl_ops_complete(dev);
 
 	if (!ret)
-		ethnl_cable_test_started(dev->phydev,
-					 ETHTOOL_MSG_CABLE_TEST_NTF);
+		ethnl_cable_test_started(phydev, ETHTOOL_MSG_CABLE_TEST_NTF);
 
 out_rtnl:
 	rtnl_unlock();
@@ -216,7 +220,7 @@  static const struct nla_policy cable_test_tdr_act_cfg_policy[] = {
 
 const struct nla_policy ethnl_cable_test_tdr_act_policy[] = {
 	[ETHTOOL_A_CABLE_TEST_TDR_HEADER]	=
-		NLA_POLICY_NESTED(ethnl_header_policy),
+		NLA_POLICY_NESTED(ethnl_header_policy_phy),
 	[ETHTOOL_A_CABLE_TEST_TDR_CFG]		= { .type = NLA_NESTED },
 };
 
@@ -305,6 +309,7 @@  int ethnl_act_cable_test_tdr(struct sk_buff *skb, struct genl_info *info)
 	struct ethnl_req_info req_info = {};
 	const struct ethtool_phy_ops *ops;
 	struct nlattr **tb = info->attrs;
+	struct phy_device *phydev;
 	struct phy_tdr_config cfg;
 	struct net_device *dev;
 	int ret;
@@ -317,10 +322,6 @@  int ethnl_act_cable_test_tdr(struct sk_buff *skb, struct genl_info *info)
 		return ret;
 
 	dev = req_info.dev;
-	if (!dev->phydev) {
-		ret = -EOPNOTSUPP;
-		goto out_dev_put;
-	}
 
 	ret = ethnl_act_cable_test_tdr_cfg(tb[ETHTOOL_A_CABLE_TEST_TDR_CFG],
 					   info, &cfg);
@@ -328,6 +329,14 @@  int ethnl_act_cable_test_tdr(struct sk_buff *skb, struct genl_info *info)
 		goto out_dev_put;
 
 	rtnl_lock();
+	phydev = ethnl_req_get_phydev(&req_info,
+				      tb[ETHTOOL_A_CABLE_TEST_TDR_HEADER],
+				      info->extack);
+	if (!IS_ERR_OR_NULL(phydev)) {
+		ret = -EOPNOTSUPP;
+		goto out_dev_put;
+	}
+
 	ops = ethtool_phy_ops;
 	if (!ops || !ops->start_cable_test_tdr) {
 		ret = -EOPNOTSUPP;
@@ -338,12 +347,12 @@  int ethnl_act_cable_test_tdr(struct sk_buff *skb, struct genl_info *info)
 	if (ret < 0)
 		goto out_rtnl;
 
-	ret = ops->start_cable_test_tdr(dev->phydev, info->extack, &cfg);
+	ret = ops->start_cable_test_tdr(phydev, info->extack, &cfg);
 
 	ethnl_ops_complete(dev);
 
 	if (!ret)
-		ethnl_cable_test_started(dev->phydev,
+		ethnl_cable_test_started(phydev,
 					 ETHTOOL_MSG_CABLE_TEST_TDR_NTF);
 
 out_rtnl: