diff options
| author | bernard <[email protected]> | 2026-08-23 10:09:34 +0800 |
|---|---|---|
| committer | Rbb666 <[email protected]> | 2026-08-30 20:55:20 +0800 |
| commit | c5ead8254e6f36465c75bb1e08efd099e4a1ac7a (patch) | |
| tree | 8b914c12ec220c40e61c3e932d24144333b541b4 /components | |
| parent | 9019e5b59420fc567e0b63e3270cf09068493959 (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.c | 125 | ||||
| -rw-r--r-- | components/drivers/serial/dev_serial_v2.c | 142 |
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: |
