[patch 11/12] lsm stacking v0.2: /proc/$$/attr/ sharing

serue
2005-06-30T20:34:51Z

This patch enables sharing of the /proc/<pid>/attr files. Input and
output now takes the form of
"whatever_data_is_expected (module_name)"
For writes, the data section (minus " (module_name)") is sent to the
module identified as "module_name". For reads, stacker appends the
" (module_name)" to whatever modules send. If any module returns
an error other than -EINVAL, that error and no data is returned.

If data is written to a procattr file without " (module_name)"
the data is sent to the selinux module.

Signed-off-by: Serge Hallyn <serue@us.ibm.com>
---
stacker.c | 125 +++++++++++++++++++++++++++++++++++++++++++++++++-------------
1 files changed, 100 insertions(+), 25 deletions(-)

Index: linux-2.6.13-rc1/security/stacker.c
===================================================================
--- linux-2.6.13-rc1.orig/security/stacker.c 2005-06-30 15:32:43.000000000 -0500
+++ linux-2.6.13-rc1/security/stacker.c 2005-06-30 15:40:19.000000000 -0500
@@ -966,24 +966,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);
}

/*
@@ -1048,23 +1140,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.