Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- /* Dtpass - Driver to access Switch's encrypted partition
- major thanks to
- https://www.apriorit.com/dev-blog/195-simple-driver-for-linux-os
- and
- https://linux-kernel-labs.github.io/master/labs/block_device_drivers.html
- for their sample code & explanation. they explain it so well how it works
- Copyright (C) 2016-2017 DacoTaco
- This program is free software; you can redistribute it and/or
- modify it under the terms of the GNU General Public License
- as published by the Free Software Foundation version 2.
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
- You should have received a copy of the GNU General Public License
- along with this program; if not, write to the Free Software
- Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
- #include <linux/init.h>
- #include <linux/module.h> // module info
- #include <linux/syscalls.h> //syscalls!
- #include <linux/types.h> //dem types
- #include <linux/fs.h> // file related stuff
- #include <linux/kernel.h> // printk <3
- #include <linux/errno.h> // error codes
- #include <linux/genhd.h>
- #include <linux/blkdev.h> //block device <3
- #include <linux/bio.h> //bio, request data structure
- #include <linux/vmalloc.h>
- #include <linux/genhd.h>
- #include <linux/fcntl.h>
- #include <linux/uaccess.h>
- //encryption stuff
- #include "aes.h"
- #include "ccrypto.c"
- #include "driver.h"
- #define BISKEY0_CRYPT 0x946105EF7E14EFEA12D37BDCFFA38430
- #define BISKEY0_TWEAK 0x680E1FC8236922D082D6D61E77DAD21B
- #define FILE_PATH "/home/dacotaco/shofel2/dtpass/mmcblk1p2_dec.bin"
- static int dev_major = 0;
- static int dev_minor = 1;
- static int nr_devices = 1;
- static const unsigned int partition_size = 0x00400000;
- #define device_name "dec_mmcblk1p"
- #define NAND_SECTOR_SIZE 0x4000
- #define NR_SECTORS (partition_size / KERNEL_SECTOR_SIZE)
- #define KERNEL_SECTOR_SIZE 512
- static struct dtpass_dev {
- spinlock_t lock; //used for exclusion & LOCKING DEM SHITZ
- struct request_queue *queue; // le queue to handle IO stuff
- struct gendisk *gd;
- char filename[256];
- struct file *fp;
- unsigned int partition_size;
- } dev;
- //----------------------------------------------
- // I/O block device
- //----------------------------------------------
- static int transfer_data(struct dtpass_dev* dev, size_t start_off, size_t len, char* dst,int direction)
- {
- int size = len;
- mm_segment_t fs_status;
- int ret = 0;
- loff_t pos = 0;
- if(size > dev->partition_size)
- {
- printk(KERN_NOTICE "DTPASS : fixing size\n");
- size = dev->partition_size;
- }
- //pos = where to start reading
- pos = (loff_t)(start_off * KERNEL_SECTOR_SIZE);
- printk( KERN_NOTICE "start_off : 0x%lx / 0x%llx ,len : 0x%lx, direction 0x%x, ",
- start_off,pos,len,direction);
- //return;
- fs_status = get_fs();
- if (direction == READ)
- {
- unsigned char *buf = (unsigned char*)vmalloc(size+1);//,GFP_KERNEL);
- if(buf == NULL)
- {
- printk(KERN_WARNING "DTPASS : failed to malloc read buf\n");
- goto return_func;
- }
- printk( KERN_NOTICE "buf : 0x%x , fd : 0x%x\n",buf,dev->fp);
- memset(buf,0,size+1);
- set_fs(KERNEL_DS);
- //vfs_llseek(dev->fp,pos,SEEK_SET);
- //any read of address 0x1000 or higher results in vfs_read returning -EINTR? :/
- ret = vfs_read(dev->fp, buf, size,&pos);
- if(ret == -EINTR)
- {
- //retry? not that it fixes anything....
- printk(KERN_NOTICE "retrying..\n");
- ret = vfs_read(dev->fp, buf, size,&pos);
- }
- if(ret < 0)
- printk(KERN_NOTICE "DTPASS : read failure : %d\n",ret);
- copy_to_user(dst,buf,size);
- vfree(buf);
- }
- else
- {
- printk(KERN_NOTICE "DTPASS : write not yet implemented!");
- }
- return_func:
- set_fs(fs_status);
- return ret;
- }
- static int process_bio(struct dtpass_dev* dev,struct bio *bio)
- {
- if(dev == NULL || bio == NULL)
- printk(KERN_NOTICE "DTPASS : bio processing called on null data");
- //process the bio data
- struct bio_vec bvec;
- struct bvec_iter iter;
- int dir = bio_data_dir(bio);
- int ret = 0;
- //loop through each bio segment
- //basically this loops trough all bio segments, copies data to the bvec vector and then retrieves data
- //from that to initiate the transfer function
- printk(KERN_NOTICE "LEGGO\n");
- bio_for_each_segment(bvec,bio,iter)
- {
- //get the data from bio needed to make the transfer
- sector_t sector = iter.bi_sector;
- char* dst = kmap_atomic(bvec.bv_page);
- unsigned long dst_offset = bvec.bv_offset;
- size_t len = bvec.bv_len;
- //process the data
- ret = transfer_data(dev,sector,len,dst+dst_offset,dir);
- //lolidk, something about manging memory from userpsace & kernel i think?
- kunmap_atomic(dst);
- }
- printk(KERN_NOTICE "KBYE\n");
- return ret;
- }
- static void block_device_request(struct request_queue *queue)
- {
- //kernel decided its time we handled the device requests. lets handle them shall we?
- //also, normally the kernel already upholds the lock, so no need to get the lock
- struct request *req;
- struct dtpass_dev *dev = queue->queuedata;
- while(1)
- {
- req = blk_fetch_request(queue);
- if(req == NULL)
- {
- //we got a null request, aka : we've processed them all
- break;
- }
- if(blk_rq_is_passthrough(req))
- {
- //we got a special command that isn't about transferring data.
- //how do we deal with these? lolidk, so meh XD
- //set request as processed with the EIO error
- printk( KERN_NOTICE "DTPASS : skipping non-fs request\n");
- __blk_end_request_all(req, -EIO);
- continue;
- }
- process_bio(dev,req->bio);
- //request done! set it processed with success , 0
- __blk_end_request_all(req,0);
- }
- return;
- }
- static int open_block_device(struct block_device *bdev,fmode_t mode)
- {
- return 0;
- }
- static void release_block_device(struct gendisk *gd, fmode_t mode)
- {
- return;
- }
- struct block_device_operations block_ops = {
- .owner = THIS_MODULE,
- .open = open_block_device,
- .release = release_block_device
- };
- //----------------------------------------------
- // block device managing
- //----------------------------------------------
- static int create_block_device(struct dtpass_dev *dev)
- {
- //Init I/O queue
- spin_lock_init(&dev->lock); //set lock pointer
- dev->queue = blk_init_queue(block_device_request, & dev->lock); //set method to handle queue's
- if (dev->queue == NULL)
- {
- goto err;
- }
- blk_queue_logical_block_size(dev->queue, KERNEL_SECTOR_SIZE);
- //blk_queue_physical_block_size(dev->queue,NAND_SECTOR_SIZE/KERNEL_SECTOR_SIZE);
- dev->queue->queuedata = dev;
- //init the gd!
- dev->gd = alloc_disk(nr_devices);
- if(!dev->gd)
- {
- printk( KERN_NOTICE "alloc_disk failure\n");
- return -ENOMEM;
- }
- //set filename of file we are using
- snprintf(dev->filename,255,FILE_PATH);
- //open file
- mm_segment_t fs_status = get_fs();
- dev->fp = filp_open(dev->filename,O_RDONLY,0);
- if(IS_ERR(dev->fp))
- {
- printk(KERN_WARNING "DTPASS : failed to open device\n");
- return PTR_ERR(dev->fp);
- }
- set_fs(fs_status);
- dev->partition_size = partition_size;
- dev->gd->major = dev_major;
- dev->gd->first_minor = 0;
- dev->gd->fops = &block_ops;
- dev->gd->queue = dev->queue;
- dev->gd->private_data = dev;
- snprintf(dev->gd->disk_name,32,device_name);
- set_capacity(dev->gd,NR_SECTORS);
- add_disk(dev->gd);
- return 0;
- err:
- return -ENOMEM;
- }
- static void delete_block_device(struct dtpass_dev *dev)
- {
- if(dev == NULL)
- return;
- //close fp
- if(dev->fp != NULL)
- filp_close(dev->fp, NULL);
- //clean up device
- if(dev->gd)
- del_gendisk(dev->gd);
- //clean up queue
- if(dev->queue)
- blk_cleanup_queue(dev->queue);
- }
- //----------------------------------------------
- // registry related sheise
- //----------------------------------------------
- static int register_device(void)
- {
- int ret;
- //we register our block device
- ret = register_blkdev(dev_major,device_name);
- if(ret < 0)
- {
- printk( KERN_WARNING "DTPASS: failed to register block device\n");
- return -EBUSY;
- }
- dev_major = ret;
- //create the block device
- ret = create_block_device(&dev);
- if(ret < 0)
- return ret;
- return 0;
- }
- static void unregister_device(void)
- {
- delete_block_device(&dev);
- unregister_blkdev(dev_major, device_name);
- }
- //----------------------------------------------
- // Module init stuff
- //----------------------------------------------
- static int __init dtpass_init(void)
- {
- int ret = register_device();
- if(ret == 0)
- {
- printk( KERN_NOTICE "DTPASS: module loaded\n" );
- }
- else
- printk( KERN_NOTICE "DTPASS: failed to load module : %u\n",ret);
- return ret;
- }
- static void __exit dtpass_dispose(void)
- {
- unregister_device();
- printk( KERN_NOTICE "DTPASS: module unloaded\n" );
- }
- module_init(dtpass_init);
- module_exit(dtpass_dispose);
- MODULE_LICENSE("GPL");
- MODULE_AUTHOR("DacoTaco");
- MODULE_DESCRIPTION("linux module to allow decrypted (read) access to the encrypted NAND partitions");
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement