On Thu, Aug 17, 2006 at 12:53:22PM -0700, Kylene Jo Hall wrote: > --- linux-2.6.18-rc3/security/slim/slm_main.c 1969-12-31 18:00:00.000000000 -0600 > +++ linux-2.6.18-rc3-working/security/slim/slm_main.c 2006-08-08 13:01:26.000000000 -0500 > @@ -0,0 +1,1526 @@ > +/* > + * SLIM - Simple Linux Integrity Module > + * > + * Copyright (C) 2005,2006 IBM Corporation > + * Author: Mimi Zohar <[email protected]> > + * Kylene Hall <[email protected]> > + * > + * This program is free software; you can redistribute it and/or modify > + * it under the terms of the GNU General Public License as published by > + * the Free Software Foundation, version 2 of the License. > + */ > + > +#include <linux/mman.h> > +#include <linux/config.h> > +#include <linux/kernel.h> > +#include <linux/security.h> > +#include <linux/integrity.h> > +#include <linux/proc_fs.h> > +#include <linux/socket.h> > +#include <linux/fs.h> > +#include <linux/file.h> > +#include <linux/namei.h> > +#include <linux/mm.h> > +#include <linux/shm.h> > +#include <linux/ipc.h> > +#include <linux/errno.h> > +#include <linux/xattr.h> > +#include <net/sock.h> > + > +#include "slim.h" > + > +#define XATTR_NAME "security.slim.level" > + > +#define EXEMPT_STR "EXEMPT" > +#define PUBLIC_STR "PUBLIC" > +#define SYSTEM_SENSITIVE_STR "SYSTEM-SENSITIVE" > +#define SYSTEM_STR "SYSTEM" > +#define UNLIMITED_STR "UNLIMITED" > +#define UNTRUSTED_STR "UNTRUSTED" > +#define USER_SENSITIVE_STR "USER-SENSITIVE" > +#define USER_STR "USER" > +#define ZERO_STR "0" > + > +char *slm_iac_str[] = { ZERO_STR, > + UNTRUSTED_STR, > + USER_STR, > + SYSTEM_STR > +}; > +static char *slm_sac_str[] = { ZERO_STR, > + PUBLIC_STR, > + USER_STR, > + USER_SENSITIVE_STR, > + SYSTEM_SENSITIVE_STR > +}; I'd find these easier to understand if the #defines were done nearer the array that uses them; some are integrity, some are secrecy, and it isn't exactly clear to me which ones are which from just the above. > +static char *get_token(char *buf_start, char *buf_end, char delimiter, > + int *token_len) > +{ > + char *bufp = buf_start; > + char *token = NULL; > + > + while (!token && (bufp < buf_end)) { /* Get start of token */ > + switch (*bufp) { > + case ' ': > + case '\n': > + case '\t': > + bufp++; > + break; > + case '#': > + while ((*bufp != '\n') && (bufp++ < buf_end)) ; > + bufp++; > + break; > + default: > + token = bufp; > + break; > + } > + } > + if (!token) > + return NULL; > + > + *token_len = 0; > + while ((*token_len == 0) && (bufp <= buf_end)) { > + if ((*bufp == delimiter) || (*bufp == '\n')) > + *token_len = bufp - token; > + if (bufp == buf_end) > + *token_len = bufp - token; > + bufp++; > + } > + if (*token_len == 0) > + token = NULL; > + return token; > +} > + > +static int is_guard_integrity(struct slm_file_xattr *level) > +{ > + if ((level->guard.iac_r != SLM_IAC_NOTDEFINED) > + && (level->guard.iac_wx != SLM_IAC_NOTDEFINED)) > + return 1; > + return 0; > +} > + > +static int is_guard_secrecy(struct slm_file_xattr *level) > +{ > + if ((level->guard.sac_rx != SLM_SAC_NOTDEFINED) > + && (level->guard.sac_w != SLM_SAC_NOTDEFINED)) > + return 1; > + return 0; > +} > + > +static int is_lower_integrity(struct slm_file_xattr *task_level, > + struct slm_file_xattr *obj_level) > +{ > + if (task_level->iac_level < obj_level->iac_level) > + return 1; > + return 0; > +} > +static int is_isec_defined(struct slm_isec_data *isec) > +{ > + if (isec && isec->level.iac_level != SLM_IAC_NOTDEFINED) > + return 1; > + return 0; > +} All of these booleans could be re-written to simply return the value of the boolean check. I don't know if those are actually easier to read, but someone should see them once and decide. :) > +/* > + * Called with current->files->file_lock. There is not a great lock to grab > + * for demotion of this type. The only place f_mode is changed after install > + * is in mark_files_ro in the filesystem code. That function is also changing > + * taking away write rights so even if we race the outcome is the same. > + */ > +static inline void do_revoke_file_wperm(struct file *file, > + struct slm_file_xattr *cur_level) > +{ > + struct inode *inode; > + struct slm_isec_data *isec; > + > + inode = file->f_dentry->d_inode; > + if (!inode) > + return; How would the code get to this point? Should this be a BUG_ON instead? > + if (!S_ISREG(inode->i_mode) || !(file->f_mode && FMODE_WRITE)) > + return; > + > + isec = inode->i_security; > + spin_lock(&isec->lock); > + if (is_lower_integrity(cur_level, &isec->level)) > + file->f_mode &= ~FMODE_WRITE; > + spin_unlock(&isec->lock); > +} > + > +/* > + * Revoke write permission on an open file. > + */ > +static void revoke_file_wperm(struct slm_file_xattr *cur_level) > +{ > + int i, j = 0; > + struct files_struct *files = current->files; > + unsigned long fd = 0; > + struct fdtable *fdt; > + struct file *file; > + > + if (!files || !cur_level) > + return; > + > + spin_lock(&files->file_lock); > + fdt = files_fdtable(files); > + > + for (;;) { > + i = j * __NFDBITS; > + if (i >= fdt->max_fdset || i >= fdt->max_fds) > + break; > + fd = fdt->open_fds->fds_bits[j++]; > + while (fd) { > + if (fd & 1) { > + file = fdt->fd[i++]; > + if (file && file->f_dentry) > + do_revoke_file_wperm(file, cur_level); Which files wouldn't have dentries? > + } > + fd >>= 1; > + } > + } > + spin_unlock(&files->file_lock); > +} > + > +static inline void do_revoke_mmap_wperm(struct vm_area_struct *mpnt, > + struct slm_isec_data *isec, > + struct slm_file_xattr *cur_level) > +{ > + unsigned long start = mpnt->vm_start; > + unsigned long end = mpnt->vm_end; > + size_t len = end - start; > + > + if ((mpnt->vm_flags & (VM_WRITE | VM_MAYWRITE)) > + && (mpnt->vm_flags & VM_SHARED) > + && (cur_level->iac_level < isec->level.iac_level)) > + do_mprotect(start, len, PROT_READ); > +} > + > +/* > + * Revoke write permission to underlying mmap file (MAP_SHARED) > + */ > +static void revoke_mmap_wperm(struct slm_file_xattr *cur_level) > +{ > + struct vm_area_struct *mpnt; > + struct file *file; > + struct dentry *dentry; > + struct slm_isec_data *isec; > + > + flush_cache_mm(current->mm); Is it a good idea to flush the cache before making the modifications? Feels like the wrong order to me. > + down_write(¤t->mm->mmap_sem); > + for (mpnt = current->mm->mmap; mpnt; mpnt = mpnt->vm_next) { > + file = mpnt->vm_file; > + if (!file) > + continue; > + > + dentry = file->f_dentry; > + if (!dentry || !dentry->d_inode) > + continue; > + > + isec = dentry->d_inode->i_security; > + do_revoke_mmap_wperm(mpnt, isec, cur_level); > + } > + up_write(¤t->mm->mmap_sem); > +} > + > +/* > + * Revoke write permissions and demote threads using shared memory > + */ > +static void revoke_permissions(struct slm_file_xattr *cur_level) > +{ > + if (!is_kernel_thread(current)) { > + revoke_mmap_wperm(cur_level); > + revoke_file_wperm(cur_level); > + } > +} > + > +static enum slm_iac_level set_iac(char *token) > +{ > + int iac; > + > + if (strncmp(token, EXEMPT_STR, strlen(EXEMPT_STR)) == 0) > + return SLM_IAC_EXEMPT; > + for (iac = 0; iac < sizeof(slm_iac_str) / sizeof(char *); iac++) { > + if (strncmp(token, slm_iac_str[iac], strlen(slm_iac_str[iac])) > + == 0) > + return iac; > + } > + return SLM_IAC_ERROR; > +} > + > +static enum slm_sac_level set_sac(char *token) > +{ > + int sac; > + > + if (strncmp(token, EXEMPT_STR, strlen(EXEMPT_STR)) == 0) > + return SLM_SAC_EXEMPT; > + for (sac = 0; sac < sizeof(slm_sac_str) / sizeof(char *); sac++) { > + if (strncmp(token, slm_sac_str[sac], strlen(slm_sac_str[sac])) > + == 0) > + return sac; > + } > + return SLM_SAC_ERROR; > +} > + > +static inline int set_bounds(char *token) > +{ > + if (strncmp(token, UNLIMITED_STR, strlen(UNLIMITED_STR)) == 0) > + return 1; > + return 0; > +} > + > +/* > + * Get the 7 access class levels from the extended attribute > + * Format: TIMESTAMP INTEGRITY SECRECY [INTEGRITY_GUARD INTEGRITY_GUARD] [SECRECY_GUARD SECRECY_GUARD] [GUARD_ TYPE] > + */ > +static int slm_parse_xattr(char *xattr_value, int xattr_len, > + struct slm_file_xattr *level) > +{ > + char *token; > + int token_len; > + char *buf, *buf_end; > + int fieldno = 0; > + int rc = 0; > + > + buf = xattr_value; > + buf_end = xattr_value + xattr_len; > + > + while ((token = get_token(buf, buf_end, ' ', &token_len)) != NULL) { > + buf = token + token_len; > + switch (++fieldno) { > + case 1: > + level->iac_level = set_iac(token); set_iac() seems an odd name for a function parsing a string to return an integer. Same with the other functions here.. > + if (level->iac_level == SLM_IAC_ERROR) { > + rc = -1; > + level->iac_level = SLM_IAC_UNTRUSTED; > + } > + break; > + case 2: > + level->sac_level = set_sac(token); > + if (level->sac_level == SLM_SAC_ERROR) { > + rc = -1; > + level->sac_level = SLM_SAC_PUBLIC; > + } > + break; > + case 3: > + level->guard.iac_r = set_iac(token); > + if (level->guard.iac_r == SLM_IAC_ERROR) { > + rc = -1; > + level->iac_level = SLM_IAC_UNTRUSTED; > + } > + break; > + case 4: > + level->guard.iac_wx = set_iac(token); > + if (level->guard.iac_wx == SLM_IAC_ERROR) { > + rc = -1; > + level->iac_level = SLM_IAC_UNTRUSTED; > + } > + break; > + case 5: > + level->guard.unlimited = set_bounds(token); > + level->guard.sac_w = set_sac(token); > + if (level->guard.sac_w == SLM_SAC_ERROR) { > + rc = -1; > + level->sac_level = SLM_SAC_PUBLIC; > + } > + break; > + case 6: > + level->guard.sac_rx = set_sac(token); > + if (level->guard.sac_rx == SLM_SAC_ERROR) { > + rc = -1; > + level->sac_level = SLM_SAC_PUBLIC; > + } > + break; > + case 7: > + level->guard.unlimited = set_bounds(token); > + default: > + break; > + } > + } > + return rc; > +} > + > +/* > + * Possible return codes: INTEGRITY_PASS, INTEGRITY_FAIL, INTEGRITY_NOLABEL, > + * or -EINVAL > + */ > +static int slm_get_xattr(struct dentry *dentry, > + struct slm_file_xattr *level, int *status) > +{ > + int xattr_len; > + char *xattr_value = NULL; > + int rc, error = -EINVAL; > + > + rc = integrity_verify_metadata(dentry, XATTR_NAME, > + &xattr_value, &xattr_len, status); > + if (rc < 0) { > + if (rc != -EOPNOTSUPP) { > + printk(KERN_INFO > + "%s integrity_verify_metadata failed " > + "(rc: %d - status: %d)\n", > + dentry->d_name.name, rc, *status); > + } > + return rc; > + } > + > + if (xattr_value) { > + memset(level, 0, sizeof(struct slm_file_xattr)); > + error = slm_parse_xattr(xattr_value, xattr_len, level); > + kfree(xattr_value); > + } > + > + if (level->iac_level != SLM_IAC_UNTRUSTED) { > + rc = integrity_verify_data(dentry, status); > + if ((rc < 0) || (*status != INTEGRITY_PASS)) { > + printk(KERN_INFO "%s integrity_verify_data failed " > + " (rc: %d status: %d)\n", dentry->d_name.name, > + rc, *status); > + return rc; > + } > + } > + > + if (error < 0) > + return -EINVAL; > + return rc; > +} slm_get_xattr() seems remarkably subtle given its name: *status can be updated at two points in the function, a positive 'rc' from integrity_verify_data() is left to return at the end, but negative 'rc' values (that aren't -EOPNOTSUPP) get returned immediately, and if an error variable is negative, a specific value is returned.. > +/* Caller responsible for necessary locking */ > +static inline void set_level(struct slm_file_xattr *level, > + enum slm_iac_level iac, enum slm_sac_level sac) > +{ > + level->iac_level = iac; > + level->sac_level = sac; > +} > +static inline void set_level_exempt(struct slm_file_xattr *level) > +{ > + set_level(level, SLM_IAC_EXEMPT, SLM_SAC_EXEMPT); > +} > + > +static inline void set_level_untrusted(struct slm_file_xattr *level) > +{ > + set_level(level, SLM_IAC_UNTRUSTED, SLM_SAC_PUBLIC); > +} > + > +static inline void set_level_tsec_write(struct slm_file_xattr *level, > + struct slm_tsec_data *tsec) > +{ > + set_level(level, tsec->iac_wx, tsec->sac_w); > +} > + > +static inline void set_level_tsec_read(struct slm_file_xattr *level, > + struct slm_tsec_data *tsec) > +{ > + set_level(level, tsec->iac_r, tsec->sac_rx); > +} > + > +static void get_sock_level(struct dentry *dentry, struct slm_file_xattr *level) > +{ > + struct slm_tsec_data *cur_tsec = current->security; > + int rc, status = 0; > + > + rc = slm_get_xattr(dentry, level, &status); > + if (rc == -EOPNOTSUPP) > + set_level_exempt(level); > + else > + set_level_tsec_read(level, cur_tsec); > +} > + > +static void get_level(struct dentry *dentry, struct slm_file_xattr *level) > +{ > + int rc, status = 0; > + > + rc = slm_get_xattr(dentry, level, &status); > + if (rc < 0) { > + switch (rc) { > + case -EOPNOTSUPP: > + set_level_exempt(level); > + break; > + case -EINVAL: /* improperly formatted */ > + default: > + set_level_untrusted(level); > + break; > + } > + } else { > + switch(status) { > + case INTEGRITY_FAIL: > + case INTEGRITY_NOLABEL: > + set_level_untrusted(level); > + break; > + } > + } > +} The complicated set of decision making in get_level() (which sets levels, heh) might be simplified if slm_get_xattr() internals were less complicated. > +static struct slm_isec_data *slm_alloc_security(gfp_t flags) > +{ > + struct slm_isec_data *isec; > + > + isec = kzalloc(sizeof(struct slm_isec_data), flags); > + if (!isec) > + return NULL; > + > + spin_lock_init(&isec->lock); > + return isec; > +} > + > +/* > + * Exempt objects without extended attribute support > + * for fastpath. Others will be handled generically > + * by the other functions. > + */ > +static int is_exempt_fastpath(struct inode *inode) > +{ > + if ((inode->i_sb->s_magic == PROC_SUPER_MAGIC) > + || S_ISCHR(inode->i_mode) || S_ISBLK(inode->i_mode)) > + return 1; > + return 0; > +} > + > +/* > + * All directories with xattr support should be labeled, but just in case > + * recursively traverse path (dentry->parent) until level info is found. > + */ > +static void slm_get_level(struct dentry *dentry, struct slm_file_xattr *level) > +{ > + struct inode *inode = dentry->d_inode; > + struct slm_isec_data *isec = inode->i_security; > + > + if (is_isec_defined(isec)) { > + memcpy(level, &isec->level, sizeof(struct slm_file_xattr)); > + return; > + } > + > + memset(level, 0, sizeof(struct slm_file_xattr)); > + if (is_exempt_fastpath(inode)) > + set_level_exempt(level); > + else if (S_ISSOCK(inode->i_mode)) > + get_sock_level(dentry, level); > + else > + get_level(dentry, level); > + > + spin_lock(&isec->lock); > + memcpy(&isec->level, level, sizeof(struct slm_file_xattr)); > + spin_unlock(&isec->lock); > +} No lock is required to read from isec->level, but a lock is required to write to it. Does this make sense? > +/* > + * new tsk->security inherits from current->security > + */ > +static struct slm_tsec_data *slm_init_task(struct task_struct *tsk, gfp_t flags) > +{ > + struct slm_tsec_data *tsec, *cur_tsec = current->security; > + > + tsec = kzalloc(sizeof(struct slm_tsec_data), flags); > + if (!tsec) > + return NULL; > + tsec->lock = SPIN_LOCK_UNLOCKED; > + if (!cur_tsec) { > + tsec->iac_r = SLM_IAC_HIGHEST - 1; > + tsec->iac_wx = SLM_IAC_HIGHEST - 1; > + tsec->sac_w = SLM_SAC_NOTDEFINED + 1; > + tsec->sac_rx = SLM_SAC_NOTDEFINED + 1; > + } else > + memcpy(tsec, cur_tsec, sizeof(struct slm_tsec_data)); > + > + return tsec; > +} > + > +static int is_iac_level_exempt(struct slm_file_xattr *level) > +{ > + if (level->iac_level == SLM_IAC_EXEMPT) > + return 1; > + return 0; > +} > + > +static int is_sac_level_exempt(struct slm_file_xattr *level) > +{ > + if (level->sac_level == SLM_SAC_EXEMPT) > + return 1; > + return 0; > +} > + > +static int is_iac_less_than_or_exempt(struct slm_file_xattr *level, > + enum slm_iac_level iac) > +{ > + if (iac <= level->iac_level) > + return 1; > + return is_iac_level_exempt(level); > +} > + > +static int is_iac_greater_than_or_exempt(struct slm_file_xattr *level, > + enum slm_iac_level iac) > +{ > + if (iac >= level->iac_level) > + return 1; > + return is_iac_level_exempt(level); > +} > + > +static int is_sac_less_than_or_exempt(struct slm_file_xattr *level, > + enum slm_sac_level sac) > +{ > + if (sac <= level->sac_level) > + return 1; > + return is_sac_level_exempt(level); > +} > + > +static int is_sac_greater_than_or_exempt(struct slm_file_xattr *level, > + enum slm_sac_level sac) > +{ > + if (sac >= level->sac_level) > + return 1; > + return is_sac_level_exempt(level); > +} > + > +/* > + * enforce: IRAC(process) <= IAC(object) > + * Permit process to read file of equal or greater integrity > + * otherwise, demote the process. > + */ > +static void enforce_integrity_read(struct slm_file_xattr *level) > +{ > + struct slm_tsec_data *cur_tsec = current->security; > + > + spin_lock(&cur_tsec->lock); > + if (!is_iac_less_than_or_exempt(level, cur_tsec->iac_r)) { > + /* Reading lower integrity, demote process */ > + /* Even in the case of a integrity guard process. */ > + cur_tsec->iac_r = level->iac_level; > + cur_tsec->iac_wx = level->iac_level; > + spin_unlock(&cur_tsec->lock); > + > + revoke_permissions(level); > + return; > + } > + spin_unlock(&cur_tsec->lock); > +} > + > +/* > + * enforce: SRXAC(process) >= SAC(object) > + * Permit process to read file of equal or lesser secrecy; > + * otherwise, promote the process. > + */ > +static void enforce_secrecy_read(struct slm_file_xattr *level) > +{ > + struct slm_tsec_data *cur_tsec = current->security; > + > + spin_lock(&cur_tsec->lock); > + if (!is_sac_greater_than_or_exempt(level, cur_tsec->sac_rx)) { > + /* Reading higher secrecy, promote process */ > + /* Even in the case of a secrecy guard process. */ > + cur_tsec->sac_rx = level->sac_level; > + cur_tsec->sac_w = level->sac_level; > + spin_unlock(&cur_tsec->lock); > + > + /* Working item: revoke write permission to lower secrecy > + * files. Prototyped but insufficiently tested for release > + * current code will only allow authorized user to release > + * sensitive data */ > + return; > + } > + spin_unlock(&cur_tsec->lock); > +} > + > +static void do_task_may_read(struct slm_file_xattr *level) > +{ > + enforce_integrity_read(level); > + enforce_secrecy_read(level); > +} > + > +/* > + * 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) > +{ > + struct slm_tsec_data *cur_tsec = current->security; > + int rc = 0; > + > + spin_lock(&cur_tsec->lock); > + if (!(is_iac_greater_than_or_exempt(level, cur_tsec->iac_wx) > + || (level->iac_level == SLM_IAC_NOTDEFINED))) > + /* can't write higher integrity */ > + rc = -EACCES; > + spin_unlock(&cur_tsec->lock); > + return rc; > +} > + > +/* > + * 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) > +{ > + struct slm_tsec_data *cur_tsec = current->security; > + int rc = 0; > + > + spin_lock(&cur_tsec->lock); > + if (!is_sac_less_than_or_exempt(level, cur_tsec->sac_w)) > + /* can't write lower secrecy */ > + rc = -EACCES; > + spin_unlock(&cur_tsec->lock); > + return rc; > +} > + > +static int do_task_may_write(struct slm_file_xattr *level) > +{ > + int rc; > + > + rc = enforce_integrity_write(level); > + if (rc < 0) > + return rc; > + > + return enforce_secrecy_write(level); > +} > + > +static int slm_set_taskperm(int mask, struct slm_file_xattr *level) > +{ > + int rc = 0; > + > + if (mask & MAY_READ) > + do_task_may_read(level); > + if ((mask & MAY_WRITE) || (mask & MAY_APPEND)) > + rc = do_task_may_write(level); > + > + return rc; > +} > + > +/* > + * file changes invalidate isec > + */ > +static int slm_file_permission(struct file *file, int mask) > +{ > + struct slm_isec_data *isec = file->f_dentry->d_inode->i_security; > + > + if (((mask & MAY_WRITE) || (mask & MAY_APPEND)) && isec) { > + spin_lock(&isec->lock); > + isec->level.iac_level = SLM_IAC_NOTDEFINED; > + spin_unlock(&isec->lock); > + } > + return 0; > +} > + > +static int is_untrusted_blk_access(struct inode *inode) > +{ > + struct slm_tsec_data *cur_tsec = current->security; > + int rc = 0; > + > + spin_lock(&cur_tsec->lock); > + if (cur_tsec && (cur_tsec->iac_wx == SLM_IAC_UNTRUSTED) > + && S_ISBLK(inode->i_mode)) > + rc = 1; > + spin_unlock(&cur_tsec->lock); > + return rc; > +} > + > +/* > + * Premise: > + * Can't write or execute higher integrity, can't read lower integrity > + * Can't read or execute higher secrecy, can't write lower secrecy > + */ > +static int slm_inode_permission(struct inode *inode, int mask, > + struct nameidata *nd) > +{ > + struct dentry *dentry = NULL; > + struct slm_file_xattr level; > + > + if (S_ISDIR(inode->i_mode) && (mask & MAY_WRITE)) > + return 0; > + > + dentry = (!nd || !nd->dentry) ? d_find_alias(inode) : nd->dentry; > + if (!dentry) > + return 0; > + > + if (is_untrusted_blk_access(inode)) > + return -EPERM; > + > + slm_get_level(dentry, &level); > + > + /* measure all SYSTEM level integrity objects */ > + if (level.iac_level == SLM_IAC_SYSTEM) > + integrity_measure(dentry, NULL, mask); > + > + return slm_set_taskperm(mask, &level); > +} > + > +/* > + * This hook is called holding the inode mutex. > + */ > +static int slm_inode_unlink(struct inode *dir, struct dentry *dentry) > +{ > + struct slm_file_xattr level; > + > + if (!dentry || !dentry->d_name.name) > + return 0; > + > + slm_get_level(dentry, &level); > + return slm_set_taskperm(MAY_WRITE, &level); > +} > + > +static void slm_inode_free_security(struct inode *inode) > +{ > + struct slm_isec_data *isec = inode->i_security; > + > + inode->i_security = NULL; > + kfree(isec); > +} > + > +/* > + * Check integrity permission to create a regular file. > + */ > +static int slm_inode_create(struct inode *parent_dir, > + struct dentry *dentry, int mask) > +{ > + struct slm_tsec_data *cur_tsec = current->security; > + struct slm_isec_data *parent_isec = parent_dir->i_security; > + struct slm_file_xattr *parent_level = &parent_isec->level; > + int rc = 0; > + > + /* > + * enforce: IWXAC(process) >= IAC(object) > + * Permit process to write a file of equal or lesser integrity. > + */ > + spin_lock(&cur_tsec->lock); > + spin_lock(&parent_isec->lock); > + if (!is_iac_greater_than_or_exempt(parent_level, cur_tsec->iac_wx)) > + rc = -EPERM; > + spin_unlock(&parent_isec->lock); > + spin_unlock(&cur_tsec->lock); > + return rc; > +} > + > +#define MAX_XATTR_SIZE 76 > + > +static int slm_set_xattr(struct slm_file_xattr *level, > + char **name, void **value, size_t * value_len) > +{ > + int len; > + int xattr_len; > + char buf[MAX_XATTR_SIZE]; > + char *bufp = buf; > + char *xattr_val = buf; > + char *xattr_name; > + > + if (!level) > + return 0; > + > + memset(buf, 0, sizeof(buf)); > + > + if (is_iac_level_exempt(level)) { > + memcpy(bufp, EXEMPT_STR, strlen(EXEMPT_STR)); > + bufp += strlen(EXEMPT_STR); > + } else { > + len = strlen(slm_iac_str[level->iac_level]); > + memcpy(bufp, slm_iac_str[level->iac_level], len); > + bufp += len; > + } > + *bufp++ = ' '; > + if (is_sac_level_exempt(level)) { > + memcpy(bufp, EXEMPT_STR, strlen(EXEMPT_STR)); > + bufp += strlen(EXEMPT_STR); > + } else { > + len = strlen(slm_sac_str[level->sac_level]); > + memcpy(bufp, slm_sac_str[level->sac_level], len); > + bufp += len; > + } > + xattr_len = bufp - buf; > + > + /* point after 'security.' */ > + xattr_name = strchr(XATTR_NAME, '.'); > + if (xattr_name) > + *name = kstrdup(xattr_name + 1, GFP_KERNEL); > + *value = kmalloc(xattr_len + 1, GFP_KERNEL); > + if (!*value) { > + kfree(name); > + return -ENOMEM; > + } > + memcpy(*value, xattr_val, xattr_len); > + *value_len = xattr_len; > + return 0; > +} > + > +/* Create the security.slim.level extended attribute */ > +static int slm_inode_init_security(struct inode *inode, struct inode *dir, > + char **name, void **value, size_t * len) > +{ > + struct slm_isec_data *isec = inode->i_security, *parent_isec = > + dir->i_security; > + struct slm_tsec_data *cur_tsec = current->security; > + struct slm_file_xattr level; > + struct xattr_data *data; > + int rc; > + > + if (!name || !value || !len) > + return 0; > + > + memset(&level, 0, sizeof(struct slm_file_xattr)); > + > + if (is_isec_defined(parent_isec)) { > + spin_lock(&parent_isec->lock); > + memcpy(&level, &parent_isec->level, > + sizeof(struct slm_file_xattr)); > + spin_unlock(&parent_isec->lock); > + } > + > + spin_lock(&cur_tsec->lock); > + /* low integrity process wrote into a higher level directory */ > + if (cur_tsec->iac_wx < level.iac_level) > + set_level_tsec_write(&level, cur_tsec); > + /* if directory is exempt, then use process level */ > + if (is_iac_level_exempt(&level)) { > + /* When a guard process creates a directory */ > + if (S_ISDIR(inode->i_mode) > + && (cur_tsec->iac_wx != cur_tsec->iac_r)) > + set_level_exempt(&level); > + else > + set_level_tsec_write(&level, cur_tsec); > + } > + > + /* if a guard process creates a UNIX socket, then EXEMPT it */ > + if (S_ISSOCK(inode->i_mode) > + && (cur_tsec->iac_wx != cur_tsec->iac_r)) > + set_level_exempt(&level); > + spin_unlock(&cur_tsec->lock); > + > + spin_lock(&isec->lock); > + memcpy(&isec->level, &level, sizeof(struct slm_file_xattr)); > + spin_unlock(&isec->lock); > + > + data = kmalloc(sizeof(struct xattr_data), GFP_KERNEL); > + if (!data) > + return -ENOMEM; > + > + /* set levels, based on parent */ > + rc = slm_set_xattr(&level, &data->name, &data->value, &data->len); > + if (rc < 0) > + return rc; if the slm_set_xattr() fails, should data be freed? > > + *name = data->name; > + *value = data->value; > + *len = data->len; > + return 0; > +} > + > +static void slm_d_instantiate(struct dentry *dentry, struct inode *inode) > +{ > + struct slm_isec_data *isec; > + struct slm_file_xattr level; > + > + if (!inode) > + return; > + > + isec = inode->i_security; > + if (is_exempt_fastpath(inode)) { > + memset(&level, 0, sizeof(struct slm_file_xattr)); > + set_level_exempt(&level); > + } else if (S_ISSOCK(inode->i_mode)) > + memset(&level, 0, sizeof(struct slm_file_xattr)); > + else > + get_level(dentry, &level); > + > + spin_lock(&isec->lock); > + memcpy(&isec->level, &level, sizeof(struct slm_file_xattr)); > + spin_unlock(&isec->lock); > +} > + > +/* > + * Check permissions to create a new directory in the existing directory > + * associated with inode structure @dir. > + */ > +static int slm_inode_mkdir(struct inode *parent_dir, > + struct dentry *dentry, int mask) > +{ > + struct slm_tsec_data *cur_tsec = current->security; > + struct slm_isec_data *parent_isec = parent_dir->i_security; > + struct slm_file_xattr *parent_level = &parent_isec->level; > + int rc = 0; > + > + spin_lock(&cur_tsec->lock); > + spin_lock(&parent_isec->lock); > + if (cur_tsec->iac_wx < parent_level->iac_level > + && parent_level->iac_level == SLM_IAC_SYSTEM) > + rc = -EACCES; > + spin_unlock(&parent_isec->lock); > + spin_unlock(&cur_tsec->lock); > + return rc; > +} > + > +static int slm_inode_rename(struct inode *old_dir, > + struct dentry *old_dentry, > + struct inode *new_dir, struct dentry *new_dentry) > +{ > + struct slm_file_xattr old_level, parent_level; > + struct dentry *parent_dentry; > + > + if (old_dir == new_dir) > + return 0; > + > + slm_get_level(old_dentry, &old_level); > + > + parent_dentry = dget_parent(new_dentry); > + slm_get_level(parent_dentry, &parent_level); > + dput(parent_dentry); > + > + if (is_lower_integrity(&old_level, &parent_level)) > + return -EPERM; > + return 0; > +} > + > +/* > + * Limit the integrity value of an object to be no greater than that > + * of the current process. This is especially important for objects > + * being promoted. > +*/ > +int slm_inode_setxattr(struct dentry *dentry, char *name, void *value, > + size_t size, int flags) > +{ > + struct slm_tsec_data *cur_tsec = current->security; > + char *data = value; > + enum slm_iac_level iac; > + > + if (strncmp(name, XATTR_NAME, strlen(XATTR_NAME)) != 0) > + return 0; > + > + if (!value) > + return -EINVAL; > + > + spin_lock(&cur_tsec->lock); > + iac = cur_tsec->iac_wx; > + spin_unlock(&cur_tsec->lock); > + > + switch (iac) { > + case SLM_IAC_USER: > + if ((strncmp(data, USER_STR, strlen(USER_STR)) != 0) && > + (strncmp(data, UNTRUSTED_STR, strlen(UNTRUSTED_STR)) != 0)) > + return -EPERM; > + break; > + case SLM_IAC_SYSTEM: > + if ((strncmp(data, SYSTEM_STR, strlen(SYSTEM_STR)) != 0) && > + (strncmp(data, USER_STR, strlen(USER_STR)) != 0) && > + (strncmp(data, UNTRUSTED_STR, strlen(UNTRUSTED_STR)) != 0) > + && (strncmp(data, EXEMPT_STR, strlen(EXEMPT_STR)) != 0)) > + return -EPERM; > + break; > + default: > + return -EPERM; > + } > + return 0; > +} > + > +/* > + * SLIM extended attribute was modified, update isec. > + */ > +static void slm_inode_post_setxattr(struct dentry *dentry, char *name, > + void *value, size_t size, int flags) > +{ > + struct slm_isec_data *slm_isec; > + struct slm_file_xattr level; > + int rc, status = 0; > + > + if (strncmp(name, XATTR_NAME, strlen(XATTR_NAME)) != 0) > + return; > + > + rc = slm_get_xattr(dentry, &level, &status); > + slm_isec = dentry->d_inode->i_security; > + spin_lock(&slm_isec->lock); > + memcpy(&slm_isec->level, &level, sizeof(struct slm_file_xattr)); > + spin_unlock(&slm_isec->lock); > +} > + > +static int slm_inode_removexattr(struct dentry *dentry, char *name) > +{ > + struct slm_isec_data *isec = dentry->d_inode->i_security; > + struct slm_tsec_data *tsec = current->security; > + enum slm_iac_level iac; > + int rc = 0; > + > + if (strncmp(name, XATTR_NAME, strlen(XATTR_NAME)) != 0) > + return 0; > + > + if (isec) { > + spin_lock(&tsec->lock); > + iac = tsec->iac_wx; > + spin_unlock(&tsec->lock); > + > + spin_lock(&isec->lock); > + switch(iac) { > + case SLM_IAC_SYSTEM: > + isec->level.iac_level = SLM_IAC_NOTDEFINED; > + break; > + case SLM_IAC_USER: > + if (isec->level.iac_level < SLM_IAC_NOTDEFINED || > + isec->level.iac_level > SLM_IAC_USER) > + rc = -EPERM; > + else > + isec->level.iac_level = SLM_IAC_NOTDEFINED; > + break; > + default: > + rc = -EPERM; > + } > + spin_unlock(&isec->lock); > + } > + return rc; > +} > + > +static int slm_inode_alloc_security(struct inode *inode) > +{ > + struct slm_isec_data *isec = slm_alloc_security(GFP_KERNEL); > + if (!isec) > + return -ENOMEM; > + > + inode->i_security = isec; > + return 0; > +} > + > +/* > + * Opening a socket demotes the integrity of a process to untrusted. > + */ > +int slm_socket_create(int family, int type, int protocol, int kern) > +{ > + struct slm_tsec_data *cur_tsec = current->security; > + struct slm_file_xattr level; > + > + /* demoting only internet sockets */ > + if ((family != AF_UNIX) && (family != AF_NETLINK)) { Comment doesn't really match the test.. > + spin_lock(&cur_tsec->lock); > + if (cur_tsec->iac_r > SLM_IAC_UNTRUSTED) { > + cur_tsec->iac_r = SLM_IAC_UNTRUSTED; > + cur_tsec->iac_wx = SLM_IAC_UNTRUSTED; > + spin_unlock(&cur_tsec->lock); > + > + memset(&level, 0, sizeof(struct slm_file_xattr)); > + level.iac_level = SLM_IAC_UNTRUSTED; > + > + revoke_permissions(&level); > + return 0; > + } > + spin_unlock(&cur_tsec->lock); > + } > + return 0; > +} > + > +/* > + * Didn't have the family type previously, so update the inode security now. > + */ > +static void slm_socket_post_create(struct socket *sock, int family, > + int type, int protocol, int kern) > +{ > + struct slm_tsec_data *cur_tsec = current->security; > + struct inode *inode = SOCK_INODE(sock); > + struct slm_isec_data *slm_isec = inode->i_security; > + > + spin_lock(&slm_isec->lock); > + if (family == PF_UNIX) { > + if (cur_tsec->iac_wx != cur_tsec->iac_r) /* guard process */ > + set_level_exempt(&slm_isec->level); > + else > + set_level_tsec_write(&slm_isec->level, cur_tsec); > + } else > + set_level_untrusted(&slm_isec->level); > + spin_unlock(&slm_isec->lock); > +} > + > +/* > + * When a task gets allocated, it inherits the current IAC and SAC. > + * Set the values and store them in p->security. > + */ > +static int slm_task_alloc_security(struct task_struct *tsk) > +{ > + struct slm_tsec_data *tsec = tsk->security; > + > + if (!tsec) { > + tsec = slm_init_task(tsk, GFP_KERNEL); > + if (!tsec) > + return -ENOMEM; > + } > + tsk->security = tsec; > + return 0; > +} > + > +static void slm_task_free_security(struct task_struct *tsk) > +{ > + struct slm_tsec_data *tsec; > + > + tsec = tsk->security; > + tsk->security = NULL; > + kfree(tsec); > +} > + > +/* init_task is an integrity guard */ > +static int slm_task_init_alloc_security(struct task_struct *tsk) > +{ > + struct slm_tsec_data *tsec = kzalloc(sizeof(struct slm_tsec_data), GFP_KERNEL); > + > + if (!tsec) > + return -ENOMEM; > + > + tsec->lock = SPIN_LOCK_UNLOCKED; > + > + tsec->iac_r = SLM_IAC_UNTRUSTED; > + tsec->iac_wx = SLM_IAC_SYSTEM; > + tsec->sac_w = SLM_SAC_PUBLIC; > + tsec->sac_rx = SLM_SAC_PUBLIC; > + > + tsec->unlimited = 1; > + > + tsk->security = tsec; > + return 0; > +} > + > +static int slm_task_post_setuid(uid_t old_ruid, uid_t old_euid, > + uid_t old_suid, int flags) > +{ > + struct slm_tsec_data *cur_tsec = current->security; > + > + if (cur_tsec && flags == LSM_SETID_ID) { > + /*set process to USER level integrity for everything but root */ > + spin_lock(&cur_tsec->lock); > + 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_USER; > + cur_tsec->iac_wx = SLM_IAC_USER; > + } else if ((current->uid == 0) && (old_ruid != 0)) { > + cur_tsec->iac_r = SLM_IAC_SYSTEM; > + cur_tsec->iac_wx = SLM_IAC_SYSTEM; > + } > + spin_unlock(&cur_tsec->lock); > + } > + return 0; > +} > + > +static inline int slm_setprocattr(struct task_struct *tsk, > + char *name, void *value, size_t size) > +{ > + return -EACCES; > + > +} > + > +static inline int slm_getprocattr(struct task_struct *tsk, > + char *name, void *value, size_t size) > +{ > + struct slm_tsec_data *tsec = tsk->security; > + size_t len = 0; > + > + if (is_kernel_thread(tsk)) > + len = snprintf(value, size, "KERNEL"); > + else { > + spin_lock(&tsec->lock); > + if (tsec->iac_wx != tsec->iac_r) > + len = snprintf(value, size, "GUARD wx:%s r:%s", > + slm_iac_str[tsec->iac_wx], > + slm_iac_str[tsec->iac_r]); > + else > + len = snprintf(value, size, "%s", > + slm_iac_str[tsec->iac_wx]); > + spin_unlock(&tsec->lock); > + } > + return min(len, size); > +} > + > +/* > + * enforce: IWXAC(process) <= IAC(object) > + * Permit process to execute file of equal or greater integrity > + */ > +static void enforce_integrity_execute(struct linux_binprm *bprm, > + struct slm_file_xattr *level, > + struct slm_tsec_data *cur_tsec) > +{ > + spin_lock(&cur_tsec->lock); > + if (is_iac_less_than_or_exempt(level, cur_tsec->iac_wx)) > + /* Being a guard process is not inherited */ > + cur_tsec->iac_r = cur_tsec->iac_wx; > + else { > + cur_tsec->iac_r = level->iac_level; > + cur_tsec->iac_wx = level->iac_level; > + spin_unlock(&cur_tsec->lock); > + > + revoke_permissions(level); > + return; > + } > + spin_unlock(&cur_tsec->lock); > +} > + > +static void enforce_guard_integrity_execute(struct linux_binprm *bprm, > + struct slm_file_xattr *level, > + struct slm_tsec_data *cur_tsec) > +{ > + if ((strcmp(bprm->filename, bprm->interp) != 0) > + && (level->guard.unlimited)) > + level->guard.unlimited = 0; > + > + spin_lock(&cur_tsec->lock); > + if (level->guard.unlimited) { > + cur_tsec->iac_r = level->guard.iac_r; > + cur_tsec->iac_wx = level->guard.iac_wx; > + } else { > + if (cur_tsec->iac_r > level->guard.iac_r) > + cur_tsec->iac_r = level->guard.iac_r; > + if (cur_tsec->iac_wx > level->guard.iac_wx) > + cur_tsec->iac_wx = level->guard.iac_wx; > + } > + spin_unlock(&cur_tsec->lock); > +} > + > +/* > + * enforce: SRXAC(process) >= SAC(object) > + * Permit process to execute file of equal or lesser secrecy > + */ > +static void enforce_secrecy_execute(struct linux_binprm *bprm, > + struct slm_file_xattr *level, > + struct slm_tsec_data *cur_tsec) > +{ > + spin_lock(&cur_tsec->lock); > + if (is_sac_greater_than_or_exempt(level, cur_tsec->sac_rx)) > + /* Being a guard process is not inherited */ > + cur_tsec->sac_w = cur_tsec->sac_rx; > + else { > + cur_tsec->sac_rx = level->sac_level; > + cur_tsec->sac_w = level->sac_level; > + > + /* Working item: revoke write permission to lower secrecy > + * files. Prototyped but insufficiently tested for release > + * current code will only allow authorized user to release > + * sensitive data */ > + } > + spin_unlock(&cur_tsec->lock); > +} > + > +static void enforce_guard_secrecy_execute(struct linux_binprm *bprm, > + struct slm_file_xattr *level, > + struct slm_tsec_data *cur_tsec) > +{ > + /* > + * set low write secrecy range, > + * not less than current value, prevent leaking data > + */ > + spin_lock(&cur_tsec->lock); > + cur_tsec->sac_w = max(cur_tsec->sac_w, level->guard.sac_w); > + /* limit secrecy range, never demote secrecy */ > + cur_tsec->sac_rx = max(cur_tsec->sac_rx, level->guard.sac_rx); > + spin_unlock(&cur_tsec->lock); > +} > + > +/* > + * Enforce process integrity & secrecy levels. > + * - update integrity process level of integrity guard program > + * - update secrecy process level of secrecy guard program > + */ > +static int slm_bprm_check_security(struct linux_binprm *bprm) > +{ > + struct dentry *dentry; > + struct slm_tsec_data *cur_tsec = current->security; > + struct slm_file_xattr level; > + int rc, status; > + > + /* Special case interpreters */ > + spin_lock(&cur_tsec->lock); > + if (strcmp(bprm->filename, bprm->interp) != 0) { > + if (!cur_tsec->script_dentry) { > + spin_unlock(&cur_tsec->lock); > + return 0; > + } else > + dentry = cur_tsec->script_dentry; > + } else { > + dentry = bprm->file->f_dentry; > + cur_tsec->script_dentry = dentry; > + } > + spin_unlock(&cur_tsec->lock); > + > + slm_get_level(dentry, &level); > + > + /* slm_inode_permission measured all SYSTEM level integrity objects */ > + if (level.iac_level != SLM_IAC_SYSTEM) > + integrity_measure(dentry, bprm->filename, MAY_EXEC); > + > + /* Possible return codes: PERMIT, DENY, NOLABEL */ > + rc = integrity_verify_data(dentry, &status); > + if (rc < 0) > + return rc; > + > + switch(status) { > + case INTEGRITY_FAIL: > + if (!is_kernel_thread(current)) > + return -EACCES; > + case INTEGRITY_NOLABEL: > + level.iac_level = SLM_IAC_UNTRUSTED; > + level.sac_level = SLM_SAC_PUBLIC; > + } > + > + enforce_integrity_execute(bprm, &level, cur_tsec); > + if (is_guard_integrity(&level)) > + enforce_guard_integrity_execute(bprm, &level, cur_tsec); > + > + enforce_secrecy_execute(bprm, &level, cur_tsec); > + if (is_guard_secrecy(&level)) > + enforce_guard_secrecy_execute(bprm, &level, cur_tsec); > + > + return 0; > +} > + > +static int slm_inode_setattr(struct dentry *dentry, struct iattr *iattr) > +{ > + struct slm_tsec_data *cur_tsec = current->security; > + struct slm_file_xattr level; > + int rc = 0; > + > + slm_get_level(dentry, &level); > + spin_lock(&cur_tsec->lock); > + if (cur_tsec->iac_wx < level.iac_level) > + rc = -EACCES; > + spin_unlock(&cur_tsec->lock); > + return rc; > +} > + > +static inline int slm_capable(struct task_struct *tsk, int cap) > +{ > + struct slm_tsec_data *tsec = tsk->security; > + int rc = 0; > + > + /* Derived from include/linux/sched.h:capable. */ > + if (cap_raised(tsk->cap_effective, cap)) { > + spin_lock(&tsec->lock); > + if (tsec->iac_wx == SLM_IAC_UNTRUSTED && > + cap == CAP_SYS_ADMIN) > + rc = -EACCES; Why is CAP_SYS_ADMIN handled specially? > + spin_unlock(&tsec->lock); > + return rc; > + } > + return -EPERM; > +} > + > +static int slm_ptrace(struct task_struct *parent, struct task_struct *child) > +{ > + struct slm_tsec_data *parent_tsec = parent->security, > + *child_tsec = child->security; > + int rc = 0; > + > + if (is_kernel_thread(parent) || is_kernel_thread(child)) > + return 0; Why was this added? > + spin_lock(&parent_tsec->lock); > + if (parent_tsec->iac_wx < child_tsec->iac_wx) > + rc = -EPERM; > + spin_unlock(&parent_tsec->lock); > + return rc; > +} > + > +static int slm_shm_alloc_security(struct shmid_kernel *shp) > +{ > + struct slm_tsec_data *cur_tsec = current->security; > + struct kern_ipc_perm *perm = &shp->shm_perm; > + struct slm_isec_data *isec = slm_alloc_security(GFP_KERNEL); > + > + if (!isec) > + return -ENOMEM; > + > + spin_lock(&cur_tsec->lock); > + if (cur_tsec->iac_wx != cur_tsec->iac_r) /* guard process */ > + set_level_exempt(&isec->level); > + else > + set_level_tsec_write(&isec->level, cur_tsec); > + spin_unlock(&cur_tsec->lock); > + perm->security = isec; > + > + return 0; > +} > + > +static void slm_shm_free_security(struct shmid_kernel *shp) > +{ > + struct kern_ipc_perm *perm = &shp->shm_perm; > + struct slm_isec_data *isec = perm->security; > + > + perm->security = NULL; > + kfree(isec); > +} > + > +/* > + * When shp exists called holding perm->lock > + */ > +static int slm_shm_shmctl(struct shmid_kernel *shp, int cmd) > +{ > + struct kern_ipc_perm *perm; > + struct slm_isec_data *perm_isec; > + struct file *file; > + struct dentry *dentry; > + struct inode *inode; > + int rc; > + > + if (!shp) > + return 0; > + > + perm = &shp->shm_perm; > + perm_isec = perm->security; > + file = shp->shm_file; > + dentry = file->f_dentry; > + inode = dentry->d_inode; > + > + spin_lock(&perm_isec->lock); > + rc = slm_set_taskperm(MAY_READ | MAY_WRITE, &perm_isec->level); > + spin_unlock(&perm_isec->lock); > + return rc; > +} > + > +/* > + * Called holding perm->lock > + */ > +static int slm_shm_shmat(struct shmid_kernel *shp, > + char __user * shmaddr, int shmflg) > +{ > + int mask = MAY_READ; > + int rc; > + struct kern_ipc_perm *perm = &shp->shm_perm; > + struct file *file = shp->shm_file; > + struct dentry *dentry = file->f_dentry; > + struct inode *inode = dentry->d_inode; > + struct slm_isec_data *perm_isec = perm->security, > + *isec = inode->i_security; > + > + if (shmflg != SHM_RDONLY) > + mask |= MAY_WRITE; > + > + spin_lock(&perm_isec->lock); > + rc = slm_set_taskperm(mask, &perm_isec->level); > + > + spin_lock(&isec->lock); > + memcpy(&isec->level, &perm_isec->level, sizeof(struct slm_file_xattr)); > + spin_unlock(&perm_isec->lock); > + spin_unlock(&isec->lock); > + > + return rc; > +} > + > +static struct security_operations slm_security_ops = { > + .bprm_check_security = slm_bprm_check_security, > + .file_permission = slm_file_permission, > + .inode_permission = slm_inode_permission, > + .inode_unlink = slm_inode_unlink, > + .inode_create = slm_inode_create, > + .inode_mkdir = slm_inode_mkdir, > + .inode_rename = slm_inode_rename, > + .inode_setattr = slm_inode_setattr, > + .inode_setxattr = slm_inode_setxattr, > + .inode_post_setxattr = slm_inode_post_setxattr, > + .inode_removexattr = slm_inode_removexattr, > + .inode_alloc_security = slm_inode_alloc_security, > + .inode_free_security = slm_inode_free_security, > + .inode_init_security = slm_inode_init_security, > + .socket_create = slm_socket_create, > + .socket_post_create = slm_socket_post_create, > + .task_alloc_security = slm_task_alloc_security, > + .task_free_security = slm_task_free_security, > + .task_init_alloc_security = slm_task_init_alloc_security, > + .task_post_setuid = slm_task_post_setuid, > + .capable = slm_capable, > + .ptrace = slm_ptrace, > + .shm_alloc_security = slm_shm_alloc_security, > + .shm_free_security = slm_shm_free_security, > + .shm_shmat = slm_shm_shmat, > + .shm_shmctl = slm_shm_shmctl, > + .getprocattr = slm_getprocattr, > + .setprocattr = slm_setprocattr, > + .d_instantiate = slm_d_instantiate > +}; > + > +static int __init init_slm(void) > +{ > + current->security = slm_init_task(current, GFP_ATOMIC); > + return register_security(&slm_security_ops); > +} > +security_initcall(init_slm); Thanks
Attachment:
pgpYkPdYCQzVl.pgp
Description: PGP signature
- Follow-Ups:
- Re: [RFC][PATCH 4/8] SLIM main patch
- From: Kylene Jo Hall <[email protected]>
- Re: [RFC][PATCH 4/8] SLIM main patch
- References:
- [RFC][PATCH 4/8] SLIM main patch
- From: Kylene Jo Hall <[email protected]>
- [RFC][PATCH 4/8] SLIM main patch
- Prev by Date: Re: [RFC][PATCH 2/9] deadlock prevention core
- Next by Date: [PATCH 5/5] Add gsm phone support for the mixer in tsc2101 alsa driver.
- Previous by thread: [RFC][PATCH 4/8] SLIM main patch
- Next by thread: Re: [RFC][PATCH 4/8] SLIM main patch
- Index(es):