BUG:在syscall中访问自定义结构时无法处理内核分页请求

问题描述 投票:0回答:1

使用具有4.4.21内核的Linux,我需要实现一个系统调用,该系统调用的参数之间包含一个自定义结构的指针。这些是要编辑的文件:

// in linux-4.4.21/arch/x86/entry/syscalls/syscall_64.tbl :
546 x32 procmem         sys_procmem

// in linux-4.4.21/include/linux/syscalls.h :
struct proc_segs;
asmlinkage longsys_procmem (int pid, struct proc_segs *info);

我将sys_procmem.c(实现)放入linux-4.4.21 / kernel / sys_procmem.c(该目录的Makefile中添加了sys_procmem.o):

#include <linux/linkage.h>
#include <linux/sched.h>
#include <linux/kernel.h>

struct proc_segs
{
  unsigned long stID;
};

asmlinkage long sys_procmem (int pid, struct proc_segs *info)
{
  printk("sys_procmem called \n"); // this is fine in dmesg
  info->stID = 1234567; // KILLED
  return 0;
}

测试:

#include <sys/syscall.h>
#include <unistd.h>
#include <stdio.h>

struct proc_segs
{
  unsigned long stID;
};

int main() {
  unsigned long info[10];
  long sysval = syscall(546, 1, info);
  printf("My stID : %lu\n", info[0]);
} // I have no idea why this works (or not on me), but it was included in the excercise's manual
//or:
int main() {
  struct proc_segs info;
  syscall(546, getpid(), &info);
  printf("My stID : %lu\n", info.stID);
}

两个人都惨遭杀害。

dmesg:

[ 3298.944925] sys_procmem called
[ 3298.944997] BUG: unable to handle kernel paging request at 00007ffe570aa8e0
[ 3298.945005] IP: [<ffffffff8109d540>] sys_procmem+0x140/0x280
[ 3298.945017] PGD 7a919067 PUD 790a6067 PMD 7a82f067 PTE 800000004c530867
[ 3298.945027] Oops: 0003 [#2] SMP 
[ 3298.945047] Modules linked in: bnep rfcomm bluetooth btrfs xor qxl raid6_pq snd_hda_codec_generic ttm snd_hda_intel snd_hda_codec kvm_intel drm_kms_helper snd_hda_core kvm drm snd_hwdep snd_pcm snd_seq_midi snd_seq_midi_event snd_rawmidi snd_seq snd_seq_device irqbypass snd_timer crct10dif_pclmul snd crc32_pclmul aesni_intel aes_x86_64 fb_sys_fops lrw syscopyarea glue_helper soundcore sysfillrect ablk_helper sysimgblt joydev lpc_ich cryptd input_leds serio_raw mac_hid parport_pc ppdev lp parport hid_generic usbhid hid e1000e psmouse ahci libahci virtio_blk
[ 3298.945122] CPU: 5 PID: 2752 Comm: test-procmem Tainted: G      D         4.4.21.1810887 #13
[ 3298.945126] Hardware name: QEMU Standard PC (Q35 + ICH9, 2009), BIOS ?-20191223_100556-anatol 04/01/2014
[ 3298.945130] task: ffff88002c1e96c0 ti: ffff880079f68000 task.ti: ffff880079f68000
[ 3298.945134] RIP: 0010:[<ffffffff8109d540>]  [<ffffffff8109d540>] sys_procmem+0x140/0x280
[ 3298.945142] RSP: 0018:ffff880079f6bf38  EFLAGS: 00010282
[ 3298.945145] RAX: 0000000000000024 RBX: ffff88013bb98000 RCX: 0000000000000006
[ 3298.945148] RDX: 0000000000000000 RSI: 0000000000000246 RDI: ffff88013fd4db30
[ 3298.945151] RBP: ffff880079f6bf48 R08: 000000000000000a R09: 0000000000000000
[ 3298.945154] R10: 0000000000000000 R11: 0000000000000304 R12: 00007ffe570aa8e0
[ 3298.945157] R13: 00007ffe570aaa10 R14: 0000000000000000 R15: 0000000000000000
[ 3298.945161] FS:  00007fe88da41740(0000) GS:ffff88013fd40000(0000) knlGS:0000000000000000
[ 3298.945165] CS:  0010 DS: 0000 ES: 0000 CR0: 0000000080050033
[ 3298.945168] CR2: 00007ffe570aa8e0 CR3: 000000007acb0000 CR4: 00000000003406e0
[ 3298.945177] Stack:
[ 3298.945180]  0000000000000000 0000000000400490 00007ffe570aa930 ffffffff817e7676
[ 3298.945187]  0000000000000000 0000000000000000 00007ffe570aaa10 0000000000000000
[ 3298.945196]  0000000000000000 00007fe88d82d6c8 0000000000000202 00007fe88d82ee80
[ 3298.945205] Call Trace:
[ 3298.945229]  [<ffffffff817e7676>] entry_SYSCALL_64_fastpath+0x16/0x75
[ 3298.945234] Code: 00 48 8b b0 08 01 00 00 31 c0 e8 69 b6 0d 00 48 8b 83 48 07 00 00 48 c7 c7 e4 51 aa 81 48 8b b0 18 01 00 00 31 c0 e8 4d b6 0d 00 <49> c7 04 24 c7 a1 1b 00 48 c7 c7 01 52 aa 81 31 c0 e8 37 b6 0d 
[ 3298.945315] RIP  [<ffffffff8109d540>] sys_procmem+0x140/0x280
[ 3298.945322]  RSP <ffff880079f6bf38>
[ 3298.945325] CR2: 00007ffe570aa8e0
[ 3298.945330] ---[ end trace 0b79468970c7e49f ]---

这是在64位Ubuntu 14.04虚拟机中完成的。我的朋友在使用VirtualBox或VMWare Player时没有问题,我的是KVM / QEMU(尽管指导老师建议我们明确使用前两个,但KVM的内核编译确实更快)。其他虚拟机管理程序与此有关吗?

c linux struct system-calls
1个回答
1
投票

感谢评论。我已经添加了copy_from_usercopy_to_user

现在可以使用。

#include <linux/uaccess.h>
// struct definition
asmlinkage long sys_procmem (int pid, struct proc_segs *info)
{

  printk("sys_procmem called \n");
  struct proc_segs temp_info;
  copy_from_user(&temp_info, info, sizeof(struct proc_segs));
  info->stID = 1234567;
  copy_to_user(info, &temp_info, sizeof(struct proc_segs));
  return 0;
}
© www.soinside.com 2019 - 2024. All rights reserved.