summaryrefslogtreecommitdiff
path: root/components
diff options
context:
space:
mode:
authorbernard <[email protected]>2026-08-23 10:09:34 +0800
committerRbb666 <[email protected]>2026-08-30 20:55:20 +0800
commitc5ead8254e6f36465c75bb1e08efd099e4a1ac7a (patch)
tree8b914c12ec220c40e61c3e932d24144333b541b4 /components
parent9019e5b59420fc567e0b63e3270cf09068493959 (diff)
[components][serial] Harden RT-Smart serial ioctl arguments
在 v1/v2 串口文件边界复制已知用户参数,补齐 v2 unread count 和 termios 缓冲区保护。 在 imx6ull UART 编程前校验波特率,并在硬件配置成功后提交串口状态。
Diffstat (limited to 'components')
-rw-r--r--components/drivers/serial/dev_serial.c125
-rw-r--r--components/drivers/serial/dev_serial_v2.c142
2 files changed, 258 insertions, 9 deletions
diff --git a/components/drivers/serial/dev_serial.c b/components/drivers/serial/dev_serial.c
index 45bf97c328..40c6fd333e 100644
--- a/components/drivers/serial/dev_serial.c
+++ b/components/drivers/serial/dev_serial.c
@@ -44,6 +44,10 @@
#include <unistd.h>
#include <poll.h>
#include <sys/ioctl.h>
+#ifdef RT_USING_LWP
+#include <lwp.h>
+#include <lwp_user_mm.h>
+#endif
#ifdef RT_USING_POSIX_TERMIOS
#include <termios.h>
@@ -138,6 +142,112 @@ static int serial_fops_ioctl(struct dfs_file *fd, int cmd, void *args)
break;
}
+#ifdef RT_USING_LWP
+ if (lwp_self() != RT_NULL)
+ {
+ union serial_user_ioctl_arg
+ {
+ struct serial_configure config;
+ struct winsize winsize;
+#ifdef RT_USING_POSIX_TERMIOS
+ struct termios termios;
+ struct termio termio;
+#endif
+ rt_uint16_t oflag;
+ rt_size_t unread_bytes;
+ } karg;
+ size_t arg_size = 0;
+ void *kptr = args;
+ rt_bool_t copy_in = RT_FALSE;
+ rt_bool_t copy_out = RT_FALSE;
+
+ switch ((rt_ubase_t)cmd)
+ {
+ case RT_DEVICE_CTRL_CONFIG:
+ arg_size = sizeof(karg.config);
+ kptr = &karg.config;
+ copy_in = RT_TRUE;
+ break;
+ case RT_DEVICE_CTRL_NOTIFY_SET:
+ return -RT_EPERM;
+ case RT_DEVICE_CTRL_CONSOLE_OFLAG:
+ arg_size = sizeof(karg.oflag);
+ kptr = &karg.oflag;
+ copy_out = RT_TRUE;
+ break;
+ case FIONREAD:
+ arg_size = sizeof(karg.unread_bytes);
+ kptr = &karg.unread_bytes;
+ copy_out = RT_TRUE;
+ break;
+#ifdef RT_USING_POSIX_TERMIOS
+ case TCGETA:
+ arg_size = sizeof(karg.termio);
+ kptr = &karg.termio;
+ copy_out = RT_TRUE;
+ break;
+ case TCGETS:
+ arg_size = sizeof(karg.termios);
+ kptr = &karg.termios;
+ copy_out = RT_TRUE;
+ break;
+ case TCSETA:
+ case TCSETAW:
+ case TCSETAF:
+ arg_size = sizeof(karg.termio);
+ kptr = &karg.termio;
+ copy_in = RT_TRUE;
+ break;
+ case TCSETS:
+ case TCSETSW:
+ case TCSETSF:
+ arg_size = sizeof(karg.termios);
+ kptr = &karg.termios;
+ copy_in = RT_TRUE;
+ break;
+#endif
+ case TIOCSWINSZ:
+ arg_size = sizeof(karg.winsize);
+ kptr = &karg.winsize;
+ copy_in = RT_TRUE;
+ break;
+ case TIOCGWINSZ:
+ arg_size = sizeof(karg.winsize);
+ kptr = &karg.winsize;
+ copy_out = RT_TRUE;
+ break;
+ default:
+ break;
+ }
+
+ if (arg_size)
+ {
+ int ret;
+
+ if (args == RT_NULL || !lwp_user_accessable(args, arg_size))
+ {
+ return -RT_EFAULT;
+ }
+ if (copy_in && lwp_get_from_user(kptr, args, arg_size) != arg_size)
+ {
+ return -RT_EFAULT;
+ }
+
+ ret = rt_device_control(device, cmd, kptr);
+ if (ret != RT_EOK)
+ {
+ return ret;
+ }
+
+ if (copy_out && lwp_put_to_user(args, kptr, arg_size) != arg_size)
+ {
+ return -RT_EFAULT;
+ }
+ return ret;
+ }
+ }
+#endif
+
return rt_device_control(device, cmd, args);
}
@@ -1090,13 +1200,22 @@ static rt_err_t rt_serial_control(struct rt_device *dev,
/*can not change buffer size*/
return -RT_EBUSY;
}
- /* set serial configure */
- serial->config = *pconfig;
+ if (pconfig->baud_rate == 0)
+ {
+ return -RT_EINVAL;
+ }
+
if (serial->parent.ref_count)
{
/* serial device has been opened, to configure it */
- serial->ops->configure(serial, (struct serial_configure *) args);
+ ret = serial->ops->configure(serial, pconfig);
+ if (ret != RT_EOK)
+ {
+ return ret;
+ }
}
+ /* set serial configure */
+ serial->config = *pconfig;
}
break;
case RT_DEVICE_CTRL_NOTIFY_SET:
diff --git a/components/drivers/serial/dev_serial_v2.c b/components/drivers/serial/dev_serial_v2.c
index e3adb167ea..409ffef5c3 100644
--- a/components/drivers/serial/dev_serial_v2.c
+++ b/components/drivers/serial/dev_serial_v2.c
@@ -36,6 +36,11 @@
#include <sys/ioctl.h>
#include <dfs_file.h>
+#ifdef RT_USING_LWP
+#include <lwp.h>
+#include <lwp_user_mm.h>
+#endif
+
#ifdef RT_USING_POSIX_TERMIOS
#include <termios.h>
#endif
@@ -146,6 +151,127 @@ static int serial_fops_ioctl(struct dfs_file *fd, int cmd, void *args)
break;
}
+#ifdef RT_USING_LWP
+ if (lwp_self() != RT_NULL)
+ {
+ union serial_user_ioctl_arg
+ {
+ struct serial_configure config;
+ struct winsize winsize;
+#ifdef RT_USING_POSIX_TERMIOS
+ struct termios termios;
+#endif
+ rt_uint16_t oflag;
+ rt_size_t unread_bytes;
+ rt_ssize_t unread_count;
+ rt_int32_t timeout;
+ } karg;
+ size_t arg_size = 0;
+ void *kptr = args;
+ rt_bool_t copy_in = RT_FALSE;
+ rt_bool_t copy_out = RT_FALSE;
+
+ switch ((rt_ubase_t)cmd)
+ {
+ case RT_DEVICE_CTRL_CONFIG:
+ arg_size = sizeof(karg.config);
+ kptr = &karg.config;
+ copy_in = RT_TRUE;
+ break;
+ case RT_SERIAL_CTRL_GET_CONFIG:
+ arg_size = sizeof(karg.config);
+ kptr = &karg.config;
+ copy_out = RT_TRUE;
+ break;
+ case RT_DEVICE_CTRL_NOTIFY_SET:
+ return -RT_EPERM;
+ case RT_DEVICE_CTRL_CONSOLE_OFLAG:
+ arg_size = sizeof(karg.oflag);
+ kptr = &karg.oflag;
+ copy_out = RT_TRUE;
+ break;
+ case RT_SERIAL_CTRL_SET_RX_TIMEOUT:
+ case RT_SERIAL_CTRL_SET_TX_TIMEOUT:
+ arg_size = sizeof(karg.timeout);
+ kptr = &karg.timeout;
+ copy_in = RT_TRUE;
+ break;
+ case RT_SERIAL_CTRL_GET_RX_TIMEOUT:
+ case RT_SERIAL_CTRL_GET_TX_TIMEOUT:
+ arg_size = sizeof(karg.timeout);
+ kptr = &karg.timeout;
+ copy_out = RT_TRUE;
+ break;
+ case FIONREAD:
+ arg_size = sizeof(karg.unread_bytes);
+ kptr = &karg.unread_bytes;
+ copy_out = RT_TRUE;
+ break;
+ case RT_SERIAL_CTRL_GET_UNREAD_BYTES_COUNT:
+ arg_size = sizeof(karg.unread_count);
+ kptr = &karg.unread_count;
+ copy_out = RT_TRUE;
+ break;
+#ifdef RT_USING_POSIX_TERMIOS
+ case TCGETA:
+ case TCGETS:
+ arg_size = sizeof(karg.termios);
+ kptr = &karg.termios;
+ copy_out = RT_TRUE;
+ break;
+ case TCSETA:
+ case TCSETAW:
+ case TCSETAF:
+ case TCSETS:
+ case TCSETSW:
+ case TCSETSF:
+ arg_size = sizeof(karg.termios);
+ kptr = &karg.termios;
+ copy_in = RT_TRUE;
+ break;
+#endif
+ case TIOCSWINSZ:
+ arg_size = sizeof(karg.winsize);
+ kptr = &karg.winsize;
+ copy_in = RT_TRUE;
+ break;
+ case TIOCGWINSZ:
+ arg_size = sizeof(karg.winsize);
+ kptr = &karg.winsize;
+ copy_out = RT_TRUE;
+ break;
+ default:
+ break;
+ }
+
+ if (arg_size)
+ {
+ int ret;
+
+ if (args == RT_NULL || !lwp_user_accessable(args, arg_size))
+ {
+ return -RT_EFAULT;
+ }
+ if (copy_in && lwp_get_from_user(kptr, args, arg_size) != arg_size)
+ {
+ return -RT_EFAULT;
+ }
+
+ ret = rt_device_control(device, cmd, kptr);
+ if (ret != RT_EOK)
+ {
+ return ret;
+ }
+
+ if (copy_out && lwp_put_to_user(args, kptr, arg_size) != arg_size)
+ {
+ return -RT_EFAULT;
+ }
+ return ret;
+ }
+ }
+#endif
+
return rt_device_control(device, cmd, args);
}
@@ -1440,8 +1566,6 @@ static rt_err_t rt_serial_control(struct rt_device *dev,
else
{
struct serial_configure *pconfig = (struct serial_configure *)args;
- struct serial_configure old_config = serial->config;
-
#ifdef RT_SERIAL_USING_DMA
if (rt_serial_rx_dma_event_mode_valid(pconfig->rx_dma_event_mode) != RT_TRUE)
{
@@ -1463,13 +1587,19 @@ static rt_err_t rt_serial_control(struct rt_device *dev,
break;
}
- /* set serial configure */
- serial->config = *pconfig;
- ret = serial->ops->configure(serial, (struct serial_configure *)args);
+ if (pconfig->baud_rate == 0)
+ {
+ ret = -RT_EINVAL;
+ break;
+ }
+
+ ret = serial->ops->configure(serial, pconfig);
if (ret != RT_EOK)
{
- serial->config = old_config;
+ break;
}
+ /* set serial configure */
+ serial->config = *pconfig;
}
break;
case RT_SERIAL_CTRL_GET_CONFIG: