博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
Android ashmem hacking
阅读量:6551 次
发布时间:2019-06-24

本文共 28012 字,大约阅读时间需要 93 分钟。

/********************************************************************** *                     Android ashmem hacking * 声明: *     最近有些东西涉及到binder,而binder又涉及到ashmem,于是先跟一下这 * 部分的内容。 * *                                    2016-1-12 深圳 南山平山村 曾剑锋 *********************************************************************//** * 参考文章: *     Android系统匿名共享内存Ashmem(Anonymous Shared Memory)驱动程序源代码分析 *         http://blog.csdn.net/luoshengyang/article/details/6664554 *//*                                                                                                   * ashmem_area - anonymous shared memory area                                                        * Lifecycle: From our parent file's open() until its release()                                      * Locking: Protected by `ashmem_mutex'                                                              * Big Note: Mappings do NOT pin this structure; it dies on close()                                  */                                                                                                 struct ashmem_area {                                                                                    char name[ASHMEM_FULL_NAME_LEN];/* optional name for /proc/pid/maps */                              struct list_head unpinned_list;    /* list of all ashmem areas */                                   struct file *file;        /* the shmem-based backing file */                                        size_t size;            /* size of the mapping, in bytes */                                         unsigned long prot_mask;    /* allowed prot bits, as vm_flags */                                };                                                                                                                                                                                                      /*                                                                                                   * ashmem_range - represents an interval of unpinned (evictable) pages                               * Lifecycle: From unpin to pin                                                                      * Locking: Protected by `ashmem_mutex'                                                              */                                                                                                 struct ashmem_range {                                                                                   struct list_head lru;        /* entry in LRU list */                                                struct list_head unpinned;    /* entry in its area's unpinned list */                               struct ashmem_area *asma;    /* associated area */                                                  size_t pgstart;            /* starting page, inclusive */                                           size_t pgend;            /* ending page, inclusive */                                               unsigned int purged;        /* ASHMEM_NOT or ASHMEM_WAS_PURGED */                               };                                                                                                  module_init(ashmem_init);             ----------+                               module_exit(ashmem_exit);                       |                                                                          |                                                   static int __init ashmem_init(void)   <---------+                                                   {                                                                                                       int ret;                                                                                                                                                                                                // static struct kmem_cache *ashmem_area_cachep __read_mostly;                                      ashmem_area_cachep = kmem_cache_create("ashmem_area_cache",                                                           sizeof(struct ashmem_area),                                                                         0, 0, NULL);                                                                      if (unlikely(!ashmem_area_cachep)) {                                                                    printk(KERN_ERR "ashmem: failed to create slab cache\n");                                           return -ENOMEM;                                                                                 }                                                                                                                                                                                                       ashmem_range_cachep = kmem_cache_create("ashmem_range_cache",                                                         sizeof(struct ashmem_range),                                                                        0, 0, NULL);                                                                      if (unlikely(!ashmem_range_cachep)) {                                                                   printk(KERN_ERR "ashmem: failed to create slab cache\n");                                           return -ENOMEM;                                                                                 }                                                                                                                                                                                                       ret = misc_register(&ashmem_misc);             -------------------+                                 if (unlikely(ret)) {                                              |                                     printk(KERN_ERR "ashmem: failed to register misc device!\n"); |                                     return ret;                                                   |                                 }                                                                 |                                                                                                   |                                 register_shrinker(&ashmem_shrinker);                              |                                                                                                   |                                 printk(KERN_INFO "ashmem: initialized\n");                        |                                                                                                   |                                 return 0;                                                         |                             }                                                                     |                                                                                                   |                             static struct file_operations ashmem_fops = {      <-------+          |                                 .owner = THIS_MODULE,                                  |          |                                 .open = ashmem_open,                            -------*-+        |                                 .release = ashmem_release,                             | |        |                                     .read = ashmem_read,                               | |        |                                     .llseek = ashmem_llseek,                           | |        |                                 .mmap = ashmem_mmap,                    ---------------*-*--------*---------+                       .unlocked_ioctl = ashmem_ioctl,         ---------------*-*--------*-------+ |                       .compat_ioctl = ashmem_ioctl,                          | |        |       | |                   };                                                         | |        |       | |                                                                              | |        |       | |                   static struct miscdevice ashmem_misc = {           <-------*-*--------+       | |                       .minor = MISC_DYNAMIC_MINOR,                           | |                | |                       .name = "ashmem",                                      | |                | |                       .fops = &ashmem_fops,                          --------+ |                | |                   };               +-------------------------------------------+                | |                                    V                                                            | |                   static int ashmem_open(struct inode *inode, struct file *file)                | |                   {                                                                             | |                       struct ashmem_area *asma;                                                 | |                       int ret;                                                                  | |                                                                                                 | |                       ret = generic_file_open(inode, file);                                     | |                       if (unlikely(ret))                                                        | |                           return ret;                                                           | |                                                                                                 | |                       // static struct kmem_cache *ashmem_area_cachep __read_mostly;            | |                       // ashmem_area_cachep = kmem_cache_create("ashmem_area_cache",            | |                       //                   sizeof(struct ashmem_area),                          | |                       //                   0, 0, NULL);                                         | |                       asma = kmem_cache_zalloc(ashmem_area_cachep, GFP_KERNEL);                 | |                       if (unlikely(!asma))                                                      | |                           return -ENOMEM;                                                       | |                                                                                                 | |                       INIT_LIST_HEAD(&asma->unpinned_list);                                     | |                       // #define ASHMEM_NAME_PREFIX "dev/ashmem/"                               | |                       // #define ASHMEM_NAME_PREFIX_LEN (sizeof(ASHMEM_NAME_PREFIX) - 1)        | |                       // #define ASHMEM_FULL_NAME_LEN (ASHMEM_NAME_LEN + ASHMEM_NAME_PREFIX_LEN)| |                       memcpy(asma->name, ASHMEM_NAME_PREFIX, ASHMEM_NAME_PREFIX_LEN);           | |                       // #define PROT_MASK        (PROT_EXEC | PROT_READ | PROT_WRITE)          | |                       asma->prot_mask = PROT_MASK;                                              | |                       // can get this asma struct in other function                             | |                       file->private_data = asma;                                                | |                                                                                                 | |                       return 0;     +-----------------------------------------------------------+ |                   }                 |                                                             |                                     V                                                             |                   static long ashmem_ioctl(struct file *file, unsigned int cmd, unsigned long arg)|                   {                                                                               |                       struct ashmem_area *asma = file->private_data;                              |                       long ret = -ENOTTY;                                                         |                                                                                                   |                       switch (cmd) {                                                              |                       case ASHMEM_SET_NAME:                                                       |                           ret = set_name(asma, (void __user *) arg);      -------+                |                           break;                                                 |                |                       case ASHMEM_GET_NAME:                                      |                |                           ret = get_name(asma, (void __user *) arg);      -------*-----+          |                           break;                                                 |     |          |                       case ASHMEM_SET_SIZE:                                      |     |          |                           ret = -EINVAL;                                         |     |          |                           if (!asma->file) {                                     |     |          |                               ret = 0;                                           |     |          |                               asma->size = (size_t) arg;                         |     |          |                           }                                                      |     |          |                           break;                                                 |     |          |                       case ASHMEM_GET_SIZE:                                      |     |          |                           ret = asma->size;                                      |     |          |                           break;                                                 |     |          |                       case ASHMEM_SET_PROT_MASK:                                 |     |          |                           ret = set_prot_mask(asma, arg);                        |     |          |                           break;                                                 |     |          |                       case ASHMEM_GET_PROT_MASK:                                 |     |          |                           ret = asma->prot_mask;                                 |     |          |                           break;                                                 |     |          |                       case ASHMEM_PIN:                                           |     |          |                       case ASHMEM_UNPIN:                                         |     |          |                       case ASHMEM_GET_PIN_STATUS:                                |     |          |                           ret = ashmem_pin_unpin(asma, cmd, (void __user *) arg);|     |          |                           break;                                                 |     |          |                       case ASHMEM_PURGE_ALL_CACHES:                              |     |          |                           ret = -EPERM;                                          |     |          |                           if (capable(CAP_SYS_ADMIN)) {                          |     |          |                               struct shrink_control sc = {                       |     |          |                                   .gfp_mask = GFP_KERNEL,                        |     |          |                                   .nr_to_scan = 0,                               |     |          |                               };                                                 |     |          |                               ret = ashmem_shrink(&ashmem_shrinker, &sc);        |     |          |                               sc.nr_to_scan = ret;                               |     |          |                               ashmem_shrink(&ashmem_shrinker, &sc);              |     |          |                           }                                                      |     |          |                           break;                                                 |     |          |                       }                                                          |     |          |                                                                                  |     |          |                       return ret;                                                |     |          |                   }               +----------------------------------------------+     |          |                                   V                                                    |          |                   static int set_name(struct ashmem_area *asma, void __user *name)     |          |                   {                                                                    |          |                       int ret = 0;                                                     |          |                                                                                        |          |                       mutex_lock(&ashmem_mutex);                                       |          |                                                                                        |          |                       /* cannot change an existing mapping's name */                   |          |                       if (unlikely(asma->file)) {                                      |          |                           ret = -EINVAL;                                               |          |                           goto out;                                                    |          |                       }                                                                |          |                                                                                        |          |                       if (unlikely(copy_from_user(asma->name + ASHMEM_NAME_PREFIX_LEN, |          |                                       name, ASHMEM_NAME_LEN)))                         |          |                           ret = -EFAULT;                                               |          |                       asma->name[ASHMEM_FULL_NAME_LEN-1] = '\0';                       |          |                                                                                        |          |                   out:                                                                 |          |                       mutex_unlock(&ashmem_mutex);                                     |          |                                                                                        |          |                       return ret;                                                      |          |                   }             +------------------------------------------------------+          |                                 V                                                                 |                   static int get_name(struct ashmem_area *asma, void __user *name)                |                   {                                                                               |                       int ret = 0;                                                                |                                                                                                   |                       mutex_lock(&ashmem_mutex);                                                  |                       if (asma->name[ASHMEM_NAME_PREFIX_LEN] != '\0') {                           |                           size_t len;                                                             |                                                                                                   |                           /*                                                                      |                            * Copying only `len', instead of ASHMEM_NAME_LEN, bytes                |                            * prevents us from revealing one user's stack to another.              |                            */                                                                     |                           len = strlen(asma->name + ASHMEM_NAME_PREFIX_LEN) + 1;                  |                           if (unlikely(copy_to_user(name,                                         |                                   asma->name + ASHMEM_NAME_PREFIX_LEN, len)))                     |                               ret = -EFAULT;                                                      |                       } else {                                                                    |                           if (unlikely(copy_to_user(name, ASHMEM_NAME_DEF,                        |                                         sizeof(ASHMEM_NAME_DEF))))                                |                               ret = -EFAULT;                                                      |                       }                                                                           |                       mutex_unlock(&ashmem_mutex);                                                |                                                                                                   |                       return ret;                                                                 |                   }                                                                               |                                                                                                   |                   static int ashmem_mmap(struct file *file, struct vm_area_struct *vma)  <--------+                   {                                                                                                       struct ashmem_area *asma = file->private_data;                                                      int ret = 0;                                                                                                                                                                                            mutex_lock(&ashmem_mutex);                                                                                                                                                                              /* user needs to SET_SIZE before mapping */                                                         if (unlikely(!asma->size)) {                                                                            ret = -EINVAL;                                                                                      goto out;                                                                                       }                                                                                                                                                                                                       /* requested protection bits must match our allowed protection mask */                              if (unlikely((vma->vm_flags & ~calc_vm_prot_bits(asma->prot_mask)) &                                                    calc_vm_prot_bits(PROT_MASK))) {                                                    ret = -EPERM;                                                                                       goto out;                                                                                       }                                                                                                   vma->vm_flags &= ~calc_vm_may_flags(~asma->prot_mask);                                                                                                                                                  if (!asma->file) {                                                                                      char *name = ASHMEM_NAME_DEF;                                                                       struct file *vmfile;                                                                                                                                                                                    if (asma->name[ASHMEM_NAME_PREFIX_LEN] != '\0')                                                         name = asma->name;                                                                                                                                                                                  /* ... and allocate the backing shmem file */                                                       vmfile = shmem_file_setup(name, asma->size, vma->vm_flags);                                         if (unlikely(IS_ERR(vmfile))) {                                                                         ret = PTR_ERR(vmfile);                                                                              goto out;                                                                                       }                                                                                                   asma->file = vmfile;                                                                            }                                                                                                   // #define get_file(x)    atomic_long_inc(&(x)->f_count)                                            get_file(asma->file);                                                                                                                                                                                   if (vma->vm_flags & VM_SHARED)                                                                          shmem_set_file(vma, asma->file);   --------------+                                              else {                                               |                                                  if (vma->vm_file)                                |                                                      fput(vma->vm_file);                          |                                                  vma->vm_file = asma->file;                       |                                              }                                                    |                                              vma->vm_flags |= VM_CAN_NONLINEAR;                   |                                                                                                   |                                          out:                                                     |                                              mutex_unlock(&ashmem_mutex);                         |                                              return ret;                                          |                                          }             +------------------------------------------+                                                        v                                                                                     void shmem_set_file(struct vm_area_struct *vma, struct file *file)                                  {                                                                                                       if (vma->vm_file)                                                                                       fput(vma->vm_file);                -------------+                                               vma->vm_file = file;                                |                                               vma->vm_ops = &shmem_vm_ops;                        |                                               vma->vm_flags |= VM_CAN_NONLINEAR;                  |                                           }                                                       |                                                                                                   |                                           void fput(struct file *file)               <------------+                                           {                                                                                                       if (atomic_long_dec_and_test(&file->f_count))                                                           __fput(file);                                                                               }

 

你可能感兴趣的文章
解决android引用library project错误
查看>>
Java并发编程之 CompletionService
查看>>
PHP 开发者准备的 12 个调试工具
查看>>
yaml格式文件(类似xml)
查看>>
@classmethod and @staticmethod
查看>>
thinkphp使用中遇到的问题
查看>>
Google I/O-javascript
查看>>
mybatis 的使用和配置
查看>>
电商网站的初期技术选型
查看>>
tpc-ds测试
查看>>
nginx反向代理配置及优化
查看>>
信息安全不可错过的30门实验
查看>>
解决开发环境与部属环境差异性的一种实践
查看>>
思科高级路由与交换(CISCO 部分) 第1-2天
查看>>
快照实现技术浅析
查看>>
使用AngularJS构建大型Web应用
查看>>
mongodb
查看>>
Java中 截取字符串的问题
查看>>
synchronized(this)总结
查看>>
酷派手机不打印日志
查看>>