我正在使用 ds18b20 温度传感器,并且正在将一些 python 代码转换为 C++,以帮助更好地学习该语言。我遇到了一个问题,我需要加载 w1-gpio 和 w1-therm 模块。我在堆栈溢出上发现了很多内容,提到应该使用 init_module ,并且在同一个线程中,其他人提到要使用fork()side exec()。经过大量谷歌搜索和阅读手册页后,我找不到任何有关如何完成这些任务的示例。有人可以指出和/或举例说明如何使用这两种方法加载这两个模块吗?或者提供不涉及 system("modprobe w1-gpio") 的替代方案?
uname -a
Run Code Online (Sandbox Code Playgroud)
产生:
Linux raspberrypi 4.1.13-v7+ #826 SMP PREEMPT Fri Nov 13 20:19:03 GMT 2015 armv7l GNU/Linux
Run Code Online (Sandbox Code Playgroud) 我在 Linux 内核模块中创建目录时遇到问题。
我想要的:在内核模块中创建一个目录。
这是我的实际代码:
struct file *fp = (struct file *) NULL;
fp = filp_open("/home/testdir", O_DIRECTORY|O_CREAT, S_IRUSR);
Run Code Online (Sandbox Code Playgroud)
但它创建一个文件而不是目录。
我尝试使用与上面相同的代码而不使用标志“O_DIRECTORY”:
struct file *fp = (struct file *) NULL;
fp = filp_open("/home/testdir", O_CREAT, S_IRUSR);
Run Code Online (Sandbox Code Playgroud)
并且结果与之前的结果类似。
我不明白这种行为。我究竟做错了什么?
编辑 1:我正在 Raspberry PI、Raspbian 上编码,内核版本:4.4.43-v7
我是 Linux 内核模块的新手。我正在根据网络课程学习字符驱动程序模块。我有一个非常简单的模块来创建/dev/chardevexample,我有一个问题需要了解:
当我这样做时echo "hello4" > /dev/chardevexample,我会write按预期看到执行一次。但是,当我这样做时cat /dev/chardevexample,我看到读取执行了两次。
我在我的代码和课程材料中都看到了这一点。第一次返回了所有数据read(),为什么还要cat再次调用呢?
到目前为止我所做的所有事情如下:
insmod chardev.ko加载我的模块echo "hello4" > /dev/chardevexample。这是写入,我在 dmesg 中看到它只发生一次 cat /dev/chardevexample。这是读取的内容,并且dmesg显示它发生了两次。我做到了strace cat /dev/chardevexample,而且我确实看到函数调用被调用两次以进行读取。中间也有写
read(3, "hello4\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"..., 131072) = 4096
write(1, "hello4\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"..., 4096hello4) = 4096
read(3, "", 131072)
Run Code Online (Sandbox Code Playgroud)dmesg读取后(cat 命令)
[909836.517402] DEBUG-device_read: To User hello4 and bytes_to_do 4096 ppos 0 # Read #1
[909836.517428] DEBUG-device_read: Data send to app hello4, …Run Code Online (Sandbox Code Playgroud)我正在尝试从芯片实验室编译这个 UART -> USB驱动程序。它只在 Ubuntu 版本上进行了测试18.04 (Bionic),我的机器运行在21.10 (Impish). 显然,差异之一是最新版本在构建内核模块时启用了严格的指针转换检查:
/lib/modules/$(uname -r)/build/Makefile
\n# enforce correct pointer usage\nKBUILD_CFLAGS += $(call cc-option,-Werror=incompatible-pointer-types)\nRun Code Online (Sandbox Code Playgroud)\n我想知道是否有办法禁用该特定标志,因为它阻止我编译驱动程序。我收到错误:
\n.../vcp_driver_source/Linux_3.x.x_4.x.x_VCP_Driver_Source/cp210x.c:290:35: error: initialization of \xe2\x80\x98void (*)(struct usb_serial_port *)\xe2\x80\x99 from incompatible pointer type \xe2\x80\x98int (*)(struct usb_serial_port *)\xe2\x80\x99 [-Werror=incompatible-pointer-types]\n 290 | .port_remove = cp210x_port_remove,\n | ^~~~~~~~~~~~~~~~~~\n.../vcp_driver_source/Linux_3.x.x_4.x.x_VCP_Driver_Source/cp210x.c:290:35: note: (near initialization for \xe2\x80\x98cp210x_device.port_remove\xe2\x80\x99)\ncc1: some warnings being treated as errors\nmake[2]: *** [scripts/Makefile.build:277: .../vcp_driver_source/Linux_3.x.x_4.x.x_VCP_Driver_Source/cp210x.o] Error 1\nmake[1]: *** [Makefile:1874: .../vcp_driver_source/Linux_3.x.x_4.x.x_VCP_Driver_Source] Error 2\nmake[1]: Leaving directory \'/usr/src/linux-headers-5.15.23-76051523-generic\'\nmake: *** [Makefile:7: …Run Code Online (Sandbox Code Playgroud) 在做了一些阅读之后,我开始明白通过LKM添加新的系统调用在2.6中变得更难.似乎syscall表不再导出,因此在运行时插入新调用(不可能?).
我想要实现的目标如下.
我有一个正在执行特定任务的内核模块.此任务取决于应由用户土地过程提供的输入.此信息需要到达模块.为此,我将介绍一个新的系统调用,它在内核模块中实现,并可从用户域进程调用.
如果我必须重新编译内核以添加我的新系统调用,我还需要在内核模块之外编写实际的系统调用逻辑,对吗?
还有另一种方法吗?
干杯,eeknay
我在内核模块中有以下代码,它在进程树中向上打印进程名称和uid直到init进程:
// recursivly walk the task's parent until we reach init
void parent_task_walk(struct task_struct *task) {
struct task_struct *parent;
char filename[MAX_FILE_LEN];
if (task && task->mm) {
parent = get_task_parent(task);
printk("%s (uid:%d)", exe_from_mm(task->mm, filename, MAX_FILE_LEN),
get_task_uid(task));
if (parent && task->pid != 1) {
printk(", ");
parent_task_walk(parent);
}
}
}
Run Code Online (Sandbox Code Playgroud)
注意:我使用了一些引用真实内核函数的宏,因为这是针对内核模块跨越多个版本的.源代码在此文件中:https://github.com/cormander/tpe-lkm/blob/319e1e29ea23055cca1c0a3bce3c865def14d3d2/core.c#L61
输出最终看起来像这样:
/bin/bash (uid:500), /usr/sbin/sshd (uid:500), /usr/sbin/sshd (uid:0), /usr/sbin/sshd (uid:0), /sbin/init (uid:0)
这是一个递归函数.可以想象,当你启动200个bash shell然后触发事件时,事情会变得很糟糕.我不确定究竟发生了什么,但机器冻结了.内核耗尽了我假设的堆栈空间,去了OOM,然后自己开枪?
我想知道处理这种情况的最佳方法是什么.我看到几个选项:
1)在N个进程后停止遍历进程树
2)在一些字符数组(最终将被打印)已满后停止行走
3)使用a goto而不是递归函数,但仍然遵守选项#1和#2的新规则
4)使用一些你将为我阐述的非递归方法
这发生在内核空间,所以不是最好客的环境.任何人都可以指出最好的方法吗?
我希望在这些系统调用返回后立即使用LKM跟踪sys_connect和sys_accept.我发现通过定义一个post处理程序,kprobes可以在探测到的系统调用返回时访问寄存器.
我的问题是我不知道如何从我在post处理程序中的数据中获取系统调用参数(即struct pt_regs).后处理程序的定义如下:
void post_handler(struct kprobe *p, struct pt_regs *regs, unsigned long flags);
Run Code Online (Sandbox Code Playgroud) 尝试一些FreeBSD内核黑客攻击,我在一个简单的钩子示例中遇到了错误.代码如下
*注意 - 我添加了#include <sys/stat.h>尽可能多的建议,但继续得到相同的错误.
#include <sys/types.h>
#include <sys/param.h>
#include <sys/proc.h>
#include <sys/module.h>
#include <sys/sysent.h>
#include <sys/kernel.h>
#include <sys/systm.h>
#include <sys/syscall.h>
#include <sys/sysproto.h>
#include <sys/stat.h>
static int mkdir_hook(struct thread *td, void *syscall_args) {
struct mkdir_args *uap;
uap = (struct mkdir_args *)syscall_args;
char path[255];
size_t done;
int error;
error = copyinstr(uap->path, path, 255, &done);
if(error != 0)
return (error);
uprintf("hooked it\n");
return (mkdir(td, syscall_args));
}
static int load(struct module *module, int cmd, void *arg) {
int error = 0; …Run Code Online (Sandbox Code Playgroud) 在内核模块中,如何列出所有内核符号及其地址?不应重新编译内核。
我知道接口中的“ cat / proc / kallsyms”,但是如何使用诸如之类的函数直接从内核数据结构中获取它们kallsyms_lookup_name。
kernel-module ×10
linux-kernel ×7
c ×4
kernel ×4
linux ×3
architecture ×1
c++ ×1
chardev ×1
freebsd ×1
kbuild ×1
makefile ×1
python ×1
raspberry-pi ×1
recursion ×1
system-calls ×1
trace ×1