#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, ...) \
/* 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),
.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)
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
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);
#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);
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;
}
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()
*
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 &&
atomic_inc(&p->cred->user->processes);
return 0;
}
+#ifdef CONFIG_RKP_KDP
+ }
+#endif /* CONFIG_RKP_KDP */
new = prepare_creds();
if (!new)
#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:
{
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),
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) ||
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);
!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);
#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);
}
* 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),
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,
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
*/
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,
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
*/
/* 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 */
}
/**
*/
int set_create_files_as(struct cred *new, struct inode *inode)
{
+ if (!uid_valid(inode->i_uid) || !gid_valid(inode->i_gid))
+ return -EINVAL;
new->fsuid = inode->i_uid;
new->fsgid = inode->i_gid;
return security_kernel_create_files_as(new, inode);
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));