| From: |
| serue@us.ibm.com |
| To: |
| linux-security-module@wirex.com |
| Subject: |
| stacking get/setprocattr support patches |
| Date: |
| Tue, 31 May 2005 12:56:13 -0500 |
| Cc: |
| Stephen Smalley <sds@epoch.ncsc.mil>, zohar@us.ibm.com |
| Archive-link: |
| Article,
Thread
|
Attached are two patches to make procattr shareable by >1
LSM. The first patch applies on top of the current set of
stacker patches from sf.net/projects/lsm-stacker, and
modifies stacker.c. The second patch is to the sf.net
libselinux sources.
Since I took Mimi's idea of switching from
selinux: user:role:type
to
user:role:type (selinux)
for both get and setprocattr, no patch is needed for
ps so long as it's ok to output the data from only the
first LSM to output data.
These patches have been tested
with stacker and an unpatched libselinux
with stacker and a patched libselinux
without stacker and a patched libselinux
and all worked as expected.
Any comments are much appreciated.
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:22:39.000000000 -0500
@@ -956,24 +956,111 @@ static void stacker_d_instantiate (struc
CALL_ALL(d_instantiate,d_instantiate(dentry,inode));
}
+/*
+ * Query all LSMs.
+ * If none returns a non-error, return -EINVAL. SO if all were to return
+ * -EPERM, we lose that info...
+ */
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, o_len, ret=0;
+ int found_nonerr = 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;
+ o_len = len;
+ rcu_read_unlock();
+ ret = m->module_operations.getprocattr(p, name,
+ value+len, size-len);
+ rcu_read_lock();
+ if (ret < 0)
+ continue;
+ found_nonerr = 1;
+ 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_nonerr ? 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 +1118,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.
Index: src/getcon.c
===================================================================
--- src.orig/getcon.c 2005-05-31 15:18:45.000000000 -0500
+++ src/getcon.c 2005-05-31 15:23:56.000000000 -0500
@@ -7,9 +7,11 @@
#include <asm/page.h>
#include "policy.h"
+extern char *find_context(char *ctx, int len);
+
int getcon(security_context_t *context)
{
- char *buf;
+ char *buf, *c;
size_t size;
int fd;
ssize_t ret;
@@ -30,11 +32,13 @@ int getcon(security_context_t *context)
if (ret < 0)
goto out2;
- *context = strdup(buf);
+ c = find_context(buf, ret);
+ *context = strdup(c);
if (!(*context)) {
ret = -1;
goto out2;
}
+
ret = 0;
out2:
free(buf);
Index: src/getexeccon.c
===================================================================
--- src.orig/getexeccon.c 2005-05-31 15:18:45.000000000 -0500
+++ src/getexeccon.c 2005-05-31 15:23:56.000000000 -0500
@@ -7,9 +7,11 @@
#include <asm/page.h>
#include "policy.h"
+extern char *find_context(char *ctx, ssize_t len);
+
int getexeccon(security_context_t *context)
{
- char *buf;
+ char *buf, *c;
size_t size;
int fd;
ssize_t ret;
@@ -35,11 +37,13 @@ int getexeccon(security_context_t *conte
goto out2;
}
- *context = strdup(buf);
+ c = find_context(buf, ret);
+ *context = strdup(c);
if (!(*context)) {
ret = -1;
goto out2;
}
+
ret = 0;
out2:
free(buf);
Index: src/getfscreatecon.c
===================================================================
--- src.orig/getfscreatecon.c 2005-05-31 15:18:45.000000000 -0500
+++ src/getfscreatecon.c 2005-05-31 15:23:56.000000000 -0500
@@ -7,9 +7,11 @@
#include <asm/page.h>
#include "policy.h"
+extern char *find_context(char *ctx, ssize_t len);
+
int getfscreatecon(security_context_t *context)
{
- char *buf;
+ char *buf, *c;
size_t size;
int fd;
ssize_t ret;
@@ -35,11 +37,13 @@ int getfscreatecon(security_context_t *c
goto out2;
}
- *context = strdup(buf);
+ c = find_context(buf, ret);
+ *context = strdup(c);
if (!(*context)) {
ret = -1;
goto out2;
}
+
ret = 0;
out2:
free(buf);
Index: src/getpidcon.c
===================================================================
--- src.orig/getpidcon.c 2005-05-31 15:18:45.000000000 -0500
+++ src/getpidcon.c 2005-05-31 15:23:56.000000000 -0500
@@ -8,10 +8,12 @@
#include <asm/page.h>
#include "policy.h"
+extern char *find_context(char *ctx, ssize_t len);
+
int getpidcon(pid_t pid, security_context_t *context)
{
char path[40];
- char *buf;
+ char *buf, *c;
size_t size;
int fd;
ssize_t ret;
@@ -34,11 +36,13 @@ int getpidcon(pid_t pid, security_contex
if (ret < 0)
goto out2;
- *context = strdup(buf);
+ c = find_context(buf, ret);
+ *context = strdup(c);
if (!(*context)) {
ret = -1;
goto out2;
}
+
ret = 0;
out2:
free(buf);
Index: src/parse_attr.c
===================================================================
--- src.orig/parse_attr.c 2005-05-31 10:27:56.348471792 -0500
+++ src/parse_attr.c 2005-05-31 15:40:46.000000000 -0500
@@ -0,0 +1,59 @@
+#include "selinux_internal.h"
+#include <string.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <unistd.h>
+
+/*
+ * We get either one line which is the selinux output, in which
+ * case we return the line itself, or a set of \n-terminated lines
+ * each ending in ' (mod_name)', in which case we return the line
+ * ending in ' (selinux)'.
+ */
+char *find_context(char *ctx, ssize_t len)
+{
+ char *ec, *sc, *sm, *em;
+
+ sc = ctx;
+
+ do {
+ ec = strstr(sc, " (");
+ if (!ec || ec-ctx > len)
+ return sc;
+ sm = ec+2;
+ em = index(sm, ')');
+ if (!em || em-ctx > len)
+ return sc;
+ if (em-sm==7 && strncmp(sm, "selinux", 7)==0) {
+ *ec = '\0';
+ return sc;
+ }
+ sc = em+2;
+ } while (sc-ctx < len);
+
+ if (sc-ctx >= len)
+ /* No line had ' (selinux)' nor was any
+ * without a trailing ' (modname)'. No
+ * selinux output at all, then? */
+ return ctx;
+
+ return sc;
+}
+
+#define PROCATTR_SELINUX " (selinux)"
+#define STACKSYS "/sys/stacker"
+
+/*
+ * Check existance of /sys/stacker to determine whether the kernel is
+ * using the stacker module. If so, we must output a trailing
+ * ' (selinux)' to our procattr data.
+ */
+char *selinux_identifier(void)
+{
+ struct stat stat_obj;
+
+ if (stat(STACKSYS, &stat_obj)==0)
+ return PROCATTR_SELINUX;
+ else
+ return "";
+}
Index: src/setcon.c
===================================================================
--- src.orig/setcon.c 2005-05-31 15:18:45.000000000 -0500
+++ src/setcon.c 2005-05-31 15:23:56.000000000 -0500
@@ -6,6 +6,9 @@
#include <fcntl.h>
#include <string.h>
#include <selinux/selinux.h>
+#include <stdio.h>
+
+extern char *selinux_identifier(void);
int setcon(security_context_t context)
{
@@ -15,8 +18,8 @@ int setcon(security_context_t context)
fd = open("/proc/self/attr/current", O_RDWR);
if (fd < 0)
return -1;
- if (context)
- ret = write(fd, context, strlen(context)+1);
+ if (context)
+ ret = dprintf(fd, "%s%s", context, selinux_identifier());
else
ret = -1; /* we can not clear this one */
close(fd);
Index: src/setexeccon.c
===================================================================
--- src.orig/setexeccon.c 2005-05-31 15:18:45.000000000 -0500
+++ src/setexeccon.c 2005-05-31 15:23:56.000000000 -0500
@@ -2,6 +2,9 @@
#include <fcntl.h>
#include <string.h>
#include "selinux_internal.h"
+#include <stdio.h>
+
+extern char *selinux_identifier(void);
int setexeccon(security_context_t context)
{
@@ -12,9 +15,9 @@ int setexeccon(security_context_t contex
if (fd < 0)
return -1;
if (context)
- ret = write(fd, context, strlen(context)+1);
+ ret = dprintf(fd, "%s%s", context, selinux_identifier());
else
- ret = write(fd, NULL, 0); /* clear */
+ ret = dprintf(fd, "%s", selinux_identifier()); /* clear */
close(fd);
if (ret < 0)
return -1;
Index: src/setfscreatecon.c
===================================================================
--- src.orig/setfscreatecon.c 2005-05-31 15:18:45.000000000 -0500
+++ src/setfscreatecon.c 2005-05-31 15:23:56.000000000 -0500
@@ -2,6 +2,9 @@
#include <string.h>
#include <fcntl.h>
#include <selinux/selinux.h>
+#include <stdio.h>
+
+extern char *selinux_identifier(void);
int setfscreatecon(char *context)
{
@@ -12,9 +15,9 @@ int setfscreatecon(char *context)
if (fd < 0)
return -1;
if (context)
- ret = write(fd, context, strlen(context)+1);
+ ret = dprintf(fd, "%s%s", context, selinux_identifier());
else
- ret = write(fd, NULL, 0); /* clear */
+ ret = dprintf(fd, "%s", selinux_identifier()); /* clear */
close(fd);
if (ret < 0)
return -1;