From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1422663AbWGNR0M (ORCPT ); Fri, 14 Jul 2006 13:26:12 -0400 Received: (majordomo@vger.kernel.org) by vger.kernel.org id S1422671AbWGNR0M (ORCPT ); Fri, 14 Jul 2006 13:26:12 -0400 Received: from e4.ny.us.ibm.com ([32.97.182.144]:27566 "EHLO e4.ny.us.ibm.com") by vger.kernel.org with ESMTP id S1422667AbWGNRYp (ORCPT ); Fri, 14 Jul 2006 13:24:45 -0400 Subject: [RFC][PATCH 6/6] SLIM: debug output From: Kylene Jo Hall To: linux-kernel , LSM ML Cc: Dave Safford , Mimi Zohar , Serge Hallyn Content-Type: text/plain Date: Fri, 14 Jul 2006 10:24:48 -0700 Message-Id: <1152897888.23584.9.camel@localhost.localdomain> Mime-Version: 1.0 X-Mailer: Evolution 2.0.4 (2.0.4-7) Content-Transfer-Encoding: 7bit Sender: linux-kernel-owner@vger.kernel.org X-Mailing-List: linux-kernel@vger.kernel.org This patch contains all the necessary pieces to add debugging output to SLIM. Signed-off-by: Mimi Zohar Signed-off-by: Kylene Hall --- security/slim/slim.h | 16 + security/slim/slm_main.c | 499 +++++++++++++++++++++++++++++++----- security/slim/slm_secfs.c | 117 ++++++++ 3 files changed, 570 insertions(+), 62 deletions(-) --- linux-2.6.17/security/slim/slim.h 2006-07-13 16:23:05.000000000 -0700 +++ linux-2.6.17/security/slim/slim.h 2006-07-13 16:29:00.000000000 -0700 @@ -100,3 +103,19 @@ extern int slm_init_config(void); extern __init int slm_init_secfs(void); extern __exit void slm_cleanup_secfs(void); + +extern __init int slm_init_debugfs(void); +extern __exit void slm_cleanup_debugfs(void); + +extern unsigned int slm_debug; +enum slm_debug_level { + SLM_BASE = 1, + SLM_INTEGRITY = 2, + SLM_SECRECY = 4, + SLM_VERBOSE = 8, +}; + +#undef dprintk +#define dprintk(level, format, a...) \ + if (slm_debug & level) \ + printk(KERN_INFO format, ##a) --- linux-2.6.17/security/slim/slm_main.c 2006-07-13 16:26:49.000000000 -0700 +++ linux-2.6.17/security/slim/slm_main.c 2006-07-13 16:12:01.000000000 -0700 @@ -37,6 +37,7 @@ #define MY_NAME "slim" #endif +unsigned int slm_debug = SLM_BASE; static char *slm_xattr_name = "security.slim.level"; static int secondary; static DEFINE_SPINLOCK(slm_inode_sec_lock); @@ -136,10 +137,17 @@ static inline void do_revoke_file_wperm( return; isec = inode->i_security; - if (!isec) + if (!isec) { + dprintk(SLM_VERBOSE, "%s: isec is null\n", __FUNCTION__); return; - if (cur_level->iac_level < isec->level.iac_level) + } + if (cur_level->iac_level < isec->level.iac_level) { file->f_mode &= ~FMODE_WRITE; + if (file->f_dentry->d_name.name) + dprintk(SLM_BASE, "pid %d - revoking write perm " + "for %s\n", current->pid, + file->f_dentry->d_name.name); + } } /* @@ -184,16 +192,26 @@ static inline void do_revoke_mmap_wperm( unsigned long end = mpnt->vm_end; size_t len = end - start; struct dentry *dentry = mpnt->vm_file->f_dentry; + struct inode *inode = dentry->d_inode; if ((mpnt->vm_flags & VM_WRITE) && (mpnt->vm_flags & VM_SHARED) && (cur_level->iac_level < isec->level.iac_level)) { if (strncmp(dentry->d_name.name, "SYSV", 4) == 0) { + dprintk(SLM_BASE, "%s: pid %d - unmap SYSV" + " shmem for %ld\n", __FUNCTION__, + current->pid, inode->i_ino); down_write(¤t->mm->mmap_sem); do_munmap(current->mm, start, len); up_write(¤t->mm->mmap_sem); - } else - do_mprotect(start, len, PROT_READ); + } else { + dprintk(SLM_BASE, + "%s: pid %d - revoking write" + " perm for %s\n", __FUNCTION__, + current->pid, dentry->d_name.name); + if (do_mprotect(start, len, PROT_READ) < 0) + dprintk(SLM_BASE, "do_mprotect failed"); + } } } @@ -219,8 +237,11 @@ static void revoke_mmap_wperm(struct slm continue; isec = dentry->d_inode->i_security; - if (!isec) + if (!isec) { + dprintk(SLM_VERBOSE, "%s: isec is null\n", + __FUNCTION__); continue; + } do_revoke_mmap_wperm(mpnt, isec, cur_level); } @@ -234,13 +255,17 @@ static int using_shmem(void) return 0; group_tsk = current->group_leader; - if ((current->pid != group_tsk->pid) && (current->mm == group_tsk->mm)) + if ((current->pid != group_tsk->pid) + && (current->mm == group_tsk->mm)) { + dprintk(SLM_INTEGRITY, "%s: pid %d using shared memory\n", + __FUNCTION__, current->pid); return 1; + } return 0; } -static void do_demote_thread_entry(struct task_struct *thread_tsk) - +static void do_demote_thread_entry(struct task_struct *thread_tsk, + const char *relation) { struct slm_tsec_data *cur_tsec = current->security, *thread_tsec = thread_tsk->security; @@ -251,6 +276,8 @@ static void do_demote_thread_entry(struc return; if (current->mm == thread_tsk->mm) return; + dprintk(SLM_INTEGRITY, "%s: demoting %s: pid %d\n", + __FUNCTION__, relation, thread_tsk->pid); if (!thread_tsec) return; @@ -260,16 +287,16 @@ static void do_demote_thread_entry(struc spin_unlock(&thread_tsec->lock); } -#define do_demote_thread_list(head, member) { \ +#define do_demote_thread_list(head, member, relation) { \ struct task_struct *thread_tsk; \ list_for_each_entry(thread_tsk, head, member) \ - do_demote_thread_entry(thread_tsk); \ + do_demote_thread_entry(thread_tsk, relation); \ } static void demote_threads(void) { - do_demote_thread_list(¤t->sibling, sibling); - do_demote_thread_list(¤t->children, children); + do_demote_thread_list(¤t->sibling, sibling, "sibling"); + do_demote_thread_list(¤t->children, children, "child"); } /* @@ -411,6 +438,8 @@ static int slm_get_xattr(struct dentry * } } + dprintk(SLM_VERBOSE, "iac %d - %s\n", level->iac_level, + slm_iac_str[level->iac_level]); return error < 0 ? -EINVAL : rc; } @@ -424,6 +453,9 @@ static void get_sock_level(struct dentry rc = slm_get_xattr(dentry, level, &xattr_status); if (rc == -EINVAL) { if (xattr_status == -EOPNOTSUPP) { + dprintk(SLM_INTEGRITY, "%s:%s - slm_get_xattr " + "not supported pid %d\n", __FUNCTION__, + dentry->d_name.name, current->pid); level->iac_level = SLM_IAC_EXEMPT; level->sac_level = SLM_SAC_EXEMPT; } else { @@ -439,6 +471,8 @@ static void get_level(struct dentry *den rc = slm_get_xattr(dentry, level, &xattr_status); if ((rc == INTEGRITY_FAIL) || (rc == INTEGRITY_NOLABEL)) { + dprintk(SLM_INTEGRITY, "%s: %s FAIL/NOLABEL (%d)\n", + __FUNCTION__, dentry->d_name.name, rc); level->iac_level = SLM_IAC_UNTRUSTED; level->sac_level = SLM_SAC_PUBLIC; } else if (xattr_status == -EOPNOTSUPP) { @@ -501,6 +535,8 @@ static void slm_get_level(struct dentry if (isec && (isec->level.iac_level != SLM_IAC_NOTDEFINED)) { memcpy(level, &isec->level, sizeof(struct slm_file_xattr)); + dprintk(SLM_VERBOSE, "%s: %s level %d \n", __FUNCTION__, + dentry->d_name.name, level->iac_level); return; } @@ -536,6 +572,9 @@ static struct slm_tsec_data *slm_init_ta return NULL; tsec->lock = SPIN_LOCK_UNLOCKED; if (!cur_tsec) { + dprintk(SLM_VERBOSE, + "%s: pid %d current->pid %d cur_tsec\n", + __FUNCTION__, tsk->pid, current->pid); tsec->iac_r = SLM_IAC_HIGHEST - 1; tsec->iac_wx = SLM_IAC_HIGHEST - 1; tsec->sac_w = SLM_SAC_NOTDEFINED + 1; @@ -551,14 +590,31 @@ static struct slm_tsec_data *slm_init_ta * Permit process to read file of equal or greater integrity * otherwise, demote the process. */ -static void enforce_integrity_read(struct slm_file_xattr *level) +static void enforce_integrity_read(struct slm_file_xattr *level, + const unsigned char *name, + struct task_struct *parent_tsk, + struct slm_tsec_data *parent_tsec) { struct slm_tsec_data *cur_tsec = current->security; if (!((cur_tsec->iac_r <= level->iac_level) || (level->iac_level == SLM_IAC_EXEMPT))) { - /* Reading lower integrity, demote process - * Even in the case of a integrity guard process. */ + + /* Reading lower integrity, demote process */ + dprintk(SLM_BASE, "ppid %d(%s p=%d-%s) " + " pid %d(%s p=%d-%s) demoting integrity to" + " iac=%d-%s(%s)\n", + parent_tsk->pid, parent_tsk->comm, + parent_tsec->iac_r, + (parent_tsec->iac_wx != parent_tsec->iac_r) + ? "GUARD" : slm_iac_str[parent_tsec-> + iac_r], + current->pid, current->comm, + cur_tsec->iac_r, (cur_tsec->iac_wx != cur_tsec->iac_r) + ? "GUARD" : slm_iac_str[cur_tsec->iac_r], + level->iac_level, slm_iac_str[level->iac_level], name); + + /* Even in the case of a integrity guard process. */ spin_lock(&cur_tsec->lock); cur_tsec->iac_r = level->iac_level; cur_tsec->iac_wx = level->iac_level; @@ -573,15 +629,29 @@ static void enforce_integrity_read(struc * Permit process to read file of equal or lesser secrecy; * otherwise, promote the process. */ -static void enforce_secrecy_read(struct slm_file_xattr *level) +static void enforce_secrecy_read(struct slm_file_xattr *level, + const unsigned char *name, + struct task_struct *parent_tsk, + struct slm_tsec_data *parent_tsec) { struct slm_tsec_data *cur_tsec = current->security; if (!((cur_tsec->sac_rx >= level->sac_level) || (level->sac_level == SLM_SAC_EXEMPT))) { - /* Reading higher secrecy, promote process - * Even in the case of a secrecy guard process. */ + /* Reading higher secrecy, promote process */ + dprintk(SLM_BASE, "ppid %d(%s p=%d-%s) " + "pid %d(%s p=%d-%s) promoting secrecy to " + "p=%d-%s(%s)\n", parent_tsk->pid, + parent_tsk->comm, parent_tsec->sac_rx, + (parent_tsec->sac_w != parent_tsec->sac_rx) + ? "GUARD" : slm_sac_str[parent_tsec-> + sac_rx], + current->pid, current->comm, + cur_tsec->sac_rx, (cur_tsec->sac_w != cur_tsec->sac_rx) + ? "GUARD" : slm_sac_str[cur_tsec->sac_rx], + level->sac_level, slm_sac_str[level->sac_level], name); + /* Even in the case of a secrecy guard process. */ spin_lock(&cur_tsec->lock); cur_tsec->sac_rx = level->sac_level; cur_tsec->sac_w = level->sac_level; @@ -593,24 +663,45 @@ static void enforce_secrecy_read(struct } } -static void do_task_may_read(struct slm_file_xattr *level) +static void do_task_may_read(struct slm_file_xattr *level, + const unsigned char *name, + struct task_struct *parent_tsk, + struct slm_tsec_data *parent_tsec) { - enforce_integrity_read(level); - enforce_secrecy_read(level); + enforce_integrity_read(level, name, parent_tsk, parent_tsec); + enforce_secrecy_read(level, name, parent_tsk, parent_tsec); } /* * enforce: IWXAC(process) >= IAC(object) * Permit process to write a file of equal or lesser integrity. */ -static int enforce_integrity_write(struct slm_file_xattr *level) +static int enforce_integrity_write(struct slm_file_xattr *level, + const unsigned char *name, + struct task_struct *parent_tsk, + struct slm_tsec_data *parent_tsec) { struct slm_tsec_data *cur_tsec = current->security; if (!((cur_tsec->iac_wx >= level->iac_level) || (level->iac_level == SLM_IAC_NOTDEFINED) - || (level->iac_level == SLM_IAC_EXEMPT))) - return -EACCES; /* can't write higher integrity */ + || (level->iac_level == SLM_IAC_EXEMPT))) { + + /* can't write higher integrity */ + dprintk(SLM_BASE, "ppid %d(%s p=%d-%s) " + "pid %d(%s p=%d-%s) can't write higher " + "integrity iac=%d-%s(%s)\n", + parent_tsk->pid, parent_tsk->comm, + parent_tsec->iac_wx, + (parent_tsec->iac_wx != parent_tsec->iac_r) + ? "GUARD" : slm_iac_str[parent_tsec-> + iac_wx], + current->pid, current->comm, + cur_tsec->iac_wx, (cur_tsec->iac_wx != cur_tsec->iac_r) + ? "GUARD" : slm_iac_str[cur_tsec->iac_wx], + level->iac_level, slm_iac_str[level->iac_level], name); + return -EACCES; + } return 0; } @@ -618,36 +709,61 @@ static int enforce_integrity_write(struc * enforce: SWAC(process) <= SAC(process) * Permit process to write a file of equal or greater secrecy */ -static int enforce_secrecy_write(struct slm_file_xattr *level) +static int enforce_secrecy_write(struct slm_file_xattr *level, + const unsigned char *name, + struct task_struct *parent_tsk, + struct slm_tsec_data *parent_tsec) { struct slm_tsec_data *cur_tsec = current->security; if (!((cur_tsec->sac_w <= level->sac_level) - || (level->sac_level == SLM_SAC_EXEMPT))) - return -EACCES; /* can't write lower secrecy */ + || (level->sac_level == SLM_SAC_EXEMPT))) { + + /* can't write lower secrecy */ + dprintk(SLM_BASE, "ppid %d(%s p=%d-%s) " + "pid %d(%s p=%d-%s) can't write lower " + "secrecy sac=%d-%s(%s)\n", + parent_tsk->pid, parent_tsk->comm, + parent_tsec->sac_w, + (parent_tsec->sac_w != parent_tsec->sac_rx) + ? "GUARD" : slm_sac_str[parent_tsec-> + sac_w], + current->pid, current->comm, + cur_tsec->sac_w, (cur_tsec->sac_w != cur_tsec->sac_rx) + ? "GUARD" : slm_sac_str[cur_tsec->sac_w], + level->sac_level, slm_sac_str[level->sac_level], name); + return -EACCES; + } return 0; } -static int do_task_may_write(struct slm_file_xattr *level) +static int do_task_may_write(struct slm_file_xattr *level, + const unsigned char *name, + struct task_struct *parent_tsk, + struct slm_tsec_data *parent_tsec) { int rc; - rc = enforce_integrity_write(level); + rc = enforce_integrity_write(level, name, parent_tsk, parent_tsec); if (rc < 0) return rc; - return enforce_secrecy_write(level); + return enforce_secrecy_write(level, name, parent_tsk, parent_tsec); } -static int slm_set_taskperm(int mask, struct slm_file_xattr *level) +static int slm_set_taskperm(int mask, struct slm_file_xattr *level, + const unsigned char *name) { - struct slm_tsec_data *cur_tsec; + struct task_struct *parent_tsk, new_tsk; + struct slm_tsec_data *cur_tsec, *parent_tsec = NULL, new_tsec; + static int ictr; int rc = 0; cur_tsec = current->security; if (!cur_tsec) { + dprintk(SLM_VERBOSE, "%s: calling init_task %d\n", + __FUNCTION__, ictr++); cur_tsec = slm_init_task(current); - if (!cur_tsec) return -ENOMEM; @@ -660,10 +776,27 @@ static int slm_set_taskperm(int mask, st task_unlock(current); } + parent_tsk = current->parent; + if (parent_tsk) + parent_tsec = parent_tsk->security; + else { + printk(KERN_INFO + "%s: current pid %d: parent_tsk is null\n", + __FUNCTION__, current->pid); + memset(&new_tsk, 0, sizeof(struct task_struct)); + parent_tsk = &new_tsk; + } + + if (!parent_tsec) { + memset(&new_tsec, 0, sizeof(struct slm_tsec_data)); + parent_tsec = &new_tsec; + } + if (mask & MAY_READ) - do_task_may_read(level); + do_task_may_read(level, name, parent_tsk, parent_tsec); if ((mask & MAY_WRITE) || (mask & MAY_APPEND)) - rc = do_task_may_write(level); + rc = do_task_may_write(level, name, parent_tsk, parent_tsec); + return rc; } @@ -693,8 +826,11 @@ static int slm_file_permission(struct fi static int slm_inode_permission(struct inode *inode, int mask, struct nameidata *nd) { + char *path = NULL; + const unsigned char *fname = NULL; struct dentry *dentry = NULL; struct slm_file_xattr level; + int rc = 0; if (S_ISDIR(inode->i_mode) && (mask & MAY_WRITE)) return 0; @@ -703,13 +839,27 @@ static int slm_inode_permission(struct i if (!dentry) return 0; + if (nd) { /* preferably use fullname */ + path = (char *)__get_free_page(GFP_KERNEL); + if (path) + fname = d_path(nd->dentry, nd->mnt, path, PAGE_SIZE); + } + + if (!fname) /* no choice, use short name */ + fname = (!dentry->d_name.name) ? dentry->d_iname : + dentry->d_name.name; + slm_get_level(dentry, &level); /* measure all SYSTEM level integrity objects */ if (level.iac_level == SLM_IAC_SYSTEM) - integrity_measure(dentry, NULL, mask); + integrity_measure(dentry, fname, mask); + + rc = slm_set_taskperm(mask, &level, fname); - return slm_set_taskperm(mask, &level); + if (path) + free_page((unsigned long)path); + return rc; } /* @@ -723,7 +873,7 @@ static int slm_inode_unlink(struct inode return 0; slm_get_level(dentry, &level); - return slm_set_taskperm(MAY_WRITE, &level); + return slm_set_taskperm(MAY_WRITE, &level, dentry->d_name.name); } static void slm_inode_free_security(struct inode *inode) @@ -744,8 +894,10 @@ static int slm_inode_create(struct inode struct slm_isec_data *parent_isec = parent_dir->i_security; struct slm_file_xattr *parent_level; - if (!parent_isec) + if (!parent_isec) { + dprintk(SLM_VERBOSE, "%s: parent_isec is null\n", __FUNCTION__); return 0; + } parent_level = &parent_isec->level; /* @@ -753,8 +905,16 @@ static int slm_inode_create(struct inode * Permit process to write a file of equal or lesser integrity. */ if (!((cur_tsec->iac_wx >= parent_level->iac_level) - || (parent_level->iac_level == SLM_IAC_EXEMPT))) + || (parent_level->iac_level == SLM_IAC_EXEMPT))) { + + dprintk(SLM_INTEGRITY, "%s: prohibit current %s level " + "process writing into %s (%s level directory)\n", + __FUNCTION__, slm_iac_str[cur_tsec->iac_wx], + (!dentry->d_name.name) + ? " " : (char *)dentry->d_name.name, + slm_iac_str[parent_level->iac_level]); return -EPERM; + } return 0; } @@ -830,9 +990,12 @@ static int slm_inode_init_security(struc memset(&level, 0, sizeof(struct slm_file_xattr)); - if (parent_isec && (parent_isec->level.iac_level != SLM_IAC_NOTDEFINED)) + if (parent_isec && (parent_isec->level.iac_level != SLM_IAC_NOTDEFINED)) { memcpy(&level, &parent_isec->level, sizeof(struct slm_file_xattr)); + dprintk(SLM_VERBOSE, "%s: level %d\n", __FUNCTION__, + parent_isec->level.iac_level); + } /* low integrity process wrote into a higher level directory */ if (cur_tsec->iac_wx < level.iac_level) { @@ -859,9 +1022,10 @@ static int slm_inode_init_security(struc level.sac_level = SLM_SAC_EXEMPT; } - if (!isec) + if (!isec) { + dprintk(SLM_VERBOSE, "%s: isec is null\n", __FUNCTION__); return 0; - + } spin_lock(&isec->lock); memcpy(&isec->level, &level, sizeof(struct slm_file_xattr)); spin_unlock(&isec->lock); @@ -919,6 +1083,13 @@ static int slm_inode_mkdir(struct inode if (cur_tsec->iac_wx < parent_level->iac_level) { if (parent_level->iac_level == SLM_IAC_SYSTEM) return -EACCES; + + dprintk(SLM_VERBOSE, "%s:ppid %d (%s) %s - creating" + " lower integrity directory, than parent\n", + __FUNCTION__, current->pid, current->comm, + (!dentry->d_name.name) + ? "" : (char *)dentry->d_name.name); + } return 0; } @@ -939,8 +1110,13 @@ static int slm_inode_rename(struct inode slm_get_level(parent_dentry, &parent_level); dput(parent_dentry); - if (old_level.iac_level < parent_level.iac_level) + if (old_level.iac_level < parent_level.iac_level) { + dprintk(SLM_BASE, "%s: prohibit rename of %s (low" + " integrity) into %s (higher level directory)\n", + __FUNCTION__, old_dentry->d_name.name, + parent_dentry->d_name.name); return -EPERM; + } return 0; } @@ -958,12 +1134,18 @@ int slm_inode_setxattr(struct dentry *de return 0; cur_tsec = current->security; - if (!cur_tsec) + if (!cur_tsec) { + dprintk(SLM_VERBOSE, "%s: cur_tsec is null\n", __FUNCTION__); return 0; + } if (!value) return -EINVAL; + dprintk(SLM_VERBOSE, "%s: name %s value %s process:iac_r %s " + "iac_wx %s\n", __FUNCTION__, name, (char *)value, + slm_iac_str[cur_tsec->iac_r], slm_iac_str[cur_tsec->iac_wx]); + switch (cur_tsec->iac_wx) { case SLM_IAC_USER: if ((memcmp @@ -1015,8 +1197,10 @@ static void slm_inode_post_setxattr(stru rc = slm_get_xattr(dentry, &level, &xattr_status); slm_isec = dentry->d_inode->i_security; - if (!slm_isec) + if (!slm_isec) { + dprintk(SLM_VERBOSE, "%s: isec is null\n", __FUNCTION__); return; + } spin_lock(&slm_isec->lock); memcpy(&slm_isec->level, &level, sizeof(struct slm_file_xattr)); spin_unlock(&slm_isec->lock); @@ -1064,6 +1248,12 @@ int slm_socket_create(int family, int ty if (cur_tsec->iac_r > SLM_IAC_UNTRUSTED) { parent_tsk = current->parent; parent_tsec = parent_tsk->security; + dprintk(SLM_INTEGRITY, + "%s: ppid %d pid %d demoting " + "family %d type %d protocol %d kern %d" + " to untrusted.\n", __FUNCTION__, + parent_tsk->pid, current->pid, family, + type, protocol, kern); spin_lock(&cur_tsec->lock); cur_tsec->iac_r = SLM_IAC_UNTRUSTED; cur_tsec->iac_wx = SLM_IAC_UNTRUSTED; @@ -1090,13 +1280,18 @@ static void slm_socket_post_create(struc inode = SOCK_INODE(sock); slm_isec = inode->i_security; - if (!slm_isec) + if (!slm_isec) { + dprintk(SLM_VERBOSE, "%s: slm_isec is null\n", __FUNCTION__); return; + } if (family == PF_UNIX) { cur_tsec = current->security; - if (!cur_tsec) /* task created before LSM hooks enabled */ + if (!cur_tsec) { /* task created before LSM hooks enabled */ + dprintk(SLM_VERBOSE, "%s: cur_tsec is null\n", + __FUNCTION__); return; + } if (cur_tsec->iac_wx != cur_tsec->iac_r) { /* guard process */ spin_lock(&slm_isec->lock); slm_isec->level.iac_level = SLM_IAC_EXEMPT; @@ -1150,19 +1345,40 @@ static int slm_task_post_setuid(uid_t ol if (!cur_tsec) ; else if (flags == LSM_SETID_ID) { /*set process to USER level integrity for everything but root */ + dprintk(SLM_VERBOSE, "ruid %d euid %d suid %d " + "cur: uid %d euid %d suid %d\n", + old_ruid, old_euid, old_suid, + current->uid, current->euid, current->suid); if ((cur_tsec->iac_r == cur_tsec->iac_wx) - && (cur_tsec->iac_r == SLM_IAC_UNTRUSTED)); - else if (current->suid != 0) { + && (cur_tsec->iac_r == SLM_IAC_UNTRUSTED)) { + dprintk(SLM_INTEGRITY, + "Integrity: pid %d iac_r %d " + " iac_wx %d remains UNTRUSTED\n", + current->pid, cur_tsec->iac_r, + cur_tsec->iac_wx); + } else if (current->suid != 0) { + dprintk(SLM_INTEGRITY, "setting: pid %d iac_r %d " + " iac_wx %d to USER\n", + current->pid, cur_tsec->iac_r, + cur_tsec->iac_wx); spin_lock(&cur_tsec->lock); cur_tsec->iac_r = SLM_IAC_USER; cur_tsec->iac_wx = SLM_IAC_USER; spin_unlock(&cur_tsec->lock); } else if ((current->uid == 0) && (old_ruid != 0)) { + dprintk(SLM_INTEGRITY, "setting: pid %d iac_r %d " + " iac_wx %d to SYSTEM\n", + current->pid, cur_tsec->iac_r, + cur_tsec->iac_wx); spin_lock(&cur_tsec->lock); cur_tsec->iac_r = SLM_IAC_SYSTEM; cur_tsec->iac_wx = SLM_IAC_SYSTEM; spin_unlock(&cur_tsec->lock); - } + } else + dprintk(SLM_INTEGRITY, "%s: pid %d iac_r %d " + " iac_wx %d \n", __FUNCTION__, + current->pid, cur_tsec->iac_r, + cur_tsec->iac_wx); } return 0; } @@ -1170,6 +1386,7 @@ static int slm_task_post_setuid(uid_t ol static inline int slm_setprocattr(struct task_struct *tsk, char *name, void *value, size_t size) { + dprintk(SLM_BASE, "%s: %s \n", __FUNCTION__, name); return -EACCES; } @@ -1204,14 +1421,69 @@ static void enforce_integrity_execute(st struct slm_file_xattr *level) { struct slm_tsec_data *cur_tsec = current->security; + struct task_struct *parent_tsk = current->parent; + struct slm_tsec_data *parent_tsec = parent_tsk->security; if ((cur_tsec->iac_wx <= level->iac_level) || (level->iac_level == SLM_IAC_EXEMPT)) { + if (!parent_tsec) { + dprintk(SLM_INTEGRITY, + "%s: pid %d(%s %d-%s) %s executing\n", + __FUNCTION__, + current->pid, current->comm, + cur_tsec->iac_wx, + (cur_tsec->iac_wx != cur_tsec->iac_r) + ? "GUARD" : slm_iac_str[cur_tsec->iac_wx], + bprm->filename); + } else + dprintk(SLM_INTEGRITY, + "%s: ppid %d(%s %d-%s) pid %d(%s %d-%s)" + " %s executing\n", + __FUNCTION__, parent_tsk->pid, + parent_tsk->comm, + (!parent_tsec) ? 0 : parent_tsec->iac_wx, + (parent_tsec->iac_wx != parent_tsec->iac_r) + ? "GUARD" : slm_iac_str[parent_tsec-> + iac_wx], + current->pid, current->comm, + cur_tsec->iac_wx, + (cur_tsec->iac_wx != cur_tsec->iac_r) + ? "GUARD" : slm_iac_str[cur_tsec->iac_wx], + bprm->filename); + /* Being a guard process is not inherited */ spin_lock(&cur_tsec->lock); cur_tsec->iac_r = cur_tsec->iac_wx; spin_unlock(&cur_tsec->lock); } else { + if (!parent_tsec) { + dprintk(SLM_BASE, + "%s: pid %d(%s %d-%s) %s executing, " + "demoting integrity to iac=%d-%s\n", + __FUNCTION__, + current->pid, current->comm, + cur_tsec->iac_wx, + (cur_tsec->iac_wx != cur_tsec->iac_r) + ? "GUARD" : slm_iac_str[cur_tsec->iac_wx], + bprm->filename, level->iac_level, + slm_iac_str[level->iac_level]); + } else + dprintk(SLM_BASE, + "%s: ppid %d(%s %d-%s) pid %d(%s %d-%s)" + " %s executing, demoting integrity to " + " iac=%d-%s\n", + __FUNCTION__, parent_tsk->pid, + parent_tsk->comm, parent_tsec->iac_wx, + (parent_tsec->iac_wx != parent_tsec->iac_r) + ? "GUARD" : slm_iac_str[parent_tsec-> + iac_wx], + current->pid, current->comm, + cur_tsec->iac_wx, + (cur_tsec->iac_wx != cur_tsec->iac_r) + ? "GUARD" : slm_iac_str[cur_tsec->iac_wx], + bprm->filename, level->iac_level, + slm_iac_str[level->iac_level]); + spin_lock(&cur_tsec->lock); cur_tsec->iac_r = level->iac_level; cur_tsec->iac_wx = level->iac_level; @@ -1225,10 +1497,25 @@ static void enforce_guard_integrity_exec struct slm_file_xattr *level) { struct slm_tsec_data *cur_tsec = current->security; + struct task_struct *parent_tsk = current->parent; if ((strcmp(bprm->filename, bprm->interp) != 0) - && (level->guard.unlimited)) + && (level->guard.unlimited)) { + dprintk(SLM_INTEGRITY, "%s:pid %d %s prohibiting " + "script from being an unlimited guard\n", + __FUNCTION__, current->pid, bprm->filename); level->guard.unlimited = 0; + } + + dprintk(SLM_INTEGRITY, + "%s: ppid %d pid %d %s (integrity guard)" + "cur: r %s wx %s new: r %s wx %s %s\n", + __FUNCTION__, parent_tsk->pid, current->pid, + bprm->filename, slm_iac_str[cur_tsec->iac_r], + slm_iac_str[cur_tsec->iac_wx], + slm_iac_str[level->guard.iac_r], + slm_iac_str[level->guard.iac_wx], + (level->guard.unlimited ? "unlimited" : "limited")); if (level->guard.unlimited) { spin_lock(&cur_tsec->lock); @@ -1253,6 +1540,8 @@ static void enforce_secrecy_execute(stru struct slm_file_xattr *level) { struct slm_tsec_data *cur_tsec = current->security; + struct task_struct *parent_tsk = current->parent; + struct slm_tsec_data *parent_tsec = parent_tsk->security; if ((cur_tsec->sac_rx >= level->sac_level) || (level->sac_level == SLM_SAC_EXEMPT)) { @@ -1261,6 +1550,35 @@ static void enforce_secrecy_execute(stru cur_tsec->sac_w = cur_tsec->sac_rx; spin_unlock(&cur_tsec->lock); } else { + if (!parent_tsec) { + dprintk(SLM_SECRECY, + "%s: pid %d(%s %d-%s) %s " + " executing, promoting secrecy to sac=%d-%s\n", + __FUNCTION__, current->pid, + current->comm, cur_tsec->sac_rx, + (cur_tsec->sac_w != cur_tsec->sac_rx) + ? "GUARD" : slm_sac_str[cur_tsec-> + sac_rx], + bprm->filename, level->sac_level, + slm_sac_str[level->sac_level]); + } else + dprintk(SLM_SECRECY, + "%s: ppid %d(%s %d-%s) pid %d(%s %d-%s) %s" + "executing, promoting secrecy to sac=%d-%s\n", + __FUNCTION__, parent_tsk->pid, + parent_tsk->comm, + parent_tsec->sac_rx, + (parent_tsec->sac_w != parent_tsec->sac_rx) + ? "GUARD" : + slm_sac_str[parent_tsec->sac_rx], + current->pid, current->comm, + cur_tsec->sac_rx, + (cur_tsec->sac_w != cur_tsec->sac_rx) + ? "GUARD" : slm_sac_str[cur_tsec-> + sac_rx], + bprm->filename, level->sac_level, + slm_sac_str[level->sac_level]); + spin_lock(&cur_tsec->lock); cur_tsec->sac_rx = level->sac_level; cur_tsec->sac_w = level->sac_level; @@ -1276,7 +1594,16 @@ static void enforce_guard_secrecy_execut struct slm_file_xattr *level) { struct slm_tsec_data *cur_tsec = current->security; + struct task_struct *parent_tsk = current->parent; + dprintk(SLM_SECRECY, + "%s: ppid %d pid %d %s (secrecy guard)" + "cur: rx %s w %s new: rx %s w %s\n", __FUNCTION__, + parent_tsk->pid, current->pid, bprm->filename, + slm_sac_str[cur_tsec->sac_rx], + slm_sac_str[cur_tsec->sac_w], + slm_sac_str[level->guard.sac_rx], + slm_sac_str[level->guard.sac_w]); /* * set low write secrecy range, * not less than current value, prevent leaking data @@ -1305,9 +1632,15 @@ static int slm_bprm_check_security(struc /* Special case interpreters */ if (strcmp(bprm->filename, bprm->interp) != 0) { - if (!cur_tsec->script_dentry) + dprintk(SLM_INTEGRITY, + "%s: executing %s (interp: %s)\n", + __FUNCTION__, bprm->filename, bprm->interp); + if (!cur_tsec->script_dentry) { + dprintk(SLM_INTEGRITY, + "%s: NULL script_dentry %s\n", + __FUNCTION__, bprm->filename); return 0; - else + } else dentry = cur_tsec->script_dentry; } else { dentry = bprm->file->f_dentry; @@ -1315,6 +1648,9 @@ static int slm_bprm_check_security(struc } slm_get_level(dentry, &level); + dprintk(SLM_INTEGRITY, "%s: %s level iac %d - %s\n", + __FUNCTION__, bprm->filename, level.iac_level, + slm_iac_str[level.iac_level]); /* slm_inode_permission measured all SYSTEM level integrity objects */ if (level.iac_level != SLM_IAC_SYSTEM) @@ -1323,8 +1659,14 @@ static int slm_bprm_check_security(struc /* Possible return codes: PERMIT, DENY, NOLABEL */ switch (integrity_verify_data(dentry)) { case INTEGRITY_FAIL: + dprintk(SLM_BASE, + "%s: %s (Integrity status: FAIL)\n", + __FUNCTION__, bprm->filename); return -EACCES; case INTEGRITY_NOLABEL: + dprintk(SLM_BASE, + "%s: %s (Integrity status: NOLABEL)\n", + __FUNCTION__, bprm->filename); level.iac_level = SLM_IAC_UNTRUSTED; } @@ -1368,6 +1710,8 @@ static int slm_shm_alloc_security(struct isec->level.sac_level = cur_tsec->sac_w; } perm->security = isec; + dprintk(SLM_INTEGRITY, "%s: level %d \n", __FUNCTION__, + isec->level.iac_level); return 0; } @@ -1415,7 +1759,7 @@ static int slm_shm_shmctl(struct shmid_k get_level(dentry, &perm_isec->level); } - return slm_set_taskperm(MAY_READ | MAY_WRITE, &perm_isec->level); + return slm_set_taskperm(MAY_READ | MAY_WRITE, &perm_isec->level, NULL); } /* @@ -1450,8 +1794,12 @@ static int slm_shm_shmat(struct shmid_ke get_level(dentry, &perm_isec->level); } - rc = slm_set_taskperm(mask, &perm_isec->level); + rc = slm_set_taskperm(mask, &perm_isec->level, NULL); + dprintk(SLM_INTEGRITY, + "%s: %d mask %d level %d replace %d\n", + __FUNCTION__, shp->id, mask, + perm_isec->level.iac_level, isec->level.iac_level); spin_lock(&isec->lock); memcpy(&isec->level, &perm_isec->level, sizeof(struct slm_file_xattr)); spin_unlock(&isec->lock); @@ -1495,30 +1843,54 @@ static int __init init_slm(void) error = strncmp(slm_xattr_name, security_prefix, strlen(security_prefix)); - if (error != 0) + if (error != 0) { + dprintk(SLM_BASE, + "%s: Invalid slm_xattr_name - %s\n", + __FUNCTION__, slm_xattr_name); return -EINVAL; + } error = slm_init_secfs(); - if (error < 0) + if (error < 0) { + dprintk(SLM_BASE, "%s: Error registering secfs\n", + __FUNCTION__); return error; + } + error = slm_init_debugfs(); + if (error < 0) + dprintk(SLM_BASE, + "%s: Error registering debugfs\n", __FUNCTION__); if (register_security(&slm_security_ops)) { if (mod_reg_security(MY_NAME, &slm_security_ops)) { + dprintk(SLM_BASE, + "%s: security hooks registration " + "failed\n", __FUNCTION__); slm_cleanup_secfs(); + slm_cleanup_debugfs(); return -EINVAL; } secondary = 1; } + dprintk(SLM_BASE, "%s: registered security hooks\n", __FUNCTION__); return 0; } static void __exit cleanup_slm(void) { slm_cleanup_secfs(); - if (secondary) - mod_unreg_security(MY_NAME, &slm_security_ops); - else - unregister_security(&slm_security_ops); + slm_cleanup_debugfs(); + if (secondary) { + if (mod_unreg_security(MY_NAME, &slm_security_ops)) + dprintk(SLM_BASE, + "%s: failure unregistering module " + "with primary module.\n", __FUNCTION__); + } else if (unregister_security(&slm_security_ops)) { + dprintk(SLM_BASE, + "%s: failure unregistering module " + "with the kernel\n", __FUNCTION__); + } + dprintk(SLM_BASE, "%s: completed \n", __FUNCTION__); } module_init(init_slm); @@ -1525,4 +1897,7 @@ module_exit(cleanup_slm); module_param(slm_xattr_name, charp, 0444); MODULE_PARM_DESC(slm_xattr_name, "SLIM extended attribute"); +module_param(slm_debug, uint, 1); +MODULE_DESCRIPTION("Simple Linux Integrity Module"); + MODULE_LICENSE("GPL"); --- linux-2.6.17/security/slim/slm_secfs.c 2006-07-13 16:28:17.000000000 -0700 +++ linux-2.6.17/security/slim/slm_secfs.c 2006-07-13 16:27:33.000000000 -0700 @@ -19,6 +19,8 @@ #include "slim.h" static struct dentry *slim_sec_dir, *slim_level; +static struct dentry *slim_debug_dir, *slim_integrity, *slim_secrecy, + *slim_verbose; static ssize_t slm_read_level(struct file *file, char __user *buf, size_t buflen, loff_t *ppos) @@ -48,10 +50,85 @@ static ssize_t slm_read_level(struct fil return len; } +static int slm_open_debug(struct inode *inode, struct file *file) +{ + if (inode->u.generic_ip) + file->private_data = inode->u.generic_ip; + return 0; +} + +static ssize_t slm_read_debug(struct file *file, char __user * buf, + size_t buflen, loff_t * ppos) +{ + ssize_t len = 0; + enum slm_debug_level type = (enum slm_debug_level)file->private_data; + char *page = (char *)__get_free_page(GFP_KERNEL); + + if (!page) + return -ENOMEM; + + switch(type) { + case SLM_INTEGRITY: + len = sprintf(page, "slm_debug: integrity %s\n", + ((slm_debug & SLM_INTEGRITY) == SLM_INTEGRITY) + ? "ON" : "OFF"); + break; + case SLM_SECRECY: + len = sprintf(page, "slm_debug: secrecy %s\n", + ((slm_debug & SLM_SECRECY) == SLM_SECRECY) + ? "ON" : "OFF"); + break; + case SLM_VERBOSE: + len = sprintf(page, "evm_debug: verbose %s\n", + ((slm_debug & SLM_VERBOSE) == SLM_VERBOSE) + ? "ON" : "OFF"); + break; + default: + break; + } + len = simple_read_from_buffer(buf, buflen, ppos, page, len); + free_page((unsigned long)page); + return len; +} + +static ssize_t slm_write_debug(struct file *file, const char __user * buf, + size_t buflen, loff_t * ppos) +{ + char flag; + enum slm_debug_level type = (enum slm_debug_level)file->private_data; + + if (copy_from_user(&flag, buf, 1)) + return -EFAULT; + + switch(type) { + case SLM_INTEGRITY: + slm_debug = (flag == '0') ? slm_debug & ~SLM_INTEGRITY : + slm_debug | SLM_INTEGRITY; + break; + case SLM_SECRECY: + slm_debug = (flag == '0') ? slm_debug & ~SLM_SECRECY : + slm_debug | SLM_SECRECY; + break; + case SLM_VERBOSE: + slm_debug = (flag == '0') ? slm_debug & ~SLM_VERBOSE : + slm_debug | SLM_VERBOSE; + break; + default: + break; + } + return buflen; +} + static struct file_operations slm_level_ops = { .read = slm_read_level, }; +static struct file_operations slm_debug_ops = { + .read = slm_read_debug, + .write = slm_write_debug, + .open = slm_open_debug, +}; + int __init slm_init_secfs(void) { slim_sec_dir = securityfs_create_dir("slim", NULL); @@ -66,8 +143,48 @@ int __init slm_init_secfs(void) return 0; } +int __init slm_init_debugfs(void) +{ + slim_debug_dir = debugfs_create_dir("slim", NULL); + if (!slim_debug_dir || IS_ERR(slim_debug_dir)) + return -EFAULT; + + slim_integrity = debugfs_create_file("integrity", S_IRUSR | S_IRGRP, + slim_debug_dir, (void *)SLM_INTEGRITY, + &slm_debug_ops); + if (!slim_integrity || IS_ERR(slim_integrity)) + goto out_del_debugdir; + slim_secrecy = debugfs_create_file("secrecy", S_IRUSR | S_IRGRP, + slim_debug_dir, (void *)SLM_SECRECY, + &slm_debug_ops); + if (!slim_secrecy || IS_ERR(slim_secrecy)) + goto out_del_integrity; + slim_verbose = debugfs_create_file("verbose", S_IRUSR | S_IRGRP, + slim_debug_dir, (void *)SLM_VERBOSE, + &slm_debug_ops); + if (!slim_verbose || IS_ERR(slim_verbose)) + goto out_del_secrecy; + return 0; + +out_del_secrecy: + debugfs_remove(slim_secrecy); +out_del_integrity: + debugfs_remove(slim_integrity); +out_del_debugdir: + debugfs_remove(slim_debug_dir); + return -EFAULT; +} + void __exit slm_cleanup_secfs(void) { securityfs_remove(slim_level); securityfs_remove(slim_sec_dir); } + +void __exit slm_cleanup_debugfs(void) +{ + debugfs_remove(slim_verbose); + debugfs_remove(slim_secrecy); + debugfs_remove(slim_integrity); + debugfs_remove(slim_debug_dir); +}