简易密码存储器

通过 ioctl 设置密码,通过 read 操作验证密码

项目简介

在本项目中,我们将创建一个Linux内核驱动,实现一个简易的密码存储器。用户可以通过ioctl系统调用设置一个密码,然后通过read操作来验证输入的密码是否正确。这个项目将帮助你理解Linux内核驱动的基本操作,包括字符设备驱动、文件操作结构体以及用户空间与内核空间的数据交换。

用户空间 内核空间 ioctl / read

驱动功能

关键数据结构

结构体/函数 描述
file_operations 定义驱动支持的文件操作,如read、write、ioctl等
ioctl 用于设置密码的命令
read 用于读取验证结果

代码实现

初始化与退出函数

#include <linux/module.h>
#include <linux/fs.h>
#include <linux/uaccess.h>
#include <linux/ioctl.h>

#define DEVICE_NAME "password_store"
#define IOCTL_SET_PASSWORD _IOW('p', 1, char *)

static char password[256] = {0};
static int major_number;

static int device_open(struct inode *inode, struct file *file) {
    return 0;
}

static int device_release(struct inode *inode, struct file *file) {
    return 0;
}

static ssize_t device_read(struct file *filp, char *buffer, size_t length, loff_t *offset) {
    char user_input[256];
    copy_from_user(user_input, buffer, length);
    user_input[length] = '\0';

    if (strcmp(user_input, password) == 0) {
        char *msg = "密码正确!\n";
        copy_to_user(buffer, msg, strlen(msg) + 1);
        return strlen(msg) + 1;
    } else {
        char *msg = "密码错误!\n";
        copy_to_user(buffer, msg, strlen(msg) + 1);
        return strlen(msg) + 1;
    }
}

static long device_ioctl(struct file *file, unsigned int cmd, unsigned long arg) {
    switch (cmd) {
        case IOCTL_SET_PASSWORD:
            copy_from_user(password, (char *)arg, strlen((char *)arg) + 1);
            break;
        default:
            return -EINVAL;
    }
    return 0;
}

static struct file_operations fops = {
    .read = device_read,
    .unlocked_ioctl = device_ioctl,
    .open = device_open,
    .release = device_release,
};

static int __init password_init(void) {
    major_number = register_chrdev(0, DEVICE_NAME, &fops);
    if (major_number < 0) {
        printk(KERN_ALERT "注册字符设备失败\n");
        return major_number;
    }
    printk(KERN_INFO "密码存储器驱动加载成功,主设备号: %d\n", major_number);
    return 0;
}

static void __exit password_exit(void) {
    unregister_chrdev(major_number, DEVICE_NAME);
    printk(KERN_INFO "密码存储器驱动卸载\n");
}

module_init(password_init);
module_exit(password_exit);

MODULE_LICENSE("GPL");
MODULE_AUTHOR("Your Name");
MODULE_DESCRIPTION("简易密码存储器驱动");

用户空间测试程序

#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/ioctl.h>
#include <string.h>

#define IOCTL_SET_PASSWORD _IOW('p', 1, char *)

int main() {
    int fd = open("/dev/password_store", O_RDWR);
    if (fd < 0) {
        perror("打开设备失败");
        return -1;
    }

    char *new_password = "mysecret";
    if (ioctl(fd, IOCTL_SET_PASSWORD, new_password) < 0) {
        perror("ioctl 失败");
        close(fd);
        return -1;
    }

    char input[256];
    printf("请输入密码: ");
    scanf("%255s", input);

    write(fd, input, strlen(input) + 1);

    char response[256];
    read(fd, response, sizeof(response));
    printf("%s", response);

    close(fd);
    return 0;
}

驱动工作流程

  1. 加载驱动时,注册字符设备并分配主设备号
  2. 用户通过ioctl设置密码,驱动将密码存储在内核空间
  3. 用户通过read操作提交密码进行验证
  4. 驱动比较用户输入的密码与存储的密码
  5. 返回验证结果给用户空间

注意:在实际应用中,密码存储应使用加密哈希而非明文,本项目为简化示例使用明文存储。

总结

通过本项目,你学会了如何创建一个简单的Linux内核驱动,实现密码的设置和验证功能。你掌握了ioctlread操作的使用,以及用户空间与内核空间的数据交换。这些技能是Linux内核驱动开发的基础,为你后续学习更复杂的驱动开发打下了坚实的基础。