BACKPORT: block/loop: set hw_sectors
[GitHub/exynos8895/android_kernel_samsung_universal8895.git] / kernel / cred.c
index ff8606f77d901d4ed1201d35d35feaa5066821e3..6876742282b78a5f31f80f01b0056bff6686e1b6 100644 (file)
@@ -18,6 +18,9 @@
 #include <linux/security.h>
 #include <linux/binfmts.h>
 #include <linux/cn_proc.h>
+#ifdef CONFIG_RKP_KDP
+#include <linux/slub_def.h>
+#endif
 
 #if 0
 #define kdebug(FMT, ...)                                               \
@@ -36,11 +39,52 @@ static struct kmem_cache *cred_jar;
 
 /* init to 2 - one for init_task, one to ensure it is never freed */
 struct group_info init_groups = { .usage = ATOMIC_INIT(2) };
+#ifdef CONFIG_RKP_KDP
+RKP_RO_AREA int rkp_cred_enable = 0;
+
+static struct kmem_cache *cred_jar_ro;
+struct kmem_cache *tsec_jar;
+struct kmem_cache *usecnt_jar;
+atomic_t init_cred_use_cnt = ATOMIC_INIT(4);
+
+unsigned  int rkp_get_usecount(struct cred *cred)
+{
+       if (rkp_ro_page((unsigned long )cred))
+                       return (unsigned int)rocred_uc_read(cred);
+       else
+                       return atomic_read(&cred->usage);
+}
+
+struct cred *get_new_cred(struct cred *cred)
+{
+       if (rkp_ro_page((unsigned long)cred))
+               rocred_uc_inc(cred);
+       else
+               atomic_inc(&cred->usage);
+       return cred;
+}
+
+void put_cred(const struct cred *_cred)
+{
+       struct cred *cred = (struct cred *) _cred;
+
+       validate_creds(cred);
+
+       if (rkp_ro_page((unsigned long)cred)) {
+               if (rocred_uc_dec_and_test(cred)) {
+                       __put_cred(cred);
+               }
+       } else {
+               if (atomic_dec_and_test(&(cred)->usage))
+                       __put_cred(cred);
+       }
+}
+#endif  /* CONFIG_RKP_KDP */
 
 /*
  * The initial credentials for the initial task
  */
-struct cred init_cred = {
+RKP_RO_AREA struct cred init_cred = {
        .usage                  = ATOMIC_INIT(4),
 #ifdef CONFIG_DEBUG_CREDENTIALS
        .subscribers            = ATOMIC_INIT(2),
@@ -62,6 +106,12 @@ struct cred init_cred = {
        .user                   = INIT_USER,
        .user_ns                = &init_user_ns,
        .group_info             = &init_groups,
+#ifdef CONFIG_RKP_KDP
+       .use_cnt                = &init_cred_use_cnt,
+       .bp_task                = &init_task,
+       .bp_pgd                 = (void *) 0,
+       .type                   = 0,
+#endif /*CONFIG_RKP_KDP*/
 };
 
 static inline void set_cred_subscribers(struct cred *cred, int n)
@@ -125,6 +175,30 @@ static void put_cred_rcu(struct rcu_head *rcu)
        kmem_cache_free(cred_jar, cred);
 }
 
+#ifdef CONFIG_RKP_KDP
+/* We use another function to free protected creds. */
+static void put_ro_cred(struct cred *cred)
+{
+
+       if (rocred_uc_read(cred) != 0)
+               panic("RO_CRED: put_ro_cred() sees %p with usage %d\n",
+                               cred, rocred_uc_read(cred));
+
+       security_cred_free(cred);
+       key_put(cred->session_keyring);
+       key_put(cred->process_keyring);
+       key_put(cred->thread_keyring);
+       key_put(cred->request_key_auth);
+       if (cred->group_info)
+               put_group_info(cred->group_info);
+       free_uid(cred->user);
+       put_user_ns(cred->user_ns);
+       if(cred->use_cnt)
+               kmem_cache_free(usecnt_jar,(void *)cred->use_cnt);
+       kmem_cache_free(cred_jar_ro, cred);
+}
+#endif
+
 /**
  * __put_cred - Destroy a set of credentials
  * @cred: The record to release
@@ -136,7 +210,11 @@ void __put_cred(struct cred *cred)
        kdebug("__put_cred(%p{%d,%d})", cred,
               atomic_read(&cred->usage),
               read_cred_subscribers(cred));
-
+#ifdef CONFIG_RKP_KDP
+       if (rkp_ro_page((unsigned long)cred))
+               BUG_ON((rocred_uc_read(cred)) != 0);
+       else
+#endif /*CONFIG_RKP_KDP*/
        BUG_ON(atomic_read(&cred->usage) != 0);
 #ifdef CONFIG_DEBUG_CREDENTIALS
        BUG_ON(read_cred_subscribers(cred) != 0);
@@ -145,7 +223,11 @@ void __put_cred(struct cred *cred)
 #endif
        BUG_ON(cred == current->cred);
        BUG_ON(cred == current->real_cred);
-
+#ifdef CONFIG_RKP_KDP
+       if (rkp_ro_page((unsigned long)cred)) {
+               put_ro_cred(cred);
+       } else
+#endif /*CONFIG_RKP_KDP*/
        call_rcu(&cred->rcu, put_cred_rcu);
 }
 EXPORT_SYMBOL(__put_cred);
@@ -187,14 +269,27 @@ void exit_creds(struct task_struct *tsk)
 const struct cred *get_task_cred(struct task_struct *task)
 {
        const struct cred *cred;
-
+#ifdef CONFIG_RKP_KDP
+       int inc_test;
+#endif /*CONFIG_RKP_KDP*/
        rcu_read_lock();
 
+#ifdef CONFIG_RKP_KDP
+       do {
+               cred = __task_cred((task));
+               BUG_ON(!cred);
+               if (rkp_ro_page((unsigned long)cred)) {
+                       inc_test = rocred_uc_inc_not_zero(cred);
+               }
+               else
+                       inc_test = atomic_inc_not_zero(&((struct cred *)cred)->usage);
+       } while (!inc_test);
+#else
        do {
                cred = __task_cred((task));
                BUG_ON(!cred);
        } while (!atomic_inc_not_zero(&((struct cred *)cred)->usage));
-
+#endif /*CONFIG_RKP_KDP*/
        rcu_read_unlock();
        return cred;
 }
@@ -309,7 +404,46 @@ struct cred *prepare_exec_creds(void)
 
        return new;
 }
+#ifdef CONFIG_RKP_KDP
+int rkp_from_tsec_jar(unsigned long addr)
+{
+       static void *objp;
+       static struct kmem_cache *s;
+       static struct page *page;
+       
+       objp = (void *)addr;
 
+       if(!objp)
+               return 0;
+
+       page = virt_to_head_page(objp);
+       s = page->slab_cache;
+       if(s && s->name) {
+               if(!strcmp(s->name,"tsec_jar")) {
+                       return 1;
+               }
+       }
+       return 0;
+}
+int chk_invalid_kern_ptr(u64 tsec) 
+{
+       return (((u64)tsec >> 36) != (u64)0xFFFFFFC);
+}
+void rkp_free_security(unsigned long tsec)
+{
+       if(!tsec || 
+               chk_invalid_kern_ptr(tsec))
+               return;
+
+       if(rkp_ro_page(tsec) && 
+               rkp_from_tsec_jar(tsec)){
+               kmem_cache_free(tsec_jar,(void *)tsec);
+       }
+       else { 
+               kfree((void *)tsec);
+       }
+}
+#endif /*CONFIG_RKP_KDP*/
 /*
  * Copy credentials for the new process created by fork()
  *
@@ -322,8 +456,26 @@ struct cred *prepare_exec_creds(void)
 int copy_creds(struct task_struct *p, unsigned long clone_flags)
 {
        struct cred *new;
+#ifdef CONFIG_RKP_KDP
+       struct cred *new_ro;
+       void *use_cnt_ptr = NULL;
+       void *tsec = NULL;
+       int rkp_use_cnt = 0;
+#endif /*CONFIG_RKP_KDP*/
        int ret;
 
+       /*
+        * Disabling cred sharing among the same thread group. This
+        * is needed because we only added one back pointer in cred.
+        *
+        * This should NOT in any way change kernel logic, if we think about what
+        * happens when a thread needs to change its credentials: it will just
+        * create a new one, while all other threads in the same thread group still
+        * reference the old one, whose reference counter decreases by 2.
+        */
+#ifdef CONFIG_RKP_KDP
+       if(!rkp_cred_enable){
+#endif  /* CONFIG_RKP_KDP */
        if (
 #ifdef CONFIG_KEYS
                !p->cred->thread_keyring &&
@@ -339,6 +491,9 @@ int copy_creds(struct task_struct *p, unsigned long clone_flags)
                atomic_inc(&p->cred->user->processes);
                return 0;
        }
+#ifdef CONFIG_RKP_KDP
+       }
+#endif  /* CONFIG_RKP_KDP */
 
        new = prepare_creds();
        if (!new)
@@ -370,9 +525,49 @@ int copy_creds(struct task_struct *p, unsigned long clone_flags)
 #endif
 
        atomic_inc(&new->user->processes);
+#ifdef CONFIG_RKP_KDP
+       if(rkp_cred_enable){
+               cred_param_t cred_param;
+               new_ro = kmem_cache_alloc(cred_jar_ro, GFP_KERNEL);
+               if (!new_ro)
+                       panic("copy_creds(): kmem_cache_alloc() failed");
+
+               use_cnt_ptr = kmem_cache_alloc(usecnt_jar,GFP_KERNEL);
+               if(!use_cnt_ptr)
+                       panic("copy_creds() : Unable to allocate usage pointer\n");
+
+               tsec = kmem_cache_alloc(tsec_jar, GFP_KERNEL);
+               if(!tsec)
+                       panic("copy_creds() : Unable to allocate security pointer\n");
+               
+               rkp_cred_fill_params(new,new_ro,use_cnt_ptr,tsec,RKP_CMD_COPY_CREDS,p);
+               rkp_call(RKP_CMDID(0x46),(unsigned long long)&cred_param,0,0,0,0);
+               if((new_ro->bp_task != p) 
+                       || new_ro->security != tsec 
+                       || new_ro->use_cnt != use_cnt_ptr) {
+                       panic("Copy Creds: RKP Call failed task=#%p:%p#, sec=#%p:%p#, usecnt=#%p:%p#",new_ro->bp_task,p,new_ro->security,tsec,new_ro->use_cnt,use_cnt_ptr);
+               }
+               rkp_use_cnt = atomic_read(&new->usage);
+               rkp_use_cnt = rkp_use_cnt + 1;
+
+               rocred_uc_set(new_ro,rkp_use_cnt);
+               p->cred = p->real_cred = new_ro;
+
+               validate_creds(new_ro);
+               rkp_free_security((unsigned long)new->security);
+               kmem_cache_free(cred_jar, new);
+       }
+       else {
+               p->cred = p->real_cred = get_cred(new);
+               alter_cred_subscribers(new, 2);
+               validate_creds(new);
+       }
+#else
        p->cred = p->real_cred = get_cred(new);
        alter_cred_subscribers(new, 2);
        validate_creds(new);
+#endif  /* CONFIG_RKP_KDP */
+
        return 0;
 
 error_put:
@@ -423,6 +618,13 @@ int commit_creds(struct cred *new)
 {
        struct task_struct *task = current;
        const struct cred *old = task->real_cred;
+#ifdef CONFIG_RKP_KDP
+       struct cred *new_ro;
+       void *use_cnt_ptr = NULL;
+       unsigned int rkp_use_cnt = 0;
+       void *tsec = NULL;
+       u64 pgd =(u64)(current->mm?current->mm->pgd:swapper_pg_dir);
+#endif
 
        kdebug("commit_creds(%p{%d,%d})", new,
               atomic_read(&new->usage),
@@ -433,10 +635,22 @@ int commit_creds(struct cred *new)
        BUG_ON(read_cred_subscribers(old) < 2);
        validate_creds(old);
        validate_creds(new);
+#endif
+#ifdef CONFIG_RKP_KDP
+       if (rkp_ro_page((unsigned long)new))
+               BUG_ON((rocred_uc_read(new)) < 1);
+       else
 #endif
        BUG_ON(atomic_read(&new->usage) < 1);
 
+
+#ifdef CONFIG_RKP_KDP
+       if(!rkp_cred_enable) {
+#endif  /* CONFIG_RKP_KDP */
        get_cred(new); /* we will require a ref for the subj creds too */
+#ifdef CONFIG_RKP_KDP
+       }
+#endif  /* CONFIG_RKP_KDP */
 
        /* dumpability changes */
        if (!uid_eq(old->euid, new->euid) ||
@@ -463,8 +677,44 @@ int commit_creds(struct cred *new)
        alter_cred_subscribers(new, 2);
        if (new->user != old->user)
                atomic_inc(&new->user->processes);
+#ifdef CONFIG_RKP_KDP
+       if(rkp_cred_enable) {
+               cred_param_t cred_param;
+               new_ro = kmem_cache_alloc(cred_jar_ro, GFP_KERNEL);
+               if (!new_ro)
+                       panic("commit_creds(): kmem_cache_alloc() failed");
+
+               use_cnt_ptr = kmem_cache_alloc(usecnt_jar,GFP_KERNEL);
+               if(!use_cnt_ptr)
+                       panic("commit_creds() : Unable to allocate usage pointer\n");
+               
+               tsec = kmem_cache_alloc(tsec_jar, GFP_KERNEL);
+               if(!tsec)
+                       panic("commit_creds() : Unable to allocate security pointer\n");
+
+               rkp_cred_fill_params(new,new_ro,use_cnt_ptr,tsec,RKP_CMD_CMMIT_CREDS,0);        
+               rkp_call(RKP_CMDID(0x46),(unsigned long long)&cred_param,0,0,0,0);
+               if((new_ro->bp_task != current)||
+                       (current->mm 
+                       && (!( in_interrupt() || in_softirq())) 
+                       && new_ro->bp_pgd != (void *)pgd) ||
+                       (new_ro->security != tsec) ||
+                       (new_ro->use_cnt != use_cnt_ptr)) {
+                       panic("Commit Creds: RKP Call failed task=#%p:%p#, sec=#%p:%p#, usecnt=#%p:%p#, pgd=#%p:%p#",new_ro->bp_task,current,new_ro->security,tsec,new_ro->use_cnt,use_cnt_ptr,new_ro->bp_pgd,(void *)pgd);
+               }
+               rcu_assign_pointer(task->real_cred, new_ro);
+               rcu_assign_pointer(task->cred, new_ro);
+
+               rocred_uc_set(new_ro,2);
+       } 
+       else {
+               rcu_assign_pointer(task->real_cred, new);
+               rcu_assign_pointer(task->cred, new);
+       }
+#else
        rcu_assign_pointer(task->real_cred, new);
        rcu_assign_pointer(task->cred, new);
+#endif  /* CONFIG_RKP_KDP */
        if (new->user != old->user)
                atomic_dec(&old->user->processes);
        alter_cred_subscribers(old, -2);
@@ -481,7 +731,17 @@ int commit_creds(struct cred *new)
            !gid_eq(new->sgid,  old->sgid) ||
            !gid_eq(new->fsgid, old->fsgid))
                proc_id_connector(task, PROC_EVENT_GID);
-
+#ifdef CONFIG_RKP_KDP
+       if (rkp_cred_enable && 
+               !rkp_ro_page((unsigned long)new)) {
+               rkp_use_cnt = atomic_read(&new->usage);
+               if(rkp_use_cnt == 1) {
+                       atomic_set(&new->usage, 0);
+                       rkp_free_security((unsigned long)new->security);
+                       kmem_cache_free(cred_jar, new);
+               }
+       }
+#endif  /* CONFIG_RKP_KDP */
        /* release the old obj and subj refs both */
        put_cred(old);
        put_cred(old);
@@ -505,6 +765,11 @@ void abort_creds(struct cred *new)
 #ifdef CONFIG_DEBUG_CREDENTIALS
        BUG_ON(read_cred_subscribers(new) != 0);
 #endif
+#ifdef CONFIG_RKP_KDP
+       if (rkp_ro_page((unsigned long)new))
+               BUG_ON((rocred_uc_read(new)) < 1);
+       else
+#endif  /* CONFIG_RKP_KDP */
        BUG_ON(atomic_read(&new->usage) < 1);
        put_cred(new);
 }
@@ -517,9 +782,21 @@ EXPORT_SYMBOL(abort_creds);
  * Install a set of temporary override subjective credentials on the current
  * process, returning the old set for later reversion.
  */
+#ifdef CONFIG_RKP_KDP
+const struct cred *rkp_override_creds(struct cred **cnew)
+#else
 const struct cred *override_creds(const struct cred *new)
+#endif  /* CONFIG_RKP_KDP */
 {
        const struct cred *old = current->cred;
+#ifdef CONFIG_RKP_KDP
+       struct cred *new = *cnew;
+       struct cred *new_ro;
+       volatile unsigned int rkp_use_count = rkp_get_usecount(new);
+       void *use_cnt_ptr = NULL;
+       void *tsec = NULL;
+       u64 pgd =(u64)(current->mm?current->mm->pgd:swapper_pg_dir);
+#endif  /* CONFIG_RKP_KDP */
 
        kdebug("override_creds(%p{%d,%d})", new,
               atomic_read(&new->usage),
@@ -527,9 +804,52 @@ const struct cred *override_creds(const struct cred *new)
 
        validate_creds(old);
        validate_creds(new);
+#ifdef CONFIG_RKP_KDP
+       if(rkp_cred_enable) {
+               cred_param_t cred_param;
+               new_ro = kmem_cache_alloc(cred_jar_ro, GFP_KERNEL);
+               if (!new_ro)
+                       panic("override_creds(): kmem_cache_alloc() failed");
+
+               use_cnt_ptr = kmem_cache_alloc(usecnt_jar,GFP_KERNEL);
+               if(!use_cnt_ptr)
+                       panic("override_creds() : Unable to allocate usage pointer\n");
+
+               tsec = kmem_cache_alloc(tsec_jar, GFP_KERNEL);
+               if(!tsec)
+                       panic("override_creds() : Unable to allocate security pointer\n");
+
+               rkp_cred_fill_params(new,new_ro,use_cnt_ptr,tsec,RKP_CMD_OVRD_CREDS,rkp_use_count);     
+               rkp_call(RKP_CMDID(0x46),(unsigned long long)&cred_param,0,0,0,0);
+               if((new_ro->bp_task != current)||
+                       (current->mm 
+                       && (!( in_interrupt() || in_softirq())) 
+                       && new_ro->bp_pgd != (void *)pgd) ||
+                       (new_ro->security != tsec) ||
+                       (new_ro->use_cnt != use_cnt_ptr)) {
+                       panic("Commit Creds: RKP Call failed task=#%p:%p#, sec=#%p:%p#, usecnt=#%p:%p#, pgd=#%p:%p#",new_ro->bp_task,current,new_ro->security,tsec,new_ro->use_cnt,use_cnt_ptr,new_ro->bp_pgd,(void *)pgd);
+               }
+               rocred_uc_set(new_ro,2);
+               rcu_assign_pointer(current->cred, new_ro);
+
+               if(!rkp_ro_page((unsigned long)new)){
+                       if(atomic_read(&new->usage) == 1) {
+                               rkp_free_security((unsigned long)new->security);
+                               kmem_cache_free(cred_jar, (void *)(*cnew));
+                               *cnew = new_ro; 
+                       }
+               }
+       }
+       else {
+               get_cred(new);
+               alter_cred_subscribers(new, 1);
+               rcu_assign_pointer(current->cred, new);
+       }
+#else
        get_cred(new);
        alter_cred_subscribers(new, 1);
        rcu_assign_pointer(current->cred, new);
+#endif  /* CONFIG_RKP_KDP */
        alter_cred_subscribers(old, -1);
 
        kdebug("override_creds() = %p{%d,%d}", old,
@@ -537,8 +857,11 @@ const struct cred *override_creds(const struct cred *new)
               read_cred_subscribers(old));
        return old;
 }
+#ifdef CONFIG_RKP_KDP
+EXPORT_SYMBOL(rkp_override_creds);
+#else
 EXPORT_SYMBOL(override_creds);
-
+#endif  /* CONFIG_RKP_KDP */
 /**
  * revert_creds - Revert a temporary subjective credentials override
  * @old: The credentials to be restored
@@ -548,6 +871,9 @@ EXPORT_SYMBOL(override_creds);
  */
 void revert_creds(const struct cred *old)
 {
+#ifdef CONFIG_RKP_KDP
+       int rkp_use_cnt = 0;
+#endif  /* CONFIG_RKP_KDP */
        const struct cred *override = current->cred;
 
        kdebug("revert_creds(%p{%d,%d})", old,
@@ -559,10 +885,45 @@ void revert_creds(const struct cred *old)
        alter_cred_subscribers(old, 1);
        rcu_assign_pointer(current->cred, old);
        alter_cred_subscribers(override, -1);
+#ifdef CONFIG_RKP_KDP
+       if(rkp_cred_enable) {
+               rkp_use_cnt = rkp_get_usecount((struct cred*)override);
+               if (rkp_ro_page((unsigned long)override)) {
+                       struct cred *rocred = (struct cred *) override;
+                       rkp_use_cnt = rocred_uc_read(rocred);
+
+                       if( (rocred->type & 0x1) 
+                               && (rkp_use_cnt == 2)){
+                               rocred_uc_set((rocred), 0);
+                               if(rocred->use_cnt)
+                                       kmem_cache_free(usecnt_jar,(void *)rocred->use_cnt);
+                               security_cred_free(rocred);
+                               kmem_cache_free(cred_jar_ro, (struct cred *)rocred);
+                               return;
+                       }
+               }
+       }
+#endif  /* CONFIG_RKP_KDP */
        put_cred(override);
 }
 EXPORT_SYMBOL(revert_creds);
 
+#ifdef CONFIG_RKP_KDP
+void cred_ctor(void *data)
+{
+       /* Dummy constructor to make sure we have separate slabs caches. */
+}
+void sec_ctor(void *data)
+{
+       /* Dummy constructor to make sure we have separate slabs caches. */
+       //printk("\n initializing sec_ctor = %p \n",data);
+}
+void usecnt_ctor(void *data)
+{
+       /* Dummy constructor to make sure we have separate slabs caches. */
+}
+#endif  /* CONFIG_RKP_KDP */
+
 /*
  * initialise the credentials stuff
  */
@@ -571,6 +932,28 @@ void __init cred_init(void)
        /* allocate a slab in which we can store credentials */
        cred_jar = kmem_cache_create("cred_jar", sizeof(struct cred),
                                     0, SLAB_HWCACHE_ALIGN|SLAB_PANIC, NULL);
+#ifdef CONFIG_RKP_KDP
+       if(rkp_cred_enable) {
+               cred_jar_ro = kmem_cache_create("cred_jar_ro", sizeof(struct cred),
+                               0, SLAB_HWCACHE_ALIGN|SLAB_PANIC, cred_ctor);
+               if(!cred_jar_ro) {
+                       panic("Unable to create RO Cred cache\n");
+               }
+
+               tsec_jar = kmem_cache_create("tsec_jar", rkp_get_task_sec_size(),
+                               0, SLAB_HWCACHE_ALIGN|SLAB_PANIC, sec_ctor);
+               if(!tsec_jar) {
+                       panic("Unable to create RO security cache\n");
+               }
+
+               usecnt_jar = kmem_cache_create("usecnt_jar", sizeof(int),
+                               0, SLAB_HWCACHE_ALIGN|SLAB_PANIC, usecnt_ctor);
+               if(!usecnt_jar) {
+                       panic("Unable to create use count jar\n");
+               }
+               rkp_call(RKP_CMDID(0x42),(unsigned long long )cred_jar_ro->size,(unsigned long long)tsec_jar->size,0,0,0);
+       }
+#endif  /* CONFIG_RKP_KDP */
 }
 
 /**
@@ -733,6 +1116,14 @@ static void dump_invalid_creds(const struct cred *cred, const char *label,
               cred == tsk->cred ? "[eff]" : "");
        printk(KERN_ERR "CRED: ->magic=%x, put_addr=%p\n",
               cred->magic, cred->put_addr);
+#ifdef CONFIG_RKP_KDP
+       if (rkp_ro_page((unsigned long)cred)) {
+               printk(KERN_ERR "CRED: ->usage(FROM ARRAY)=%d, subscr=%d\n",
+                               atomic_read(&cred_usage[cred_usage_offset(cred)),
+                               read_cred_subscribers(cred));
+       }
+       else
+#endif  /* CONFIG_RKP_KDP */
        printk(KERN_ERR "CRED: ->usage=%d, subscr=%d\n",
               atomic_read(&cred->usage),
               read_cred_subscribers(cred));