[BUG REPORT] Integer overflow in `page_align_up`
描述错误/Describe the bug
There is an integer overflow in page_align_up() at kernel/src/libs/align.rs:135 when program calls memory related syscall (i.e., mmap, munmap, and mprotect) with large len.
https://github.com/DragonOS-Community/DragonOS/blob/72423f90bb39a9a3919b3630857785653c97d36c/kernel/src/libs/align.rs#L133-L136
请填写您的电脑的信息/Environment
- OS Version:Debian GNU/Linux 11
- DragonOS Version:72423f9
- DADK Version:dadk 0.2.0
- Rust Version:rustc 1.84.0-nightly (fbab78289 2024-11-04)
重现步骤/To Reproduce
- Compile a program which calls system call
munmapwith largelen
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/mman.h>
#include <unistd.h>
int main() {
void *addr = mmap(NULL, 0x1000, 0x3, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
munmap(addr, 0xffffffffffffffff);
perror("mmap error");
return EXIT_SUCCESS;
}
- Run the compiled program
期望行为/Expected behavior DragonOS should check the add behavior first and not overflow here.
屏幕截图/Log I add log before and after the alignment:
root@DragonOS:/$ /bin/overflow
[ WARN ] (src/syscall/mod.rs:626) len before align: 0xffffffffffffffff
[ WARN ] (src/syscall/mod.rs:628) len after align: 0x0
mmap error: Invalid argument
I'm trying to add check for overflow in kernel/Cargo.toml, but after adding the check I cannot enter the DragonOS.
我尝试在 kernel/Cargo.toml 中增加对 overflow 的检查,但是这样编译后无法正常进入系统:
# The release profile, used for `cargo build --release`
[profile.release]
debug = false
overflow-checks = true
cc @MemoryShore @Jomocool 麻烦看看~
但是这个貌似也是正常?Linux上面传入过大的len的话,会返回什么? @Marsman1996
但是这个貌似也是正常?Linux上面传入过大的len的话,会返回什么? @Marsman1996
以 munmap 为例,会返回 EINVAL
https://elixir.bootlin.com/linux/v6.10.5/source/mm/mmap.c#L2738
但是在 Rust 程序中,这样的溢出在 debug 模式下会导致 panic。
不过 DragonOS 似乎写死了就以 release 编译👀
kernel/src/Makefile
kernel_rust:
RUSTFLAGS="$(RUSTFLAGS)" cargo +nightly-2024-11-05 $(CARGO_ZBUILD) build --release --target $(TARGET_JSON)
这里可以考虑在内核里面加个判断啥的,实现行为上跟Linux一致? 你方便发个pr吗 @Marsman1996
这里可以考虑在内核里面加个判断啥的,实现行为上跟Linux一致? 你方便发个pr吗 @Marsman1996
👌
我没太理解,按照上面你所描述的,dragonos不也是返回了EINVAL吗? @Marsman1996
我没太理解,按照上面你所描述的,dragonos不也是返回了EINVAL吗? @Marsman1996
dragonos现在是直接返回usize吧
我没太理解,按照上面你所描述的,dragonos不也是返回了EINVAL吗? @Marsman1996
dragonos 在 align 溢出后返回 len 的值为 0x0,而在 munmap 对 len 做检查,会在 len == 0x0 时对系统返回 EINVAL
https://github.com/DragonOS-Community/DragonOS/blob/e92424df8d2ee08d0800ea9f9f7fd3e23434243d/kernel/src/mm/syscall.rs#L457-L459
也就是说虽然 dragonos 目前也是返回的 EINVAL,但是溢出已经发生了
我没太理解,按照上面你所描述的,dragonos不也是返回了EINVAL吗? @Marsman1996
dragonos 在 align 溢出后返回
len的值为0x0,而在munmap对len做检查,会在len == 0x0时对系统返回EINVALhttps://github.com/DragonOS-Community/DragonOS/blob/e92424df8d2ee08d0800ea9f9f7fd3e23434243d/kernel/src/mm/syscall.rs#L457-L459
也就是说虽然 dragonos 目前也是返回的
EINVAL,但是溢出已经发生了
那么, 在 https://github.com/DragonOS-Community/DragonOS/pull/1078 的修改后,貌似这个地方就不会返回EINVAL了。这样貌似不对?
我没太理解,按照上面你所描述的,dragonos不也是返回了EINVAL吗? @Marsman1996
dragonos 在 align 溢出后返回
len的值为0x0,而在munmap对len做检查,会在len == 0x0时对系统返回EINVALhttps://github.com/DragonOS-Community/DragonOS/blob/e92424df8d2ee08d0800ea9f9f7fd3e23434243d/kernel/src/mm/syscall.rs#L457-L459也就是说虽然 dragonos 目前也是返回的
EINVAL,但是溢出已经发生了那么, 在 #1078 的修改后,貌似这个地方就不会返回EINVAL了。这样貌似不对?
使用 wrapping_add 后,page_align_up 的
addr.wrapping_add(page_size - 1) & (!(page_size - 1))
在溢出时返回值依然是 0x0 所以还是会在上文提到的位置返回 EINVAL