📄 bc_dev22.c
字号:
/******************************************************************* * Copyright (c) 1994-1998 Jetico, Inc., Finland * All rights reserved. * * File: driver/bc_dev.c * * Description: BestCrypt pseudo-device driver. * * Scope: BestCrypt pseudo-device driver * * Platforms: Linux * * Ideas: Igor M. Arsenin * Serge A. Frolov * Vitaliy G. Zolotarev * * Author: Nail R. Kaipov * * Created: 10-Nov-1998 * * Revision: 06-Aug-1999. new strategy routine * 15-Sep-1999. 2.3.x kernels support * 11-Oct-1999. strategy bugfix * 15-Dec-1999. driver refinement * 21-Mar-2000. bugfix for large blocks (v0.4b-2) * 02-May-2001. SMP bugfix, /proc update * 06-Jun-2001. writing magic in bc_clr_fd * *******************************************************************/#ifndef EXPORT_SYMTAB#define EXPORT_SYMTAB#endif#include "bc_cfg.h"#include <linux/module.h>#include <linux/fs.h> /* inode et al */#include <linux/proc_fs.h> /* inode et al */#include <linux/vmalloc.h> /* vmalloc() */#include <linux/kernel.h> /* printk() */#include <asm/uaccess.h> /* put_user() */#include <asm/atomic.h> /* atomic operations */#include <linux/hdreg.h> /* hd_geometry */#include <linux/file.h> /* inode et al */#include "bc_types.h" /* bc types */#include "bc_ioctl.h" /* ioctl codes */#include "bc_mgr.h"#include "bc_dev.h" /* bc types codes */#define DEVICE_OFF(dev)#include <linux/blk.h>#define __KERNEL_SYSCALLS__#include <linux/unistd.h>static int bc_devices = DEFAULT_BC_DEVICES;static int bc_partitions = DEFAULT_BC_PARTITIONS;static int bc_minor_shift = 0;static int bc_start_minor = 128;static struct bc_device *bc_dev;static struct bc_disk *bc_dsk;static struct gendisk bc_gendisk;static int bc_sizes [MAX_MINORS];static int bc_blksizes [MAX_MINORS];static struct hd_struct bc_hd [MAX_MINORS];struct request *BC_CURRENT = NULL;static struct wait_queue *wait_open = 0;/* pid control table support */#define BC_PID_SIZE 64static pid_t *bc_pid_table;static int bc_pid_size;static int bc_pid_next;static struct semaphore bc_pid_sema;static struct timer_list bc_pid_timer;struct bc_buffer_desc { atomic_t count; char *ptr;} bc_buffers[BC_BUFFERS];static ssize_t bc_read (struct file *, char *, size_t, loff_t *);static ssize_t bc_write (struct file *, const char *, size_t, loff_t *);static int bc_ioctl (struct inode *, struct file *, unsigned int, unsigned long);static int bc_open (struct inode *, struct file *); static int bc_release (struct inode *, struct file *);static int dummy_ioctl (struct inode *i, struct file *f, u_int cmd, u_long arg) { return -ENODEV; }static int dummy_open (struct inode *i, struct file *f) { return -ENODEV; }static int dummy_release(struct inode *i, struct file *f) { return -ENODEV; }static int *save_blksize;static int *save_blksize_size;static int max_loop;static struct proc_dir_entry *proc_bcrypt, *proc_tmp;#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,3,32))#define BC_GET_REQUEST_FN(_MAJOR_) blk_dev[_MAJOR_].request_queue.request_fnstatic void dummy_request_fn (request_queue_t *rq) { return; }static void (*save_request_fn)(request_queue_t *rq) = dummy_request_fn;#else#define BC_GET_REQUEST_FN(_MAJOR_) blk_dev[_MAJOR_].request_fnstatic void dummy_request_fn(void) { return; }static void (*save_request_fn)(void) = dummy_request_fn;#endifstatic struct file_operations save_fops = { read :block_read, write :block_write, ioctl :dummy_ioctl, open :dummy_open, release:dummy_release, fsync :block_fsync};static struct file_operations bc_fops = { read :bc_read, write :bc_write, ioctl :bc_ioctl, open :bc_open, release:bc_release, fsync :block_fsync};EXPORT_SYMBOL(register_bc_algo);EXPORT_SYMBOL(unregister_bc_algo);MODULE_PARM(bc_devices, "i");MODULE_PARM_DESC(bc_devices, "Max. number of devices (1-127).");MODULE_PARM(bc_partitions, "i");MODULE_PARM_DESC(bc_partitions, "Max. number of partitions per device (0-31).");MODULE_AUTHOR("Jetico, Inc.");MODULE_DESCRIPTION("BestCrypt encrypted block device driver.");/*-----------------------------------------------------------*/static inline struct bc_device *get_bcdev(kdev_t dev){ int mn = MINOR(dev) - bc_start_minor; if ((MAJOR_NR == MAJOR(dev)) && (MAX_MINORS > MINOR(dev))) { mn >>=bc_minor_shift; if ((mn >= 0) && (mn < bc_devices)) return bc_dev+mn; } return NULL;}static inline struct bc_disk *get_bcdsk(kdev_t dev){ int mn = MINOR(dev) - bc_start_minor; if ((MAJOR_NR == MAJOR(dev)) && (MAX_MINORS > MINOR(dev))) { if ((mn >= 0) && (mn < bc_devices*bc_partitions)) return bc_dsk+mn; } return NULL;}static inline int is_parent(struct bc_disk *bd){ if (NULL != bd) return !((bd->bd_number-bc_start_minor) & ((1 << bc_minor_shift) - 1)); return 0;}static inline void reset_dev(struct bc_device *bc){ int i, j; struct bc_disk *bd; if (NULL == bc) return; bc->bc_offset = 0L; bc->bc_start_sector = 0L; bc->bc_num_sectors = 0L; bc->bc_dev = 0; bc->bc_key = 0; bc->bc_alg = NULL; bc->bc_file = NULL; bc->bc_dentry = NULL; bc->bc_activity = 0; memset(&bc->bc_flags, 0, sizeof(bc->bc_flags)); bd = &bc_dsk[bc->bc_number << bc_minor_shift]; for (i = 0; i < 1 << bc_minor_shift; i++) { j = bd->bd_number; memset(bd, 0, sizeof(struct bc_disk)); bd->bd_number = j; bd++; } }/*-----------------------------------------------------------*/static inline int bc_find_pid(pid_t pid) { register int i; for (i = 0; i < bc_pid_next; i++) if (pid == bc_pid_table[i]) return i; return -1;}static int bc_find_pid_safe(pid_t pid){ int i; down(&bc_pid_sema); i = bc_find_pid(pid); up(&bc_pid_sema); return i;}static int bc_add_pid(pid_t pid) { pid_t *tmp; down(&bc_pid_sema); if (bc_find_pid(pid) > -1) { up(&bc_pid_sema); return 0; } if (bc_pid_next < bc_pid_size) { bc_pid_table[bc_pid_next] = pid; bc_pid_next++; } else { tmp = kmalloc((bc_pid_size+BC_PID_SIZE) * sizeof(pid_t), GFP_KERNEL); if (NULL == tmp) { up(&bc_pid_sema); return -ENOMEM; } memcpy(bc_pid_table, tmp, bc_pid_size * sizeof(pid_t)); kfree(bc_pid_table); bc_pid_table = tmp; bc_pid_size += BC_PID_SIZE; bc_pid_table[bc_pid_next] = pid; bc_pid_next++; } if (1 == bc_pid_next) { bc_pid_timer.expires = jiffies + 5 * HZ; add_timer(&bc_pid_timer); } up(&bc_pid_sema); return 0;}static int bc_del_pid(pid_t pid) { int i; pid_t *tmp; down(&bc_pid_sema); i = bc_find_pid(pid); if (0 > i) { up(&bc_pid_sema); return 0; } bc_pid_next--; if (bc_pid_next) bc_pid_table[i] = bc_pid_table[bc_pid_next]; bc_pid_table[bc_pid_next] = 0; if (bc_pid_size-bc_pid_next > 2*BC_PID_SIZE) { tmp = kmalloc((bc_pid_size-BC_PID_SIZE) * sizeof(pid_t), GFP_KERNEL); if (NULL == tmp) { up(&bc_pid_sema); return 0; } bc_pid_size -= BC_PID_SIZE; memcpy(bc_pid_table, tmp, bc_pid_size * sizeof(pid_t)); kfree(bc_pid_table); bc_pid_table = tmp; } up(&bc_pid_sema); return 0;}static void bc_pid_timer_proc(unsigned long unused) { register int i; down(&bc_pid_sema); for (i = 0; i < bc_pid_next; i++) { if (NULL == find_task_by_pid(bc_pid_table[i])) { bc_pid_next--; if (bc_pid_next) bc_pid_table[i] = bc_pid_table[bc_pid_next]; bc_pid_table[bc_pid_next] = 0; i--; } } if (bc_pid_next) { bc_pid_timer.expires = jiffies + 5 * HZ; add_timer(&bc_pid_timer); } up(&bc_pid_sema);}/*-----------------------------------------------------------*/static void grab_requests();static void bc_request();static void do_bc_request() {#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,3,32))#define BC_NULL NULL#else#define BC_NULL#endif if (NULL == CURRENT) return; grab_requests(); save_request_fn(BC_NULL); bc_request(BC_NULL);#undef BC_NULL}static void grab_requests(){ register struct request *prev, *tail, *curr; if (NULL == (curr = CURRENT)) return; if (NULL != (tail = BC_CURRENT)) while (tail->next) tail = tail->next; prev = NULL; while (curr) { if (get_bcdev(curr->rq_dev)) { if (tail) tail->next = curr; else BC_CURRENT = curr; if (prev) prev->next = curr->next; else CURRENT = curr->next; tail = curr; } else { if (prev) prev = prev->next; else prev = CURRENT; } curr = curr->next; } if (tail) tail->next = NULL;}#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,3,32))static void bc_request(request_queue_t *abcd)#elsestatic void bc_request()#endif{ struct bc_device *bc; struct bc_disk *bd; struct request *req; struct file *file; size_t len, ret, size; loff_t pos, sec; char *dst, *buf = NULL; u16 iv[4]; u64 iv64, iv64le; mm_segment_t fs; int uptodate, i;repeat: if (!BC_CURRENT) return; req = BC_CURRENT; BC_CURRENT = req->next; uptodate = 0; bc = get_bcdev(req->rq_dev); bd = get_bcdsk(req->rq_dev); if (!bc || !bd || !bc->bc_dentry || !bc->bc_dentry->d_inode) { goto error_out; } if (!bd->bd_flags.configured) { if (bc->bc_flags.busy) { bd->bd_offset = bc->bc_offset + (((loff_t)bc_gendisk.part[bd->bd_number].start_sect)<<9); } else { printk(KERN_ERR "bc: device not configured yet.\n"); goto error_out; } } if (WRITE == req->cmd) { if (bc->bc_flags.readonly) { goto error_out; } } else if (READ != req->cmd) { printk(KERN_ERR "bc: unknown command (%d).", req->cmd); goto error_out; } sec = (loff_t)req->sector + bc->bc_start_sector; pos = sec * 512 + bd->bd_offset; len = req->current_nr_sectors << 9; dst = req->buffer; file = bc->bc_file; iv[0] = iv[1] = iv[2] = iv[3] = sec & 0xFFFF; iv64 = sec+1; bc->bc_activity = 1; if (READ == req->cmd) { fs = get_fs(); set_fs(KERNEL_DS); spin_unlock_irq(&io_request_lock); ret = file->f_op->read(file, dst, len, &pos); spin_lock_irq(&io_request_lock); set_fs(fs); if (ret != len) { printk(KERN_ERR "bc: read error wanted %ld, read %ld\n", (unsigned long)len, (unsigned long)ret); goto error_out; } if (bc->bc_flags.iv_64bit) { iv64le = __cpu_to_le64(iv64); bc->bc_alg->decrypt(bc->bc_key, (char *)(&iv64le), dst, dst, len); } else { bc->bc_alg->decrypt(bc->bc_key, (char *)iv, dst, dst, len); } } else { for (i = 0; i < BC_BUFFERS; i++) { if (atomic_dec_and_test(&bc_buffers[i].count)) { buf = bc_buffers[i].ptr; break; } else atomic_inc(&bc_buffers[i].count); } if (BC_BUFFERS == i) { printk(KERN_ERR "bc: insufficient resources\n"); goto error_out; } size = BC_BUFFER_SIZE; while (len > 0) { if (size > len) size = len; if (bc->bc_flags.iv_64bit) { iv64le = __cpu_to_le64(iv64); bc->bc_alg->encrypt(bc->bc_key, (char *)(&iv64le), dst, buf, size); } else { bc->bc_alg->encrypt(bc->bc_key, (char *)iv, dst, buf, size); } fs = get_fs(); set_fs(KERNEL_DS); spin_unlock_irq(&io_request_lock); ret = file->f_op->write(file, buf, size, &pos); spin_lock_irq(&io_request_lock); set_fs(fs); if (ret != size) { printk(KERN_ERR "bc: write error wanted %ld, wrote %ld\n", (unsigned long)size, (unsigned long)ret); atomic_inc(&bc_buffers[i].count); goto error_out; } if (bc->bc_flags.iv_64bit) { iv64 += BC_BUFFER_SIZE / 512; } else { iv[0] = ((int)iv[0] + BC_BUFFER_SIZE / 512) & 0xFFFF; iv[3] = iv[2] = iv[1] = iv[0]; } dst += size; len -= size;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -