* [PATCH 1/7] libselinux: labeling support (try 4)
@ 2007-06-15 23:29 Eamon Walsh
2007-06-15 23:35 ` [PATCH 2/7] " Eamon Walsh
` (5 more replies)
0 siblings, 6 replies; 9+ messages in thread
From: Eamon Walsh @ 2007-06-15 23:29 UTC (permalink / raw)
To: SE Linux; +Cc: Stephen Smalley, Karl MacMillan
Changes from the third version: remove handle typedef, includes patch
for setfiles, rebases matchpathcon code to use new interface, includes
X backend, fixes setfiles -c, rolls in callback interface patch.
This is a labeling API that provides a common way to map from various
string namespaces into security contexts.
This version of the patchset simplifies the lookup model down to
(string,number) to context. There are no void pointers or variadic
functions which was one of the objections to the previous patchsets.
A lot of the file contexts stuff such as the inode tracking support
has also been dropped with the understanding that this stuff should
be in the setfiles code, not libselinux. This is a pure lookup
interface only.
This patchset includes 3 backends, for file contexts, media contexts
and X. Future work would include libsemanage interfaces for
managing the data the way the file contexts data is currently done.
This patch includes the new callback interface.
Signed-off-by: Eamon Walsh <ewalsh@tycho.nsa.gov>
---
include/selinux/selinux.h | 25 +++++++++++++++++
src/callbacks.c | 67 ++++++++++++++++++++++++++++++++++++++++++++++
src/callbacks.h | 24 ++++++++++++++++
3 files changed, 116 insertions(+)
Index: libselinux/include/selinux/selinux.h
===================================================================
--- libselinux/include/selinux/selinux.h (revision 2474)
+++ libselinux/include/selinux/selinux.h (working copy)
@@ -132,6 +132,31 @@
unsigned int seqno;
};
+/* Callback facilities */
+union selinux_callback {
+ /* log the printf-style format and arguments,
+ with the type code indicating the type of message */
+ int (*func_log) (int type, const char *fmt, ...);
+ /* store a string representation of auditdata (corresponding
+ to the given security class) into msgbuf. */
+ int (*func_audit) (void *auditdata, security_class_t cls,
+ char *msgbuf, size_t msgbufsize);
+ /* validate the supplied context, modifying if necessary */
+ int (*func_validate) (security_context_t *ctx);
+};
+
+#define SELINUX_CB_LOG 0
+#define SELINUX_CB_AUDIT 1
+#define SELINUX_CB_VALIDATE 2
+
+extern void selinux_set_callback(int type, union selinux_callback cb);
+
+ /* Logging type codes, passed to the logging callback */
+#define SELINUX_ERROR 0
+#define SELINUX_WARNING 1
+#define SELINUX_INFO 2
+#define SELINUX_AVC 3
+
/* Compute an access decision. */
extern int security_compute_av(security_context_t scon,
security_context_t tcon,
Index: libselinux/src/callbacks.h
===================================================================
--- libselinux/src/callbacks.h (revision 0)
+++ libselinux/src/callbacks.h (revision 0)
@@ -0,0 +1,24 @@
+/*
+ * This file describes the callbacks passed to selinux_init() and available
+ * for use from the library code. They all have default implementations.
+ */
+#ifndef _SELINUX_CALLBACKS_H_
+#define _SELINUX_CALLBACKS_H_
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <selinux/selinux.h>
+#include "dso.h"
+
+/* callback pointers */
+extern int __attribute__ ((format(printf, 2, 3)))
+(*selinux_log) (int type, const char *, ...) hidden;
+
+extern int
+(*selinux_audit) (void *, security_class_t, char *, size_t) hidden;
+
+extern int
+(*selinux_validate)(security_context_t *ctx) hidden;
+
+#endif /* _SELINUX_CALLBACKS_H_ */
Index: libselinux/src/callbacks.c
===================================================================
--- libselinux/src/callbacks.c (revision 0)
+++ libselinux/src/callbacks.c (revision 0)
@@ -0,0 +1,67 @@
+/*
+ * User-supplied callbacks and default implementations.
+ * Class and permission mappings.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdarg.h>
+#include <selinux/selinux.h>
+#include "callbacks.h"
+
+/* default implementations */
+static int __attribute__ ((format(printf, 2, 3)))
+default_selinux_log(int type __attribute__((unused)), const char *fmt, ...)
+{
+ int rc;
+ va_list ap;
+ va_start(ap, fmt);
+ rc = vfprintf(stderr, fmt, ap);
+ va_end(ap);
+ return rc;
+}
+
+static int
+default_selinux_audit(void *ptr __attribute__((unused)),
+ security_class_t cls __attribute__((unused)),
+ char *buf __attribute__((unused)),
+ size_t len __attribute__((unused)))
+{
+ return 0;
+}
+
+static int
+default_selinux_validate(security_context_t *ctx)
+{
+ return security_check_context(*ctx);
+}
+
+/* callback pointers */
+int __attribute__ ((format(printf, 2, 3)))
+(*selinux_log)(int, const char *, ...) =
+ default_selinux_log;
+
+int
+(*selinux_audit) (void *, security_class_t, char *, size_t) =
+ default_selinux_audit;
+
+int
+(*selinux_validate)(security_context_t *ctx) =
+ default_selinux_validate;
+
+/* callback setting function */
+void
+selinux_set_callback(int type, union selinux_callback cb)
+{
+ switch (type) {
+ case SELINUX_CB_LOG:
+ selinux_log = cb.func_log;
+ break;
+ case SELINUX_CB_AUDIT:
+ selinux_audit = cb.func_audit;
+ break;
+ case SELINUX_CB_VALIDATE:
+ selinux_validate = cb.func_validate;
+ break;
+ }
+}
--
Eamon Walsh <ewalsh@tycho.nsa.gov>
National Security Agency
--
This message was distributed to subscribers of the selinux mailing list.
If you no longer wish to subscribe, send mail to majordomo@tycho.nsa.gov with
the words "unsubscribe selinux" without quotes as the message.
^ permalink raw reply [flat|nested] 9+ messages in thread
* [PATCH 2/7] libselinux: labeling support (try 4)
2007-06-15 23:29 [PATCH 1/7] libselinux: labeling support (try 4) Eamon Walsh
@ 2007-06-15 23:35 ` Eamon Walsh
2007-06-15 23:37 ` [PATCH 3/7] " Eamon Walsh
` (4 subsequent siblings)
5 siblings, 0 replies; 9+ messages in thread
From: Eamon Walsh @ 2007-06-15 23:35 UTC (permalink / raw)
To: SE Linux; +Cc: Stephen Smalley, Karl MacMillan
This patch includes the interface and generic handle code. Tested
with some sample input values, worked OK.
Signed-off-by: Eamon Walsh <ewalsh@tycho.nsa.gov>
---
include/selinux/label.h | 124 ++++++++++++++++++++++++++++++++++++++++++
src/label.c | 140 ++++++++++++++++++++++++++++++++++++++++++++++++
src/label_internal.h | 74 +++++++++++++++++++++++++
3 files changed, 338 insertions(+)
Index: libselinux/include/selinux/label.h
===================================================================
--- libselinux/include/selinux/label.h (revision 0)
+++ libselinux/include/selinux/label.h (revision 0)
@@ -0,0 +1,124 @@
+/*
+ * Labeling interface for userspace object managers and others.
+ *
+ * Author : Eamon Walsh <ewalsh@tycho.nsa.gov>
+ */
+#ifndef _SELABEL_H_
+#define _SELABEL_H_
+
+#include <sys/types.h>
+#include <selinux/selinux.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*
+ * Opaque type used for all label handles.
+ */
+
+struct selabel_handle;
+
+/*
+ * Available backends.
+ */
+
+/* file contexts */
+#define SELABEL_CTX_FILE 0
+/* media contexts */
+#define SELABEL_CTX_MEDIA 1
+/* x contexts */
+#define SELABEL_CTX_X 2
+
+/*
+ * Available options
+ */
+
+/* no-op option, useful for unused slots in an array of options */
+#define SELABEL_OPT_UNUSED 0
+/* validate contexts before returning them (boolean value) */
+#define SELABEL_OPT_VALIDATE 1
+/* don't use local customizations to backend data (boolean value) */
+#define SELABEL_OPT_BASEONLY 2
+/* specify an alternate path to use when loading backend data */
+#define SELABEL_OPT_PATH 3
+/* select a subset of the search space as an optimization (file backend) */
+#define SELABEL_OPT_SUBSET 4
+/* total number of options */
+#define SELABEL_NOPT 6
+
+struct selabel_opt {
+ int type;
+ const char *value;
+};
+
+/*
+ * Label operations
+ */
+
+/**
+ * selabel_open - Create a labeling handle.
+ * @backend: one of the constants specifying a supported labeling backend.
+ * @opts: array of selabel_opt structures specifying label options or NULL.
+ * @nopts: number of elements in opts array or zero for no options.
+ *
+ * Open a labeling backend for use. The available backend identifiers are
+ * listed above. Options may be provided via the opts parameter; available
+ * options are listed above. Not all options may be supported by every
+ * backend. Return value is the created handle on success or NULL with
+ * @errno set on failure.
+ */
+struct selabel_handle *selabel_open(unsigned int backend,
+ struct selabel_opt *opts, size_t nopts);
+
+/**
+ * selabel_close - Close a labeling handle.
+ * @handle: specifies handle to close
+ *
+ * Destroy the specified handle, closing files, freeing allocated memory,
+ * etc. The handle may not be further used after it has been closed.
+ */
+void selabel_close(struct selabel_handle *handle);
+
+/**
+ * selabel_lookup - Perform labeling lookup operation.
+ * @handle: specifies backend instance to query
+ * @con: returns the appropriate context with which to label the object
+ * @key: string input to lookup operation
+ * @type: numeric input to the lookup operation
+ *
+ * Perform a labeling lookup operation. Return %0 on success, -%1 with
+ * @errno set on failure. The key and type arguments are the inputs to the
+ * lookup operation; appropriate values are dictated by the backend in use.
+ * The result is returned in the memory pointed to by @con and must be freed
+ * by the user with freecon().
+ */
+int selabel_lookup(struct selabel_handle *handle, security_context_t *con,
+ const char *key, int type);
+int selabel_lookup_raw(struct selabel_handle *handle, security_context_t *con,
+ const char *key, int type);
+
+/**
+ * selabel_stats - log labeling operation statistics.
+ * @handle: specifies backend instance to query
+ *
+ * Log a message with information about the number of queries performed,
+ * number of unused matching entries, or other operational statistics.
+ * Message is backend-specific, some backends may not output a message.
+ */
+void selabel_stats(struct selabel_handle *handle);
+
+/*
+ * Type codes used by specific backends
+ */
+
+/* X backend */
+#define SELABEL_X_PROP 1
+#define SELABEL_X_EXT 2
+#define SELABEL_X_CLIENT 3
+
+
+#ifdef __cplusplus
+}
+#endif
+#endif /* _SELABEL_H_ */
Index: libselinux/src/label_internal.h
===================================================================
--- libselinux/src/label_internal.h (revision 0)
+++ libselinux/src/label_internal.h (revision 0)
@@ -0,0 +1,74 @@
+/*
+ * This file describes the internal interface used by the labeler
+ * for calling the user-supplied memory allocation, validation,
+ * and locking routine.
+ *
+ * Author : Eamon Walsh <ewalsh@epoch.ncsc.mil>
+ */
+#ifndef _SELABEL_INTERNAL_H_
+#define _SELABEL_INTERNAL_H_
+
+#include <stdlib.h>
+#include <stdarg.h>
+#include <selinux/selinux.h>
+#include <selinux/label.h>
+#include "dso.h"
+
+/*
+ * Installed backends
+ */
+int selabel_file_init(struct selabel_handle *rec, struct selabel_opt *opts,
+ size_t nopts) hidden;
+int selabel_media_init(struct selabel_handle *rec, struct selabel_opt *opts,
+ size_t nopts) hidden;
+int selabel_x_init(struct selabel_handle *rec, struct selabel_opt *opts,
+ size_t nopts) hidden;
+
+/*
+ * Labeling internal structures
+ */
+struct selabel_lookup_rec {
+ security_context_t ctx_raw;
+ security_context_t ctx_trans;
+ int validated;
+};
+
+struct selabel_handle {
+ /* arguments that were passed to selabel_open */
+ unsigned int backend;
+ int validating;
+
+ /* labeling operations */
+ struct selabel_lookup_rec *(*func_lookup) (struct selabel_handle *h,
+ const char *key, int type);
+ void (*func_close) (struct selabel_handle *h);
+ void (*func_stats) (struct selabel_handle *h);
+
+ /* supports backend-specific state information */
+ void *data;
+};
+
+/*
+ * Validation function
+ */
+extern int
+selabel_validate(struct selabel_handle *rec,
+ struct selabel_lookup_rec *contexts) hidden;
+
+/*
+ * Compatibility support
+ */
+extern void __attribute__ ((format(printf, 1, 2)))
+(*myprintf) (const char *fmt,...);
+
+#define COMPAT_LOG(type, fmt...) if (myprintf) \
+ myprintf(fmt); \
+ else \
+ selinux_log(type, fmt);
+
+extern int
+compat_validate(struct selabel_handle *rec,
+ struct selabel_lookup_rec *contexts,
+ const char *path, unsigned lineno) hidden;
+
+#endif /* _SELABEL_INTERNAL_H_ */
Index: libselinux/src/label.c
===================================================================
--- libselinux/src/label.c (revision 0)
+++ libselinux/src/label.c (revision 0)
@@ -0,0 +1,140 @@
+/*
+ * Generalized labeling frontend for userspace object managers.
+ *
+ * Author : Eamon Walsh <ewalsh@epoch.ncsc.mil>
+ */
+
+#include <sys/types.h>
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include "callbacks.h"
+#include "label_internal.h"
+
+#define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0]))
+
+typedef int (*selabel_initfunc)(struct selabel_handle *rec,
+ struct selabel_opt *opts, size_t nopts);
+
+static selabel_initfunc initfuncs[] = {
+ &selabel_file_init,
+ &selabel_media_init,
+ &selabel_x_init
+};
+
+/*
+ * Validation functions
+ */
+
+static inline int selabel_is_validate_set(struct selabel_opt *opts, size_t n)
+{
+ while (n--)
+ if (opts[n].type == SELABEL_OPT_VALIDATE)
+ return !!opts[n].value;
+
+ return 0;
+}
+
+int selabel_validate(struct selabel_handle *rec,
+ struct selabel_lookup_rec *contexts)
+{
+ int rc = 0;
+
+ if (!rec->validating || contexts->validated)
+ goto out;
+
+ rc = selinux_validate(&contexts->ctx_raw);
+ if (rc < 0)
+ goto out;
+
+ contexts->validated = 1;
+out:
+ return rc;
+}
+
+/*
+ * Public API
+ */
+
+struct selabel_handle *selabel_open(unsigned int backend,
+ struct selabel_opt *opts, size_t nopts)
+{
+ struct selabel_handle *rec = NULL;
+
+ if (backend >= ARRAY_SIZE(initfuncs)) {
+ errno = EINVAL;
+ goto out;
+ }
+
+ rec = (struct selabel_handle *)malloc(sizeof(*rec));
+ if (!rec)
+ goto out;
+
+ memset(rec, 0, sizeof(*rec));
+ rec->backend = backend;
+ rec->validating = selabel_is_validate_set(opts, nopts);
+
+ if ((*initfuncs[backend])(rec, opts, nopts)) {
+ free(rec);
+ rec = NULL;
+ }
+
+out:
+ return rec;
+}
+
+static struct selabel_lookup_rec *
+selabel_lookup_common(struct selabel_handle *rec, int translating,
+ const char *key, int type)
+{
+ struct selabel_lookup_rec *lr = rec->func_lookup(rec, key, type);
+ if (!lr)
+ return NULL;
+
+ if (compat_validate(rec, lr, "file_contexts", 0))
+ return NULL;
+
+ if (translating &&
+ selinux_raw_to_trans_context(lr->ctx_raw, &lr->ctx_trans))
+ return NULL;
+
+ return lr;
+}
+
+int selabel_lookup(struct selabel_handle *rec, security_context_t *con,
+ const char *key, int type)
+{
+ struct selabel_lookup_rec *lr;
+
+ lr = selabel_lookup_common(rec, 1, key, type);
+ if (!lr)
+ return -1;
+
+ *con = strdup(lr->ctx_trans);
+ return *con ? 0 : -1;
+}
+
+int selabel_lookup_raw(struct selabel_handle *rec, security_context_t *con,
+ const char *key, int type)
+{
+ struct selabel_lookup_rec *lr;
+
+ lr = selabel_lookup_common(rec, 0, key, type);
+ if (!lr)
+ return -1;
+
+ *con = strdup(lr->ctx_raw);
+ return *con ? 0 : -1;
+}
+
+void selabel_close(struct selabel_handle *rec)
+{
+ rec->func_close(rec);
+ free(rec);
+}
+
+void selabel_stats(struct selabel_handle *rec)
+{
+ rec->func_stats(rec);
+}
--
Eamon Walsh <ewalsh@tycho.nsa.gov>
National Security Agency
--
This message was distributed to subscribers of the selinux mailing list.
If you no longer wish to subscribe, send mail to majordomo@tycho.nsa.gov with
the words "unsubscribe selinux" without quotes as the message.
^ permalink raw reply [flat|nested] 9+ messages in thread
* [PATCH 3/7] libselinux: labeling support (try 4)
2007-06-15 23:29 [PATCH 1/7] libselinux: labeling support (try 4) Eamon Walsh
2007-06-15 23:35 ` [PATCH 2/7] " Eamon Walsh
@ 2007-06-15 23:37 ` Eamon Walsh
2007-06-15 23:39 ` [PATCH 4/7] " Eamon Walsh
` (3 subsequent siblings)
5 siblings, 0 replies; 9+ messages in thread
From: Eamon Walsh @ 2007-06-15 23:37 UTC (permalink / raw)
To: SE Linux; +Cc: Stephen Smalley, Karl MacMillan
This patch includes the media backend code.
Signed-off-by: Eamon Walsh <ewalsh@tycho.nsa.gov>
---
label_media.c | 219 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 219 insertions(+)
Index: libselinux/src/label_media.c
===================================================================
--- libselinux/src/label_media.c (revision 0)
+++ libselinux/src/label_media.c (revision 0)
@@ -0,0 +1,219 @@
+/*
+ * Media contexts backend for labeling system
+ *
+ * Author : Eamon Walsh <ewalsh@tycho.nsa.gov>
+ */
+
+#include <sys/stat.h>
+#include <string.h>
+#include <stdio.h>
+#include <stdio_ext.h>
+#include <ctype.h>
+#include <errno.h>
+#include <limits.h>
+#include "callbacks.h"
+#include "label_internal.h"
+
+/*
+ * Internals
+ */
+
+/* A context specification. */
+typedef struct spec {
+ struct selabel_lookup_rec lr; /* holds contexts for lookup result */
+ char *key; /* key string */
+ int matches; /* number of matches made during operation */
+} spec_t;
+
+struct saved_data {
+ unsigned int nspec;
+ spec_t *spec_arr;
+};
+
+static int process_line(const char *path, char *line_buf, int pass,
+ unsigned lineno, struct selabel_handle *rec)
+{
+ struct saved_data *data = (struct saved_data *)rec->data;
+ int items;
+ char *buf_p;
+ char *key, *context;
+
+ buf_p = line_buf;
+ while (isspace(*buf_p))
+ buf_p++;
+ /* Skip comment lines and empty lines. */
+ if (*buf_p == '#' || *buf_p == 0)
+ return 0;
+ items = sscanf(line_buf, "%as %as ", &key, &context);
+ if (items < 2) {
+ selinux_log(SELINUX_WARNING,
+ "%s: line %d is missing fields, skipping\n", path,
+ lineno);
+ if (items == 1)
+ free(key);
+ return 0;
+ }
+
+ if (pass == 1) {
+ data->spec_arr[data->nspec].key = key;
+ data->spec_arr[data->nspec].lr.ctx_raw = context;
+ }
+
+ data->nspec++;
+ if (pass == 0) {
+ free(key);
+ free(context);
+ }
+ return 0;
+}
+
+static int init(struct selabel_handle *rec, struct selabel_opt *opts,
+ size_t n)
+{
+ FILE *fp;
+ struct saved_data *data = (struct saved_data *)rec->data;
+ const char *path = NULL;
+ char *line_buf = NULL;
+ size_t line_len = 0;
+ int status = -1;
+ unsigned int lineno, pass, maxnspec;
+ struct stat sb;
+
+ /* Process arguments */
+ while (n--)
+ switch(opts[n].type) {
+ case SELABEL_OPT_PATH:
+ path = opts[n].value;
+ break;
+ }
+
+ /* Open the specification file. */
+ if (!path)
+ path = selinux_media_context_path();
+ if ((fp = fopen(path, "r")) == NULL)
+ return -1;
+ __fsetlocking(fp, FSETLOCKING_BYCALLER);
+
+ if (fstat(fileno(fp), &sb) < 0)
+ return -1;
+ if (!S_ISREG(sb.st_mode)) {
+ errno = EINVAL;
+ return -1;
+ }
+
+ /*
+ * Perform two passes over the specification file.
+ * The first pass counts the number of specifications and
+ * performs simple validation of the input. At the end
+ * of the first pass, the spec array is allocated.
+ * The second pass performs detailed validation of the input
+ * and fills in the spec array.
+ */
+ maxnspec = UINT_MAX / sizeof(spec_t);
+ for (pass = 0; pass < 2; pass++) {
+ lineno = 0;
+ data->nspec = 0;
+ while (getline(&line_buf, &line_len, fp) > 0 &&
+ data->nspec < maxnspec) {
+ if (process_line(path, line_buf, pass, ++lineno, rec))
+ goto finish;
+ }
+ lineno = 0;
+
+ if (pass == 0) {
+ if (data->nspec == 0) {
+ status = 0;
+ goto finish;
+ }
+ data->spec_arr = malloc(sizeof(spec_t)*data->nspec);
+ if (data->spec_arr == NULL)
+ goto finish;
+ memset(data->spec_arr, 0, sizeof(spec_t)*data->nspec);
+ maxnspec = data->nspec;
+ rewind(fp);
+ }
+ }
+ free(line_buf);
+
+ status = 0;
+finish:
+ fclose(fp);
+ return status;
+}
+
+/*
+ * Backend interface routines
+ */
+static void close(struct selabel_handle *rec)
+{
+ struct saved_data *data = (struct saved_data *)rec->data;
+ struct spec *spec, *spec_arr = data->spec_arr;
+ unsigned int i;
+
+ for (i = 0; i < data->nspec; i++) {
+ spec = &spec_arr[i];
+ free(spec->key);
+ free(spec->lr.ctx_raw);
+ free(spec->lr.ctx_trans);
+ }
+
+ if (spec_arr)
+ free(spec_arr);
+
+ memset(data, 0, sizeof(*data));
+}
+
+static struct selabel_lookup_rec *lookup(struct selabel_handle *rec,
+ const char *key,
+ int type __attribute__((unused)))
+{
+ struct saved_data *data = (struct saved_data *)rec->data;
+ spec_t *spec_arr = data->spec_arr;
+ unsigned int i;
+
+ for (i = 0; i < data->nspec; i++) {
+ if (!strncmp(spec_arr[i].key, key, strlen(key) + 1))
+ break;
+ if (!strncmp(spec_arr[i].key, "*", 2))
+ break;
+ }
+
+ if (i >= data->nspec) {
+ /* No matching specification. */
+ errno = ENOENT;
+ return NULL;
+ }
+
+ spec_arr[i].matches++;
+ return &spec_arr[i].lr;
+}
+
+static void stats(struct selabel_handle *rec)
+{
+ struct saved_data *data = (struct saved_data *)rec->data;
+ unsigned int i, total = 0;
+
+ for (i = 0; i < data->nspec; i++)
+ total += data->spec_arr[i].matches;
+
+ selinux_log(SELINUX_INFO, "%u entries, %u matches made\n",
+ data->nspec, total);
+}
+
+int selabel_media_init(struct selabel_handle *rec, struct selabel_opt *opts,
+ size_t nopts)
+{
+ struct saved_data *data;
+
+ data = (struct saved_data *)malloc(sizeof(*data));
+ if (!data)
+ return -1;
+ memset(data, 0, sizeof(*data));
+
+ rec->data = data;
+ rec->func_close = &close;
+ rec->func_lookup = &lookup;
+ rec->func_stats = &stats;
+
+ return init(rec, opts, nopts);
+}
--
Eamon Walsh <ewalsh@tycho.nsa.gov>
National Security Agency
--
This message was distributed to subscribers of the selinux mailing list.
If you no longer wish to subscribe, send mail to majordomo@tycho.nsa.gov with
the words "unsubscribe selinux" without quotes as the message.
^ permalink raw reply [flat|nested] 9+ messages in thread
* [PATCH 4/7] libselinux: labeling support (try 4)
2007-06-15 23:29 [PATCH 1/7] libselinux: labeling support (try 4) Eamon Walsh
2007-06-15 23:35 ` [PATCH 2/7] " Eamon Walsh
2007-06-15 23:37 ` [PATCH 3/7] " Eamon Walsh
@ 2007-06-15 23:39 ` Eamon Walsh
2007-06-15 23:40 ` [PATCH 5/7] " Eamon Walsh
` (2 subsequent siblings)
5 siblings, 0 replies; 9+ messages in thread
From: Eamon Walsh @ 2007-06-15 23:39 UTC (permalink / raw)
To: SE Linux; +Cc: Stephen Smalley, Karl MacMillan
This patch includes the file contexts backend code.
Signed-off-by: Eamon Walsh <ewalsh@tycho.nsa.gov>
---
label_file.c | 641 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 641 insertions(+)
Index: libselinux/src/label_file.c
===================================================================
--- libselinux/src/label_file.c (revision 0)
+++ libselinux/src/label_file.c (revision 0)
@@ -0,0 +1,641 @@
+/*
+ * File contexts backend for labeling system
+ *
+ * Author : Eamon Walsh <ewalsh@tycho.nsa.gov>
+ * Author : Stephen Smalley <sds@tycho.nsa.gov>
+ *
+ * This library derived in part from setfiles and the setfiles.pl script
+ * developed by Secure Computing Corporation.
+ */
+
+#include <fcntl.h>
+#include <stdarg.h>
+#include <string.h>
+#include <stdio.h>
+#include <stdio_ext.h>
+#include <ctype.h>
+#include <errno.h>
+#include <limits.h>
+#include <regex.h>
+#include "callbacks.h"
+#include "label_internal.h"
+
+/*
+ * Internals, mostly moved over from matchpathcon.c
+ */
+
+/* A file security context specification. */
+typedef struct spec {
+ struct selabel_lookup_rec lr; /* holds contexts for lookup result */
+ char *regex_str; /* regular expession string for diagnostics */
+ char *type_str; /* type string for diagnostic messages */
+ regex_t regex; /* compiled regular expression */
+ mode_t mode; /* mode format value */
+ int matches; /* number of matching pathnames */
+ int hasMetaChars; /* regular expression has meta-chars */
+ int stem_id; /* indicates which stem-compression item */
+} spec_t;
+
+/* A regular expression stem */
+typedef struct stem {
+ char *buf;
+ int len;
+} stem_t;
+
+/* Our stored configuration */
+struct saved_data {
+ /*
+ * The array of specifications, initially in the same order as in
+ * the specification file. Sorting occurs based on hasMetaChars.
+ */
+ spec_t *spec_arr;
+ unsigned int nspec;
+
+ /*
+ * The array of regular expression stems.
+ */
+ stem_t *stem_arr;
+ int num_stems;
+ int alloc_stems;
+};
+
+/* Return the length of the text that can be considered the stem, returns 0
+ * if there is no identifiable stem */
+static int get_stem_from_spec(const char *const buf)
+{
+ const char *tmp = strchr(buf + 1, '/');
+ const char *ind;
+
+ if (!tmp)
+ return 0;
+
+ for (ind = buf; ind < tmp; ind++) {
+ if (strchr(".^$?*+|[({", (int)*ind))
+ return 0;
+ }
+ return tmp - buf;
+}
+
+/* return the length of the text that is the stem of a file name */
+static int get_stem_from_file_name(const char *const buf)
+{
+ const char *tmp = strchr(buf + 1, '/');
+
+ if (!tmp)
+ return 0;
+ return tmp - buf;
+}
+
+/* find the stem of a file spec, returns the index into stem_arr for a new
+ * or existing stem, (or -1 if there is no possible stem - IE for a file in
+ * the root directory or a regex that is too complex for us). Makes buf
+ * point to the text AFTER the stem. */
+static int find_stem_from_spec(struct saved_data *data, const char **buf)
+{
+ int i, num = data->num_stems;
+ int stem_len = get_stem_from_spec(*buf);
+
+ if (!stem_len)
+ return -1;
+ for (i = 0; i < num; i++) {
+ if (stem_len == data->stem_arr[i].len
+ && !strncmp(*buf, data->stem_arr[i].buf, stem_len)) {
+ *buf += stem_len;
+ return i;
+ }
+ }
+ if (data->alloc_stems == num) {
+ stem_t *tmp_arr;
+ data->alloc_stems = data->alloc_stems * 2 + 16;
+ tmp_arr = realloc(data->stem_arr,
+ sizeof(stem_t) * data->alloc_stems);
+ if (!tmp_arr)
+ return -1;
+ data->stem_arr = tmp_arr;
+ }
+ data->stem_arr[num].len = stem_len;
+ data->stem_arr[num].buf = malloc(stem_len + 1);
+ if (!data->stem_arr[num].buf)
+ return -1;
+ memcpy(data->stem_arr[num].buf, *buf, stem_len);
+ data->stem_arr[num].buf[stem_len] = '\0';
+ data->num_stems++;
+ *buf += stem_len;
+ return num;
+}
+
+/* find the stem of a file name, returns the index into stem_arr (or -1 if
+ * there is no match - IE for a file in the root directory or a regex that is
+ * too complex for us). Makes buf point to the text AFTER the stem. */
+static int find_stem_from_file(struct saved_data *data, const char **buf)
+{
+ int i;
+ int stem_len = get_stem_from_file_name(*buf);
+
+ if (!stem_len)
+ return -1;
+ for (i = 0; i < data->num_stems; i++) {
+ if (stem_len == data->stem_arr[i].len
+ && !strncmp(*buf, data->stem_arr[i].buf, stem_len)) {
+ *buf += stem_len;
+ return i;
+ }
+ }
+ return -1;
+}
+
+/*
+ * Warn about duplicate specifications.
+ */
+static void nodups_specs(struct saved_data *data, const char *path)
+{
+ unsigned int ii, jj;
+ struct spec *curr_spec, *spec_arr = data->spec_arr;
+
+ for (ii = 0; ii < data->nspec; ii++) {
+ curr_spec = &spec_arr[ii];
+ for (jj = ii + 1; jj < data->nspec; jj++) {
+ if ((!strcmp
+ (spec_arr[jj].regex_str, curr_spec->regex_str))
+ && (!spec_arr[jj].mode || !curr_spec->mode
+ || spec_arr[jj].mode == curr_spec->mode)) {
+ if (strcmp
+ (spec_arr[jj].lr.ctx_raw,
+ curr_spec->lr.ctx_raw)) {
+ COMPAT_LOG
+ (SELINUX_WARNING,
+ "%s: Multiple different specifications for %s (%s and %s).\n",
+ path, curr_spec->regex_str,
+ spec_arr[jj].lr.ctx_raw,
+ curr_spec->lr.ctx_raw);
+ } else {
+ COMPAT_LOG
+ (SELINUX_WARNING,
+ "%s: Multiple same specifications for %s.\n",
+ path, curr_spec->regex_str);
+ }
+ }
+ }
+ }
+}
+
+/* Determine if the regular expression specification has any meta characters. */
+static void spec_hasMetaChars(struct spec *spec)
+{
+ char *c;
+ int len;
+ char *end;
+
+ c = spec->regex_str;
+ len = strlen(spec->regex_str);
+ end = c + len;
+
+ spec->hasMetaChars = 0;
+
+ /* Look at each character in the RE specification string for a
+ * meta character. Return when any meta character reached. */
+ while (c != end) {
+ switch (*c) {
+ case '.':
+ case '^':
+ case '$':
+ case '?':
+ case '*':
+ case '+':
+ case '|':
+ case '[':
+ case '(':
+ case '{':
+ spec->hasMetaChars = 1;
+ return;
+ case '\\': /* skip the next character */
+ c++;
+ break;
+ default:
+ break;
+
+ }
+ c++;
+ }
+ return;
+}
+
+static int process_line(struct selabel_handle *rec,
+ const char *path, const char *prefix,
+ char *line_buf, int pass, unsigned lineno)
+{
+ int items, len, regerr;
+ char *buf_p, *regex, *anchored_regex, *type, *context;
+ const char *reg_buf;
+ struct saved_data *data = (struct saved_data *)rec->data;
+ spec_t *spec_arr = data->spec_arr;
+ unsigned int nspec = data->nspec;
+
+ len = strlen(line_buf);
+ if (line_buf[len - 1] == '\n')
+ line_buf[len - 1] = 0;
+ buf_p = line_buf;
+ while (isspace(*buf_p))
+ buf_p++;
+ /* Skip comment lines and empty lines. */
+ if (*buf_p == '#' || *buf_p == 0)
+ return 0;
+ items = sscanf(line_buf, "%as %as %as", ®ex, &type, &context);
+ if (items < 2) {
+ COMPAT_LOG(SELINUX_WARNING,
+ "%s: line %d is missing fields, skipping\n", path,
+ lineno);
+ return 0;
+ } else if (items == 2) {
+ /* The type field is optional. */
+ free(context);
+ context = type;
+ type = 0;
+ }
+
+ reg_buf = regex;
+ len = get_stem_from_spec(reg_buf);
+ if (len && prefix && strncmp(prefix, regex, len)) {
+ /* Stem of regex does not match requested prefix, discard. */
+ free(regex);
+ free(type);
+ free(context);
+ return 0;
+ }
+
+ if (pass == 1) {
+ /* On the second pass, compile and store the specification in spec. */
+ char *cp;
+ spec_arr[nspec].stem_id = find_stem_from_spec(data, ®_buf);
+ spec_arr[nspec].regex_str = regex;
+
+ /* Anchor the regular expression. */
+ len = strlen(reg_buf);
+ cp = anchored_regex = malloc(len + 3);
+ if (!anchored_regex)
+ return -1;
+ /* Create ^...$ regexp. */
+ *cp++ = '^';
+ cp = mempcpy(cp, reg_buf, len);
+ *cp++ = '$';
+ *cp = '\0';
+
+ /* Compile the regular expression. */
+ regerr =
+ regcomp(&spec_arr[nspec].regex,
+ anchored_regex, REG_EXTENDED | REG_NOSUB);
+ if (regerr != 0) {
+ size_t errsz = 0;
+ char *errbuf = NULL;
+ errsz = regerror(regerr, &spec_arr[nspec].regex,
+ errbuf, errsz);
+ if (errsz)
+ errbuf = malloc(errsz);
+ if (errbuf)
+ (void)regerror(regerr,
+ &spec_arr[nspec].regex,
+ errbuf, errsz);
+ COMPAT_LOG(SELINUX_WARNING,
+ "%s: line %d has invalid regex %s: %s\n",
+ path, lineno, anchored_regex,
+ (errbuf ? errbuf : "out of memory"));
+ free(anchored_regex);
+ return 0;
+ }
+ free(anchored_regex);
+
+ /* Convert the type string to a mode format */
+ spec_arr[nspec].type_str = type;
+ spec_arr[nspec].mode = 0;
+ if (!type)
+ goto skip_type;
+ len = strlen(type);
+ if (type[0] != '-' || len != 2) {
+ COMPAT_LOG(SELINUX_WARNING,
+ "%s: line %d has invalid file type %s\n",
+ path, lineno, type);
+ return 0;
+ }
+ switch (type[1]) {
+ case 'b':
+ spec_arr[nspec].mode = S_IFBLK;
+ break;
+ case 'c':
+ spec_arr[nspec].mode = S_IFCHR;
+ break;
+ case 'd':
+ spec_arr[nspec].mode = S_IFDIR;
+ break;
+ case 'p':
+ spec_arr[nspec].mode = S_IFIFO;
+ break;
+ case 'l':
+ spec_arr[nspec].mode = S_IFLNK;
+ break;
+ case 's':
+ spec_arr[nspec].mode = S_IFSOCK;
+ break;
+ case '-':
+ spec_arr[nspec].mode = S_IFREG;
+ break;
+ default:
+ COMPAT_LOG(SELINUX_WARNING,
+ "%s: line %d has invalid file type %s\n",
+ path, lineno, type);
+ return 0;
+ }
+
+ skip_type:
+ spec_arr[nspec].lr.ctx_raw = context;
+
+ /* Determine if specification has
+ * any meta characters in the RE */
+ spec_hasMetaChars(&spec_arr[nspec]);
+
+ if (strcmp(context, "<<none>>") && rec->validating)
+ compat_validate(rec, &spec_arr[nspec].lr, path, lineno);
+ }
+
+ data->nspec = ++nspec;
+ if (pass == 0) {
+ free(regex);
+ if (type)
+ free(type);
+ free(context);
+ }
+ return 0;
+}
+
+static int init(struct selabel_handle *rec, struct selabel_opt *opts, size_t n)
+{
+ struct saved_data *data = (struct saved_data *)rec->data;
+ const char *path = NULL;
+ const char *prefix = NULL;
+ FILE *fp;
+ FILE *localfp = NULL;
+ FILE *homedirfp = NULL;
+ char local_path[PATH_MAX + 1];
+ char homedir_path[PATH_MAX + 1];
+ char *line_buf = NULL;
+ size_t line_len = 0;
+ unsigned int lineno, pass, i, j, maxnspec;
+ spec_t *spec_copy = NULL;
+ int status = -1, baseonly = 0;
+ struct stat sb;
+
+ /* Process arguments */
+ while (n--)
+ switch(opts[n].type) {
+ case SELABEL_OPT_PATH:
+ path = opts[n].value;
+ break;
+ case SELABEL_OPT_SUBSET:
+ prefix = opts[n].value;
+ break;
+ case SELABEL_OPT_BASEONLY:
+ baseonly = !!opts[n].value;
+ break;
+ }
+
+ /* Open the specification file. */
+ if (!path)
+ path = selinux_file_context_path();
+ if ((fp = fopen(path, "r")) == NULL)
+ return -1;
+ __fsetlocking(fp, FSETLOCKING_BYCALLER);
+
+ if (fstat(fileno(fp), &sb) < 0)
+ return -1;
+ if (!S_ISREG(sb.st_mode)) {
+ errno = EINVAL;
+ return -1;
+ }
+
+ if (!baseonly) {
+ snprintf(homedir_path, sizeof(homedir_path), "%s.homedirs",
+ path);
+ homedirfp = fopen(homedir_path, "r");
+ if (homedirfp != NULL)
+ __fsetlocking(homedirfp, FSETLOCKING_BYCALLER);
+
+ snprintf(local_path, sizeof(local_path), "%s.local", path);
+ localfp = fopen(local_path, "r");
+ if (localfp != NULL)
+ __fsetlocking(localfp, FSETLOCKING_BYCALLER);
+ }
+
+ /*
+ * Perform two passes over the specification file.
+ * The first pass counts the number of specifications and
+ * performs simple validation of the input. At the end
+ * of the first pass, the spec array is allocated.
+ * The second pass performs detailed validation of the input
+ * and fills in the spec array.
+ */
+ maxnspec = UINT_MAX / sizeof(spec_t);
+ for (pass = 0; pass < 2; pass++) {
+ lineno = 0;
+ data->nspec = 0;
+ while (getline(&line_buf, &line_len, fp) > 0
+ && data->nspec < maxnspec) {
+ if (process_line(rec, path, prefix, line_buf,
+ pass, ++lineno) != 0)
+ goto finish;
+ }
+ lineno = 0;
+ if (homedirfp)
+ while (getline(&line_buf, &line_len, homedirfp) > 0
+ && data->nspec < maxnspec) {
+ if (process_line
+ (rec, homedir_path, prefix,
+ line_buf, pass, ++lineno) != 0)
+ goto finish;
+ }
+
+ lineno = 0;
+ if (localfp)
+ while (getline(&line_buf, &line_len, localfp) > 0
+ && data->nspec < maxnspec) {
+ if (process_line
+ (rec, local_path, prefix, line_buf,
+ pass, ++lineno) != 0)
+ goto finish;
+ }
+
+ if (pass == 0) {
+ if (data->nspec == 0) {
+ status = 0;
+ goto finish;
+ }
+ if (NULL == (data->spec_arr =
+ malloc(sizeof(spec_t) * data->nspec)))
+ goto finish;
+ memset(data->spec_arr, 0, sizeof(spec_t)*data->nspec);
+ maxnspec = data->nspec;
+ rewind(fp);
+ if (homedirfp)
+ rewind(homedirfp);
+ if (localfp)
+ rewind(localfp);
+ }
+ }
+ free(line_buf);
+
+ /* Move exact pathname specifications to the end. */
+ spec_copy = malloc(sizeof(spec_t) * data->nspec);
+ if (!spec_copy)
+ goto finish;
+ j = 0;
+ for (i = 0; i < data->nspec; i++)
+ if (data->spec_arr[i].hasMetaChars)
+ memcpy(&spec_copy[j++],
+ &data->spec_arr[i], sizeof(spec_t));
+ for (i = 0; i < data->nspec; i++)
+ if (!data->spec_arr[i].hasMetaChars)
+ memcpy(&spec_copy[j++],
+ &data->spec_arr[i], sizeof(spec_t));
+ free(data->spec_arr);
+ data->spec_arr = spec_copy;
+
+ nodups_specs(data, path);
+
+ status = 0;
+finish:
+ fclose(fp);
+ if (data->spec_arr != spec_copy)
+ free(data->spec_arr);
+ if (homedirfp)
+ fclose(homedirfp);
+ if (localfp)
+ fclose(localfp);
+ return status;
+}
+
+/*
+ * Backend interface routines
+ */
+static void close(struct selabel_handle *rec)
+{
+ struct saved_data *data = (struct saved_data *)rec->data;
+ struct spec *spec;
+ struct stem *stem;
+ unsigned int i;
+
+ for (i = 0; i < data->nspec; i++) {
+ spec = &data->spec_arr[i];
+ free(spec->regex_str);
+ free(spec->type_str);
+ free(spec->lr.ctx_raw);
+ free(spec->lr.ctx_trans);
+ regfree(&spec->regex);
+ }
+
+ for (i = 0; i < (unsigned int)data->num_stems; i++) {
+ stem = &data->stem_arr[i];
+ free(stem->buf);
+ }
+
+ if (data->spec_arr)
+ free(data->spec_arr);
+ if (data->stem_arr)
+ free(data->stem_arr);
+
+ memset(data, 0, sizeof(*data));
+}
+
+static struct selabel_lookup_rec *lookup(struct selabel_handle *rec,
+ const char *key, int type)
+{
+ struct saved_data *data = (struct saved_data *)rec->data;
+ spec_t *spec_arr = data->spec_arr;
+ int i, rc, file_stem;
+ mode_t mode = (mode_t)type;
+ const char *buf = key;
+
+ if (!data->nspec) {
+ errno = ENOENT;
+ return NULL;
+ }
+
+ file_stem = find_stem_from_file(data, &buf);
+ mode &= S_IFMT;
+
+ /*
+ * Check for matching specifications in reverse order, so that
+ * the last matching specification is used.
+ */
+ for (i = data->nspec - 1; i >= 0; i--) {
+ /* if the spec in question matches no stem or has the same
+ * stem as the file AND if the spec in question has no mode
+ * specified or if the mode matches the file mode then we do
+ * a regex check */
+ if ((spec_arr[i].stem_id == -1
+ || spec_arr[i].stem_id == file_stem)
+ && (!mode || !spec_arr[i].mode
+ || mode == spec_arr[i].mode)) {
+ if (spec_arr[i].stem_id == -1)
+ rc = regexec(&spec_arr[i].regex, key, 0, 0, 0);
+ else
+ rc = regexec(&spec_arr[i].regex, buf, 0, 0, 0);
+
+ if (rc == 0) {
+ spec_arr[i].matches++;
+ break;
+ }
+ if (rc == REG_NOMATCH)
+ continue;
+ /* else it's an error */
+ return NULL;
+ }
+ }
+
+ if (i < 0 || strcmp(spec_arr[i].lr.ctx_raw, "<<none>>") == 0) {
+ /* No matching specification. */
+ errno = ENOENT;
+ return NULL;
+ }
+
+ return &spec_arr[i].lr;
+}
+
+static void stats(struct selabel_handle *rec)
+{
+ struct saved_data *data = (struct saved_data *)rec->data;
+ unsigned int i, nspec = data->nspec;
+ spec_t *spec_arr = data->spec_arr;
+
+ for (i = 0; i < nspec; i++) {
+ if (spec_arr[i].matches == 0) {
+ if (spec_arr[i].type_str) {
+ COMPAT_LOG(SELINUX_WARNING,
+ "Warning! No matches for (%s, %s, %s)\n",
+ spec_arr[i].regex_str,
+ spec_arr[i].type_str,
+ spec_arr[i].lr.ctx_raw);
+ } else {
+ COMPAT_LOG(SELINUX_WARNING,
+ "Warning! No matches for (%s, %s)\n",
+ spec_arr[i].regex_str,
+ spec_arr[i].lr.ctx_raw);
+ }
+ }
+ }
+}
+
+int selabel_file_init(struct selabel_handle *rec, struct selabel_opt *opts,
+ size_t nopts)
+{
+ struct saved_data *data;
+
+ data = (struct saved_data *)malloc(sizeof(*data));
+ if (!data)
+ return -1;
+ memset(data, 0, sizeof(*data));
+
+ rec->data = data;
+ rec->func_close = &close;
+ rec->func_stats = &stats;
+ rec->func_lookup = &lookup;
+
+ return init(rec, opts, nopts);
+}
--
Eamon Walsh <ewalsh@tycho.nsa.gov>
National Security Agency
--
This message was distributed to subscribers of the selinux mailing list.
If you no longer wish to subscribe, send mail to majordomo@tycho.nsa.gov with
the words "unsubscribe selinux" without quotes as the message.
^ permalink raw reply [flat|nested] 9+ messages in thread
* [PATCH 5/7] libselinux: labeling support (try 4)
2007-06-15 23:29 [PATCH 1/7] libselinux: labeling support (try 4) Eamon Walsh
` (2 preceding siblings ...)
2007-06-15 23:39 ` [PATCH 4/7] " Eamon Walsh
@ 2007-06-15 23:40 ` Eamon Walsh
2007-06-15 23:43 ` [PATCH 6/7] " Eamon Walsh
2007-06-15 23:46 ` [PATCH 7/7] " Eamon Walsh
5 siblings, 0 replies; 9+ messages in thread
From: Eamon Walsh @ 2007-06-15 23:40 UTC (permalink / raw)
To: SE Linux; +Cc: Stephen Smalley, Karl MacMillan
This patch includes the x contexts backend code.
Signed-off-by: Eamon Walsh <ewalsh@tycho.nsa.gov>
---
label_x.c | 238 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 238 insertions(+)
Index: libselinux/src/label_x.c
===================================================================
--- libselinux/src/label_x.c (revision 0)
+++ libselinux/src/label_x.c (revision 0)
@@ -0,0 +1,238 @@
+/*
+ * Media contexts backend for X contexts
+ *
+ * Author : Eamon Walsh <ewalsh@tycho.nsa.gov>
+ */
+
+#include <sys/stat.h>
+#include <string.h>
+#include <stdio.h>
+#include <stdio_ext.h>
+#include <ctype.h>
+#include <errno.h>
+#include <limits.h>
+#include "callbacks.h"
+#include "label_internal.h"
+
+/*
+ * Internals
+ */
+
+/* A context specification. */
+typedef struct spec {
+ struct selabel_lookup_rec lr; /* holds contexts for lookup result */
+ char *key; /* key string */
+ int type; /* type of record (prop, ext, client) */
+ int matches; /* number of matches made during operation */
+} spec_t;
+
+struct saved_data {
+ unsigned int nspec;
+ spec_t *spec_arr;
+};
+
+static int process_line(const char *path, char *line_buf, int pass,
+ unsigned lineno, struct selabel_handle *rec)
+{
+ struct saved_data *data = (struct saved_data *)rec->data;
+ int items;
+ char *buf_p;
+ char *type, *key, *context;
+
+ buf_p = line_buf;
+ while (isspace(*buf_p))
+ buf_p++;
+ /* Skip comment lines and empty lines. */
+ if (*buf_p == '#' || *buf_p == 0)
+ return 0;
+ items = sscanf(line_buf, "%as %as %as ", &type, &key, &context);
+ if (items < 3) {
+ selinux_log(SELINUX_WARNING,
+ "%s: line %d is missing fields, skipping\n", path,
+ lineno);
+ if (items > 0)
+ free(type);
+ if (items > 1)
+ free(key);
+ return 0;
+ }
+
+ if (pass == 1) {
+ /* Convert the type string to a mode format */
+ if (!strcmp(type, "property"))
+ data->spec_arr[data->nspec].type = SELABEL_X_PROP;
+ else if (!strcmp(type, "extension"))
+ data->spec_arr[data->nspec].type = SELABEL_X_EXT;
+ else if (!strcmp(type, "client"))
+ data->spec_arr[data->nspec].type = SELABEL_X_CLIENT;
+ else {
+ selinux_log(SELINUX_WARNING,
+ "%s: line %d has invalid file type %s\n",
+ path, lineno, type);
+ return 0;
+ }
+ data->spec_arr[data->nspec].key = key;
+ data->spec_arr[data->nspec].lr.ctx_raw = context;
+ free(type);
+ }
+
+ data->nspec++;
+ if (pass == 0) {
+ free(type);
+ free(key);
+ free(context);
+ }
+ return 0;
+}
+
+static int init(struct selabel_handle *rec, struct selabel_opt *opts,
+ size_t n)
+{
+ FILE *fp;
+ struct saved_data *data = (struct saved_data *)rec->data;
+ const char *path = NULL;
+ char *line_buf = NULL;
+ size_t line_len = 0;
+ int status = -1;
+ unsigned int lineno, pass, maxnspec;
+ struct stat sb;
+
+ /* Process arguments */
+ while (n--)
+ switch(opts[n].type) {
+ case SELABEL_OPT_PATH:
+ path = opts[n].value;
+ break;
+ }
+
+ /* Open the specification file. */
+ if (!path)
+ path = "/etc/selinux/refpolicy/contexts/x_contexts";
+ if ((fp = fopen(path, "r")) == NULL)
+ return -1;
+ __fsetlocking(fp, FSETLOCKING_BYCALLER);
+
+ if (fstat(fileno(fp), &sb) < 0)
+ return -1;
+ if (!S_ISREG(sb.st_mode)) {
+ errno = EINVAL;
+ return -1;
+ }
+
+ /*
+ * Perform two passes over the specification file.
+ * The first pass counts the number of specifications and
+ * performs simple validation of the input. At the end
+ * of the first pass, the spec array is allocated.
+ * The second pass performs detailed validation of the input
+ * and fills in the spec array.
+ */
+ maxnspec = UINT_MAX / sizeof(spec_t);
+ for (pass = 0; pass < 2; pass++) {
+ lineno = 0;
+ data->nspec = 0;
+ while (getline(&line_buf, &line_len, fp) > 0 &&
+ data->nspec < maxnspec) {
+ if (process_line(path, line_buf, pass, ++lineno, rec))
+ goto finish;
+ }
+ lineno = 0;
+
+ if (pass == 0) {
+ if (data->nspec == 0) {
+ status = 0;
+ goto finish;
+ }
+ data->spec_arr = malloc(sizeof(spec_t)*data->nspec);
+ if (data->spec_arr == NULL)
+ goto finish;
+ memset(data->spec_arr, 0, sizeof(spec_t)*data->nspec);
+ maxnspec = data->nspec;
+ rewind(fp);
+ }
+ }
+ free(line_buf);
+
+ status = 0;
+finish:
+ fclose(fp);
+ return status;
+}
+
+/*
+ * Backend interface routines
+ */
+static void close(struct selabel_handle *rec)
+{
+ struct saved_data *data = (struct saved_data *)rec->data;
+ struct spec *spec, *spec_arr = data->spec_arr;
+ unsigned int i;
+
+ for (i = 0; i < data->nspec; i++) {
+ spec = &spec_arr[i];
+ free(spec->key);
+ free(spec->lr.ctx_raw);
+ free(spec->lr.ctx_trans);
+ }
+
+ if (spec_arr)
+ free(spec_arr);
+
+ memset(data, 0, sizeof(*data));
+}
+
+static struct selabel_lookup_rec *lookup(struct selabel_handle *rec,
+ const char *key, int type)
+{
+ struct saved_data *data = (struct saved_data *)rec->data;
+ spec_t *spec_arr = data->spec_arr;
+ unsigned int i;
+
+ for (i = 0; i < data->nspec; i++) {
+ if (spec_arr[i].type != type)
+ continue;
+ if (!strncmp(spec_arr[i].key, key, strlen(key) + 1))
+ break;
+ if (!strncmp(spec_arr[i].key, "*", 2))
+ break;
+ }
+
+ if (i >= data->nspec) {
+ /* No matching specification. */
+ errno = ENOENT;
+ return NULL;
+ }
+
+ spec_arr[i].matches++;
+ return &spec_arr[i].lr;
+}
+
+static void stats(struct selabel_handle *rec)
+{
+ struct saved_data *data = (struct saved_data *)rec->data;
+ unsigned int i, total = 0;
+
+ for (i = 0; i < data->nspec; i++)
+ total += data->spec_arr[i].matches;
+
+ selinux_log(SELINUX_INFO, "%u entries, %u matches made\n",
+ data->nspec, total);
+}
+
+int selabel_x_init(struct selabel_handle *rec, struct selabel_opt *opts,
+ size_t nopts)
+{
+ struct saved_data *data;
+
+ data = (struct saved_data *)malloc(sizeof(*data));
+ if (!data)
+ return -1;
+ memset(data, 0, sizeof(*data));
+
+ rec->data = data;
+ rec->func_close = &close;
+ rec->func_lookup = &lookup;
+ rec->func_stats = &stats;
+
+ return init(rec, opts, nopts);
+}
--
Eamon Walsh <ewalsh@tycho.nsa.gov>
National Security Agency
--
This message was distributed to subscribers of the selinux mailing list.
If you no longer wish to subscribe, send mail to majordomo@tycho.nsa.gov with
the words "unsubscribe selinux" without quotes as the message.
^ permalink raw reply [flat|nested] 9+ messages in thread
* [PATCH 6/7] libselinux: labeling support (try 4)
2007-06-15 23:29 [PATCH 1/7] libselinux: labeling support (try 4) Eamon Walsh
` (3 preceding siblings ...)
2007-06-15 23:40 ` [PATCH 5/7] " Eamon Walsh
@ 2007-06-15 23:43 ` Eamon Walsh
2007-06-20 14:43 ` Stephen Smalley
2007-06-15 23:46 ` [PATCH 7/7] " Eamon Walsh
5 siblings, 1 reply; 9+ messages in thread
From: Eamon Walsh @ 2007-06-15 23:43 UTC (permalink / raw)
To: SE Linux; +Cc: Stephen Smalley, Karl MacMillan
This patch rebases the matchpathcon code to use the new interface.
Signed-off-by: Eamon Walsh <ewalsh@tycho.nsa.gov>
---
matchpathcon.c | 803 +++++++--------------------------------------------------
1 file changed, 112 insertions(+), 691 deletions(-)
Index: libselinux/src/matchpathcon.c
===================================================================
--- libselinux/src/matchpathcon.c (revision 2474)
+++ libselinux/src/matchpathcon.c (working copy)
@@ -1,19 +1,54 @@
-#include <unistd.h>
-#include <fcntl.h>
#include <sys/stat.h>
#include <string.h>
-#include "selinux_internal.h"
-#include <stdio.h>
-#include <stdio_ext.h>
-#include <stdlib.h>
-#include <ctype.h>
#include <errno.h>
-#include <limits.h>
-#include <regex.h>
-#include <stdarg.h>
-#include "policy.h"
-#include "context_internal.h"
+#include <stdio.h>
+#include "selinux_internal.h"
+#include "label_internal.h"
+#include "callbacks.h"
+static __thread struct selabel_handle *hnd;
+
+/*
+ * An array for mapping integers to contexts
+ */
+static __thread char **con_array;
+static __thread int con_array_size;
+static __thread int con_array_used;
+
+static int add_array_elt(char *con)
+{
+ if (con_array_size) {
+ while (con_array_used >= con_array_size) {
+ con_array_size *= 2;
+ con_array = (char **)realloc(con_array, sizeof(char*) *
+ con_array_size);
+ if (!con_array) {
+ con_array_size = con_array_used = 0;
+ return -1;
+ }
+ }
+ } else {
+ con_array_size = 1000;
+ con_array = (char **)malloc(sizeof(char*) * con_array_size);
+ if (!con_array) {
+ con_array_size = con_array_used = 0;
+ return -1;
+ }
+ }
+
+ con_array[con_array_used] = strdup(con);
+ if (!con_array[con_array_used])
+ return -1;
+ return con_array_used++;
+}
+
+static void free_array_elts(void)
+{
+ con_array_size = con_array_used = 0;
+ free(con_array);
+ con_array = NULL;
+}
+
static void
#ifdef __GNUC__
__attribute__ ((format(printf, 1, 2)))
@@ -26,11 +61,11 @@
va_end(ap);
}
-static void
+void
#ifdef __GNUC__
__attribute__ ((format(printf, 1, 2)))
#endif
- (*myprintf) (const char *fmt,...) = &default_printf;
+ (*myprintf) (const char *fmt,...);
void set_matchpathcon_printf(void (*f) (const char *fmt, ...))
{
@@ -66,7 +101,7 @@
}
static int (*mycanoncon) (const char *p, unsigned l, char **c) =
- &default_canoncon;
+ NULL;
void set_matchpathcon_canoncon(int (*f) (const char *p, unsigned l, char **c))
{
@@ -76,137 +111,23 @@
mycanoncon = &default_canoncon;
}
-static __thread unsigned int myflags;
+static __thread struct selabel_opt options[SELABEL_NOPT];
+static __thread int notrans;
void set_matchpathcon_flags(unsigned int flags)
{
- myflags = flags;
-}
-
-/*
- * A file security context specification.
- */
-typedef struct spec {
- char *regex_str; /* regular expession string for diagnostic messages */
- char *type_str; /* type string for diagnostic messages */
- char *context; /* context string */
- int context_valid; /* context string has been validated/canonicalized */
- int translated; /* context string has been translated */
- regex_t regex; /* compiled regular expression */
- mode_t mode; /* mode format value */
- int matches; /* number of matching pathnames */
- int hasMetaChars; /* indicates whether the RE has
- any meta characters.
- 0 = no meta chars
- 1 = has one or more meta chars */
- int stem_id; /* indicates which of the stem-compression
- * items it matches */
-} spec_t;
-
-typedef struct stem {
- char *buf;
- int len;
-} stem_t;
-
-static stem_t *stem_arr = NULL;
-static int num_stems = 0;
-static int alloc_stems = 0;
-
-static const char *const regex_chars = ".^$?*+|[({";
-
-/* Return the length of the text that can be considered the stem, returns 0
- * if there is no identifiable stem */
-static int get_stem_from_spec(const char *const buf)
-{
- const char *tmp = strchr(buf + 1, '/');
- const char *ind;
-
- if (!tmp)
- return 0;
-
- for (ind = buf; ind < tmp; ind++) {
- if (strchr(regex_chars, (int)*ind))
- return 0;
- }
- return tmp - buf;
-}
-
-/* return the length of the text that is the stem of a file name */
-static int get_stem_from_file_name(const char *const buf)
-{
- const char *tmp = strchr(buf + 1, '/');
-
- if (!tmp)
- return 0;
- return tmp - buf;
-}
-
-/* find the stem of a file spec, returns the index into stem_arr for a new
- * or existing stem, (or -1 if there is no possible stem - IE for a file in
- * the root directory or a regex that is too complex for us). Makes buf
- * point to the text AFTER the stem. */
-static int find_stem_from_spec(const char **buf)
-{
int i;
- int stem_len = get_stem_from_spec(*buf);
-
- if (!stem_len)
- return -1;
- for (i = 0; i < num_stems; i++) {
- if (stem_len == stem_arr[i].len
- && !strncmp(*buf, stem_arr[i].buf, stem_len)) {
- *buf += stem_len;
- return i;
- }
- }
- if (num_stems == alloc_stems) {
- stem_t *tmp_arr;
- alloc_stems = alloc_stems * 2 + 16;
- tmp_arr = realloc(stem_arr, sizeof(stem_t) * alloc_stems);
- if (!tmp_arr)
- return -1;
- stem_arr = tmp_arr;
- }
- stem_arr[num_stems].len = stem_len;
- stem_arr[num_stems].buf = malloc(stem_len + 1);
- if (!stem_arr[num_stems].buf)
- return -1;
- memcpy(stem_arr[num_stems].buf, *buf, stem_len);
- stem_arr[num_stems].buf[stem_len] = '\0';
- num_stems++;
- *buf += stem_len;
- return num_stems - 1;
+ memset(options, 0, sizeof(options));
+ i = SELABEL_OPT_BASEONLY;
+ options[i].type = i;
+ options[i].value = (char *)(flags & MATCHPATHCON_BASEONLY);
+ i = SELABEL_OPT_VALIDATE;
+ options[i].type = i;
+ options[i].value = (char *)(flags & MATCHPATHCON_VALIDATE);
+ notrans = flags & MATCHPATHCON_NOTRANS;
}
-/* find the stem of a file name, returns the index into stem_arr (or -1 if
- * there is no match - IE for a file in the root directory or a regex that is
- * too complex for us). Makes buf point to the text AFTER the stem. */
-static int find_stem_from_file(const char **buf)
-{
- int i;
- int stem_len = get_stem_from_file_name(*buf);
-
- if (!stem_len)
- return -1;
- for (i = 0; i < num_stems; i++) {
- if (stem_len == stem_arr[i].len
- && !strncmp(*buf, stem_arr[i].buf, stem_len)) {
- *buf += stem_len;
- return i;
- }
- }
- return -1;
-}
-
/*
- * The array of specifications, initially in the
- * same order as in the specification file.
- * Sorting occurs based on hasMetaChars
- */
-static spec_t *spec_arr;
-static unsigned int nspec;
-
-/*
* An association between an inode and a
* specification.
*/
@@ -238,7 +159,7 @@
int matchpathcon_filespec_add(ino_t ino, int specind, const char *file)
{
file_spec_t *prevfl, *fl;
- int h, no_conflict, ret;
+ int h, ret;
struct stat sb;
if (!fl_head) {
@@ -264,21 +185,14 @@
}
- no_conflict =
- (strcmp
- (spec_arr[fl->specind].context,
- spec_arr[specind].context) == 0);
- if (no_conflict)
+ if (!strcmp(con_array[fl->specind],
+ con_array[specind]))
return fl->specind;
myprintf
("%s: conflicting specifications for %s and %s, using %s.\n",
__FUNCTION__, file, fl->file,
- ((specind >
- fl->specind) ? spec_arr[specind].
- context : spec_arr[fl->specind].context));
- fl->specind =
- (specind > fl->specind) ? specind : fl->specind;
+ con_array[fl->specind]);
free(fl->file);
fl->file = malloc(strlen(file) + 1);
if (!fl->file)
@@ -350,6 +264,8 @@
file_spec_t *fl, *tmp;
int h;
+ free_array_elts();
+
if (!fl_head)
return;
@@ -367,393 +283,20 @@
fl_head = NULL;
}
-/*
- * Warn about duplicate specifications.
- */
-static void nodups_specs(const char *path)
+int matchpathcon_init_prefix(const char *path, const char *subset)
{
- unsigned int ii, jj;
- struct spec *curr_spec;
+ if (!mycanoncon)
+ mycanoncon = default_canoncon;
- for (ii = 0; ii < nspec; ii++) {
- curr_spec = &spec_arr[ii];
- for (jj = ii + 1; jj < nspec; jj++) {
- if ((!strcmp
- (spec_arr[jj].regex_str, curr_spec->regex_str))
- && (!spec_arr[jj].mode || !curr_spec->mode
- || spec_arr[jj].mode == curr_spec->mode)) {
- if (strcmp
- (spec_arr[jj].context,
- curr_spec->context)) {
- myprintf
- ("%s: Multiple different specifications for %s (%s and %s).\n",
- path, curr_spec->regex_str,
- spec_arr[jj].context,
- curr_spec->context);
- } else {
- myprintf
- ("%s: Multiple same specifications for %s.\n",
- path, curr_spec->regex_str);
- }
- }
- }
- }
-}
+ options[SELABEL_OPT_SUBSET].type = SELABEL_OPT_SUBSET;
+ options[SELABEL_OPT_SUBSET].value = subset;
+ options[SELABEL_OPT_PATH].type = SELABEL_OPT_PATH;
+ options[SELABEL_OPT_PATH].value = path;
-/* Determine if the regular expression specification has any meta characters. */
-static void spec_hasMetaChars(struct spec *spec)
-{
- char *c;
- int len;
- char *end;
-
- c = spec->regex_str;
- len = strlen(spec->regex_str);
- end = c + len;
-
- spec->hasMetaChars = 0;
-
- /* Look at each character in the RE specification string for a
- * meta character. Return when any meta character reached. */
- while (c != end) {
- switch (*c) {
- case '.':
- case '^':
- case '$':
- case '?':
- case '*':
- case '+':
- case '|':
- case '[':
- case '(':
- case '{':
- spec->hasMetaChars = 1;
- return;
- case '\\': /* skip the next character */
- c++;
- break;
- default:
- break;
-
- }
- c++;
- }
- return;
+ hnd = selabel_open(SELABEL_CTX_FILE, options, SELABEL_NOPT);
+ return hnd ? 0 : -1;
}
-static int process_line(const char *path, const char *prefix, char *line_buf,
- int pass, unsigned lineno)
-{
- int items, len, regerr, ret;
- char *buf_p, *ptr;
- char *regex=NULL, *type=NULL, *context=NULL;
- const char *reg_buf;
- char *anchored_regex = NULL;
- ret = 0;
- len = strlen(line_buf);
- if (line_buf[len - 1] == '\n')
- line_buf[len - 1] = 0;
- buf_p = line_buf;
- while (isspace(*buf_p))
- buf_p++;
- /* Skip comment lines and empty lines. */
- if (*buf_p == '#' || *buf_p == 0)
- return 0;
-
- items = 0;
- regex = strtok_r(buf_p, " \t", &ptr);
- if (regex)
- items += 1;
- type = strtok_r(NULL, " \t", &ptr);
- if (type)
- items += 1;
- context = strtok_r(NULL, " \t", &ptr);
- if (context)
- items += 1;
-
- if (items < 2) {
- myprintf("%s: line %d is missing fields, skipping\n", path,
- lineno);
- return 0;
- } else if (items == 2) {
- /* The type field is optional. */
- context = type;
- type = NULL;
- }
-
- regex = strdup(regex);
- if (!regex) {
- return -1;
- }
- if (type) {
- type = strdup(type);
- if (!type) {
- free(regex);
- return -1;
- }
- }
- context = strdup(context);
- if (!context) {
- ret = -1;
- goto finish;
- }
-
- reg_buf = regex;
- len = get_stem_from_spec(reg_buf);
- if (len && prefix && strncmp(prefix, regex, len)) {
- /* Stem of regex does not match requested prefix, discard. */
- goto finish;
- }
-
- if (pass == 1) {
- /* On the second pass, compile and store the specification in spec. */
- char *cp;
- spec_arr[nspec].stem_id = find_stem_from_spec(®_buf);
- spec_arr[nspec].regex_str = regex;
-
- /* Anchor the regular expression. */
- len = strlen(reg_buf);
- cp = anchored_regex = malloc(len + 3);
- if (!anchored_regex) {
- ret = -1;
- goto finish;
- }
- /* Create ^...$ regexp. */
- *cp++ = '^';
- cp = mempcpy(cp, reg_buf, len);
- *cp++ = '$';
- *cp = '\0';
-
- /* Compile the regular expression. */
- regerr =
- regcomp(&spec_arr[nspec].regex,
- anchored_regex, REG_EXTENDED | REG_NOSUB);
- if (regerr != 0) {
- size_t errsz = 0;
- char *errbuf = NULL;
- errsz = regerror(regerr, &spec_arr[nspec].regex,
- errbuf, errsz);
- if (errsz)
- errbuf = malloc(errsz);
- if (errbuf)
- (void)regerror(regerr,
- &spec_arr[nspec].regex,
- errbuf, errsz);
- myprintf("%s: line %d has invalid regex %s: %s\n",
- path, lineno, anchored_regex,
- (errbuf ? errbuf : "out of memory"));
- free(anchored_regex);
- anchored_regex = NULL;
- free(errbuf);
- goto finish;
- }
- free(anchored_regex);
- anchored_regex = NULL;
-
- /* Convert the type string to a mode format */
- spec_arr[nspec].type_str = type;
- spec_arr[nspec].mode = 0;
- if (!type)
- goto skip_type;
- len = strlen(type);
- if (type[0] != '-' || len != 2) {
- myprintf("%s: line %d has invalid file type %s\n",
- path, lineno, type);
- goto finish;
- }
- switch (type[1]) {
- case 'b':
- spec_arr[nspec].mode = S_IFBLK;
- break;
- case 'c':
- spec_arr[nspec].mode = S_IFCHR;
- break;
- case 'd':
- spec_arr[nspec].mode = S_IFDIR;
- break;
- case 'p':
- spec_arr[nspec].mode = S_IFIFO;
- break;
- case 'l':
- spec_arr[nspec].mode = S_IFLNK;
- break;
- case 's':
- spec_arr[nspec].mode = S_IFSOCK;
- break;
- case '-':
- spec_arr[nspec].mode = S_IFREG;
- break;
- default:
- myprintf("%s: line %d has invalid file type %s\n",
- path, lineno, type);
- goto finish;
- }
-
- skip_type:
- if (strcmp(context, "<<none>>")) {
- if (myflags & MATCHPATHCON_VALIDATE) {
- if (myinvalidcon) {
- /* Old-style validation of context. */
- if (myinvalidcon(path, lineno, context))
- goto finish;
- } else {
- /* New canonicalization of context. */
- if (mycanoncon(path, lineno, &context))
- goto finish;
- }
- spec_arr[nspec].context_valid = 1;
- }
- }
-
- spec_arr[nspec].context = context;
-
- /* Determine if specification has
- * any meta characters in the RE */
- spec_hasMetaChars(&spec_arr[nspec]);
-
- /* Prevent stored strings from being freed. */
- regex = NULL;
- type = NULL;
- context = NULL;
- }
-
- nspec++;
-finish:
- free(regex);
- free(type);
- free(context);
- return ret;
-}
-
-int matchpathcon_init_prefix(const char *path, const char *prefix)
-{
- FILE *fp;
- FILE *localfp = NULL;
- FILE *homedirfp = NULL;
- char local_path[PATH_MAX + 1];
- char homedir_path[PATH_MAX + 1];
- char *line_buf = NULL;
- size_t line_len = 0;
- unsigned int lineno, pass, i, j, maxnspec;
- spec_t *spec_copy = NULL;
- int status = -1;
- struct stat sb;
-
- /* Open the specification file. */
- if (!path)
- path = selinux_file_context_path();
- if ((fp = fopen(path, "r")) == NULL)
- return -1;
- __fsetlocking(fp, FSETLOCKING_BYCALLER);
-
- if (fstat(fileno(fp), &sb) < 0)
- return -1;
- if (!S_ISREG(sb.st_mode)) {
- errno = EINVAL;
- return -1;
- }
-
- if ((myflags & MATCHPATHCON_BASEONLY) == 0) {
- snprintf(homedir_path, sizeof(homedir_path), "%s.homedirs",
- path);
- homedirfp = fopen(homedir_path, "r");
- if (homedirfp != NULL)
- __fsetlocking(homedirfp, FSETLOCKING_BYCALLER);
-
- snprintf(local_path, sizeof(local_path), "%s.local", path);
- localfp = fopen(local_path, "r");
- if (localfp != NULL)
- __fsetlocking(localfp, FSETLOCKING_BYCALLER);
- }
-
- /*
- * Perform two passes over the specification file.
- * The first pass counts the number of specifications and
- * performs simple validation of the input. At the end
- * of the first pass, the spec array is allocated.
- * The second pass performs detailed validation of the input
- * and fills in the spec array.
- */
- maxnspec = UINT_MAX / sizeof(spec_t);
- for (pass = 0; pass < 2; pass++) {
- lineno = 0;
- nspec = 0;
- while (getline(&line_buf, &line_len, fp) > 0
- && nspec < maxnspec) {
- if (process_line(path, prefix, line_buf, pass, ++lineno)
- != 0)
- goto finish;
- }
- lineno = 0;
- if (homedirfp)
- while (getline(&line_buf, &line_len, homedirfp) > 0
- && nspec < maxnspec) {
- if (process_line
- (homedir_path, prefix, line_buf, pass,
- ++lineno) != 0)
- goto finish;
- }
-
- lineno = 0;
- if (localfp)
- while (getline(&line_buf, &line_len, localfp) > 0
- && nspec < maxnspec) {
- if (process_line
- (local_path, prefix, line_buf, pass,
- ++lineno) != 0)
- goto finish;
- }
-
- if (pass == 0) {
- if (nspec == 0) {
- status = 0;
- goto finish;
- }
- if ((spec_arr = malloc(sizeof(spec_t) * nspec)) == NULL)
- goto finish;
- memset(spec_arr, '\0', sizeof(spec_t) * nspec);
- maxnspec = nspec;
- rewind(fp);
- if (homedirfp)
- rewind(homedirfp);
- if (localfp)
- rewind(localfp);
- }
- }
- free(line_buf);
- line_buf = NULL;
-
- /* Move exact pathname specifications to the end. */
- spec_copy = malloc(sizeof(spec_t) * nspec);
- if (!spec_copy)
- goto finish;
- j = 0;
- for (i = 0; i < nspec; i++) {
- if (spec_arr[i].hasMetaChars)
- memcpy(&spec_copy[j++], &spec_arr[i], sizeof(spec_t));
- }
- for (i = 0; i < nspec; i++) {
- if (!spec_arr[i].hasMetaChars)
- memcpy(&spec_copy[j++], &spec_arr[i], sizeof(spec_t));
- }
- free(spec_arr);
- spec_arr = spec_copy;
-
- nodups_specs(path);
-
- status = 0;
- finish:
- fclose(fp);
- free(line_buf);
- if (spec_arr != spec_copy)
- free(spec_arr);
- if (homedirfp)
- fclose(homedirfp);
- if (localfp)
- fclose(localfp);
- return status;
-}
-
hidden_def(matchpathcon_init_prefix)
int matchpathcon_init(const char *path)
@@ -763,172 +306,33 @@
void matchpathcon_fini(void)
{
- struct spec *spec;
- struct stem *stem;
- unsigned int i;
-
- for (i = 0; i < nspec; i++) {
- spec = &spec_arr[i];
- free(spec->regex_str);
- free(spec->type_str);
- free(spec->context);
- regfree(&spec->regex);
- }
- free(spec_arr);
- spec_arr = NULL;
- nspec = 0;
-
- for (i = 0; i < (unsigned int)num_stems; i++) {
- stem = &stem_arr[i];
- free(stem->buf);
- }
- free(stem_arr);
- stem_arr = NULL;
- num_stems = 0;
- alloc_stems = 0;
+ selabel_close(hnd);
+ hnd = NULL;
}
-static int matchpathcon_common(const char *name, mode_t mode)
-{
- int i, ret, file_stem;
- const char *buf = name;
-
- if (!nspec) {
- ret = matchpathcon_init_prefix(NULL, NULL);
- if (ret < 0)
- return ret;
- if (!nspec) {
- errno = ENOENT;
- return -1;
- }
- }
-
- file_stem = find_stem_from_file(&buf);
-
- mode &= S_IFMT;
-
- /*
- * Check for matching specifications in reverse order, so that
- * the last matching specification is used.
- */
- for (i = nspec - 1; i >= 0; i--) {
- /* if the spec in question matches no stem or has the same
- * stem as the file AND if the spec in question has no mode
- * specified or if the mode matches the file mode then we do
- * a regex check */
- if ((spec_arr[i].stem_id == -1
- || spec_arr[i].stem_id == file_stem)
- && (!mode || !spec_arr[i].mode
- || ((mode & S_IFMT) == spec_arr[i].mode))) {
- if (spec_arr[i].stem_id == -1)
- ret =
- regexec(&spec_arr[i].regex, name, 0, NULL,
- 0);
- else
- ret =
- regexec(&spec_arr[i].regex, buf, 0, NULL,
- 0);
- if (ret == 0)
- break;
-
- if (ret == REG_NOMATCH)
- continue;
- /* else it's an error */
- return -1;
- }
- }
-
- if (i < 0) {
- /* No matching specification. */
- errno = ENOENT;
- return -1;
- }
-
- spec_arr[i].matches++;
-
- return i;
-
-}
-
int matchpathcon(const char *name, mode_t mode, security_context_t * con)
{
- int i = matchpathcon_common(name, mode);
+ if (!mycanoncon)
+ mycanoncon = default_canoncon;
- if (i < 0)
- return -1;
-
- if (strcmp(spec_arr[i].context, "<<none>>") == 0) {
- errno = ENOENT;
- return -1;
- }
-
- if (!spec_arr[i].context_valid) {
- if (myinvalidcon) {
- /* Old-style validation of context. */
- if (myinvalidcon
- ("file_contexts", 0, spec_arr[i].context))
- goto bad;
- } else {
- /* New canonicalization of context. */
- if (mycanoncon
- ("file_contexts", 0, &spec_arr[i].context))
- goto bad;
- }
- spec_arr[i].context_valid = 1;
- }
-
- if (!spec_arr[i].translated && !(myflags & MATCHPATHCON_NOTRANS)) {
- char *tmpcon = NULL;
- if (selinux_raw_to_trans_context(spec_arr[i].context, &tmpcon))
- return -1;
- free(spec_arr[i].context);
- spec_arr[i].context = tmpcon;
- spec_arr[i].translated = 1;
- }
-
- *con = strdup(spec_arr[i].context);
- if (!(*con))
- return -1;
-
- return 0;
-
- bad:
- errno = EINVAL;
- return -1;
+ return notrans ?
+ selabel_lookup_raw(hnd, con, name, mode) :
+ selabel_lookup(hnd, con, name, mode);
}
int matchpathcon_index(const char *name, mode_t mode, security_context_t * con)
{
- int i = matchpathcon_common(name, mode);
+ int i = matchpathcon(name, mode, con);
if (i < 0)
return -1;
- *con = strdup(spec_arr[i].context);
- if (!(*con))
- return -1;
-
- return i;
+ return add_array_elt(*con);
}
-void matchpathcon_checkmatches(char *str)
+void matchpathcon_checkmatches(char *str __attribute__((unused)))
{
- unsigned int i;
- for (i = 0; i < nspec; i++) {
- if (spec_arr[i].matches == 0) {
- if (spec_arr[i].type_str) {
- myprintf
- ("%s: Warning! No matches for (%s, %s, %s)\n",
- str, spec_arr[i].regex_str,
- spec_arr[i].type_str, spec_arr[i].context);
- } else {
- myprintf
- ("%s: Warning! No matches for (%s, %s)\n",
- str, spec_arr[i].regex_str,
- spec_arr[i].context);
- }
- }
- }
+ selabel_stats(hnd);
}
/* Compare two contexts to see if their differences are "significant",
@@ -958,7 +362,6 @@
{
security_context_t con = NULL;
security_context_t fcontext = NULL;
- unsigned int localflags = myflags;
int rc = 0;
rc = lgetfilecon_raw(path, &con);
@@ -969,15 +372,14 @@
return 0;
}
- set_matchpathcon_flags(myflags | MATCHPATHCON_NOTRANS);
- if (matchpathcon(path, mode, &fcontext) != 0) {
+ if (selabel_lookup_raw(hnd, &fcontext, path, mode) != 0) {
if (errno != ENOENT)
rc = 1;
else
rc = 0;
} else
rc = (selinux_file_context_cmp(fcontext, con) == 0);
- set_matchpathcon_flags(localflags);
+
freecon(con);
freecon(fcontext);
return rc;
@@ -988,21 +390,40 @@
struct stat st;
int rc = -1;
security_context_t scontext = NULL;
- unsigned int localflags = myflags;
if (lstat(path, &st) != 0)
return rc;
- set_matchpathcon_flags(myflags | MATCHPATHCON_NOTRANS);
-
/* If there's an error determining the context, or it has none,
return to allow default context */
- if (matchpathcon(path, st.st_mode, &scontext)) {
+ if (selabel_lookup_raw(hnd, &scontext, path, st.st_mode)) {
if (errno == ENOENT)
rc = 0;
} else {
rc = lsetfilecon_raw(path, scontext);
freecon(scontext);
}
- set_matchpathcon_flags(localflags);
return rc;
}
+
+int compat_validate(struct selabel_handle *rec,
+ struct selabel_lookup_rec *contexts,
+ const char *path, unsigned lineno)
+{
+ int rc;
+ char **ctx = &contexts->ctx_raw;
+
+ if (myinvalidcon)
+ rc = myinvalidcon(path, lineno, *ctx);
+ else if (mycanoncon)
+ rc = mycanoncon(path, lineno, ctx);
+ else {
+ rc = selabel_validate(rec, contexts);
+ if (rc < 0) {
+ COMPAT_LOG(SELINUX_WARNING,
+ "%s: line %d has invalid context %s\n",
+ path, lineno, *ctx);
+ }
+ }
+
+ return rc ? -1 : 0;
+}
--
Eamon Walsh <ewalsh@tycho.nsa.gov>
National Security Agency
--
This message was distributed to subscribers of the selinux mailing list.
If you no longer wish to subscribe, send mail to majordomo@tycho.nsa.gov with
the words "unsubscribe selinux" without quotes as the message.
^ permalink raw reply [flat|nested] 9+ messages in thread
* [PATCH 7/7] libselinux: labeling support (try 4)
2007-06-15 23:29 [PATCH 1/7] libselinux: labeling support (try 4) Eamon Walsh
` (4 preceding siblings ...)
2007-06-15 23:43 ` [PATCH 6/7] " Eamon Walsh
@ 2007-06-15 23:46 ` Eamon Walsh
5 siblings, 0 replies; 9+ messages in thread
From: Eamon Walsh @ 2007-06-15 23:46 UTC (permalink / raw)
To: SE Linux; +Cc: Stephen Smalley, Karl MacMillan
This patch changes setfiles to use the new interface.
Signed-off-by: Eamon Walsh <ewalsh@tycho.nsa.gov>
---
setfiles.c | 275 ++++++++++++++++++++++++++++++++++++++++++++++---------------
1 file changed, 210 insertions(+), 65 deletions(-)
Index: policycoreutils/setfiles/setfiles.c
===================================================================
--- policycoreutils/setfiles/setfiles.c (revision 2474)
+++ policycoreutils/setfiles/setfiles.c (working copy)
@@ -16,6 +16,7 @@
#include <limits.h>
#include <sepol/sepol.h>
#include <selinux/selinux.h>
+#include <selinux/label.h>
#include <syslog.h>
#include <libgen.h>
#ifdef USE_AUDIT
@@ -70,21 +71,165 @@
static int abort_on_error; /* Abort the file tree walk upon an error. */
static int add_assoc; /* Track inode associations for conflict detection. */
static int nftw_flags; /* Flags to nftw, e.g. follow links, follow mounts */
-static int matchpathcon_flags; /* Flags to matchpathcon */
+static int base_only; /* Don't use local file_contexts customizations */
+static int ctx_validate; /* Validate contexts */
+static const char *altpath; /* Alternate path to file_contexts */
-static void
-#ifdef __GNUC__
- __attribute__ ((format(printf, 1, 2)))
-#endif
- qprintf(const char *fmt, ...)
+/* Label interface handle */
+static struct selabel_handle *hnd;
+
+/*
+ * An association between an inode and a context.
+ */
+typedef struct file_spec {
+ ino_t ino; /* inode number */
+ char *con; /* matched context */
+ char *file; /* full pathname */
+ struct file_spec *next; /* next association in hash bucket chain */
+} file_spec_t;
+
+/*
+ * The hash table of associations, hashed by inode number.
+ * Chaining is used for collisions, with elements ordered
+ * by inode number in each bucket. Each hash bucket has a dummy
+ * header.
+ */
+#define HASH_BITS 16
+#define HASH_BUCKETS (1 << HASH_BITS)
+#define HASH_MASK (HASH_BUCKETS-1)
+static file_spec_t *fl_head;
+
+/*
+ * Try to add an association between an inode and a context.
+ * If there is a different context that matched the inode,
+ * then use the first context that matched.
+ */
+int filespec_add(ino_t ino, const security_context_t con, const char *file)
{
- va_list ap;
- va_start(ap, fmt);
- if (!quiet)
- vfprintf(stdout, fmt, ap);
- va_end(ap);
+ file_spec_t *prevfl, *fl;
+ int h, ret;
+ struct stat sb;
+
+ if (!fl_head) {
+ fl_head = malloc(sizeof(file_spec_t) * HASH_BUCKETS);
+ if (!fl_head)
+ goto oom;
+ memset(fl_head, 0, sizeof(file_spec_t) * HASH_BUCKETS);
+ }
+
+ h = (ino + (ino >> HASH_BITS)) & HASH_MASK;
+ for (prevfl = &fl_head[h], fl = fl_head[h].next; fl;
+ prevfl = fl, fl = fl->next) {
+ if (ino == fl->ino) {
+ ret = lstat(fl->file, &sb);
+ if (ret < 0 || sb.st_ino != ino) {
+ freecon(fl->con);
+ free(fl->file);
+ fl->file = strdup(file);
+ if (!fl->file)
+ goto oom;
+ fl->con = strdup(con);
+ if (!fl->con)
+ goto oom;
+ return 1;
+ }
+
+ if (strcmp(fl->con, con) == 0)
+ return 1;
+
+ fprintf(stderr,
+ "%s: conflicting specifications for %s and %s, using %s.\n",
+ __FUNCTION__, file, fl->file, fl->con);
+ free(fl->file);
+ fl->file = strdup(file);
+ if (!fl->file)
+ goto oom;
+ return 1;
+ }
+
+ if (ino > fl->ino)
+ break;
+ }
+
+ fl = malloc(sizeof(file_spec_t));
+ if (!fl)
+ goto oom;
+ fl->ino = ino;
+ fl->con = strdup(con);
+ if (!fl->con)
+ goto oom_freefl;
+ fl->file = strdup(file);
+ if (!fl->file)
+ goto oom_freefl;
+ fl->next = prevfl->next;
+ prevfl->next = fl;
+ return 0;
+ oom_freefl:
+ free(fl);
+ oom:
+ fprintf(stderr,
+ "%s: insufficient memory for file label entry for %s\n",
+ __FUNCTION__, file);
+ return -1;
}
+/*
+ * Evaluate the association hash table distribution.
+ */
+void filespec_eval(void)
+{
+ file_spec_t *fl;
+ int h, used, nel, len, longest;
+
+ if (!fl_head)
+ return;
+
+ used = 0;
+ longest = 0;
+ nel = 0;
+ for (h = 0; h < HASH_BUCKETS; h++) {
+ len = 0;
+ for (fl = fl_head[h].next; fl; fl = fl->next) {
+ len++;
+ }
+ if (len)
+ used++;
+ if (len > longest)
+ longest = len;
+ nel += len;
+ }
+
+ printf
+ ("%s: hash table stats: %d elements, %d/%d buckets used, longest chain length %d\n",
+ __FUNCTION__, nel, used, HASH_BUCKETS, longest);
+}
+
+/*
+ * Destroy the association hash table.
+ */
+void filespec_destroy(void)
+{
+ file_spec_t *fl, *tmp;
+ int h;
+
+ if (!fl_head)
+ return;
+
+ for (h = 0; h < HASH_BUCKETS; h++) {
+ fl = fl_head[h].next;
+ while (fl) {
+ tmp = fl;
+ fl = fl->next;
+ freecon(tmp->con);
+ free(tmp->file);
+ free(tmp);
+ }
+ fl_head[h].next = NULL;
+ }
+ free(fl_head);
+ fl_head = NULL;
+}
+
static int add_exclude(const char *directory)
{
struct stat sb;
@@ -230,9 +375,9 @@
if (rootpath != NULL && name[0] == '\0')
/* this is actually the root dir of the alt root */
- return matchpathcon_index("/", sb->st_mode, con);
+ return selabel_lookup_raw(hnd, con, "/", sb->st_mode);
else
- return matchpathcon_index(name, sb->st_mode, con);
+ return selabel_lookup_raw(hnd, con, name, sb->st_mode);
}
void usage(const char *const name)
@@ -282,7 +427,7 @@
{
char *my_file = strdupa(file);
struct stat my_sb;
- int i, j, ret;
+ int ret;
char *context, *newcon;
int user_only_changed = 0;
size_t len = strlen(my_file);
@@ -293,10 +438,9 @@
if (len > 1 && my_file[len - 1] == '/')
my_file[len - 1] = 0;
- i = match(my_file, &my_sb, &newcon);
- if (i < 0)
- /* No matching specification. */
- return 0;
+ if (match(my_file, &my_sb, &newcon) < 0)
+ /* Check for no matching specification. */
+ return (errno == ENOENT) ? 0 : -1;
if (progress) {
count++;
@@ -317,14 +461,13 @@
* then use the last matching specification.
*/
if (add_assoc) {
- j = matchpathcon_filespec_add(my_sb.st_ino, i, my_file);
- if (j < 0)
+ ret = filespec_add(my_sb.st_ino, newcon, my_file);
+ if (ret < 0)
goto err;
- if (j != i) {
+ if (ret > 0)
/* There was already an association and it took precedence. */
goto out;
- }
}
if (debug) {
@@ -460,33 +603,25 @@
rootpathlen = len;
}
-int canoncon(const char *path, unsigned lineno, char **contextp)
+int canoncon(char **contextp)
{
char *context = *contextp, *tmpcon;
- int valid = 1;
+ int rc = 0;
if (policyfile) {
- valid = (sepol_check_context(context) >= 0);
- } else if (security_canonicalize_context_raw(context, &tmpcon) < 0) {
- if (errno != ENOENT) {
- valid = 0;
- inc_err();
+ if (sepol_check_context(context) < 0) {
+ fprintf(stderr, "invalid context %s\n", context);
+ exit(1);
}
- } else {
+ } else if (security_canonicalize_context_raw(context, &tmpcon) == 0) {
free(context);
*contextp = tmpcon;
+ } else if (errno != ENOENT) {
+ rc = -1;
+ inc_err();
}
- if (!valid) {
- fprintf(stderr, "%s: line %u has invalid context %s\n",
- path, lineno, context);
-
- /* Exit immediately if we're in checking mode. */
- if (policyfile)
- exit(1);
- }
-
- return !valid;
+ return rc;
}
static int pre_stat(const char *file_unused __attribute__ ((unused)),
@@ -557,10 +692,9 @@
out:
if (add_assoc) {
- set_matchpathcon_printf(&qprintf);
- matchpathcon_filespec_eval();
- set_matchpathcon_printf(NULL);
- matchpathcon_filespec_destroy();
+ if (!quiet)
+ filespec_eval();
+ filespec_destroy();
}
return rc;
@@ -605,14 +739,20 @@
int main(int argc, char **argv)
{
struct stat sb;
- int opt, rc, i = 0;
+ int opt, i = 0;
char *input_filename = NULL;
int use_input_file = 0;
char *buf = NULL;
size_t buf_len;
char *base;
+ struct selabel_opt opts[] = {
+ { SELABEL_OPT_VALIDATE, NULL },
+ { SELABEL_OPT_BASEONLY, NULL },
+ { SELABEL_OPT_PATH, NULL }
+ };
memset(excludeArray, 0, sizeof(excludeArray));
+ altpath = NULL;
progname = strdup(argv[0]);
if (!progname) {
@@ -637,7 +777,7 @@
abort_on_error = 1;
add_assoc = 1;
nftw_flags = FTW_PHYS | FTW_MOUNT;
- matchpathcon_flags = MATCHPATHCON_VALIDATE | MATCHPATHCON_NOTRANS;
+ ctx_validate = 1;
} else {
/*
* restorecon:
@@ -648,15 +788,15 @@
* Follows mounts,
* Does lazy validation of contexts upon use.
*/
- if (strcmp(base, RESTORECON))
- qprintf("Executed with an unrecognized name (%s), defaulting to %s behavior.\n", base, RESTORECON);
+ if (strcmp(base, RESTORECON) && !quiet)
+ printf("Executed with an unrecognized name (%s), defaulting to %s behavior.\n", base, RESTORECON);
iamrestorecon = 1;
recurse = 0;
expand_realpath = 1;
abort_on_error = 0;
add_assoc = 0;
nftw_flags = FTW_PHYS;
- matchpathcon_flags = MATCHPATHCON_NOTRANS;
+ ctx_validate = 0;
/* restorecon only: silent exit if no SELinux.
Allows unconditional execution by scripts. */
@@ -664,8 +804,6 @@
exit(0);
}
- set_matchpathcon_flags(matchpathcon_flags);
-
/* Process any options. */
while ((opt = getopt(argc, argv, "c:de:f:ilnpqrsvo:FRW")) > 0) {
switch (opt) {
@@ -700,9 +838,8 @@
/* Only process the specified file_contexts file, not
any .homedirs or .local files, and do not perform
context translations. */
- set_matchpathcon_flags(MATCHPATHCON_BASEONLY |
- MATCHPATHCON_NOTRANS |
- MATCHPATHCON_VALIDATE);
+ base_only = 1;
+ ctx_validate = 1;
break;
}
@@ -812,7 +949,8 @@
/* Use our own invalid context checking function so that
we can support either checking against the active policy or
checking against a binary policy file. */
- set_matchpathcon_canoncon(&canoncon);
+ selinux_set_callback(SELINUX_CB_VALIDATE,
+ (union selinux_callback)&canoncon);
if (stat(argv[optind], &sb) < 0) {
perror(argv[optind]);
@@ -824,19 +962,24 @@
exit(1);
}
- /* Load the file contexts configuration and check it. */
- rc = matchpathcon_init(argv[optind]);
- if (rc < 0) {
- perror(argv[optind]);
- exit(1);
- }
-
+ altpath = argv[optind];
optind++;
+ }
- if (nerr)
- exit(1);
+ /* Load the file contexts configuration and check it. */
+ opts[0].value = (char *)ctx_validate;
+ opts[1].value = (char *)base_only;
+ opts[2].value = altpath;
+
+ hnd = selabel_open(SELABEL_CTX_FILE, opts, 3);
+ if (!hnd) {
+ perror(altpath);
+ exit(1);
}
+ if (nerr)
+ exit(1);
+
if (use_input_file) {
FILE *f = stdin;
ssize_t len;
@@ -863,8 +1006,10 @@
maybe_audit_mass_relabel();
if (warn_no_match)
- matchpathcon_checkmatches(argv[0]);
+ selabel_stats(hnd);
+ selabel_close(hnd);
+
if (outfile)
fclose(outfile);
--
Eamon Walsh <ewalsh@tycho.nsa.gov>
National Security Agency
--
This message was distributed to subscribers of the selinux mailing list.
If you no longer wish to subscribe, send mail to majordomo@tycho.nsa.gov with
the words "unsubscribe selinux" without quotes as the message.
^ permalink raw reply [flat|nested] 9+ messages in thread
* Re: [PATCH 6/7] libselinux: labeling support (try 4)
2007-06-15 23:43 ` [PATCH 6/7] " Eamon Walsh
@ 2007-06-20 14:43 ` Stephen Smalley
2007-06-20 15:13 ` Stephen Smalley
0 siblings, 1 reply; 9+ messages in thread
From: Stephen Smalley @ 2007-06-20 14:43 UTC (permalink / raw)
To: Eamon Walsh; +Cc: SE Linux, Karl MacMillan
On Fri, 2007-06-15 at 19:43 -0400, Eamon Walsh wrote:
> This patch rebases the matchpathcon code to use the new interface.
matchpathcon() is supposed to internally call matchpathcon_init if it
hasn't already been called, and this behavior is relied upon by some
programs including restorecon. So I'll have to at least modify your
matchpathcon() to call matchpathcon_init if !hnd. You'll see similar
logic in the original matchpathcon_common() function before your patch.
>
> Signed-off-by: Eamon Walsh <ewalsh@tycho.nsa.gov>
> ---
>
> matchpathcon.c | 803 +++++++--------------------------------------------------
> 1 file changed, 112 insertions(+), 691 deletions(-)
>
>
> Index: libselinux/src/matchpathcon.c
> ===================================================================
> --- libselinux/src/matchpathcon.c (revision 2474)
> +++ libselinux/src/matchpathcon.c (working copy)
> @@ -1,19 +1,54 @@
> -#include <unistd.h>
> -#include <fcntl.h>
> #include <sys/stat.h>
> #include <string.h>
> -#include "selinux_internal.h"
> -#include <stdio.h>
> -#include <stdio_ext.h>
> -#include <stdlib.h>
> -#include <ctype.h>
> #include <errno.h>
> -#include <limits.h>
> -#include <regex.h>
> -#include <stdarg.h>
> -#include "policy.h"
> -#include "context_internal.h"
> +#include <stdio.h>
> +#include "selinux_internal.h"
> +#include "label_internal.h"
> +#include "callbacks.h"
>
> +static __thread struct selabel_handle *hnd;
> +
> +/*
> + * An array for mapping integers to contexts
> + */
> +static __thread char **con_array;
> +static __thread int con_array_size;
> +static __thread int con_array_used;
> +
> +static int add_array_elt(char *con)
> +{
> + if (con_array_size) {
> + while (con_array_used >= con_array_size) {
> + con_array_size *= 2;
> + con_array = (char **)realloc(con_array, sizeof(char*) *
> + con_array_size);
> + if (!con_array) {
> + con_array_size = con_array_used = 0;
> + return -1;
> + }
> + }
> + } else {
> + con_array_size = 1000;
> + con_array = (char **)malloc(sizeof(char*) * con_array_size);
> + if (!con_array) {
> + con_array_size = con_array_used = 0;
> + return -1;
> + }
> + }
> +
> + con_array[con_array_used] = strdup(con);
> + if (!con_array[con_array_used])
> + return -1;
> + return con_array_used++;
> +}
> +
> +static void free_array_elts(void)
> +{
> + con_array_size = con_array_used = 0;
> + free(con_array);
> + con_array = NULL;
> +}
> +
> static void
> #ifdef __GNUC__
> __attribute__ ((format(printf, 1, 2)))
> @@ -26,11 +61,11 @@
> va_end(ap);
> }
>
> -static void
> +void
> #ifdef __GNUC__
> __attribute__ ((format(printf, 1, 2)))
> #endif
> - (*myprintf) (const char *fmt,...) = &default_printf;
> + (*myprintf) (const char *fmt,...);
>
> void set_matchpathcon_printf(void (*f) (const char *fmt, ...))
> {
> @@ -66,7 +101,7 @@
> }
>
> static int (*mycanoncon) (const char *p, unsigned l, char **c) =
> - &default_canoncon;
> + NULL;
>
> void set_matchpathcon_canoncon(int (*f) (const char *p, unsigned l, char **c))
> {
> @@ -76,137 +111,23 @@
> mycanoncon = &default_canoncon;
> }
>
> -static __thread unsigned int myflags;
> +static __thread struct selabel_opt options[SELABEL_NOPT];
> +static __thread int notrans;
>
> void set_matchpathcon_flags(unsigned int flags)
> {
> - myflags = flags;
> -}
> -
> -/*
> - * A file security context specification.
> - */
> -typedef struct spec {
> - char *regex_str; /* regular expession string for diagnostic messages */
> - char *type_str; /* type string for diagnostic messages */
> - char *context; /* context string */
> - int context_valid; /* context string has been validated/canonicalized */
> - int translated; /* context string has been translated */
> - regex_t regex; /* compiled regular expression */
> - mode_t mode; /* mode format value */
> - int matches; /* number of matching pathnames */
> - int hasMetaChars; /* indicates whether the RE has
> - any meta characters.
> - 0 = no meta chars
> - 1 = has one or more meta chars */
> - int stem_id; /* indicates which of the stem-compression
> - * items it matches */
> -} spec_t;
> -
> -typedef struct stem {
> - char *buf;
> - int len;
> -} stem_t;
> -
> -static stem_t *stem_arr = NULL;
> -static int num_stems = 0;
> -static int alloc_stems = 0;
> -
> -static const char *const regex_chars = ".^$?*+|[({";
> -
> -/* Return the length of the text that can be considered the stem, returns 0
> - * if there is no identifiable stem */
> -static int get_stem_from_spec(const char *const buf)
> -{
> - const char *tmp = strchr(buf + 1, '/');
> - const char *ind;
> -
> - if (!tmp)
> - return 0;
> -
> - for (ind = buf; ind < tmp; ind++) {
> - if (strchr(regex_chars, (int)*ind))
> - return 0;
> - }
> - return tmp - buf;
> -}
> -
> -/* return the length of the text that is the stem of a file name */
> -static int get_stem_from_file_name(const char *const buf)
> -{
> - const char *tmp = strchr(buf + 1, '/');
> -
> - if (!tmp)
> - return 0;
> - return tmp - buf;
> -}
> -
> -/* find the stem of a file spec, returns the index into stem_arr for a new
> - * or existing stem, (or -1 if there is no possible stem - IE for a file in
> - * the root directory or a regex that is too complex for us). Makes buf
> - * point to the text AFTER the stem. */
> -static int find_stem_from_spec(const char **buf)
> -{
> int i;
> - int stem_len = get_stem_from_spec(*buf);
> -
> - if (!stem_len)
> - return -1;
> - for (i = 0; i < num_stems; i++) {
> - if (stem_len == stem_arr[i].len
> - && !strncmp(*buf, stem_arr[i].buf, stem_len)) {
> - *buf += stem_len;
> - return i;
> - }
> - }
> - if (num_stems == alloc_stems) {
> - stem_t *tmp_arr;
> - alloc_stems = alloc_stems * 2 + 16;
> - tmp_arr = realloc(stem_arr, sizeof(stem_t) * alloc_stems);
> - if (!tmp_arr)
> - return -1;
> - stem_arr = tmp_arr;
> - }
> - stem_arr[num_stems].len = stem_len;
> - stem_arr[num_stems].buf = malloc(stem_len + 1);
> - if (!stem_arr[num_stems].buf)
> - return -1;
> - memcpy(stem_arr[num_stems].buf, *buf, stem_len);
> - stem_arr[num_stems].buf[stem_len] = '\0';
> - num_stems++;
> - *buf += stem_len;
> - return num_stems - 1;
> + memset(options, 0, sizeof(options));
> + i = SELABEL_OPT_BASEONLY;
> + options[i].type = i;
> + options[i].value = (char *)(flags & MATCHPATHCON_BASEONLY);
> + i = SELABEL_OPT_VALIDATE;
> + options[i].type = i;
> + options[i].value = (char *)(flags & MATCHPATHCON_VALIDATE);
> + notrans = flags & MATCHPATHCON_NOTRANS;
> }
>
> -/* find the stem of a file name, returns the index into stem_arr (or -1 if
> - * there is no match - IE for a file in the root directory or a regex that is
> - * too complex for us). Makes buf point to the text AFTER the stem. */
> -static int find_stem_from_file(const char **buf)
> -{
> - int i;
> - int stem_len = get_stem_from_file_name(*buf);
> -
> - if (!stem_len)
> - return -1;
> - for (i = 0; i < num_stems; i++) {
> - if (stem_len == stem_arr[i].len
> - && !strncmp(*buf, stem_arr[i].buf, stem_len)) {
> - *buf += stem_len;
> - return i;
> - }
> - }
> - return -1;
> -}
> -
> /*
> - * The array of specifications, initially in the
> - * same order as in the specification file.
> - * Sorting occurs based on hasMetaChars
> - */
> -static spec_t *spec_arr;
> -static unsigned int nspec;
> -
> -/*
> * An association between an inode and a
> * specification.
> */
> @@ -238,7 +159,7 @@
> int matchpathcon_filespec_add(ino_t ino, int specind, const char *file)
> {
> file_spec_t *prevfl, *fl;
> - int h, no_conflict, ret;
> + int h, ret;
> struct stat sb;
>
> if (!fl_head) {
> @@ -264,21 +185,14 @@
>
> }
>
> - no_conflict =
> - (strcmp
> - (spec_arr[fl->specind].context,
> - spec_arr[specind].context) == 0);
> - if (no_conflict)
> + if (!strcmp(con_array[fl->specind],
> + con_array[specind]))
> return fl->specind;
>
> myprintf
> ("%s: conflicting specifications for %s and %s, using %s.\n",
> __FUNCTION__, file, fl->file,
> - ((specind >
> - fl->specind) ? spec_arr[specind].
> - context : spec_arr[fl->specind].context));
> - fl->specind =
> - (specind > fl->specind) ? specind : fl->specind;
> + con_array[fl->specind]);
> free(fl->file);
> fl->file = malloc(strlen(file) + 1);
> if (!fl->file)
> @@ -350,6 +264,8 @@
> file_spec_t *fl, *tmp;
> int h;
>
> + free_array_elts();
> +
> if (!fl_head)
> return;
>
> @@ -367,393 +283,20 @@
> fl_head = NULL;
> }
>
> -/*
> - * Warn about duplicate specifications.
> - */
> -static void nodups_specs(const char *path)
> +int matchpathcon_init_prefix(const char *path, const char *subset)
> {
> - unsigned int ii, jj;
> - struct spec *curr_spec;
> + if (!mycanoncon)
> + mycanoncon = default_canoncon;
>
> - for (ii = 0; ii < nspec; ii++) {
> - curr_spec = &spec_arr[ii];
> - for (jj = ii + 1; jj < nspec; jj++) {
> - if ((!strcmp
> - (spec_arr[jj].regex_str, curr_spec->regex_str))
> - && (!spec_arr[jj].mode || !curr_spec->mode
> - || spec_arr[jj].mode == curr_spec->mode)) {
> - if (strcmp
> - (spec_arr[jj].context,
> - curr_spec->context)) {
> - myprintf
> - ("%s: Multiple different specifications for %s (%s and %s).\n",
> - path, curr_spec->regex_str,
> - spec_arr[jj].context,
> - curr_spec->context);
> - } else {
> - myprintf
> - ("%s: Multiple same specifications for %s.\n",
> - path, curr_spec->regex_str);
> - }
> - }
> - }
> - }
> -}
> + options[SELABEL_OPT_SUBSET].type = SELABEL_OPT_SUBSET;
> + options[SELABEL_OPT_SUBSET].value = subset;
> + options[SELABEL_OPT_PATH].type = SELABEL_OPT_PATH;
> + options[SELABEL_OPT_PATH].value = path;
>
> -/* Determine if the regular expression specification has any meta characters. */
> -static void spec_hasMetaChars(struct spec *spec)
> -{
> - char *c;
> - int len;
> - char *end;
> -
> - c = spec->regex_str;
> - len = strlen(spec->regex_str);
> - end = c + len;
> -
> - spec->hasMetaChars = 0;
> -
> - /* Look at each character in the RE specification string for a
> - * meta character. Return when any meta character reached. */
> - while (c != end) {
> - switch (*c) {
> - case '.':
> - case '^':
> - case '$':
> - case '?':
> - case '*':
> - case '+':
> - case '|':
> - case '[':
> - case '(':
> - case '{':
> - spec->hasMetaChars = 1;
> - return;
> - case '\\': /* skip the next character */
> - c++;
> - break;
> - default:
> - break;
> -
> - }
> - c++;
> - }
> - return;
> + hnd = selabel_open(SELABEL_CTX_FILE, options, SELABEL_NOPT);
> + return hnd ? 0 : -1;
> }
> -static int process_line(const char *path, const char *prefix, char *line_buf,
> - int pass, unsigned lineno)
> -{
> - int items, len, regerr, ret;
> - char *buf_p, *ptr;
> - char *regex=NULL, *type=NULL, *context=NULL;
> - const char *reg_buf;
> - char *anchored_regex = NULL;
>
> - ret = 0;
> - len = strlen(line_buf);
> - if (line_buf[len - 1] == '\n')
> - line_buf[len - 1] = 0;
> - buf_p = line_buf;
> - while (isspace(*buf_p))
> - buf_p++;
> - /* Skip comment lines and empty lines. */
> - if (*buf_p == '#' || *buf_p == 0)
> - return 0;
> -
> - items = 0;
> - regex = strtok_r(buf_p, " \t", &ptr);
> - if (regex)
> - items += 1;
> - type = strtok_r(NULL, " \t", &ptr);
> - if (type)
> - items += 1;
> - context = strtok_r(NULL, " \t", &ptr);
> - if (context)
> - items += 1;
> -
> - if (items < 2) {
> - myprintf("%s: line %d is missing fields, skipping\n", path,
> - lineno);
> - return 0;
> - } else if (items == 2) {
> - /* The type field is optional. */
> - context = type;
> - type = NULL;
> - }
> -
> - regex = strdup(regex);
> - if (!regex) {
> - return -1;
> - }
> - if (type) {
> - type = strdup(type);
> - if (!type) {
> - free(regex);
> - return -1;
> - }
> - }
> - context = strdup(context);
> - if (!context) {
> - ret = -1;
> - goto finish;
> - }
> -
> - reg_buf = regex;
> - len = get_stem_from_spec(reg_buf);
> - if (len && prefix && strncmp(prefix, regex, len)) {
> - /* Stem of regex does not match requested prefix, discard. */
> - goto finish;
> - }
> -
> - if (pass == 1) {
> - /* On the second pass, compile and store the specification in spec. */
> - char *cp;
> - spec_arr[nspec].stem_id = find_stem_from_spec(®_buf);
> - spec_arr[nspec].regex_str = regex;
> -
> - /* Anchor the regular expression. */
> - len = strlen(reg_buf);
> - cp = anchored_regex = malloc(len + 3);
> - if (!anchored_regex) {
> - ret = -1;
> - goto finish;
> - }
> - /* Create ^...$ regexp. */
> - *cp++ = '^';
> - cp = mempcpy(cp, reg_buf, len);
> - *cp++ = '$';
> - *cp = '\0';
> -
> - /* Compile the regular expression. */
> - regerr =
> - regcomp(&spec_arr[nspec].regex,
> - anchored_regex, REG_EXTENDED | REG_NOSUB);
> - if (regerr != 0) {
> - size_t errsz = 0;
> - char *errbuf = NULL;
> - errsz = regerror(regerr, &spec_arr[nspec].regex,
> - errbuf, errsz);
> - if (errsz)
> - errbuf = malloc(errsz);
> - if (errbuf)
> - (void)regerror(regerr,
> - &spec_arr[nspec].regex,
> - errbuf, errsz);
> - myprintf("%s: line %d has invalid regex %s: %s\n",
> - path, lineno, anchored_regex,
> - (errbuf ? errbuf : "out of memory"));
> - free(anchored_regex);
> - anchored_regex = NULL;
> - free(errbuf);
> - goto finish;
> - }
> - free(anchored_regex);
> - anchored_regex = NULL;
> -
> - /* Convert the type string to a mode format */
> - spec_arr[nspec].type_str = type;
> - spec_arr[nspec].mode = 0;
> - if (!type)
> - goto skip_type;
> - len = strlen(type);
> - if (type[0] != '-' || len != 2) {
> - myprintf("%s: line %d has invalid file type %s\n",
> - path, lineno, type);
> - goto finish;
> - }
> - switch (type[1]) {
> - case 'b':
> - spec_arr[nspec].mode = S_IFBLK;
> - break;
> - case 'c':
> - spec_arr[nspec].mode = S_IFCHR;
> - break;
> - case 'd':
> - spec_arr[nspec].mode = S_IFDIR;
> - break;
> - case 'p':
> - spec_arr[nspec].mode = S_IFIFO;
> - break;
> - case 'l':
> - spec_arr[nspec].mode = S_IFLNK;
> - break;
> - case 's':
> - spec_arr[nspec].mode = S_IFSOCK;
> - break;
> - case '-':
> - spec_arr[nspec].mode = S_IFREG;
> - break;
> - default:
> - myprintf("%s: line %d has invalid file type %s\n",
> - path, lineno, type);
> - goto finish;
> - }
> -
> - skip_type:
> - if (strcmp(context, "<<none>>")) {
> - if (myflags & MATCHPATHCON_VALIDATE) {
> - if (myinvalidcon) {
> - /* Old-style validation of context. */
> - if (myinvalidcon(path, lineno, context))
> - goto finish;
> - } else {
> - /* New canonicalization of context. */
> - if (mycanoncon(path, lineno, &context))
> - goto finish;
> - }
> - spec_arr[nspec].context_valid = 1;
> - }
> - }
> -
> - spec_arr[nspec].context = context;
> -
> - /* Determine if specification has
> - * any meta characters in the RE */
> - spec_hasMetaChars(&spec_arr[nspec]);
> -
> - /* Prevent stored strings from being freed. */
> - regex = NULL;
> - type = NULL;
> - context = NULL;
> - }
> -
> - nspec++;
> -finish:
> - free(regex);
> - free(type);
> - free(context);
> - return ret;
> -}
> -
> -int matchpathcon_init_prefix(const char *path, const char *prefix)
> -{
> - FILE *fp;
> - FILE *localfp = NULL;
> - FILE *homedirfp = NULL;
> - char local_path[PATH_MAX + 1];
> - char homedir_path[PATH_MAX + 1];
> - char *line_buf = NULL;
> - size_t line_len = 0;
> - unsigned int lineno, pass, i, j, maxnspec;
> - spec_t *spec_copy = NULL;
> - int status = -1;
> - struct stat sb;
> -
> - /* Open the specification file. */
> - if (!path)
> - path = selinux_file_context_path();
> - if ((fp = fopen(path, "r")) == NULL)
> - return -1;
> - __fsetlocking(fp, FSETLOCKING_BYCALLER);
> -
> - if (fstat(fileno(fp), &sb) < 0)
> - return -1;
> - if (!S_ISREG(sb.st_mode)) {
> - errno = EINVAL;
> - return -1;
> - }
> -
> - if ((myflags & MATCHPATHCON_BASEONLY) == 0) {
> - snprintf(homedir_path, sizeof(homedir_path), "%s.homedirs",
> - path);
> - homedirfp = fopen(homedir_path, "r");
> - if (homedirfp != NULL)
> - __fsetlocking(homedirfp, FSETLOCKING_BYCALLER);
> -
> - snprintf(local_path, sizeof(local_path), "%s.local", path);
> - localfp = fopen(local_path, "r");
> - if (localfp != NULL)
> - __fsetlocking(localfp, FSETLOCKING_BYCALLER);
> - }
> -
> - /*
> - * Perform two passes over the specification file.
> - * The first pass counts the number of specifications and
> - * performs simple validation of the input. At the end
> - * of the first pass, the spec array is allocated.
> - * The second pass performs detailed validation of the input
> - * and fills in the spec array.
> - */
> - maxnspec = UINT_MAX / sizeof(spec_t);
> - for (pass = 0; pass < 2; pass++) {
> - lineno = 0;
> - nspec = 0;
> - while (getline(&line_buf, &line_len, fp) > 0
> - && nspec < maxnspec) {
> - if (process_line(path, prefix, line_buf, pass, ++lineno)
> - != 0)
> - goto finish;
> - }
> - lineno = 0;
> - if (homedirfp)
> - while (getline(&line_buf, &line_len, homedirfp) > 0
> - && nspec < maxnspec) {
> - if (process_line
> - (homedir_path, prefix, line_buf, pass,
> - ++lineno) != 0)
> - goto finish;
> - }
> -
> - lineno = 0;
> - if (localfp)
> - while (getline(&line_buf, &line_len, localfp) > 0
> - && nspec < maxnspec) {
> - if (process_line
> - (local_path, prefix, line_buf, pass,
> - ++lineno) != 0)
> - goto finish;
> - }
> -
> - if (pass == 0) {
> - if (nspec == 0) {
> - status = 0;
> - goto finish;
> - }
> - if ((spec_arr = malloc(sizeof(spec_t) * nspec)) == NULL)
> - goto finish;
> - memset(spec_arr, '\0', sizeof(spec_t) * nspec);
> - maxnspec = nspec;
> - rewind(fp);
> - if (homedirfp)
> - rewind(homedirfp);
> - if (localfp)
> - rewind(localfp);
> - }
> - }
> - free(line_buf);
> - line_buf = NULL;
> -
> - /* Move exact pathname specifications to the end. */
> - spec_copy = malloc(sizeof(spec_t) * nspec);
> - if (!spec_copy)
> - goto finish;
> - j = 0;
> - for (i = 0; i < nspec; i++) {
> - if (spec_arr[i].hasMetaChars)
> - memcpy(&spec_copy[j++], &spec_arr[i], sizeof(spec_t));
> - }
> - for (i = 0; i < nspec; i++) {
> - if (!spec_arr[i].hasMetaChars)
> - memcpy(&spec_copy[j++], &spec_arr[i], sizeof(spec_t));
> - }
> - free(spec_arr);
> - spec_arr = spec_copy;
> -
> - nodups_specs(path);
> -
> - status = 0;
> - finish:
> - fclose(fp);
> - free(line_buf);
> - if (spec_arr != spec_copy)
> - free(spec_arr);
> - if (homedirfp)
> - fclose(homedirfp);
> - if (localfp)
> - fclose(localfp);
> - return status;
> -}
> -
> hidden_def(matchpathcon_init_prefix)
>
> int matchpathcon_init(const char *path)
> @@ -763,172 +306,33 @@
>
> void matchpathcon_fini(void)
> {
> - struct spec *spec;
> - struct stem *stem;
> - unsigned int i;
> -
> - for (i = 0; i < nspec; i++) {
> - spec = &spec_arr[i];
> - free(spec->regex_str);
> - free(spec->type_str);
> - free(spec->context);
> - regfree(&spec->regex);
> - }
> - free(spec_arr);
> - spec_arr = NULL;
> - nspec = 0;
> -
> - for (i = 0; i < (unsigned int)num_stems; i++) {
> - stem = &stem_arr[i];
> - free(stem->buf);
> - }
> - free(stem_arr);
> - stem_arr = NULL;
> - num_stems = 0;
> - alloc_stems = 0;
> + selabel_close(hnd);
> + hnd = NULL;
> }
>
> -static int matchpathcon_common(const char *name, mode_t mode)
> -{
> - int i, ret, file_stem;
> - const char *buf = name;
> -
> - if (!nspec) {
> - ret = matchpathcon_init_prefix(NULL, NULL);
> - if (ret < 0)
> - return ret;
> - if (!nspec) {
> - errno = ENOENT;
> - return -1;
> - }
> - }
> -
> - file_stem = find_stem_from_file(&buf);
> -
> - mode &= S_IFMT;
> -
> - /*
> - * Check for matching specifications in reverse order, so that
> - * the last matching specification is used.
> - */
> - for (i = nspec - 1; i >= 0; i--) {
> - /* if the spec in question matches no stem or has the same
> - * stem as the file AND if the spec in question has no mode
> - * specified or if the mode matches the file mode then we do
> - * a regex check */
> - if ((spec_arr[i].stem_id == -1
> - || spec_arr[i].stem_id == file_stem)
> - && (!mode || !spec_arr[i].mode
> - || ((mode & S_IFMT) == spec_arr[i].mode))) {
> - if (spec_arr[i].stem_id == -1)
> - ret =
> - regexec(&spec_arr[i].regex, name, 0, NULL,
> - 0);
> - else
> - ret =
> - regexec(&spec_arr[i].regex, buf, 0, NULL,
> - 0);
> - if (ret == 0)
> - break;
> -
> - if (ret == REG_NOMATCH)
> - continue;
> - /* else it's an error */
> - return -1;
> - }
> - }
> -
> - if (i < 0) {
> - /* No matching specification. */
> - errno = ENOENT;
> - return -1;
> - }
> -
> - spec_arr[i].matches++;
> -
> - return i;
> -
> -}
> -
> int matchpathcon(const char *name, mode_t mode, security_context_t * con)
> {
> - int i = matchpathcon_common(name, mode);
> + if (!mycanoncon)
> + mycanoncon = default_canoncon;
>
> - if (i < 0)
> - return -1;
> -
> - if (strcmp(spec_arr[i].context, "<<none>>") == 0) {
> - errno = ENOENT;
> - return -1;
> - }
> -
> - if (!spec_arr[i].context_valid) {
> - if (myinvalidcon) {
> - /* Old-style validation of context. */
> - if (myinvalidcon
> - ("file_contexts", 0, spec_arr[i].context))
> - goto bad;
> - } else {
> - /* New canonicalization of context. */
> - if (mycanoncon
> - ("file_contexts", 0, &spec_arr[i].context))
> - goto bad;
> - }
> - spec_arr[i].context_valid = 1;
> - }
> -
> - if (!spec_arr[i].translated && !(myflags & MATCHPATHCON_NOTRANS)) {
> - char *tmpcon = NULL;
> - if (selinux_raw_to_trans_context(spec_arr[i].context, &tmpcon))
> - return -1;
> - free(spec_arr[i].context);
> - spec_arr[i].context = tmpcon;
> - spec_arr[i].translated = 1;
> - }
> -
> - *con = strdup(spec_arr[i].context);
> - if (!(*con))
> - return -1;
> -
> - return 0;
> -
> - bad:
> - errno = EINVAL;
> - return -1;
> + return notrans ?
> + selabel_lookup_raw(hnd, con, name, mode) :
> + selabel_lookup(hnd, con, name, mode);
> }
>
> int matchpathcon_index(const char *name, mode_t mode, security_context_t * con)
> {
> - int i = matchpathcon_common(name, mode);
> + int i = matchpathcon(name, mode, con);
>
> if (i < 0)
> return -1;
>
> - *con = strdup(spec_arr[i].context);
> - if (!(*con))
> - return -1;
> -
> - return i;
> + return add_array_elt(*con);
> }
>
> -void matchpathcon_checkmatches(char *str)
> +void matchpathcon_checkmatches(char *str __attribute__((unused)))
> {
> - unsigned int i;
> - for (i = 0; i < nspec; i++) {
> - if (spec_arr[i].matches == 0) {
> - if (spec_arr[i].type_str) {
> - myprintf
> - ("%s: Warning! No matches for (%s, %s, %s)\n",
> - str, spec_arr[i].regex_str,
> - spec_arr[i].type_str, spec_arr[i].context);
> - } else {
> - myprintf
> - ("%s: Warning! No matches for (%s, %s)\n",
> - str, spec_arr[i].regex_str,
> - spec_arr[i].context);
> - }
> - }
> - }
> + selabel_stats(hnd);
> }
>
> /* Compare two contexts to see if their differences are "significant",
> @@ -958,7 +362,6 @@
> {
> security_context_t con = NULL;
> security_context_t fcontext = NULL;
> - unsigned int localflags = myflags;
> int rc = 0;
>
> rc = lgetfilecon_raw(path, &con);
> @@ -969,15 +372,14 @@
> return 0;
> }
>
> - set_matchpathcon_flags(myflags | MATCHPATHCON_NOTRANS);
> - if (matchpathcon(path, mode, &fcontext) != 0) {
> + if (selabel_lookup_raw(hnd, &fcontext, path, mode) != 0) {
> if (errno != ENOENT)
> rc = 1;
> else
> rc = 0;
> } else
> rc = (selinux_file_context_cmp(fcontext, con) == 0);
> - set_matchpathcon_flags(localflags);
> +
> freecon(con);
> freecon(fcontext);
> return rc;
> @@ -988,21 +390,40 @@
> struct stat st;
> int rc = -1;
> security_context_t scontext = NULL;
> - unsigned int localflags = myflags;
> if (lstat(path, &st) != 0)
> return rc;
>
> - set_matchpathcon_flags(myflags | MATCHPATHCON_NOTRANS);
> -
> /* If there's an error determining the context, or it has none,
> return to allow default context */
> - if (matchpathcon(path, st.st_mode, &scontext)) {
> + if (selabel_lookup_raw(hnd, &scontext, path, st.st_mode)) {
> if (errno == ENOENT)
> rc = 0;
> } else {
> rc = lsetfilecon_raw(path, scontext);
> freecon(scontext);
> }
> - set_matchpathcon_flags(localflags);
> return rc;
> }
> +
> +int compat_validate(struct selabel_handle *rec,
> + struct selabel_lookup_rec *contexts,
> + const char *path, unsigned lineno)
> +{
> + int rc;
> + char **ctx = &contexts->ctx_raw;
> +
> + if (myinvalidcon)
> + rc = myinvalidcon(path, lineno, *ctx);
> + else if (mycanoncon)
> + rc = mycanoncon(path, lineno, ctx);
> + else {
> + rc = selabel_validate(rec, contexts);
> + if (rc < 0) {
> + COMPAT_LOG(SELINUX_WARNING,
> + "%s: line %d has invalid context %s\n",
> + path, lineno, *ctx);
> + }
> + }
> +
> + return rc ? -1 : 0;
> +}
>
>
--
Stephen Smalley
National Security Agency
--
This message was distributed to subscribers of the selinux mailing list.
If you no longer wish to subscribe, send mail to majordomo@tycho.nsa.gov with
the words "unsubscribe selinux" without quotes as the message.
^ permalink raw reply [flat|nested] 9+ messages in thread
* Re: [PATCH 6/7] libselinux: labeling support (try 4)
2007-06-20 14:43 ` Stephen Smalley
@ 2007-06-20 15:13 ` Stephen Smalley
0 siblings, 0 replies; 9+ messages in thread
From: Stephen Smalley @ 2007-06-20 15:13 UTC (permalink / raw)
To: Eamon Walsh; +Cc: SE Linux, Karl MacMillan
On Wed, 2007-06-20 at 10:43 -0400, Stephen Smalley wrote:
> On Fri, 2007-06-15 at 19:43 -0400, Eamon Walsh wrote:
> > This patch rebases the matchpathcon code to use the new interface.
>
> matchpathcon() is supposed to internally call matchpathcon_init if it
> hasn't already been called, and this behavior is relied upon by some
> programs including restorecon. So I'll have to at least modify your
> matchpathcon() to call matchpathcon_init if !hnd. You'll see similar
> logic in the original matchpathcon_common() function before your patch.
Like so, on top of your patch:
diff -u libselinux/src/matchpathcon.c libselinux/src/matchpathcon.c
--- libselinux/src/matchpathcon.c (working copy)
+++ libselinux/src/matchpathcon.c (working copy)
@@ -312,8 +312,8 @@
int matchpathcon(const char *name, mode_t mode, security_context_t * con)
{
- if (!mycanoncon)
- mycanoncon = default_canoncon;
+ if (!hnd && (matchpathcon_init_prefix(NULL, NULL) < 0))
+ return -1;
return notrans ?
selabel_lookup_raw(hnd, con, name, mode) :
--
Stephen Smalley
National Security Agency
--
This message was distributed to subscribers of the selinux mailing list.
If you no longer wish to subscribe, send mail to majordomo@tycho.nsa.gov with
the words "unsubscribe selinux" without quotes as the message.
^ permalink raw reply [flat|nested] 9+ messages in thread
end of thread, other threads:[~2007-06-20 15:13 UTC | newest]
Thread overview: 9+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2007-06-15 23:29 [PATCH 1/7] libselinux: labeling support (try 4) Eamon Walsh
2007-06-15 23:35 ` [PATCH 2/7] " Eamon Walsh
2007-06-15 23:37 ` [PATCH 3/7] " Eamon Walsh
2007-06-15 23:39 ` [PATCH 4/7] " Eamon Walsh
2007-06-15 23:40 ` [PATCH 5/7] " Eamon Walsh
2007-06-15 23:43 ` [PATCH 6/7] " Eamon Walsh
2007-06-20 14:43 ` Stephen Smalley
2007-06-20 15:13 ` Stephen Smalley
2007-06-15 23:46 ` [PATCH 7/7] " Eamon Walsh
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.