→ wens: array 是 struct xxx XXX[N] 宣告? copy_to_user 呼叫方法呢03/27 16:17
→ wens: 要問 code 就要把 code 貼出來,不要請人隔空抓藥...03/27 16:18
→ dces4212: 抱歉 原本想說只是個很直觀的array of struct跟struct03/27 20:41
→ dces4212: 的配置差別 所以就沒貼上來,等等補上!03/27 20:41
※ 編輯: dces4212 (140.128.72.6), 03/27/2019 20:54:24
→ wens: 不太相干的事情: 不要用 VLA, 很容易爆 stack03/28 00:17
→ dces4212: 有爆過了哈哈 慘死 要做完整應該會根據資料結構算個上限03/28 00:28
→ dces4212: 16 KB真的不小心就爆掉..,只是現在遇到這問題實在不解.03/28 00:29
→ wens: 你出現錯誤的時候 g 是多少? 我覺得可能是你 stack 爆了去踩03/28 00:35
→ wens: 到 text section ...03/28 00:35
→ wens: 看 mm/usercopy.c 應該是沒大到踩到 text section 不然錯誤03/28 00:49
→ wens: 訊息不太一樣,而且中間踩到 unmapped page 應該會先炸03/28 00:50
→ wens: 看起來像是 x86 上超出 stack frame 之類的03/28 00:51
→ wens: 乖乖用 kmalloc 吧03/28 00:51
只要用array of struct當copy_to_user()的arg就一次都沒成功過(g範圍是0~100),但只
要單用struct就不會出問題。會考慮kmalloc的,感謝。目前推測觸發BUG()的地方是這裡
(因為就連g很小的時候都有問題,就不太可能是#L50的檢查了)
(https://elixir.bootlin.com/linux/v4.15.18/source/mm/usercopy.c#L54),#L54做的
檢查其實看不太懂,#L50已經檢查過是否要複製的範圍在stack內,不知道這個是不是檢
查是否為stack內可存取的記憶體,註解寫的if object is safely感覺又不太像這意思,
不知道大大有啥看法。
※ 編輯: dces4212 (49.213.161.228), 03/28/2019 01:13:03
→ wens: 對吼... 應該要請你附 backtrace 跟解析過的行數才對XD03/28 10:52
→ wens: arch_within_stack_frames 好像 x86 才有實作03/28 10:52
→ dces4212: backtrace 是指 call stack 跟dump出的register那些嗎03/28 13:24
→ dces4212: 應該是只有x86有這實作 arch/下只看到x8603/28 13:32
→ wens: 對啊 # backtrace 是指 call stack 跟dump出的register03/28 15:56
了解!
[ 4167.013170] usercopy: kernel memory exposure attempt detected from
00000000e7ee16e5 (<process stack>) (16 bytes)
[ 4167.013177] ------------[ cut here ]------------
[ 4167.013178] kernel BUG at
/build/linux-7kdHqT/linux-4.15.0/mm/usercopy.c:72!
[ 4167.013183] invalid opcode: 0000 [#1] SMP PTI
[ 4167.013184] Modules linked in: fibdrv(OE)....(已省略)
[ 4167.013262] CPU: 1 PID: 16325 Comm: client Tainted: G W OE
4.15.0-46-generic #49-Ubuntu
[ 4167.013263] Hardware name: ASUSTeK COMPUTER INC. UX430UN/UX430UN, BIOS
UX430UN.302 11/28/2017
[ 4167.013268] RIP: 0010:__check_object_size+0x123/0x1b0
[ 4167.013269] RSP: 0018:ffffbc64858f7e08 EFLAGS: 00010286
[ 4167.013271] RAX: 0000000000000064 RBX: 0000000000000010 RCX:
0000000000000006
[ 4167.013273] RDX: 0000000000000000 RSI: 0000000000000092 RDI:
ffff9ac0eec96490
[ 4167.013274] RBP: ffffbc64858f7e28 R08: 0000000000000000 R09:
0000000000001831
[ 4167.013275] R10: 0000000000000000 R11: ffffffffaff5380d R12:
0000000000000001
[ 4167.013276] R13: ffffbc64858f7e38 R14: ffffbc64858f7e28 R15:
1ffff78c90b1efc7
[ 4167.013278] FS: 00007ff1e9d3d500(0000) GS:ffff9ac0eec80000(0000)
knlGS:0000000000000000
[ 4167.013279] CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033
[ 4167.013281] CR2: 00007fffc3d96080 CR3: 00000003d28fe006 CR4:
00000000003606e0
[ 4167.013282] Call Trace:
[ 4167.013288] fib_read+0x159/0x197 [fibdrv]
[ 4167.013290] ? fib_read+0x34/0x197 [fibdrv]
[ 4167.013293] __vfs_read+0x1b/0x40
[ 4167.013294] vfs_read+0x8e/0x130
[ 4167.013296] SyS_read+0x55/0xc0
[ 4167.013300] do_syscall_64+0x73/0x130
[ 4167.013303] entry_SYSCALL_64_after_hwframe+0x3d/0xa2
[ 4167.013305] RIP: 0033:0x7ff1e9861081
[ 4167.013306] RSP: 002b:00007fffc3d51638 EFLAGS: 00000246 ORIG_RAX:
0000000000000000
[ 4167.013308] RAX: ffffffffffffffda RBX: 0000000000000000 RCX:
00007ff1e9861081
[ 4167.013309] RDX: 0000000000000010 RSI: 00007fffc3d51650 RDI:
0000000000000003
[ 4167.013310] RBP: 00007fffc3d516a0 R08: 00007ff1e9b3dd80 R09:
00007ff1e9b3dd80
[ 4167.013311] R10: 00007fffc3d51620 R11: 0000000000000246 R12:
000055f6d8e947c0
[ 4167.013313] R13: 00007fffc3d51780 R14: 0000000000000000 R15:
0000000000000000
[ 4167.013314] Code: 48 0f 45 d1 48 c7 c6 53 f2 6d af 48 c7 c1 ef ff 6e af 48
0f 45 f1 49 89 d9 49 89 c0 4c 89 f1 48 c7 c7 f8 ff 6e af e8 fd dd e7 ff <0f>
0b f3 c3 48 8b 3d 82 18 1a 01 48 8b 0d 13 99 1d 01 be 00 00
[ 4167.013369] RIP: __check_object_size+0x123/0x1b0 RSP: ffffbc64858f7e08
※ 編輯: dces4212 (49.213.161.228), 03/28/2019 21:31:09
→ dces4212: 補充一下,copy_to_user只有在fib__sequence用到03/28 21:32
→ xam: struct U64 fib[g + 1] 為什麼你這樣寫編譯會過?03/31 04:31
推 yvb: 樓上: google: VLA c9903/31 10:04
→ yvb: 回原PO: 你確認過 wens 在 8 樓的問題了嗎?03/31 10:06
→ yvb: g=0 時, fib[0-1] => fib[-1] 是該被 usercopy 報 BUG(),03/31 10:09
→ yvb: 但你確定 g=1 到 g=100 也報 BUG() ? 03/31 10:10
推 xam: 看起來kernel對vla的支援還有點問題03/31 10:11
→ yvb: 另外, 既然for(...k<=g...)算到 fib[g], 為何是回 fib[g-1]?03/31 10:14
→ yvb: @xam: 嗯,要看原PO用的是gcc還是clang.若是clang也許有問題.03/31 10:33
→ yvb: 又, 原PO用的是4.15, 要4.20才有設-Wvla對VLA給warning.03/31 10:38
→ yvb: @xam: 又看了一下那篇,指的是struct的member用到VLA有問題,03/31 10:44
→ yvb: 而原PO的VLA是C99-style,所以clang支援.03/31 10:47
→ yvb: 至於第1點, 只是 overhead 問題; 但第3點就不大明暸了...03/31 10:54
→ yvb: 猜測是要做陣列大小檢查(還是直接改用kmalloc乾脆XD).03/31 11:01
→ xam: 用了 kmalloc 就是避用 vla 啊03/31 11:03
→ yvb: 是說原PO的 fib[g+1] 其實大小只要 fib[3], 撘配 % 運算即可.03/31 11:03
→ xam: 然後我猜直接 struct U64 fib[101] 應該也會正常.... 03/31 11:05
發現有意思的地方了...,g=0的時候只要用tmp=fib[-1]再把tmp餵給copy_to_user就不會
觸發BUG(),但假如直接餵fib[-1]給copy_to_user就會panic。推測先餵給tmp這邊沒有檢
查是否非法存取所以沒事(目前在userspace測試只能往後拿到6KB左右的資料,之後就被
seg fault了,而kernel space是比較有趣的地方,只要我不把往後拿拿到的資料餵給
copy_to_user,我往後-20000 * 16 byte (struct大小為16bytes)都可以拿到,但假如要
傳到userspace我只能在stack frame(16KB)內偷資料,只要超過就會被panic,這邊很怪
的
地方是kernel怎知道我這tmp裡面偷拿了甚至超過stack frame(16KB)的資料,目前猜測是
kernel 自己有個trap之類的機制隨時在監測是否有access violation)。
另外我是用GCC編譯的。
感謝兩位大大,讓我知道根本不是array of struct跟struct記憶體配置差別,是我自己
在copy_to_user面前非法存取了哈哈。
※ 編輯: dces4212 (49.213.161.228), 03/31/2019 21:25:14
→ dces4212: 另外我發現我在g=0 時,fib[1].lsl = 1;這段expression03/31 21:27
→ dces4212: 也非法存取了.. 只是沒有panic03/31 21:28
忘記補充一點,剛剛測試發現當g=0的時候我對fib[0]賦值後再使用copy_to_user會發生
copy失敗的問題(copy_to_user回傳了16 bytes),蠻怪的..,g>0後都可以正常複製。
※ 編輯: dces4212 (49.213.161.228), 03/31/2019 22:05:31
推 yvb: 觸發BUG()就是因為arch_within_stack_frames()回傳BAD_STACK.04/04 12:11
→ yvb: 超過16KB被panic: google "虛擬記憶體" "MMU" "分頁表" 幾項.04/04 12:12
→ yvb: fib[1].lsl = 1 可能寫到其它變數(a,tmp,k), 或變數間有空區.04/04 12:12
→ yvb: 至於 fib[0]賦值後 copy失敗 ==> 程式碼是修改成怎樣? 04/04 12:13
程式碼幾乎一樣,一開始是發現g=0時userspace拿到的資料是0(應為1,fib[0]=1),這時
候覺得很奇怪所以就加個if(g=0) {printk(當下的fib[0].msl, lsl 還有copy_to_user的
ret val)},然後發現fib在kernelspace是有拿到1的,還有copy_to_user的ret是16(複製
失敗大小,成功應為0),差不多是這樣。手機排版,sorry.
※ 編輯: dces4212 (101.10.82.251), 04/05/2019 16:00:31
推 yvb: 所以 g==0 時, 依舊會執行 fib[1].lsl = 1; 的意思?04/09 13:07
→ yvb: 或許上述 assignment 恰巧改寫到 copy_to_user(buf, ...) 中 04/09 13:08
→ yvb: buf 的位址? 編譯器產生怎樣的 obj 不是光看 src 就可得知的.04/09 13:08
→ yvb: 若是已避掉非法存取, 似乎沒道理發生問題, 除非編譯器有bug?04/09 13:12
沒錯,fib[1].lsl=1;這段每次都會執行到。剛測試了一下,發現確實是這個assigment去
改到buf的內容,會確定的原因挺詭異的,我最先是在assigment前後放printk看buf的內
容,然後只要我保留那段assigment,我新加的printk就會導致panic,而一旦我把那段
assigment 移掉,printk就正常印出位置了...,看來是非法寫入後又嘗試讀取相關記憶
體導致的,這跟之前說tmp偷到的資料只要不copy_to_user就沒事有差不多的概念..,挺
好奇kernel是怎做這個檢查的..,因為這不是直接觸發BUG(),不知道y大有什麼看法?
感謝大大!
※ 編輯: dces4212 (49.213.161.228), 04/12/2019 03:10:28
※ 編輯: dces4212 (49.213.161.228), 04/12/2019 03:11:12
推 yvb: 就如前幾句說的, obj code 不是光看 src code 就可得知的.04/16 20:26
→ yvb: 或許 objdump -S 搭配 panic 訊息可窺之一二 (也或許不能).04/16 20:27
→ yvb: 另外, 是用什麼參數印 buf? &fib[1].lsl 及 &buf 又各是多少?04/16 20:28
了解,感謝y大。
用的參數是%p, &fib[1].lsl 及 &buf 都落在0x0~0xffffffff間(多次測試)
→ zack2004: 想知道為什麼原PO要用VLA?目的是什麼?04/24 20:54
→ zack2004: Linux kernel目前已禁用VLA。且從需求來看,這函式不需04/24 20:55
→ zack2004: 要不定長度的暫存空間。04/24 20:56
感謝z大提醒,這是作業,預期是會有不同項的費氏數列輸入,並且在計算過程中一一印
出每一項的結果,其實也可以不用VLA來實做的。
※ 編輯: dces4212 (49.213.161.228), 04/26/2019 05:02:50
※ 編輯: dces4212 (101.9.132.120), 04/26/2019 05:15:12
→ dces4212: 忽然想到好像不該用%p 04/26 05:23
→ dces4212: -formats.txt 04/26 05:23
→ dces4212: 用px pK可能比較妥 04/26 05:24