Index: linux-2.6.9/security/selinux/hooks.c =================================================================== --- linux-2.6.9.orig/security/selinux/hooks.c 2004-12-01 10:49:11.163716504 -0600 +++ linux-2.6.9/security/selinux/hooks.c 2004-12-01 10:55:50.439017432 -0600 @@ -79,6 +79,12 @@ #ifdef CONFIG_SECURITY_SELINUX_DEVELOP int selinux_enforcing = 0; +static int secondary; + +static struct security_operations *secondary_ops; +static struct security_operations nul_security_ops; +static char *secondary_name; + static int __init enforcing_setup(char *str) { selinux_enforcing = simple_strtol(str,NULL,0); @@ -98,15 +104,6 @@ __setup("selinux=", selinux_enabled_setup); #endif -/* Original (dummy) security module. */ -static struct security_operations *original_ops = NULL; - -/* Minimal support for a secondary security module, - just to allow the use of the dummy or capability modules. - The owlsm module can alternatively be used as a secondary - module as long as CONFIG_OWLSM_FD is not enabled. */ -static struct security_operations *secondary_ops = NULL; - /* Lists of inode and superblock security structures initialized before the policy was loaded. */ static LIST_HEAD(superblock_security_head); @@ -123,30 +120,31 @@ return -ENOMEM; memset(tsec, 0, sizeof(struct task_security_struct)); - tsec->magic = SELINUX_MAGIC; tsec->task = task; tsec->osid = tsec->sid = tsec->ptrace_sid = SECINITSID_UNLABELED; - task->security = tsec; + security_set_value_nocheck_type(&task->security, SELINUX_LSM_ID, + tsec); return 0; } static void task_free_security(struct task_struct *task) { - struct task_security_struct *tsec = task->security; - - if (!tsec || tsec->magic != SELINUX_MAGIC) - return; + struct task_security_struct *tsec; + + tsec = security_del_value_type(&task->security, SELINUX_LSM_ID, + struct task_security_struct); - task->security = NULL; kfree(tsec); } static int inode_alloc_security(struct inode *inode) { - struct task_security_struct *tsec = current->security; + struct task_security_struct *tsec; struct inode_security_struct *isec; + tsec = security_get_value_type(¤t->security, SELINUX_LSM_ID, + struct task_security_struct); isec = kmalloc(sizeof(struct inode_security_struct), GFP_KERNEL); if (!isec) return -ENOMEM; @@ -154,68 +152,73 @@ memset(isec, 0, sizeof(struct inode_security_struct)); init_MUTEX(&isec->sem); INIT_LIST_HEAD(&isec->list); - isec->magic = SELINUX_MAGIC; isec->inode = inode; isec->sid = SECINITSID_UNLABELED; isec->sclass = SECCLASS_FILE; - if (tsec && tsec->magic == SELINUX_MAGIC) + if (tsec) isec->task_sid = tsec->sid; else isec->task_sid = SECINITSID_UNLABELED; - inode->i_security = isec; + security_set_value_nocheck_type(&inode->i_security, SELINUX_LSM_ID, + isec); return 0; } static void inode_free_security(struct inode *inode) { - struct inode_security_struct *isec = inode->i_security; - struct superblock_security_struct *sbsec = inode->i_sb->s_security; + struct inode_security_struct *isec; + struct superblock_security_struct *sbsec; - if (!isec || isec->magic != SELINUX_MAGIC) + isec = security_del_value_type(&inode->i_security, SELINUX_LSM_ID, + struct inode_security_struct); + if (!isec) return; + sbsec = security_get_value_type(&inode->i_sb->s_security, + SELINUX_LSM_ID, struct superblock_security_struct); + spin_lock(&sbsec->isec_lock); if (!list_empty(&isec->list)) list_del_init(&isec->list); spin_unlock(&sbsec->isec_lock); - inode->i_security = NULL; kfree(isec); } static int file_alloc_security(struct file *file) { - struct task_security_struct *tsec = current->security; + struct task_security_struct *tsec; struct file_security_struct *fsec; + tsec = security_get_value_type(¤t->security, SELINUX_LSM_ID, + struct task_security_struct); fsec = kmalloc(sizeof(struct file_security_struct), GFP_ATOMIC); if (!fsec) return -ENOMEM; memset(fsec, 0, sizeof(struct file_security_struct)); - fsec->magic = SELINUX_MAGIC; fsec->file = file; - if (tsec && tsec->magic == SELINUX_MAGIC) { + if (tsec) { fsec->sid = tsec->sid; fsec->fown_sid = tsec->sid; } else { fsec->sid = SECINITSID_UNLABELED; fsec->fown_sid = SECINITSID_UNLABELED; } - file->f_security = fsec; + security_set_value_nocheck_type(&file->f_security, SELINUX_LSM_ID, + fsec); return 0; } static void file_free_security(struct file *file) { - struct file_security_struct *fsec = file->f_security; + struct file_security_struct *fsec; - if (!fsec || fsec->magic != SELINUX_MAGIC) - return; + fsec = security_del_value_type(&file->f_security, SELINUX_LSM_ID, + struct file_security_struct); - file->f_security = NULL; kfree(fsec); } @@ -232,20 +235,22 @@ INIT_LIST_HEAD(&sbsec->list); INIT_LIST_HEAD(&sbsec->isec_head); spin_lock_init(&sbsec->isec_lock); - sbsec->magic = SELINUX_MAGIC; sbsec->sb = sb; sbsec->sid = SECINITSID_UNLABELED; sbsec->def_sid = SECINITSID_FILE; - sb->s_security = sbsec; + security_set_value_nocheck_type(&sb->s_security, SELINUX_LSM_ID, + sbsec); return 0; } static void superblock_free_security(struct super_block *sb) { - struct superblock_security_struct *sbsec = sb->s_security; + struct superblock_security_struct *sbsec; - if (!sbsec || sbsec->magic != SELINUX_MAGIC) + sbsec = security_del_value_type(&sb->s_security, SELINUX_LSM_ID, + struct superblock_security_struct); + if (!sbsec) return; spin_lock(&sb_security_lock); @@ -253,7 +258,6 @@ list_del_init(&sbsec->list); spin_unlock(&sb_security_lock); - sb->s_security = NULL; kfree(sbsec); } @@ -270,22 +274,24 @@ return -ENOMEM; memset(ssec, 0, sizeof(*ssec)); - ssec->magic = SELINUX_MAGIC; ssec->sk = sk; ssec->peer_sid = SECINITSID_UNLABELED; - sk->sk_security = ssec; + security_set_value_nocheck_type(&sk->sk_security, SELINUX_LSM_ID, + ssec); return 0; } static void sk_free_security(struct sock *sk) { - struct sk_security_struct *ssec = sk->sk_security; + struct sk_security_struct *ssec; - if (sk->sk_family != PF_UNIX || ssec->magic != SELINUX_MAGIC) + if (sk->sk_family != PF_UNIX) return; - sk->sk_security = NULL; + ssec = security_del_value_type(&sk->sk_security, SELINUX_LSM_ID, + struct sk_security_struct); + kfree(ssec); } #endif /* CONFIG_SECURITY_NETWORK */ @@ -332,8 +338,13 @@ const char *name; u32 sid; int alloc = 0, rc = 0, seen = 0; - struct task_security_struct *tsec = current->security; - struct superblock_security_struct *sbsec = sb->s_security; + struct task_security_struct *tsec; + struct superblock_security_struct *sbsec; + + tsec = security_get_value_type(¤t->security, SELINUX_LSM_ID, + struct task_security_struct); + sbsec = security_get_value_type(&sb->s_security, SELINUX_LSM_ID, + struct superblock_security_struct); if (!data) goto out; @@ -499,11 +510,14 @@ static int superblock_doinit(struct super_block *sb, void *data) { - struct superblock_security_struct *sbsec = sb->s_security; + struct superblock_security_struct *sbsec; struct dentry *root = sb->s_root; struct inode *inode = root->d_inode; int rc = 0; + sbsec = security_get_value_type(&sb->s_security, SELINUX_LSM_ID, + struct superblock_security_struct); + down(&sbsec->sem); if (sbsec->initialized) goto out; @@ -722,7 +736,7 @@ static int inode_doinit_with_dentry(struct inode *inode, struct dentry *opt_dentry) { struct superblock_security_struct *sbsec = NULL; - struct inode_security_struct *isec = inode->i_security; + struct inode_security_struct *isec; u32 sid; struct dentry *dentry; #define INITCONTEXTLEN 255 @@ -731,6 +745,9 @@ int rc = 0; int hold_sem = 0; + isec = security_get_value_type(&inode->i_security, SELINUX_LSM_ID, + struct inode_security_struct); + if (isec->initialized) goto out; @@ -739,7 +756,8 @@ if (isec->initialized) goto out; - sbsec = inode->i_sb->s_security; + sbsec = security_get_value_type(&inode->i_sb->s_security, + SELINUX_LSM_ID, struct superblock_security_struct); if (!sbsec->initialized) { /* Defer initialization until selinux_complete_init, after the initial policy is loaded and the security @@ -921,8 +939,10 @@ { struct task_security_struct *tsec1, *tsec2; - tsec1 = tsk1->security; - tsec2 = tsk2->security; + tsec1 = security_get_value_type(&tsk1->security, SELINUX_LSM_ID, + struct task_security_struct); + tsec2 = security_get_value_type(&tsk2->security, SELINUX_LSM_ID, + struct task_security_struct); return avc_has_perm(tsec1->sid, tsec2->sid, SECCLASS_PROCESS, perms, &tsec2->avcr, NULL); } @@ -934,7 +954,8 @@ struct task_security_struct *tsec; struct avc_audit_data ad; - tsec = tsk->security; + tsec = security_get_value_type(&tsk->security, SELINUX_LSM_ID, + struct task_security_struct); AVC_AUDIT_DATA_INIT(&ad,CAP); ad.tsk = tsk; @@ -950,7 +971,8 @@ { struct task_security_struct *tsec; - tsec = tsk->security; + tsec = security_get_value_type(&tsk->security, SELINUX_LSM_ID, + struct task_security_struct); return avc_has_perm(tsec->sid, SECINITSID_KERNEL, SECCLASS_SYSTEM, perms, NULL, NULL); @@ -971,8 +993,10 @@ struct inode_security_struct *isec; struct avc_audit_data ad; - tsec = tsk->security; - isec = inode->i_security; + tsec = security_get_value_type(&tsk->security, SELINUX_LSM_ID, + struct task_security_struct); + isec = security_get_value_type(&inode->i_security, SELINUX_LSM_ID, + struct inode_security_struct); if (!adp) { adp = &ad; @@ -1012,14 +1036,19 @@ struct file *file, u32 av) { - struct task_security_struct *tsec = tsk->security; - struct file_security_struct *fsec = file->f_security; + struct task_security_struct *tsec; + struct file_security_struct *fsec; struct vfsmount *mnt = file->f_vfsmnt; struct dentry *dentry = file->f_dentry; struct inode *inode = dentry->d_inode; struct avc_audit_data ad; int rc; + tsec = security_get_value_type(&tsk->security, SELINUX_LSM_ID, + struct task_security_struct); + fsec = security_get_value_type(&file->f_security, SELINUX_LSM_ID, + struct file_security_struct); + AVC_AUDIT_DATA_INIT(&ad, FS); ad.u.fs.mnt = mnt; ad.u.fs.dentry = dentry; @@ -1052,9 +1081,12 @@ struct avc_audit_data ad; int rc; - tsec = current->security; - dsec = dir->i_security; - sbsec = dir->i_sb->s_security; + tsec = security_get_value_type(¤t->security, SELINUX_LSM_ID, + struct task_security_struct); + dsec = security_get_value_type(&dir->i_security, SELINUX_LSM_ID, + struct inode_security_struct); + sbsec = security_get_value_type(&dir->i_sb->s_security, SELINUX_LSM_ID, + struct superblock_security_struct); AVC_AUDIT_DATA_INIT(&ad, FS); ad.u.fs.dentry = dentry; @@ -1099,9 +1131,12 @@ u32 av; int rc; - tsec = current->security; - dsec = dir->i_security; - isec = dentry->d_inode->i_security; + tsec = security_get_value_type(¤t->security, SELINUX_LSM_ID, + struct task_security_struct); + dsec = security_get_value_type(&dir->i_security, SELINUX_LSM_ID, + struct inode_security_struct); + isec = security_get_value_type(&dentry->d_inode->i_security, + SELINUX_LSM_ID, struct inode_security_struct); AVC_AUDIT_DATA_INIT(&ad, FS); ad.u.fs.dentry = dentry; @@ -1145,11 +1180,15 @@ int old_is_dir, new_is_dir; int rc; - tsec = current->security; - old_dsec = old_dir->i_security; - old_isec = old_dentry->d_inode->i_security; + tsec = security_get_value_type(¤t->security, SELINUX_LSM_ID, + struct task_security_struct); + old_dsec = security_get_value_type(&old_dir->i_security, SELINUX_LSM_ID, + struct inode_security_struct); + old_isec = security_get_value_type(&old_dentry->d_inode->i_security, + SELINUX_LSM_ID, struct inode_security_struct); old_is_dir = S_ISDIR(old_dentry->d_inode->i_mode); - new_dsec = new_dir->i_security; + new_dsec = security_get_value_type(&new_dir->i_security, SELINUX_LSM_ID, + struct inode_security_struct); AVC_AUDIT_DATA_INIT(&ad, FS); @@ -1183,7 +1222,8 @@ if (rc) return rc; if (new_dentry->d_inode) { - new_isec = new_dentry->d_inode->i_security; + new_isec = security_get_value_type(&new_dentry->d_inode->i_security, + SELINUX_LSM_ID, struct inode_security_struct); new_is_dir = S_ISDIR(new_dentry->d_inode->i_mode); rc = avc_has_perm(tsec->sid, new_isec->sid, new_isec->sclass, @@ -1205,8 +1245,10 @@ struct task_security_struct *tsec; struct superblock_security_struct *sbsec; - tsec = tsk->security; - sbsec = sb->s_security; + tsec = security_get_value_type(&tsk->security, SELINUX_LSM_ID, + struct task_security_struct); + sbsec = security_get_value_type(&sb->s_security, SELINUX_LSM_ID, + struct superblock_security_struct); return avc_has_perm(tsec->sid, sbsec->sid, SECCLASS_FILESYSTEM, perms, NULL, ad); } @@ -1259,8 +1301,13 @@ /* Set an inode's SID to a specified value. */ int inode_security_set_sid(struct inode *inode, u32 sid) { - struct inode_security_struct *isec = inode->i_security; - struct superblock_security_struct *sbsec = inode->i_sb->s_security; + struct inode_security_struct *isec; + struct superblock_security_struct *sbsec; + + isec = security_get_value_type(&inode->i_security, SELINUX_LSM_ID, + struct inode_security_struct); + sbsec = security_get_value_type(&inode->i_sb->s_security, + SELINUX_LSM_ID, struct superblock_security_struct); if (!sbsec->initialized) { /* Defer initialization to selinux_complete_init. */ @@ -1289,9 +1336,12 @@ unsigned int len; int rc; - tsec = current->security; - dsec = dir->i_security; - sbsec = dir->i_sb->s_security; + tsec = security_get_value_type(¤t->security, SELINUX_LSM_ID, + struct task_security_struct); + dsec = security_get_value_type(&dir->i_security, SELINUX_LSM_ID, + struct inode_security_struct); + sbsec = security_get_value_type(&dir->i_sb->s_security, SELINUX_LSM_ID, + struct superblock_security_struct); inode = dentry->d_inode; if (!inode) { @@ -1358,14 +1408,19 @@ static int selinux_ptrace(struct task_struct *parent, struct task_struct *child) { - struct task_security_struct *psec = parent->security; - struct task_security_struct *csec = child->security; + struct task_security_struct *psec; + struct task_security_struct *csec; int rc; rc = secondary_ops->ptrace(parent,child); if (rc) return rc; + psec = security_get_value_type(&parent->security, SELINUX_LSM_ID, + struct task_security_struct); + csec = security_get_value_type(&child->security, SELINUX_LSM_ID, + struct task_security_struct); + rc = task_has_perm(parent, child, PROCESS__PTRACE); /* Save the SID of the tracing process for later use in apply_creds. */ if (!rc) @@ -1432,7 +1487,8 @@ if (rc) return rc; - tsec = current->security; + tsec = security_get_value_type(¤t->security, SELINUX_LSM_ID, + struct task_security_struct); rc = selinux_proc_get_sid(table->de, (op == 001) ? SECCLASS_DIR : SECCLASS_FILE, &tsid); @@ -1541,7 +1597,10 @@ { unsigned long free, allowed; int rc; - struct task_security_struct *tsec = current->security; + struct task_security_struct *tsec; + + tsec = security_get_value_type(¤t->security, SELINUX_LSM_ID, + struct task_security_struct); vm_acct_memory(pages); @@ -1608,12 +1667,12 @@ return -ENOMEM; memset(bsec, 0, sizeof *bsec); - bsec->magic = SELINUX_MAGIC; bsec->bprm = bprm; bsec->sid = SECINITSID_UNLABELED; bsec->set = 0; - bprm->security = bsec; + security_set_value_nocheck_type(&bprm->security, SELINUX_LSM_ID, + bsec); return 0; } @@ -1631,13 +1690,16 @@ if (rc) return rc; - bsec = bprm->security; + bsec = security_get_value_type(&bprm->security, SELINUX_LSM_ID, + struct bprm_security_struct); if (bsec->set) return 0; - tsec = current->security; - isec = inode->i_security; + tsec = security_get_value_type(¤t->security, SELINUX_LSM_ID, + struct task_security_struct); + isec = security_get_value_type(&inode->i_security, SELINUX_LSM_ID, + struct inode_security_struct); /* Default to the current task SID. */ bsec->sid = tsec->sid; @@ -1701,12 +1763,13 @@ return secondary_ops->bprm_check_security(bprm); } - static int selinux_bprm_secureexec (struct linux_binprm *bprm) { - struct task_security_struct *tsec = current->security; + struct task_security_struct *tsec; int atsecure = 0; + tsec = security_get_value_type(¤t->security, SELINUX_LSM_ID, + struct task_security_struct); if (tsec->osid != tsec->sid) { /* Enable secure mode for SIDs transitions unless the noatsecure permission is granted between @@ -1721,8 +1784,10 @@ static void selinux_bprm_free_security(struct linux_binprm *bprm) { - struct bprm_security_struct *bsec = bprm->security; - bprm->security = NULL; + struct bprm_security_struct *bsec; + + bsec = security_del_value_type(&bprm->security, SELINUX_LSM_ID, + struct bprm_security_struct); kfree(bsec); } @@ -1824,9 +1889,10 @@ secondary_ops->bprm_apply_creds(bprm, unsafe); - tsec = current->security; - - bsec = bprm->security; + tsec = security_get_value_type(¤t->security, SELINUX_LSM_ID, + struct task_security_struct); + bsec = security_get_value_type(&bprm->security, SELINUX_LSM_ID, + struct bprm_security_struct); sid = bsec->sid; tsec->osid = tsec->sid; @@ -2211,9 +2277,9 @@ static int selinux_inode_setxattr(struct dentry *dentry, char *name, void *value, size_t size, int flags) { - struct task_security_struct *tsec = current->security; + struct task_security_struct *tsec; struct inode *inode = dentry->d_inode; - struct inode_security_struct *isec = inode->i_security; + struct inode_security_struct *isec; struct superblock_security_struct *sbsec; struct avc_audit_data ad; u32 newsid; @@ -2233,7 +2299,8 @@ return dentry_has_perm(current, NULL, dentry, FILE__SETATTR); } - sbsec = inode->i_sb->s_security; + sbsec = security_get_value_type(&inode->i_sb->s_security, + SELINUX_LSM_ID, struct superblock_security_struct); if (sbsec->behavior == SECURITY_FS_USE_MNTPOINT) return -EOPNOTSUPP; @@ -2243,6 +2310,10 @@ AVC_AUDIT_DATA_INIT(&ad,FS); ad.u.fs.dentry = dentry; + tsec = security_get_value_type(¤t->security, SELINUX_LSM_ID, + struct task_security_struct); + isec = security_get_value_type(&inode->i_security, SELINUX_LSM_ID, + struct inode_security_struct); rc = avc_has_perm(tsec->sid, isec->sid, isec->sclass, FILE__RELABELFROM, &isec->avcr, &ad); @@ -2270,10 +2341,13 @@ void *value, size_t size, int flags) { struct inode *inode = dentry->d_inode; - struct inode_security_struct *isec = inode->i_security; + struct inode_security_struct *isec; u32 newsid; int rc; + isec = security_get_value_type(&inode->i_security, SELINUX_LSM_ID, + struct inode_security_struct); + if (strcmp(name, XATTR_NAME_SELINUX)) { /* Not an attribute we recognize, so nothing to do. */ return; @@ -2293,7 +2367,10 @@ static int selinux_inode_getxattr (struct dentry *dentry, char *name) { struct inode *inode = dentry->d_inode; - struct superblock_security_struct *sbsec = inode->i_sb->s_security; + struct superblock_security_struct *sbsec; + + sbsec = security_get_value_type(&inode->i_sb->s_security, + SELINUX_LSM_ID, struct superblock_security_struct); if (sbsec->behavior == SECURITY_FS_USE_MNTPOINT) return -EOPNOTSUPP; @@ -2330,7 +2407,7 @@ static int selinux_inode_getsecurity(struct inode *inode, const char *name, void *buffer, size_t size) { - struct inode_security_struct *isec = inode->i_security; + struct inode_security_struct *isec; char *context; unsigned len; int rc; @@ -2340,6 +2417,9 @@ if (strcmp(name, XATTR_SELINUX_SUFFIX)) return -EOPNOTSUPP; + isec = security_get_value_type(&inode->i_security, SELINUX_LSM_ID, + struct inode_security_struct); + rc = security_sid_to_context(isec->sid, &context, &len); if (rc) return rc; @@ -2360,13 +2440,16 @@ static int selinux_inode_setsecurity(struct inode *inode, const char *name, const void *value, size_t size, int flags) { - struct inode_security_struct *isec = inode->i_security; + struct inode_security_struct *isec; u32 newsid; int rc; if (strcmp(name, XATTR_SELINUX_SUFFIX)) return -EOPNOTSUPP; + isec = security_get_value_type(&inode->i_security, SELINUX_LSM_ID, + struct inode_security_struct); + if (!value || !size) return -EACCES; @@ -2557,8 +2640,10 @@ struct task_security_struct *tsec; struct file_security_struct *fsec; - tsec = current->security; - fsec = file->f_security; + tsec = security_get_value_type(¤t->security, SELINUX_LSM_ID, + struct task_security_struct); + fsec = security_get_value_type(&file->f_security, SELINUX_LSM_ID, + struct file_security_struct); fsec->fown_sid = tsec->sid; return 0; @@ -2575,8 +2660,10 @@ /* struct fown_struct is never outside the context of a struct file */ file = (struct file *)((long)fown - offsetof(struct file,f_owner)); - tsec = tsk->security; - fsec = file->f_security; + tsec = security_get_value_type(&tsk->security, SELINUX_LSM_ID, + struct task_security_struct); + fsec = security_get_value_type(&file->f_security, SELINUX_LSM_ID, + struct file_security_struct); if (!signum) perm = signal_to_av(SIGIO); /* as per send_sigio_to_task */ @@ -2610,12 +2697,14 @@ struct task_security_struct *tsec1, *tsec2; int rc; - tsec1 = current->security; + tsec1 = security_get_value_type(¤t->security, SELINUX_LSM_ID, + struct task_security_struct); rc = task_alloc_security(tsk); if (rc) return rc; - tsec2 = tsk->security; + tsec2 = security_get_value_type(&tsk->security, SELINUX_LSM_ID, + struct task_security_struct); tsec2->osid = tsec1->osid; tsec2->sid = tsec1->sid; @@ -2714,8 +2803,10 @@ { struct task_security_struct *tsec1, *tsec2; - tsec1 = current->security; - tsec2 = p->security; + tsec1 = security_get_value_type(¤t->security, SELINUX_LSM_ID, + struct task_security_struct); + tsec2 = security_get_value_type(&p->security, SELINUX_LSM_ID, + struct task_security_struct); /* No auditing from the setscheduler hook, since the runqueue lock is held and the system will deadlock if we try to log an audit @@ -2778,7 +2869,8 @@ secondary_ops->task_reparent_to_init(p); - tsec = p->security; + tsec = security_get_value_type(&p->security, SELINUX_LSM_ID, + struct task_security_struct); tsec->osid = tsec->sid; tsec->sid = SECINITSID_KERNEL; return; @@ -2787,8 +2879,13 @@ static void selinux_task_to_inode(struct task_struct *p, struct inode *inode) { - struct task_security_struct *tsec = p->security; - struct inode_security_struct *isec = inode->i_security; + struct task_security_struct *tsec; + struct inode_security_struct *isec; + + tsec = security_get_value_type(&p->security, SELINUX_LSM_ID, + struct task_security_struct); + isec = security_get_value_type(&inode->i_security, SELINUX_LSM_ID, + struct inode_security_struct); isec->sid = tsec->sid; isec->initialized = 1; @@ -2957,8 +3054,10 @@ struct avc_audit_data ad; int err = 0; - tsec = task->security; - isec = SOCK_INODE(sock)->i_security; + tsec = security_get_value_type(&task->security, SELINUX_LSM_ID, + struct task_security_struct); + isec = security_get_value_type(&SOCK_INODE(sock)->i_security, SELINUX_LSM_ID, + struct inode_security_struct); if (isec->sid == SECINITSID_KERNEL) goto out; @@ -2981,7 +3080,8 @@ if (kern) goto out; - tsec = current->security; + tsec = security_get_value_type(¤t->security, SELINUX_LSM_ID, + struct task_security_struct); err = avc_has_perm(tsec->sid, tsec->sid, socket_type_to_security_class(family, type, protocol), SOCKET__CREATE, NULL, NULL); @@ -3000,9 +3100,11 @@ err = inode_doinit(SOCK_INODE(sock)); if (err < 0) return; - isec = SOCK_INODE(sock)->i_security; + isec = security_get_value_type(&SOCK_INODE(sock)->i_security, + SELINUX_LSM_ID, struct inode_security_struct); - tsec = current->security; + tsec = security_get_value_type(¤t->security, SELINUX_LSM_ID, + struct task_security_struct); isec->sclass = socket_type_to_security_class(family, type, protocol); isec->sid = kern ? SECINITSID_KERNEL : tsec->sid; @@ -3039,8 +3141,10 @@ struct sock *sk = sock->sk; u32 sid, node_perm, addrlen; - tsec = current->security; - isec = SOCK_INODE(sock)->i_security; + tsec = security_get_value_type(¤t->security, + SELINUX_LSM_ID, struct task_security_struct); + isec = security_get_value_type(&SOCK_INODE(sock)->i_security, + SELINUX_LSM_ID, struct inode_security_struct); if (family == PF_INET) { addr4 = (struct sockaddr_in *)address; @@ -3129,9 +3233,11 @@ err = inode_doinit(SOCK_INODE(newsock)); if (err < 0) return err; - newisec = SOCK_INODE(newsock)->i_security; + newisec = security_get_value_type(&SOCK_INODE(newsock)->i_security, + SELINUX_LSM_ID, struct inode_security_struct); - isec = SOCK_INODE(sock)->i_security; + isec = security_get_value_type(&SOCK_INODE(sock)->i_security, + SELINUX_LSM_ID, struct inode_security_struct); newisec->sclass = isec->sclass; newisec->sid = isec->sid; @@ -3190,8 +3296,10 @@ if (err) return err; - isec = SOCK_INODE(sock)->i_security; - other_isec = SOCK_INODE(other)->i_security; + isec = security_get_value_type(&SOCK_INODE(sock)->i_security, + SELINUX_LSM_ID, struct inode_security_struct); + other_isec = security_get_value_type(&SOCK_INODE(other)->i_security, + SELINUX_LSM_ID, struct inode_security_struct); AVC_AUDIT_DATA_INIT(&ad,NET); ad.u.net.sk = other->sk; @@ -3204,11 +3312,13 @@ return err; /* connecting socket */ - ssec = sock->sk->sk_security; + ssec = security_get_value_type(&sock->sk->sk_security, SELINUX_LSM_ID, + struct sk_security_struct); ssec->peer_sid = other_isec->sid; /* server child socket */ - ssec = newsk->sk_security; + ssec = security_get_value_type(&newsk->sk_security, SELINUX_LSM_ID, + struct sk_security_struct); ssec->peer_sid = isec->sid; return 0; @@ -3222,8 +3332,10 @@ struct avc_audit_data ad; int err; - isec = SOCK_INODE(sock)->i_security; - other_isec = SOCK_INODE(other)->i_security; + isec = security_get_value_type(&SOCK_INODE(sock)->i_security, + SELINUX_LSM_ID, struct inode_security_struct); + other_isec = security_get_value_type(&SOCK_INODE(other)->i_security, + SELINUX_LSM_ID, struct inode_security_struct); AVC_AUDIT_DATA_INIT(&ad,NET); ad.u.net.sk = other->sk; @@ -3265,7 +3377,8 @@ inode = SOCK_INODE(sock); if (inode) { struct inode_security_struct *isec; - isec = inode->i_security; + isec = security_get_value_type(&inode->i_security, + SELINUX_LSM_ID, struct inode_security_struct); sock_sid = isec->sid; sock_class = isec->sclass; } @@ -3349,13 +3462,15 @@ struct sk_security_struct *ssec; struct inode_security_struct *isec; - isec = SOCK_INODE(sock)->i_security; + isec = security_get_value_type(&SOCK_INODE(sock)->i_security, + SELINUX_LSM_ID, struct inode_security_struct); if (isec->sclass != SECCLASS_UNIX_STREAM_SOCKET) { err = -ENOPROTOOPT; goto out; } - ssec = sock->sk->sk_security; + ssec = security_get_value_type(&sock->sk->sk_security, SELINUX_LSM_ID, + struct sk_security_struct); err = security_sid_to_context(ssec->peer_sid, &scontext, &scontext_len); if (err) @@ -3394,7 +3509,10 @@ u32 perm; struct nlmsghdr *nlh; struct socket *sock = sk->sk_socket; - struct inode_security_struct *isec = SOCK_INODE(sock)->i_security; + struct inode_security_struct *isec; + + isec = security_get_value_type(&SOCK_INODE(sock)->i_security, + SELINUX_LSM_ID, struct inode_security_struct); if (skb->len < NLMSG_SPACE(0)) { err = -EINVAL; @@ -3451,7 +3569,8 @@ if (err) goto out; - isec = inode->i_security; + isec = security_get_value_type(&inode->i_security, SELINUX_LSM_ID, + struct inode_security_struct); switch (isec->sclass) { case SECCLASS_UDP_SOCKET: @@ -3577,15 +3696,17 @@ struct kern_ipc_perm *perm, u16 sclass) { - struct task_security_struct *tsec = task->security; + struct task_security_struct *tsec; struct ipc_security_struct *isec; + tsec = security_get_value_type(&task->security, SELINUX_LSM_ID, + struct task_security_struct); + isec = kmalloc(sizeof(struct ipc_security_struct), GFP_KERNEL); if (!isec) return -ENOMEM; memset(isec, 0, sizeof(struct ipc_security_struct)); - isec->magic = SELINUX_MAGIC; isec->sclass = sclass; isec->ipc_perm = perm; if (tsec) { @@ -3593,18 +3714,19 @@ } else { isec->sid = SECINITSID_UNLABELED; } - perm->security = isec; + security_set_value_nocheck_type(&perm->security, SELINUX_LSM_ID, + isec); return 0; } static void ipc_free_security(struct kern_ipc_perm *perm) { - struct ipc_security_struct *isec = perm->security; - if (!isec || isec->magic != SELINUX_MAGIC) - return; + struct ipc_security_struct *isec; + + isec = security_del_value_type(&perm->security, SELINUX_LSM_ID, + struct ipc_security_struct); - perm->security = NULL; kfree(isec); } @@ -3617,21 +3739,21 @@ return -ENOMEM; memset(msec, 0, sizeof(struct msg_security_struct)); - msec->magic = SELINUX_MAGIC; msec->msg = msg; msec->sid = SECINITSID_UNLABELED; - msg->security = msec; + security_set_value_nocheck_type(&msg->security, SELINUX_LSM_ID, + msec); return 0; } static void msg_msg_free_security(struct msg_msg *msg) { - struct msg_security_struct *msec = msg->security; - if (!msec || msec->magic != SELINUX_MAGIC) - return; + struct msg_security_struct *msec; + + msec = security_del_value_type(&msg->security, SELINUX_LSM_ID, + struct msg_security_struct); - msg->security = NULL; kfree(msec); } @@ -3642,8 +3764,10 @@ struct ipc_security_struct *isec; struct avc_audit_data ad; - tsec = current->security; - isec = ipc_perms->security; + tsec = security_get_value_type(¤t->security, SELINUX_LSM_ID, + struct task_security_struct); + isec = security_get_value_type(&ipc_perms->security, SELINUX_LSM_ID, + struct ipc_security_struct); AVC_AUDIT_DATA_INIT(&ad, IPC); ad.u.ipc_id = ipc_perms->key; @@ -3674,8 +3798,10 @@ if (rc) return rc; - tsec = current->security; - isec = msq->q_perm.security; + tsec = security_get_value_type(¤t->security, SELINUX_LSM_ID, + struct task_security_struct); + isec = security_get_value_type(&msq->q_perm.security, SELINUX_LSM_ID, + struct ipc_security_struct); AVC_AUDIT_DATA_INIT(&ad, IPC); ad.u.ipc_id = msq->q_perm.key; @@ -3700,8 +3826,10 @@ struct ipc_security_struct *isec; struct avc_audit_data ad; - tsec = current->security; - isec = msq->q_perm.security; + tsec = security_get_value_type(¤t->security, SELINUX_LSM_ID, + struct task_security_struct); + isec = security_get_value_type(&msq->q_perm.security, SELINUX_LSM_ID, + struct ipc_security_struct); AVC_AUDIT_DATA_INIT(&ad, IPC); ad.u.ipc_id = msq->q_perm.key; @@ -3746,9 +3874,12 @@ struct avc_audit_data ad; int rc; - tsec = current->security; - isec = msq->q_perm.security; - msec = msg->security; + tsec = security_get_value_type(¤t->security, SELINUX_LSM_ID, + struct task_security_struct); + isec = security_get_value_type(&msq->q_perm.security, SELINUX_LSM_ID, + struct ipc_security_struct); + msec = security_get_value_type(&msg->security, SELINUX_LSM_ID, + struct msg_security_struct); /* * First time through, need to assign label to the message @@ -3796,9 +3927,12 @@ struct avc_audit_data ad; int rc; - tsec = target->security; - isec = msq->q_perm.security; - msec = msg->security; + tsec = security_get_value_type(&target->security, SELINUX_LSM_ID, + struct task_security_struct); + isec = security_get_value_type(&msq->q_perm.security, SELINUX_LSM_ID, + struct ipc_security_struct); + msec = security_get_value_type(&msg->security, SELINUX_LSM_ID, + struct msg_security_struct); AVC_AUDIT_DATA_INIT(&ad, IPC); ad.u.ipc_id = msq->q_perm.key; @@ -3825,8 +3959,10 @@ if (rc) return rc; - tsec = current->security; - isec = shp->shm_perm.security; + tsec = security_get_value_type(¤t->security, SELINUX_LSM_ID, + struct task_security_struct); + isec = security_get_value_type(&shp->shm_perm.security, SELINUX_LSM_ID, + struct ipc_security_struct); AVC_AUDIT_DATA_INIT(&ad, IPC); ad.u.ipc_id = shp->shm_perm.key; @@ -3851,8 +3987,10 @@ struct ipc_security_struct *isec; struct avc_audit_data ad; - tsec = current->security; - isec = shp->shm_perm.security; + tsec = security_get_value_type(¤t->security, SELINUX_LSM_ID, + struct task_security_struct); + isec = security_get_value_type(&shp->shm_perm.security, SELINUX_LSM_ID, + struct ipc_security_struct); AVC_AUDIT_DATA_INIT(&ad, IPC); ad.u.ipc_id = shp->shm_perm.key; @@ -3924,8 +4062,10 @@ if (rc) return rc; - tsec = current->security; - isec = sma->sem_perm.security; + tsec = security_get_value_type(¤t->security, SELINUX_LSM_ID, + struct task_security_struct); + isec = security_get_value_type(&sma->sem_perm.security, SELINUX_LSM_ID, + struct ipc_security_struct); AVC_AUDIT_DATA_INIT(&ad, IPC); ad.u.ipc_id = sma->sem_perm.key; @@ -3950,8 +4090,10 @@ struct ipc_security_struct *isec; struct avc_audit_data ad; - tsec = current->security; - isec = sma->sem_perm.security; + tsec = security_get_value_type(¤t->security, SELINUX_LSM_ID, + struct task_security_struct); + isec = security_get_value_type(&sma->sem_perm.security, SELINUX_LSM_ID, + struct ipc_security_struct); AVC_AUDIT_DATA_INIT(&ad, IPC); ad.u.ipc_id = sma->sem_perm.key; @@ -4017,11 +4159,13 @@ static int selinux_ipc_permission(struct kern_ipc_perm *ipcp, short flag) { - struct ipc_security_struct *isec = ipcp->security; + struct ipc_security_struct *isec; u16 sclass = SECCLASS_IPC; u32 av = 0; - if (isec && isec->magic == SELINUX_MAGIC) + isec = security_get_value_type(&ipcp->security, SELINUX_LSM_ID, + struct ipc_security_struct); + if (isec) sclass = isec->sclass; av = 0; @@ -4039,17 +4183,21 @@ /* module stacking operations */ int selinux_register_security (const char *name, struct security_operations *ops) { - if (secondary_ops != original_ops) { + if (secondary_ops != &nul_security_ops) { printk(KERN_INFO "%s: There is already a secondary security " "module registered.\n", __FUNCTION__); return -EINVAL; } secondary_ops = ops; + secondary_name = kmalloc(strlen(name)+1, GFP_KERNEL); + if (!secondary_name) + secondary_name = "error_module"; + else + strlcpy(secondary_name, name, strlen(name)+1); printk(KERN_INFO "%s: Registering secondary module %s\n", - __FUNCTION__, - name); + __FUNCTION__, name); return 0; } @@ -4062,7 +4210,10 @@ return -EINVAL; } - secondary_ops = original_ops; + secondary_ops = &nul_security_ops; + if (strcpy(secondary_name, "error_module")!=0) + kfree(secondary_name); + secondary_name = NULL; return 0; } @@ -4090,7 +4241,8 @@ if (!size) return -ERANGE; - tsec = p->security; + tsec = security_get_value_type(&p->security, SELINUX_LSM_ID, + struct task_security_struct); if (!strcmp(name, "current")) sid = tsec->sid; @@ -4160,7 +4312,8 @@ operation. See selinux_bprm_set_security for the execve checks and may_create for the file creation checks. The operation will then fail if the context is not permitted. */ - tsec = p->security; + tsec = security_get_value_type(&p->security, SELINUX_LSM_ID, + struct task_security_struct); if (!strcmp(name, "exec")) tsec->exec_sid = sid; else if (!strcmp(name, "fscreate")) @@ -4247,8 +4400,8 @@ .task_alloc_security = selinux_task_alloc_security, .task_free_security = selinux_task_free_security, .task_setuid = selinux_task_setuid, - .task_post_setuid = selinux_task_post_setuid, .task_setgid = selinux_task_setgid, + .task_post_setuid = selinux_task_post_setuid, .task_setpgid = selinux_task_setpgid, .task_getpgid = selinux_task_getpgid, .task_getsid = selinux_task_getsid, @@ -4319,6 +4472,13 @@ #endif }; +void security_fixup_ops (struct security_operations *ops); + +#if defined(CONFIG_SECURITY_STACKER) && defined(CONFIG_SECURITY_CAPABILITIES) +int lsm_adopt_next_secondary(char *name); +#endif + +#define MY_NAME "selinux" __init int selinux_init(void) { struct task_security_struct *tsec; @@ -4333,22 +4493,37 @@ /* Set the security state for the initial task. */ if (task_alloc_security(current)) panic("SELinux: Failed to initialize initial task.\n"); - tsec = current->security; + tsec = security_get_value_type(¤t->security, SELINUX_LSM_ID, + struct task_security_struct); tsec->osid = tsec->sid = SECINITSID_KERNEL; avc_init(); - original_ops = secondary_ops = security_ops; - if (!secondary_ops) - panic ("SELinux: No initial security operations\n"); - if (register_security (&selinux_ops)) - panic("SELinux: Unable to register with kernel.\n"); + security_fixup_ops(&nul_security_ops); + secondary_ops = &nul_security_ops; + + if (register_security (&selinux_ops)) { + secondary = 1; + if (mod_reg_security( MY_NAME, &selinux_ops)) { + printk(KERN_ERR "%s: Failed to register with primary LSM.\n", + __FUNCTION__); + panic("SELinux: Unable to register with kernel.\n"); + } else { + printk(KERN_ERR "%s: registered with primary LSM.\n", + __FUNCTION__); + } + } if (selinux_enforcing) { printk(KERN_INFO "SELinux: Starting in enforcing mode\n"); } else { printk(KERN_INFO "SELinux: Starting in permissive mode\n"); } + +#if defined(CONFIG_SECURITY_STACKER) && defined(CONFIG_SECURITY_CAPABILITIES) + lsm_adopt_next_secondary( MY_NAME ); + printk(KERN_INFO "SELinux: stacking next module under myself.\n"); +#endif return 0; } @@ -4473,8 +4648,23 @@ selinux_disabled = 1; - /* Reset security_ops to the secondary module, dummy or capability. */ - security_ops = secondary_ops; + if (secondary) { + if (mod_unreg_security(MY_NAME, &selinux_ops)) + printk(KERN_INFO "Failure unregistering selinux.\n"); + else + printk(KERN_INFO "Unregistered selinux.\n"); + secondary = 0; + if (secondary_name) + if (mod_reg_security(secondary_name, secondary_ops)) + printk(KERN_INFO "Failure registering secondary.\n"); + } else { + if (unregister_security(&selinux_ops)) + printk(KERN_INFO "Failure unregistering selinux.\n"); + else + printk(KERN_INFO "Unregistered selinux.\n"); + if (secondary_ops) + register_security(secondary_ops); + } /* Unregister netfilter hooks. */ selinux_nf_ip_exit(); Index: linux-2.6.9/security/selinux/include/objsec.h =================================================================== --- linux-2.6.9.orig/security/selinux/include/objsec.h 2004-12-01 10:49:11.164716352 -0600 +++ linux-2.6.9/security/selinux/include/objsec.h 2004-12-01 10:54:19.649819488 -0600 @@ -23,11 +23,14 @@ #include #include #include +#include #include "flask.h" #include "avc.h" +#define SELINUX_LSM_ID 0xB65 + struct task_security_struct { - unsigned long magic; /* magic number for this module */ + struct security_list lsm_list; struct task_struct *task; /* back pointer to task object */ u32 osid; /* SID prior to last execve */ u32 sid; /* current SID */ @@ -38,7 +41,7 @@ }; struct inode_security_struct { - unsigned long magic; /* magic number for this module */ + struct security_list lsm_list; struct inode *inode; /* back pointer to inode object */ struct list_head list; /* list of inode_security_struct */ u32 task_sid; /* SID of creating task */ @@ -51,7 +54,7 @@ }; struct file_security_struct { - unsigned long magic; /* magic number for this module */ + struct security_list lsm_list; struct file *file; /* back pointer to file object */ u32 sid; /* SID of open file description */ u32 fown_sid; /* SID of file owner (for SIGIO) */ @@ -60,7 +63,7 @@ }; struct superblock_security_struct { - unsigned long magic; /* magic number for this module */ + struct security_list lsm_list; struct super_block *sb; /* back pointer to sb object */ struct list_head list; /* list of superblock_security_struct */ u32 sid; /* SID of file system */ @@ -74,14 +77,14 @@ }; struct msg_security_struct { - unsigned long magic; /* magic number for this module */ + struct security_list lsm_list; struct msg_msg *msg; /* back pointer */ u32 sid; /* SID of message */ struct avc_entry_ref avcr; /* reference to permissions */ }; struct ipc_security_struct { - unsigned long magic; /* magic number for this module */ + struct security_list lsm_list; struct kern_ipc_perm *ipc_perm; /* back pointer */ u16 sclass; /* security class of this object */ u32 sid; /* SID of IPC resource */ @@ -89,7 +92,7 @@ }; struct bprm_security_struct { - unsigned long magic; /* magic number for this module */ + struct security_list lsm_list; struct linux_binprm *bprm; /* back pointer to bprm object */ u32 sid; /* SID for transformed process */ unsigned char set; @@ -102,7 +105,7 @@ }; struct sk_security_struct { - unsigned long magic; /* magic number for this module */ + struct security_list lsm_list; struct sock *sk; /* back pointer to sk object */ u32 peer_sid; /* SID of peer */ }; Index: linux-2.6.9/security/selinux/selinuxfs.c =================================================================== --- linux-2.6.9.orig/security/selinux/selinuxfs.c 2004-12-01 10:49:11.165716200 -0600 +++ linux-2.6.9/security/selinux/selinuxfs.c 2004-12-01 10:54:19.650819336 -0600 @@ -46,7 +46,8 @@ { struct task_security_struct *tsec; - tsec = tsk->security; + tsec = security_get_value_type(&tsk->security, SELINUX_LSM_ID, + struct task_security_struct); if (!tsec) return -EACCES; @@ -856,7 +857,8 @@ ret = -ENAMETOOLONG; goto err; } - isec = (struct inode_security_struct*)inode->i_security; + isec = security_get_value_type(&inode->i_security, + SELINUX_LSM_ID, struct inode_security_struct); if ((ret = security_genfs_sid("selinuxfs", page, SECCLASS_FILE, &sid))) goto err; isec->sid = sid; @@ -934,7 +936,8 @@ inode = sel_make_inode(sb, S_IFCHR | S_IRUGO | S_IWUGO); if (!inode) goto out; - isec = (struct inode_security_struct*)inode->i_security; + isec = security_get_value_type(&inode->i_security, SELINUX_LSM_ID, + struct inode_security_struct); isec->sid = SECINITSID_DEVNULL; isec->sclass = SECCLASS_CHR_FILE; isec->initialized = 1;