Thanks for the comments, Stephen. Quoting Stephen Smalley (sds@private): > I think preserving -EACCES and -EPERM on getprocattr from the modules is > important. More generally, if any of them return anything other than - > EINVAL, you should likely return immediately with the returned error, so > that e.g. if SELinux denies access, then no other module will end up > returning its attribute value. Otherwise, you have an information flow > in violation of the MAC policy. I must have talked myself out of that this weekend, but clearly you're right. The attached patch fixes that. > Doesn't look like you break out of your loop when the value buffer is > completely depleted by a module, although I suppose subsequent modules > would see a zero length and immediately return. Right - I should hope no module would try to take up PAGE_SIZE space, but the subsequent modules are supposed to be nice about it. It'd be nice if it were meaningful to return -EAGAIN, but of course userspace can't send in its own buffer... > o_len unused? Oh yes, sorry! thanks, -serge Index: linux-2.6.12-rc2-stack/security/stacker.c =================================================================== --- linux-2.6.12-rc2-stack.orig/security/stacker.c 2005-05-25 16:01:52.000000000 -0500 +++ linux-2.6.12-rc2-stack/security/stacker.c 2005-05-31 15:52:49.000000000 -0500 @@ -956,24 +956,116 @@ static void stacker_d_instantiate (struc CALL_ALL(d_instantiate,d_instantiate(dentry,inode)); } +/* + * Query all LSMs. + * If all return EINVAL, we return EINVAL. If any returns any other + * error, then we return that error. Otherwise, we concatenate all + * modules' results. + */ static int stacker_getprocattr(struct task_struct *p, char *name, void *value, size_t size) { - if (!selinux_module) - return -EINVAL; - if (!selinux_module->module_operations.getprocattr) + struct module_entry *m; + int len = 0, ret; + int found_noneinval = 0; + + + if (list_empty(&stacked_modules)) return -EINVAL; - return selinux_module->module_operations.getprocattr(p, name, value, size); + + rcu_read_lock(); + stack_for_each_entry(m, &stacked_modules, lsm_list) { + if (!m->module_operations.getprocattr) + continue; + rcu_read_unlock(); + ret = m->module_operations.getprocattr(p, name, + value+len, size-len); + rcu_read_lock(); + if (ret == -EINVAL) + continue; + found_noneinval = 1; + if (ret < 0) { + memset(value, 0, len); + len = ret; + break; + } + if (ret == 0) + continue; + len += ret; + if (len+m->namelen+4 < size) { + char *v = value; + if (v[len-1]=='\n') + len--; + len += sprintf(value+len, " (%s)\n", m->module_name); + } + } + rcu_read_unlock(); + + return found_noneinval ? len : -EINVAL; +} + +static struct module_entry * +find_active_lsm(const char *name, int len) +{ + struct module_entry *m, *ret = NULL; + + rcu_read_lock(); + stack_for_each_entry(m, &stacked_modules, lsm_list) { + if (m->namelen == len && !strncmp(m->module_name, name, len)) { + ret = m; + break; + } + } + + rcu_read_unlock(); + return ret; } -static int stacker_setprocattr(struct task_struct *p, char *name, void *value, size_t size) +/* + * We assume input will be either + * "data" - in which case it goes to selinux, or + * "data (mod_name)" in which case the data goes to module mod_name. + */ +static int +stacker_setprocattr(struct task_struct *p, char *name, void *value, size_t size) { + struct module_entry *callm = selinux_module; + char *realv = (char *)value; + size_t dsize = size; + int loc = 0, end_data = size; - if (!selinux_module) + if (list_empty(&stacked_modules)) return -EINVAL; - if (!selinux_module->module_operations.setprocattr) + + if (dsize && realv[dsize-1] == '\n') + dsize--; + + if (!dsize || realv[dsize-1]!=')') + goto call; + + dsize--; + loc = dsize-1; + while (loc && realv[loc]!='(') + loc--; + if (!loc) + goto call; + + callm = find_active_lsm(realv+loc+1, dsize-loc-1); + if (!callm) + goto call; + + + loc--; + while (loc && realv[loc]==' ') + loc--; + + end_data = loc+1; +call: + if (!callm || !callm->module_operations.setprocattr) return -EINVAL; - return selinux_module->module_operations.setprocattr(p, name, value, size); + + return callm->module_operations.setprocattr(p, name, value, end_data) + + (size-end_data); } /* @@ -1031,23 +1123,6 @@ out: return ret; } -static struct module_entry * -find_active_lsm(const char *name, int len) -{ - struct module_entry *m, *ret = NULL; - - rcu_read_lock(); - stack_for_each_entry(m, &stacked_modules, lsm_list) { - if (m->namelen == len && !strncmp(m->module_name, name, len)) { - ret = m; - break; - } - } - - rcu_read_unlock(); - return ret; -} - /* * Currently this version of stacker does not allow for module * unregistering.
This archive was generated by hypermail 2.1.3 : Tue May 31 2005 - 13:58:19 PDT