Re: [RFC][PATCH] Process Attribute API for Security Modules

From: Jan Harkes (jaharkesat_private)
Date: Wed Apr 23 2003 - 13:44:10 PDT

  • Next message: Jakob Oestergaard: "Re: [PATCH] Extended Attributes for Security Modules against 2.5.68"

    I understand that some of my comments are probably specific to whatever
    policies the underlying security module implements, but
    
    On Tue, Apr 08, 2003 at 04:17:52PM -0400, Stephen Smalley wrote:
    > 2) /proc/PID/attr/exec represents the attributes to assign to the
    > process upon a subsequent execve call.  A write to this node followed by
    > an execve replaces the execve_secure call of the original SELinux API. 
    > This is needed to support role/domain transitions in SELinux, and execve
    > is the preferred point to make such transitions because it offers better
    > control over the initialization of the process in the new security label
    > and the inheritance of state.  In SELinux, this attribute is reset on
    > execve after use so that the new program reverts to the default behavior
    > for any exec calls that it may make.  In SELinux, a process can only set
    > its own /proc/PID/attr/exec attribute.
    
    The generic API seems to allow any one to read attr/current and exec
    labels and you are not making any special mention of it. It would be
    possible for any process to obtain someone elses 'security context' by
    simply reading the label, writing it to attr/exec and then execing
    itself into the existing security context.
    
    > 3) /proc/PID/attr/fscreate represents the attributes to assign to files
    > created by subsequent calls to open, mkdir, symlink, and mknod. A write
    
    So is this equivalent to fsuid? i.e. when it isn't initialized is the
    current context passed during open/mkdir/symlink/mknod?
    
    There are filesystems that are eager to get per-process hooks to store
    their own security labels or tokens. But with this API it won't be
    possible to run both SE-Linux or other security module and have an
    appropriately secure paritioning of AFS or Coda identities at the same
    time.
    
    And to reduce some of the code-bloat. How about dropping all those
    #define ATTR_GET/ATTR_READ and such by doing something like the
    following,
    
    
    static ssize_t proc_pid_attr_read(struct file * file, char * buf,
    				  size_t count, loff_t *ppos)
    {
    	struct inode * inode = file->f_dentry->d_inode;
    	unsigned long page;
    	ssize_t length;
    	ssize_t end;
    	struct task_struct *task = proc_task(inode);
    
    	if (count > PAGE_SIZE)
    		count = PAGE_SIZE;
    	if (!(page = __get_free_page(GFP_KERNEL)))
    		return -ENOMEM;
    
    	length = security_getprocattr(task, file->f_dentry->d_name,
    				      (char *)page, count);
    	if (length < 0) {
    		free_page(page);
    		return length;
    	}
    	/* Static 4kB (or whatever) block capacity */
    	if (*ppos >= length) {
    		free_page(page);
    		return 0;
    	}
    	if (count + *ppos > length)
    		count = length - *ppos;
    	end = count + *ppos;
    	copy_to_user(buf, (char *) page + *ppos, count);
    	*ppos = end;
    	free_page(page);
    	return count;
    }
    
    static ssize_t proc_pid_attr_write(struct file * file, const char * buf,
    				   size_t count, loff_t *ppos)
    { 
    	struct inode * inode = file->f_dentry->d_inode;
    	char *page; 
    	ssize_t length; 
    	struct task_struct *task = proc_task(inode); 
    
    	if (count > PAGE_SIZE) 
    		count = PAGE_SIZE; 
    	if (*ppos != 0) {
    		/* No partial writes. */
    		return -EINVAL;
    	}
    	page = (char*)__get_free_page(GFP_USER); 
    	if (!page) 
    		return -ENOMEM;
    	length = -EFAULT; 
    	if (copy_from_user(page, buf, count)) 
    		goto out;
    
    	length = security_setprocattr(task, file->f_dentry->d_name, buffer, count); \
    out:
    	free_page((unsigned long) page);
    	return length;
    } 
    
    static struct file_operations proc_pid_attr_operations = {
    	.read		= proc_pid_attr_read,
    	.write		= proc_pid_attr_write,
    };
    
    static struct dentry *proc_attr_lookup(struct inode *dir, struct dentry *dentry)
    {
    	struct inode *inode;
    	int error;
    	struct task_struct *task = proc_task(dir);
    	struct pid_entry *p;
    	struct proc_inode *ei;
    
    	error = -ENOENT;
    	inode = NULL;
    
    	for (p = attr_stuff; p->name; p++) {
    		if (p->len != dentry->d_name.len)
    			continue;
    		if (!memcmp(dentry->d_name.name, p->name, p->len))
    			break;
    	}
    	if (!p->name)
    		goto out;
    
    	error = -EINVAL;
    	inode = proc_pid_make_inode(dir->i_sb, task, p->type);
    	if (!inode)
    		goto out;
    
    	ei = PROC_I(inode);
    	inode->i_mode = p->mode;
    	inode->i_fop = &proc_pid_attr_operations;
    	dentry->d_op = &pid_dentry_operations;
    	d_add(dentry, inode);
    	if (!proc_task(dentry->d_inode)->pid)
    		d_drop(dentry);
    	return NULL;
    
    out:
    	return ERR_PTR(error);
    }
    
    Jan
    _______________________________________________
    linux-security-module mailing list
    linux-security-moduleat_private
    http://mail.wirex.com/mailman/listinfo/linux-security-module
    



    This archive was generated by hypermail 2b30 : Wed Apr 23 2003 - 13:44:26 PDT