• SD卡加密—内核修改


    bio_vec[i]对应一个block或者一个page
    bio面向page或者面向块,详见第五次汇报里讲解的。
    1struct bio {
    sector_t bi_sector; /* device address in 512 byte
    ……
    void *backup;//结构体末尾加变量backup空指针,作用?
    };
    struct page {
    unsigned long flags; /* Atomic flags, some possibly
    ……
    unsigned long buffer_flag;//page结构体末尾加入这个标记,标记函数是否经过了mpage_readpages
    };
    buffer_flag识别函数是否经过了mpage_readpages函数。只有读文件数据经过该函数,读取目录和挂载过程不经过该函数,这个特点可以在generic_make_request()函数和回调函数中用于分辨本次IO是读文件IO(加解密),还是读取文件夹的IO(不加密))。
    1 void generic_make_request(struct bio *bio)
    {
    struct bio_list bio_list_on_stack;
     
    /********************/
     
     
    unsigned char *address_bf;
    int major;
    int i,j;
    unsigned long rw_flag;
    unsigned long int tt,nvec;
    unsigned long buffer_flag=9;
    address_bf=page_address(bio->bi_io_vec[0].bv_page);
    address_bf=address_bf+bio->bi_io_vec[0].bv_offset;
    major=MAJOR(bio->bi_bdev->bd_dev);//求设备号,SD卡设备号179
    tt=bio->bi_sector;
    nvec=bio->bi_vcnt;
    rw_flag=(bio->bi_rw)&WRITE;
    if(major==179)
    {
    printk(" generic: %s:  tt:%ld  nvec:%ld", (rw_flag)?"write":"read", tt, nvec);
    for(i=0;i<nvec;i++)
    {
    if (bio->bi_io_vec[i].bv_page->buffer_flag == 2) //该标记在函数?中,赋值2,只有读文件时经过该函数,读目录(区)不经过。满足条件,说明是读文件,则将标记改为3.
    bio->bi_io_vec[i].bv_page->buffer_flag = 3;
    buffer_flag = bio->bi_io_vec[i].bv_page->buffer_flag;
     
    printk(" %s buffer_flag:%ld", (rw_flag)?"write":"read", buffer_flag);
    }
    }
     
        if((major==179)&&(rw_flag)&&(buffer_flag==3))   //(tt>1000)
      {
      for(i=0;i<bio->bi_io_vec[0].bv_len/512;i++)
      {
      printk("before write:%d ", address_bf[i*512]);
    for(j=0;j<512;j++)
    {
    address_bf[j+i*512]^=0xff;
    }
    }
    }
    /************************/
     
    if (current->bio_list) {
    /* make_request is active */
    ………
    ………
    }
    2mpage机制的回调函数:
    static void mpage_end_io(struct bio *bio, int err)//bio->bi_io_vec数组对应各个数据段,每个数据段对应pages(非mpage机制每个数据段对应一个块),如:bio->bi_io_vec[0]对应一页。
    {
    const int uptodate = test_bit(BIO_UPTODATE, &bio->bi_flags);
    struct bio_vec *bvec = bio->bi_io_vec + bio->bi_vcnt - 1;
    unsigned long buffer_flag=6;
     
    do {
    struct page *page = bvec->bv_page;
     
    if (--bvec >= bio->bi_io_vec)
    prefetchw(&bvec->bv_page->flags);
    if (bio_data_dir(bio) == READ) {
    if (uptodate) {
    /******************/
    struct bio_vec *bvecx;
    unsigned char *address_bf;
    unsigned long int tt;
     
    bvecx=bvec+1;
    buffer_flag = bvecx->bv_page->buffer_flag;
    address_bf=page_address(bvecx->bv_page);
    address_bf=address_bf+bvecx->bv_offset;
     
     
    tt = bio->bi_sector;//这个扇区号为绝对扇区号,generic_make_request()等函数里的bio中的扇区号为从分区表起始的相对扇区号。本特点本项目中没有用到。
    printk(" mpage_end_io:tt:%ld ",tt);
    if (buffer_flag == 3){   //(tt>1000)//buffer_flag == 3说明为读取文件,而不是目录,
    //yy=tt;
    int i,j;
     
    int major=MAJOR(bio->bi_bdev->bd_dev);
    printk(" major:%d",major);
    if(major==179)
    {
     
    for(i=0;i<bvecx->bv_len/512;i++)
    {
    printk(" mpage_end_io:before read:%d ", address_bf[i*512]);
        for(j=0;j<512;j++)
    {
     address_bf[j+i*512]^=0xff;
      }
    }
      }
    }
    /******************/
    SetPageUptodate(page);
    3异步读回调函数: static void end_buffer_async_read(struct buffer_head *bh, int uptodate)
    {
    unsigned long flags;
    struct buffer_head *first;
    struct buffer_head *tmp;
    struct page *page;
    int page_uptodate = 1;
    unsigned long buffer_flag=8;
     
    BUG_ON(!buffer_async_read(bh));
     
    page = bh->b_page;
    buffer_flag = page->buffer_flag;
    if (uptodate) {
    /****************/
    unsigned char *tmp1;
    tmp1=(unsigned char*)bh->b_data;
    unsigned long int tt = (bh->b_blocknr * (bh->b_size >> 9));
    printk(" end_buffer_async_read:tt:%ld",tt);
     
    if (buffer_flag == 3){   //(tt>1000)
    int i,j;
    int major=MAJOR(bh->b_bdev->bd_dev);
    if(major==179)
    {
     
    for(i=0;i<((bh->b_size)/512);i++)
    {
    printk(" async before read :%d", tmp1[i*512]);
        for(j=0;j<512;j++)
    {
    //printk(KERN_INFO "The original data is:%d ", tmp1[j+i*512]);
     tmp1[j+i*512]^=0xff;
     //printk(KERN_INFO "The encryption data is%d ", tmp1[j+i*512]);
      }
    }
     }
    }
    /*****************/
    set_buffer_uptodate(bh);
    4同步读回调函数:static void __end_buffer_read_notouch(struct buffer_head *bh, int uptodate)//(end_buffer_sync_read调用该函数)
    {
    if (uptodate) {
    /**********/
    unsigned char *tmp1;
    tmp1=(unsigned char*)bh->b_data;
    unsigned long int tt = (bh->b_blocknr * (bh->b_size >> 9));
    unsigned long buffer_flag=7;
     
    printk(" notouch:tt:%ld",tt);
    buffer_flag = bh->b_page->buffer_flag;
     
    if (buffer_flag == 3){   //(tt>1000)
    int i,j;
    int major=MAJOR(bh->b_bdev->bd_dev);
    if(major==179)
    {
     
    for(i=0;i<((bh->b_size)/512);i++)
    {
    printk(" notouch:before read:%d", tmp1[i*512]);
        for(j=0;j<512;j++)
    {
    //printk(KERN_INFO "The original data is:%d ", tmp1[j+i*512]);
     tmp1[j+i*512]^=0xff;
     //printk(KERN_INFO "The encryption data is%d ", tmp1[j+i*512]);
      }
    }
     }
    }
    /*************/
     
    set_buffer_uptodate(bh);
    } else {
    /* This happens, due to failed READA attempts. */
    clear_buffer_uptodate(bh);
    }
     
    unlock_buffer(bh);
    }
    5触屏读取文件经过该函数,开发板通过USB连接电脑则不通过这个函数。所以用电脑读不出手机SD卡上的数据。
    int mpage_readpages(struct address_space *mapping, struct list_head *pages,
    unsigned nr_pages, get_block_t get_block)
    {
    struct bio *bio = NULL;
    unsigned page_idx;
    sector_t last_block_in_bio = 0;
    struct buffer_head map_bh;
    unsigned long first_logical_block = 0;
    struct blk_plug plug;
     
    blk_start_plug(&plug);
     
    map_bh.b_state = 0;
    map_bh.b_size = 0;
    for (page_idx = 0; page_idx < nr_pages; page_idx++) {
    struct page *page = list_entry(pages->prev, struct page, lru);
     
    prefetchw(&page->flags);
    list_del(&page->lru);
    if (!add_to_page_cache_lru(page, mapping,
    page->index, GFP_KERNEL)) {
    printk(" mpage_readpages !add_to..");
    page->buffer_flag = 2;
    bio = do_mpage_readpage(bio, page,
    nr_pages - page_idx,
    &last_block_in_bio, &map_bh,
    &first_logical_block,
    get_block);
    }
    page_cache_release(page);
    }
    BUG_ON(!list_empty(pages));
    if (bio)
    {
    printk(" mpage_readpages if(bio)");
    mpage_bio_submit(READ, bio);
    }
    blk_finish_plug(&plug);
    return 0;
    }
    6 触屏写入文件经过该函数,创建目录不经过该函数,所以创建文件夹不加密,从而达到只对SD卡文件数据进行加密的目的。
    static int __mpage_writepage(struct page *page, struct writeback_control *wbc,
          void *data)
    {
    struct mpage_data *mpd = data;
    struct bio *bio = mpd->bio;
    struct address_space *mapping = page->mapping;
    struct inode *inode = page->mapping->host;
    const unsigned blkbits = inode->i_blkbits;
    unsigned long end_index;
    const unsigned blocks_per_page = PAGE_CACHE_SIZE >> blkbits;
    sector_t last_block;
    sector_t block_in_file;
    sector_t blocks[MAX_BUF_PER_PAGE];
    unsigned page_block;
    unsigned first_unmapped = blocks_per_page;
    struct block_device *bdev = NULL;
    int boundary = 0;
    sector_t boundary_block = 0;
    struct block_device *boundary_bdev = NULL;
    int length;
    struct buffer_head map_bh;
    loff_t i_size = i_size_read(inode);
    int ret = 0;
     
    printk(" __mpage_writepage ");
    page->buffer_flag = 2;
     
    if (page_has_buffers(page)) {
    struct buffer_head *head = page_buffers(page);
    struct buffer_head *bh = head;
     
    /* If they're all mapped and dirty, do it */
    page_block = 0;
    do {
    BUG_ON(buffer_locked(bh));
    if (!buffer_mapped(bh)) {
    /*
            ………
            ……
     
    confused:
    if (bio)
    bio = mpage_bio_submit(WRITE, bio);
     
    if (mpd->use_writepage) {
    ret = mapping->a_ops->writepage(page, wbc);
    } else {
    ret = -EAGAIN;
    goto out;
    }
    /*
     * The caller has a ref on the inode, so *mapping is stable
     */
    mapping_set_error(mapping, ret);
    out:
    mpd->bio = bio;
    return ret;
    }
     
    7static void do_generic_file_read(struct file *filp, loff_t *ppos,
    read_descriptor_t *desc, read_actor_t actor)
    {
    ………
    readpage:
    /*
     * A previous I/O error may have been due to temporary
     * failures, eg. multipath errors.
     * PG_error will be set again if readpage fails.
     */
    ClearPageError(page);
    /* Start the actual read. The read will unlock the page. */
    /**yyx***/
    page->buffer_flag = 1;
    error = mapping->a_ops->readpage(filp, page);
     
    if (unlikely(error)) {
    if (error == AOP_TRUNCATED_PAGE) {
    }
     
     
    针对:写入SD卡后,立即读取,读出内容为乱码问题。

     

     

    1、修改部分代码:红色字体为修改部分

    static void mpage_end_io(s  truct bio *bio, int err)//bio->bi_io_vec数组对应各个数据段,每个数据段对应pages(非mpage机制每个数据段对应一个块),如:bio->bi_io_vec[0]对应一页。

    {

           const int uptodate = test_bit(BIO_UPTODATE, &bio->bi_flags);

           struct bio_vec *bvec = bio->bi_io_vec + bio->bi_vcnt - 1;

           unsigned long buffer_flag=6;

           int i,j;                                

           int major=MAJOR(bio->bi_bdev->bd_dev);//求出主设备号

                               

        int nvec;

           do {

                  struct page *page = bvec->bv_page;

                  if (--bvec >= bio->bi_io_vec)

                         prefetchw(&bvec->bv_page->flags);

                  if (bio_data_dir(bio) == READ) {

                         if (uptodate) {

                                /******************/

                                struct bio_vec *bvecx;

                                unsigned char *address_bf;//

                                unsigned long int tt;//

                               

                                bvecx=bvec+1;

                                buffer_flag = bvecx->bv_page->buffer_flag;//page页的自定义的标记位buffer_flag

                               

                                //printk(" 1111 ");

                                address_bf=page_address(bvecx->bv_page);//求出页的起始地址

                                address_bf=address_bf+bvecx->bv_offset;//页起始地址加上偏移值求出读地址

                                //printk(" 22222 ");

                                //struct buffer_head *bh;

                                //bh=bio->bi_private;

                                //printk(" 33333 ");

                                //unsigned char *tmp1;

                                //tmp1=(unsigned char*)bh->b_data;

                               

                                tt = bio->bi_sector;///这个扇区号为绝对扇区号,generic_make_request()等函数里的bio中的扇区号为从分区表起始的相对扇区号。本特点本项目中没有用到。

                                printk(" mpage_end_io:tt:%ld ",tt);

                               

                                if (buffer_flag == 3){   //buffer_flag是自己在page中定义的一个项,用于区分读写的是普通文件还是文件目录表,分区表之类的

                                       if(major==179)//major是179,就是针对的是SD卡

                                       {

                 

                                              for(i=0;i<bvecx->bv_len/512;i++)//bvecx->bv_len代表一个字段的长度,一个 扇区是512字节,表示有多少个扇区

                                              {

                                                     printk("before read:%d ", address_bf[i*512]);

                                                     for(j=0;j<512;j++)

                                                     {

                                                             address_bf[j+i*512]^=0xff;//针对每个扇区的每个字节按位取反(相当于加密)

                                                     }

                                              }

                                       }

                                }

                                /******************/

                                SetPageUptodate(page);

                         } else {

                                ClearPageUptodate(page);

                                SetPageError(page);

                         }

                         unlock_page(page);

                  } else { /* bio_data_dir(bio) == WRITE */在这部分是针对写返回的操作

                 

                         struct bio_vec *bvecx;

                         unsigned char *address_bf;

                        

                         bvecx=bvec+1;

                         buffer_flag = bvecx->bv_page->buffer_flag;//

                         address_bf=page_address(bvecx->bv_page);//

                         address_bf=address_bf+bvecx->bv_offset;//

                if(major==179)

                 

                         {nvec=bio->bi_vcnt;

                         //printk(" major");

                         //printk(" generic: %s:  tt:%ld  nvec:%ld", (rw_flag)?"write":"read", tt, nvec);

                         for(i=0;i<nvec;i++)//每个bio中段个数

                                {    

                                       if(i>1)

                                       {

                                       printk("%d mpage nvec= ",i);

                                       }

                                       //buffer_flag=bio->bi_io_vec[i].bv_page->buffer_flag;

                                       buffer_flag = bio->bi_io_vec[i].bv_page->buffer_flag;

                                       //address_bf=page_address(bio->bi_io_vec[i].bv_page);

                                       //address_bf=address_bf+bio->bi_io_vec[i].bv_offset;

                                       if (buffer_flag == 3)//如果是写SD卡返回,在generic_make_request中,如果执行generic_make_request函数,则将此标记位置为3,此位置判断是否为3,如果是3的话,就判定他执行了generic_make_request函数

                                       {     //bio->bi_io_vec[i].bv_page->buffer_flag = 3;

                                              //buffer_flag = bio->bi_io_vec[i].bv_page->buffer_flag;

                                              address_bf=page_address(bio->bi_io_vec[i].bv_page);//

                                              address_bf=address_bf+bio->bi_io_vec[i].bv_offset;

                                              memcpy(address_bf,bio->bi_io_vec[i].bv_data_address,bio->bi_io_vec[i].bv_len);//参照generic_make_request函数,在generic_make_request函数中,针对要操作的缓冲区,又申请了一个缓冲区,将原先的明文备份,此处是将备份的明文重新拷贝到原先的缓冲区中,使系统感觉不到加密,

                                              kfree(bio->bi_io_vec[i].bv_data_address);//将申请的用于备份的缓冲区释放掉

                                              printk(" nvec ");

                                              printk("mpage success ");

                                       }

                                       printk(" end_ion   success");

          

                                }

                         }

                        

          

                 

                         if (!uptodate) {

                                SetPageError(page);

                                if (page->mapping)

                                       set_bit(AS_EIO, &page->mapping->flags);

                         }

                         end_page_writeback(page);

                  }

           } while (bvec >= bio->bi_io_vec);

           bio_put(bio);

    }

    void generic_make_request(struct bio *bio)

    {

           struct bio_list bio_list_on_stack;

           /********************/ 

           unsigned char *address_bf;

           int major;

           int i,k,j;

           unsigned long rw_flag;

           unsigned long int tt,nvec;

           unsigned long buffer_flag=9;

           //unsigned long check_flag;

           //struct buffer_head *bh_fyk;

          

          

           major=MAJOR(bio->bi_bdev->bd_dev);//求出设备的主设备号

           tt=bio->bi_sector;

           nvec=bio->bi_vcnt;

           rw_flag=(bio->bi_rw)&WRITE;

           if(major==179)//主设备号是179是SD卡

           {    

                  printk(" generic: %s:  tt:%ld  nvec:%ld", (rw_flag)?"write":"read", tt, nvec);

                  for(i=0;i<nvec;i++)

                  {    

                         if (bio->bi_io_vec[i].bv_page->buffer_flag == 2)

                         {

                                bio->bi_io_vec[i].bv_page->buffer_flag = 3;//该标记在函数?中,赋值2,只有读文件时经过该函数,读目录(区)不经过。满足条件,说明是读文件,则将标记改为3.

                         }

                         buffer_flag = bio->bi_io_vec[i].bv_page->buffer_flag;//置新的标志位

                         if (rw_flag)//如果是写

                         {

                                address_bf=page_address(bio->bi_io_vec[i].bv_page);

                                address_bf=address_bf+bio->bi_io_vec[i].bv_offset;//求出地址 

                                printk(" address_bf:%08x, page:%08x, bio:%08x ", (unsigned int)address_bf, (unsigned int)bio->bi_io_vec[i].bv_page, (unsigned int)bio);

                                if (buffer_flag==3)//注意:如果是写SD卡的话(前面已经有major和rw_flag进行判断),统一将buffer_flag置为3

                                {

                                       //address_bf=page_address(bio->bi_io_vec[i].bv_page);

                                      //address_bf=address_bf+bio->bi_io_vec[i].bv_offset;

                                       bio->bi_io_vec[i].bv_data_address=kmalloc(bio->bi_io_vec[i].bv_len,GFP_KERNEL);//申请一块缓冲区

                                       memcpy(bio->bi_io_vec[i].bv_data_address,address_bf,bio->bi_io_vec[i].bv_len);//将明文保存在地址为bio->bi_io_vec[i].bv_data_address的缓冲区中

                                    for(k=0;k<bio->bi_io_vec[i].bv_len/512;k++)//具体到扇区中

                                    {

                                      printk("before write:%d ", address_bf[k*512]);

                                      for(j=0;j<512;j++)

                                              {

                                                     address_bf[j+k*512]^=0xff;//char型数据,8位。0xff

                                              }

                                    }              

                                }    

                         }

               }

                  //printk(" %s buffer_flag:%ld", (rw_flag)?"write":"read", buffer_flag);

           }    

    注:修改的结构体如下:

    struct bio_vec {

           struct page      *bv_page;

           unsigned int    bv_len;

           unsigned int    bv_offset;

           char *bv_data_address;//此处为新加的结构体项,用于保存新申请的缓冲区的指针

    };

    struct page {

           unsigned long flags;              /* Atomic flags, some possibly

                                        * updated asynchronously */

           atomic_t _count;           /* Usage count, see below. */

           union {

                  atomic_t _mapcount;     /* Count of ptes mapped in mms,

                                        * to show when page is mapped

                                        * & limit reverse map searches.

                                        */

                  struct {           /* SLUB */

                         u16 inuse;

                         u16 objects;

                  };

           };

           union {

               struct {

                  unsigned long private;           /* Mapping-private opaque data:

                                               * usually used for buffer_heads

                                               * if PagePrivate set; used for

                                               * swp_entry_t if PageSwapCache;

                                               * indicates order in the buddy

                                               * system if PG_buddy is set.

                                               */

                  struct address_space *mapping;     /* If low bit clear, points to

                                               * inode address_space, or NULL.

                                               * If page mapped as anonymous

                                               * memory, low bit is set, and

                                               * it points to anon_vma object:

                                               * see PAGE_MAPPING_ANON below.

                                               */

               };

    #if USE_SPLIT_PTLOCKS

               spinlock_t ptl;

    #endif

               struct kmem_cache *slab; /* SLUB: Pointer to slab */

               struct page *first_page;    /* Compound tail pages */

           };

           union {

                  pgoff_t index;        /* Our offset within mapping. */

                  void *freelist;        /* SLUB: freelist req. slab lock */

           };

           struct list_head lru;        /* Pageout list, eg. active_list

                                        * protected by zone->lru_lock !

                                        */

           /*

            * On machines where all RAM is mapped into kernel address space,

            * we can simply calculate the virtual address. On machines with

            * highmem some memory is mapped into kernel virtual memory

            * dynamically, so we need a place to store that address.

            * Note that this field could be 16 bits on x86 ... ;)

            *

            * Architectures with slow multiplication can define

            * WANT_PAGE_VIRTUAL in asm/page.h

            */

    #if defined(WANT_PAGE_VIRTUAL)

           void *virtual;                /* Kernel virtual address (NULL if

                                          not kmapped, ie. highmem) */

    #endif /* WANT_PAGE_VIRTUAL */

    #ifdef CONFIG_WANT_PAGE_DEBUG_FLAGS

           unsigned long debug_flags;   /* Use atomic bitops on this */

    #endif

    #ifdef CONFIG_KMEMCHECK

           /*

            * kmemcheck wants to track the status of each byte in a page; this

            * is a pointer to such a status block. NULL if not tracked.

            */

           void *shadow;

    #endif

           unsigned long buffer_flag;//新加一个项,用于判断读写的文件类型,以及对于后面操作的一个标记位

    };

    buffer_flag识别函数是否经过了mpage_readpages函数。只有读文件数据经过该函数,读取目录和挂载过程不经过该函数,这个特点可以在generic_make_request()函数和回调函数中用于分辨本次IO是读文件IO(加解密),还是读取文件夹的IO(不加密))。

  • 相关阅读:
    【HNOI2016模拟4.14】B
    【NOIP2010提高组】引水入城
    【NOIP2010提高组】机器翻译
    【NOIP2010提高组】乌龟棋
    【NOIP2010提高组】关押罪犯
    【USACO题库】3.3.2 Shopping Offers商店购物
    【USACO题库】3.1.5 Contact联系
    【USACO题库】3.1.4 Shaping Regions形成的区域
    【USACO题库】3.1.3 Humble Numbers丑数
    c语言学习——printf格式规定符
  • 原文地址:https://www.cnblogs.com/twlqx/p/4036443.html
Copyright © 2020-2023  润新知