From: Hauke Mehrtens Date: Mon, 13 Oct 2025 22:32:26 +0000 (+0200) Subject: ltq-ptm: Fix unprivileged local user memory read and write X-Git-Tag: v24.10.4~19 X-Git-Url: http://git.openwrt.org/?a=commitdiff_plain;h=e001b31163a77683ee741d169f794cfa50926f37;p=openwrt%2Fopenwrt.git ltq-ptm: Fix unprivileged local user memory read and write Use the copy_from_user() and copy_to_user() functions for accessing memory provided by the user in the ptm netdev iotls. In addition also check for root permission before executing ioctl. Suggested-by: Stanislav Fort from Aisle Research Reported-by: Stanislav Fort from Aisle Research Signed-off-by: Hauke Mehrtens (cherry picked from commit 2a76abc5442e3f74d95b4caa9bb57e5488fc132e) --- diff --git a/package/kernel/lantiq/ltq-ptm/patches/100-fix-compilation-warning-debugfs.patch b/package/kernel/lantiq/ltq-ptm/patches/100-fix-compilation-warning-debugfs.patch index 7317d51163..94de9a67b3 100644 --- a/package/kernel/lantiq/ltq-ptm/patches/100-fix-compilation-warning-debugfs.patch +++ b/package/kernel/lantiq/ltq-ptm/patches/100-fix-compilation-warning-debugfs.patch @@ -1,6 +1,6 @@ --- a/ifxmips_ptm_adsl.c +++ b/ifxmips_ptm_adsl.c -@@ -175,9 +175,11 @@ static INLINE void mailbox_signal(unsign +@@ -177,9 +177,11 @@ static INLINE void mailbox_signal(unsign */ static INLINE void proc_file_create(void); static INLINE void proc_file_delete(void); @@ -12,7 +12,7 @@ #if defined(ENABLE_FW_PROC) && ENABLE_FW_PROC static int proc_read_genconf(char *, char **, off_t, int, int *, void *); #endif -@@ -896,6 +898,7 @@ static INLINE void proc_file_delete(void +@@ -927,6 +929,7 @@ static INLINE void proc_file_delete(void remove_proc_entry("driver/ifx_ptm", NULL); } @@ -20,7 +20,7 @@ static int proc_read_version(char *buf, char **start, off_t offset, int count, int *eof, void *data) { int len = 0; -@@ -970,8 +973,9 @@ static int proc_write_wanmib(struct file +@@ -1001,8 +1004,9 @@ static int proc_write_wanmib(struct file return count; } diff --git a/package/kernel/lantiq/ltq-ptm/patches/101-fix-more-compilation-warning-debugfs.patch b/package/kernel/lantiq/ltq-ptm/patches/101-fix-more-compilation-warning-debugfs.patch index 538d569cbe..a42dc9d56a 100644 --- a/package/kernel/lantiq/ltq-ptm/patches/101-fix-more-compilation-warning-debugfs.patch +++ b/package/kernel/lantiq/ltq-ptm/patches/101-fix-more-compilation-warning-debugfs.patch @@ -1,6 +1,6 @@ --- a/ifxmips_ptm_adsl.c +++ b/ifxmips_ptm_adsl.c -@@ -180,7 +180,7 @@ static int proc_read_version(char *, cha +@@ -182,7 +182,7 @@ static int proc_read_version(char *, cha static int proc_read_wanmib(char *, char **, off_t, int, int *, void *); static int proc_write_wanmib(struct file *, const char *, unsigned long, void *); #endif @@ -9,7 +9,7 @@ static int proc_read_genconf(char *, char **, off_t, int, int *, void *); #endif #if defined(ENABLE_DBG_PROC) && ENABLE_DBG_PROC -@@ -191,8 +191,8 @@ static int proc_write_wanmib(struct file +@@ -193,8 +193,8 @@ static int proc_write_wanmib(struct file /* * Proc Help Functions */ @@ -19,7 +19,7 @@ static INLINE int strincmp(const char *, const char *, int); #endif static INLINE int ifx_ptm_version(char *); -@@ -1166,8 +1166,6 @@ static int proc_write_dbg(struct file *f +@@ -1197,8 +1197,6 @@ static int proc_write_dbg(struct file *f return count; } @@ -28,7 +28,7 @@ static INLINE int stricmp(const char *p1, const char *p2) { int c1, c2; -@@ -1185,7 +1183,6 @@ static INLINE int stricmp(const char *p1 +@@ -1216,7 +1214,6 @@ static INLINE int stricmp(const char *p1 return *p1 - *p2; } diff --git a/package/kernel/lantiq/ltq-ptm/src/ifxmips_ptm_adsl.c b/package/kernel/lantiq/ltq-ptm/src/ifxmips_ptm_adsl.c index 5e5535348d..05e8106984 100644 --- a/package/kernel/lantiq/ltq-ptm/src/ifxmips_ptm_adsl.c +++ b/package/kernel/lantiq/ltq-ptm/src/ifxmips_ptm_adsl.c @@ -46,6 +46,8 @@ #include #include #include +#include +#include #include /* @@ -463,56 +465,85 @@ static int ptm_ioctl(struct net_device *dev, struct ifreq *ifr, void __user *dat { int ndev; + if (!capable(CAP_NET_ADMIN)) + return -EPERM; + for ( ndev = 0; ndev < ARRAY_SIZE(g_net_dev) && g_net_dev[ndev] != dev; ndev++ ); ASSERT(ndev >= 0 && ndev < ARRAY_SIZE(g_net_dev), "ndev = %d (wrong value)", ndev); switch ( cmd ) { case IFX_PTM_MIB_CW_GET: - ((PTM_CW_IF_ENTRY_T *)data)->ifRxNoIdleCodewords = WAN_MIB_TABLE[ndev].wrx_nonidle_cw; - ((PTM_CW_IF_ENTRY_T *)data)->ifRxIdleCodewords = WAN_MIB_TABLE[ndev].wrx_idle_cw; - ((PTM_CW_IF_ENTRY_T *)data)->ifRxCodingViolation = WAN_MIB_TABLE[ndev].wrx_err_cw; - ((PTM_CW_IF_ENTRY_T *)data)->ifTxNoIdleCodewords = 0; - ((PTM_CW_IF_ENTRY_T *)data)->ifTxIdleCodewords = 0; - break; - case IFX_PTM_MIB_FRAME_GET: - ((PTM_FRAME_MIB_T *)data)->RxCorrect = WAN_MIB_TABLE[ndev].wrx_correct_pdu; - ((PTM_FRAME_MIB_T *)data)->TC_CrcError = WAN_MIB_TABLE[ndev].wrx_tccrc_err_pdu; - ((PTM_FRAME_MIB_T *)data)->RxDropped = WAN_MIB_TABLE[ndev].wrx_nodesc_drop_pdu + WAN_MIB_TABLE[ndev].wrx_len_violation_drop_pdu; - ((PTM_FRAME_MIB_T *)data)->TxSend = WAN_MIB_TABLE[ndev].wtx_total_pdu; - break; - case IFX_PTM_CFG_GET: - ((IFX_PTM_CFG_T *)data)->RxEthCrcPresent = CFG_ETH_EFMTC_CRC->rx_eth_crc_present; - ((IFX_PTM_CFG_T *)data)->RxEthCrcCheck = CFG_ETH_EFMTC_CRC->rx_eth_crc_check; - ((IFX_PTM_CFG_T *)data)->RxTcCrcCheck = CFG_ETH_EFMTC_CRC->rx_tc_crc_check; - ((IFX_PTM_CFG_T *)data)->RxTcCrcLen = CFG_ETH_EFMTC_CRC->rx_tc_crc_len; - ((IFX_PTM_CFG_T *)data)->TxEthCrcGen = CFG_ETH_EFMTC_CRC->tx_eth_crc_gen; - ((IFX_PTM_CFG_T *)data)->TxTcCrcGen = CFG_ETH_EFMTC_CRC->tx_tc_crc_gen; - ((IFX_PTM_CFG_T *)data)->TxTcCrcLen = CFG_ETH_EFMTC_CRC->tx_tc_crc_len; - break; - case IFX_PTM_CFG_SET: - CFG_ETH_EFMTC_CRC->rx_eth_crc_present = ((IFX_PTM_CFG_T *)data)->RxEthCrcPresent ? 1 : 0; - CFG_ETH_EFMTC_CRC->rx_eth_crc_check = ((IFX_PTM_CFG_T *)data)->RxEthCrcCheck ? 1 : 0; - if ( ((IFX_PTM_CFG_T *)data)->RxTcCrcCheck && (((IFX_PTM_CFG_T *)data)->RxTcCrcLen == 16 || ((IFX_PTM_CFG_T *)data)->RxTcCrcLen == 32) ) { - CFG_ETH_EFMTC_CRC->rx_tc_crc_check = 1; - CFG_ETH_EFMTC_CRC->rx_tc_crc_len = ((IFX_PTM_CFG_T *)data)->RxTcCrcLen; + PTM_CW_IF_ENTRY_T tmp = {0}; + + tmp.ifRxNoIdleCodewords = WAN_MIB_TABLE[ndev].wrx_nonidle_cw; + tmp.ifRxIdleCodewords = WAN_MIB_TABLE[ndev].wrx_idle_cw; + tmp.ifRxCodingViolation = WAN_MIB_TABLE[ndev].wrx_err_cw; + tmp.ifTxNoIdleCodewords = 0; + tmp.ifTxIdleCodewords = 0; + + if (copy_to_user(data, &tmp, sizeof(tmp))) + return -EFAULT; } - else + break; + case IFX_PTM_MIB_FRAME_GET: { - CFG_ETH_EFMTC_CRC->rx_tc_crc_check = 0; - CFG_ETH_EFMTC_CRC->rx_tc_crc_len = 0; + PTM_FRAME_MIB_T tmp = {0}; + + tmp.RxCorrect = WAN_MIB_TABLE[ndev].wrx_correct_pdu; + tmp.TC_CrcError = WAN_MIB_TABLE[ndev].wrx_tccrc_err_pdu; + tmp.RxDropped = WAN_MIB_TABLE[ndev].wrx_nodesc_drop_pdu + WAN_MIB_TABLE[ndev].wrx_len_violation_drop_pdu; + tmp.TxSend = WAN_MIB_TABLE[ndev].wtx_total_pdu; + if (copy_to_user(data, &tmp, sizeof(tmp))) + return -EFAULT; } - CFG_ETH_EFMTC_CRC->tx_eth_crc_gen = ((IFX_PTM_CFG_T *)data)->TxEthCrcGen ? 1 : 0; - if ( ((IFX_PTM_CFG_T *)data)->TxTcCrcGen && (((IFX_PTM_CFG_T *)data)->TxTcCrcLen == 16 || ((IFX_PTM_CFG_T *)data)->TxTcCrcLen == 32) ) + break; + case IFX_PTM_CFG_GET: { - CFG_ETH_EFMTC_CRC->tx_tc_crc_gen = 1; - CFG_ETH_EFMTC_CRC->tx_tc_crc_len = ((IFX_PTM_CFG_T *)data)->TxTcCrcLen; + IFX_PTM_CFG_T tmp = {0}; + + tmp.RxEthCrcPresent = CFG_ETH_EFMTC_CRC->rx_eth_crc_present; + tmp.RxEthCrcCheck = CFG_ETH_EFMTC_CRC->rx_eth_crc_check; + tmp.RxTcCrcCheck = CFG_ETH_EFMTC_CRC->rx_tc_crc_check; + tmp.RxTcCrcLen = CFG_ETH_EFMTC_CRC->rx_tc_crc_len; + tmp.TxEthCrcGen = CFG_ETH_EFMTC_CRC->tx_eth_crc_gen; + tmp.TxTcCrcGen = CFG_ETH_EFMTC_CRC->tx_tc_crc_gen; + tmp.TxTcCrcLen = CFG_ETH_EFMTC_CRC->tx_tc_crc_len; + if (copy_to_user(data, &tmp, sizeof(tmp))) + return -EFAULT; } - else + break; + case IFX_PTM_CFG_SET: { - CFG_ETH_EFMTC_CRC->tx_tc_crc_gen = 0; - CFG_ETH_EFMTC_CRC->tx_tc_crc_len = 0; + IFX_PTM_CFG_T cfg = {0}; + + if (copy_from_user(&cfg, data, sizeof(cfg))) + return -EFAULT; + + CFG_ETH_EFMTC_CRC->rx_eth_crc_present = cfg.RxEthCrcPresent ? 1 : 0; + CFG_ETH_EFMTC_CRC->rx_eth_crc_check = cfg.RxEthCrcCheck ? 1 : 0; + if ( cfg.RxTcCrcCheck && (cfg.RxTcCrcLen == 16 || cfg.RxTcCrcLen == 32) ) + { + CFG_ETH_EFMTC_CRC->rx_tc_crc_check = 1; + CFG_ETH_EFMTC_CRC->rx_tc_crc_len = cfg.RxTcCrcLen; + } + else + { + CFG_ETH_EFMTC_CRC->rx_tc_crc_check = 0; + CFG_ETH_EFMTC_CRC->rx_tc_crc_len = 0; + } + CFG_ETH_EFMTC_CRC->tx_eth_crc_gen = cfg.TxEthCrcGen ? 1 : 0; + if ( cfg.TxTcCrcGen && (cfg.TxTcCrcLen == 16 || cfg.TxTcCrcLen == 32) ) + { + CFG_ETH_EFMTC_CRC->tx_tc_crc_gen = 1; + CFG_ETH_EFMTC_CRC->tx_tc_crc_len = cfg.TxTcCrcLen; + } + else + { + CFG_ETH_EFMTC_CRC->tx_tc_crc_gen = 0; + CFG_ETH_EFMTC_CRC->tx_tc_crc_len = 0; + } } break; default: diff --git a/package/kernel/lantiq/ltq-ptm/src/ifxmips_ptm_vdsl.c b/package/kernel/lantiq/ltq-ptm/src/ifxmips_ptm_vdsl.c index c5bbd9fd87..edd4108de1 100644 --- a/package/kernel/lantiq/ltq-ptm/src/ifxmips_ptm_vdsl.c +++ b/package/kernel/lantiq/ltq-ptm/src/ifxmips_ptm_vdsl.c @@ -381,14 +381,24 @@ static int ptm_ioctl(struct net_device *dev, struct ifreq *ifr, void __user *dat { ASSERT(dev == g_net_dev[0], "incorrect device"); + if (!capable(CAP_NET_ADMIN)) + return -EPERM; + switch ( cmd ) { case IFX_PTM_MIB_CW_GET: - ((PTM_CW_IF_ENTRY_T *)data)->ifRxNoIdleCodewords = IFX_REG_R32(DREG_AR_CELL0) + IFX_REG_R32(DREG_AR_CELL1); - ((PTM_CW_IF_ENTRY_T *)data)->ifRxIdleCodewords = IFX_REG_R32(DREG_AR_IDLE_CNT0) + IFX_REG_R32(DREG_AR_IDLE_CNT1); - ((PTM_CW_IF_ENTRY_T *)data)->ifRxCodingViolation = IFX_REG_R32(DREG_AR_CVN_CNT0) + IFX_REG_R32(DREG_AR_CVN_CNT1) + IFX_REG_R32(DREG_AR_CVNP_CNT0) + IFX_REG_R32(DREG_AR_CVNP_CNT1); - ((PTM_CW_IF_ENTRY_T *)data)->ifTxNoIdleCodewords = IFX_REG_R32(DREG_AT_CELL0) + IFX_REG_R32(DREG_AT_CELL1); - ((PTM_CW_IF_ENTRY_T *)data)->ifTxIdleCodewords = IFX_REG_R32(DREG_AT_IDLE_CNT0) + IFX_REG_R32(DREG_AT_IDLE_CNT1); + { + PTM_CW_IF_ENTRY_T tmp = {0}; + + tmp.ifRxNoIdleCodewords = IFX_REG_R32(DREG_AR_CELL0) + IFX_REG_R32(DREG_AR_CELL1); + tmp.ifRxIdleCodewords = IFX_REG_R32(DREG_AR_IDLE_CNT0) + IFX_REG_R32(DREG_AR_IDLE_CNT1); + tmp.ifRxCodingViolation = IFX_REG_R32(DREG_AR_CVN_CNT0) + IFX_REG_R32(DREG_AR_CVN_CNT1) + IFX_REG_R32(DREG_AR_CVNP_CNT0) + IFX_REG_R32(DREG_AR_CVNP_CNT1); + tmp.ifTxNoIdleCodewords = IFX_REG_R32(DREG_AT_CELL0) + IFX_REG_R32(DREG_AT_CELL1); + tmp.ifTxIdleCodewords = IFX_REG_R32(DREG_AT_IDLE_CNT0) + IFX_REG_R32(DREG_AT_IDLE_CNT1); + + if (copy_to_user(data, &tmp, sizeof(tmp))) + return -EFAULT; + } break; case IFX_PTM_MIB_FRAME_GET: { @@ -401,38 +411,50 @@ static int ptm_ioctl(struct net_device *dev, struct ifreq *ifr, void __user *dat for ( i = 0; i < 8; i++ ) tmp.TxSend += WAN_TX_MIB_TABLE(i)->wtx_total_pdu; - *((PTM_FRAME_MIB_T *)data) = tmp; + if (copy_to_user(data, &tmp, sizeof(tmp))) + return -EFAULT; } break; case IFX_PTM_CFG_GET: - // use bear channel 0 preemption gamma interface settings - ((IFX_PTM_CFG_T *)data)->RxEthCrcPresent = 1; - ((IFX_PTM_CFG_T *)data)->RxEthCrcCheck = RX_GAMMA_ITF_CFG(0)->rx_eth_fcs_ver_dis == 0 ? 1 : 0; - ((IFX_PTM_CFG_T *)data)->RxTcCrcCheck = RX_GAMMA_ITF_CFG(0)->rx_tc_crc_ver_dis == 0 ? 1 : 0;; - ((IFX_PTM_CFG_T *)data)->RxTcCrcLen = RX_GAMMA_ITF_CFG(0)->rx_tc_crc_size == 0 ? 0 : (RX_GAMMA_ITF_CFG(0)->rx_tc_crc_size * 16); - ((IFX_PTM_CFG_T *)data)->TxEthCrcGen = TX_GAMMA_ITF_CFG(0)->tx_eth_fcs_gen_dis == 0 ? 1 : 0; - ((IFX_PTM_CFG_T *)data)->TxTcCrcGen = TX_GAMMA_ITF_CFG(0)->tx_tc_crc_size == 0 ? 0 : 1; - ((IFX_PTM_CFG_T *)data)->TxTcCrcLen = TX_GAMMA_ITF_CFG(0)->tx_tc_crc_size == 0 ? 0 : (TX_GAMMA_ITF_CFG(0)->tx_tc_crc_size * 16); + { + IFX_PTM_CFG_T tmp = {0}; + + // use bear channel 0 preemption gamma interface settings + tmp.RxEthCrcPresent = 1; + tmp.RxEthCrcCheck = RX_GAMMA_ITF_CFG(0)->rx_eth_fcs_ver_dis == 0 ? 1 : 0; + tmp.RxTcCrcCheck = RX_GAMMA_ITF_CFG(0)->rx_tc_crc_ver_dis == 0 ? 1 : 0; + tmp.RxTcCrcLen = RX_GAMMA_ITF_CFG(0)->rx_tc_crc_size == 0 ? 0 : (RX_GAMMA_ITF_CFG(0)->rx_tc_crc_size * 16); + tmp.TxEthCrcGen = TX_GAMMA_ITF_CFG(0)->tx_eth_fcs_gen_dis == 0 ? 1 : 0; + tmp.TxTcCrcGen = TX_GAMMA_ITF_CFG(0)->tx_tc_crc_size == 0 ? 0 : 1; + tmp.TxTcCrcLen = TX_GAMMA_ITF_CFG(0)->tx_tc_crc_size == 0 ? 0 : (TX_GAMMA_ITF_CFG(0)->tx_tc_crc_size * 16); + + if (copy_to_user(data, &tmp, sizeof(tmp))) + return -EFAULT; + } break; case IFX_PTM_CFG_SET: { + IFX_PTM_CFG_T cfg; int i; + if (copy_from_user(&cfg, data, sizeof(cfg))) + return -EFAULT; + for ( i = 0; i < 4; i++ ) { - RX_GAMMA_ITF_CFG(i)->rx_eth_fcs_ver_dis = ((IFX_PTM_CFG_T *)data)->RxEthCrcCheck ? 0 : 1; + RX_GAMMA_ITF_CFG(i)->rx_eth_fcs_ver_dis = cfg.RxEthCrcCheck ? 0 : 1; - RX_GAMMA_ITF_CFG(0)->rx_tc_crc_ver_dis = ((IFX_PTM_CFG_T *)data)->RxTcCrcCheck ? 0 : 1; + RX_GAMMA_ITF_CFG(0)->rx_tc_crc_ver_dis = cfg.RxTcCrcCheck ? 0 : 1; - switch ( ((IFX_PTM_CFG_T *)data)->RxTcCrcLen ) { + switch ( cfg.RxTcCrcLen ) { case 16: RX_GAMMA_ITF_CFG(0)->rx_tc_crc_size = 1; break; case 32: RX_GAMMA_ITF_CFG(0)->rx_tc_crc_size = 2; break; default: RX_GAMMA_ITF_CFG(0)->rx_tc_crc_size = 0; } - TX_GAMMA_ITF_CFG(0)->tx_eth_fcs_gen_dis = ((IFX_PTM_CFG_T *)data)->TxEthCrcGen ? 0 : 1; + TX_GAMMA_ITF_CFG(0)->tx_eth_fcs_gen_dis = cfg.TxEthCrcGen ? 0 : 1; - if ( ((IFX_PTM_CFG_T *)data)->TxTcCrcGen ) { - switch ( ((IFX_PTM_CFG_T *)data)->TxTcCrcLen ) { + if ( cfg.TxTcCrcGen ) { + switch ( cfg.TxTcCrcLen ) { case 16: TX_GAMMA_ITF_CFG(0)->tx_tc_crc_size = 1; break; case 32: TX_GAMMA_ITF_CFG(0)->tx_tc_crc_size = 2; break; default: TX_GAMMA_ITF_CFG(0)->tx_tc_crc_size = 0;