* [PATCH] Basic policy representation
@ 2007-05-07 22:06 Karl MacMillan
2007-05-08 14:45 ` Joshua Brindle
` (2 more replies)
0 siblings, 3 replies; 25+ messages in thread
From: Karl MacMillan @ 2007-05-07 22:06 UTC (permalink / raw)
To: selinux
Add support for the basic policy object model and the sepol_policy
and sepol_module objects to libsepol. This version has significant
changes from the last posted version:
1) sepol_handle is passed everywhere
2) public and private interfaces to the object system are correctly
split (into policy.[c,h] and policy_internal.[c,h].
3) object ouput has been converted from writing to a FILE to returning
allocated strings. This will help integrate better with scripting
languages.
4) Basic documentation is included for the base objects.
5) Enums are used instead of defines - this is a change from the style
for libsepol, but it makes documenting the enums much easier.
Signed-off-by: User "Karl MacMillan <kmacmillan@mentalrootkit.com>"
---
7 files changed, 1667 insertions(+), 4 deletions(-)
libsepol/include/sepol/policy.h | 522 +++++++++++++++++++++++++++++++
libsepol/src/policy.c | 638 +++++++++++++++++++++++++++++++++++++++
libsepol/src/policy_internal.c | 102 ++++++
libsepol/src/policy_internal.h | 269 ++++++++++++++++
libsepol/tests/libsepol-tests.c | 10
libsepol/tests/test-policy.c | 118 +++++++
libsepol/tests/test-policy.h | 12
diff -r cacdf4377ebf -r bd4ee6e00a63 libsepol/include/sepol/policy.h
--- a/libsepol/include/sepol/policy.h Mon May 07 15:50:27 2007 -0400
+++ b/libsepol/include/sepol/policy.h Mon May 07 18:03:03 2007 -0400
@@ -0,0 +1,522 @@
+/* Author : Karl MacMillan <kmacmillan@mentalrootkit.com> */
+
+#ifndef __sepol_policy_h__
+#define __sepol_policy_h__
+
+#include <sepol/handle.h>
+
+#include <sepol/objpool.h>
+#include <sepol/objset.h>
+#include <sepol/list.h>
+
+#include <sys/types.h>
+#include <stdint.h>
+#include <stdio.h>
+
+/**
+ * \defgroup sepol_policy sepol_policy: policy representation
+ * Introduction to the policy object system
+ *
+ *
+ * The policy is represented as a tree of objects that loosely
+ * resemble an abstract syntax tree or intermediate representation
+ * commonly found in compilers. This tree representation is used as
+ * the output of the policy parser the format for selinux policy
+ * modules. The data structures are also intended to be flexible
+ * enough to represent an selinux policy for syntax/semantic checking,
+ * analysis, generation, and storage.
+ *
+ * The basic structure is that of a tree holding selinux policy
+ * language components (e.g., type declarations, rules, conditional
+ * blocks, etc.). To implement this tree structure in a form that can
+ * be processed easily, a basic object orientied structure is
+ * implemented in C.
+ *
+ * The object oriented system allows the use of polymorphic functions,
+ * making it possible to process objects in the tree with only limited
+ * informatio about the specific types (e.g., it is possible to
+ * traverse the tree and output all of the objects as strings without
+ * the traversal function knowing detailed type information about each
+ * object - it simple class sepol_object_strout on each object).
+ *
+ * See sepol_object and sepol_parent for more information on this object
+ * oriented type system.
+ *
+ */
+
+/**
+ * \ingroup sepol_policy
+ *
+ * Every type in the policy object system is identified
+ * by a numberic typeid.
+ */
+enum sepol_typeid {
+ SEPOL_TYPEID_NONE, /** special typeid representing no type */
+ SEPOL_TYPEID_OBJECT, /** typeid for base class of all objects */
+ SEPOL_TYPEID_PARENT, /** typeid for base class of objects that contain other objects */
+ SEPOL_TYPEID_POLICY, /** typeid for policy object */
+ SEPOL_TYPEID_MODULE, /** typeid for the module object */
+ SEPOL_TYPEID_BLOCK, /** tyepid for the block object */
+ SEPOL_TYPEID_COND, /** typeid for the cond object */
+ SEPOL_TYPEID_OPTIONAL, /** typeid for the optional object */
+ SEPOL_TYPEID_TYPE, /** typed for the type object */
+ SEPOL_TYPEID_CLASS, /** typeid for the class object */
+ SEPOL_TYPEID_ATTRIBUTE, /** typeid for the attribute object */
+ SEPOL_TYPEID_TYPEALIAS, /** typeid for the typealias object */
+ SEPOL_TYPEID_BOOL, /** typeid for the bool object */
+ SEPOL_TYPEID_AVRULE, /** typeid for the avrule object */
+ SEPOL_TYPEID_TYPERULE, /** typeid for the typerule object */
+ SEPOL_TYPEID_SECURITY_CONTEXT, /** typeid for the securit context object */
+ SEPOL_TYPEID_ISID, /** typeid for the isid object */
+ SEPOL_TYPEID_TYPEATTRIBUTE, /** typeid for the typeattribute object */
+ SEPOL_TYPEID_COND_EXPR, /** typeid for the cond expr object */
+ SEPOL_TYPEID_SENS, /** typeid for the sends object */
+ SEPOL_TYPEID_DOMINANCE, /** typeid for the dominance object */
+ SEPOL_TYPEID_CATEGORY, /** typeid for the category object */
+ SEPOL_TYPEID_ROLE_DOMINANCE, /** typeid for the role dominance object */
+ SEPOL_TYPEID_ROLE /** typeid for the role object */
+};
+
+/**
+ * \ingroup sepol_policy
+ *
+ * Convert a typeid to a string representation. The returned string
+ * is constant and should not be altered or freed.
+ *
+ * @param typeid typeid to convert to string
+ *
+ * \retval string string representing the typeid
+ */
+const char *sepol_typeid_tostring(int typeid);
+
+/**
+ * \ingroup sepol_policy
+ * \struct sepol_object
+ *
+ * sepol_object is the base class of all objects in this type system.
+ * There is no way to directly create an sepol_object - it is an
+ * abstract base class.
+ *
+ * The type system works by:
+ * - mandating that sepol_object (or one of its subclasses) be the
+ * first entry in every struct. This allows the structs to be
+ * freely cast to an sepol_object or any of the other objects
+ * in the hierarchy of that struct.
+ * - Storing information about the types in the form of IDs. This
+ * allows callers to determine type information at runtime.
+ * - Storing function pointers to class specific function
+ * implementations in each object instance. This allows functions
+ * to have a limited form of polymorphism.
+ *
+ * sepol_object is also the parent class of all objects that are
+ * exclusively leaves in the tree (i.e., objects that cannot contain
+ * other objects).
+ *
+ * Properties that all sepol_objects share:
+ * - string pool (strpool): [optional] an objpool for storing
+ * strings stored in the objects. The object may be the owner of
+ * the string pool (see sepol_object_is_strpool_owner), reference
+ * the string pool of another object (usually the root of a policy
+ * tree), or not have a string pool at all.
+ * - type identifier (typeid): The sepol_typeid for this object.
+ */
+struct sepol_object;
+
+/**
+ * \ingroup sepol_policy
+ *
+ * Convert an object to an sepol_object
+ *
+ * @param x object
+ */
+#define SEPOL_OBJECT(x) ((struct sepol_object *)x)
+
+/**
+ * \ingroup sepol_policy
+ *
+ * Free an sepol_object. This can be called for any
+ * subclass of sepol_object.
+ *
+ * @param n object to free
+ *
+ * \retval SEPOL_OK success
+ * \retval <0 error
+ */
+extern int sepol_object_free(struct sepol_handle *h, struct sepol_object *o);
+
+/**
+ * \ingroup sepol_policy
+ *
+ * Make this object the owner of a string pool. See sepol_object for
+ * more information on string pools.
+ *
+ * @param o object to which to add string pool
+ *
+ * \retval SEPOL_OK success
+ * \retval SEPOL_ENOMEM out of memory
+ */
+extern int sepol_object_create_strpool(struct sepol_handle *h, struct sepol_object *o);
+
+/**
+ * \ingroup sepol_policy
+ *
+ * Return the strpool for this object if any.
+ *
+ * @param o object from which to return string pool.
+ *
+ * \retval non-NULL string pool this object is using.
+ * \retval NULL object does not use string pool.
+ */
+extern struct sepol_objpool *sepol_object_get_strpool(struct sepol_object *o);
+
+/**
+ * \ingroup sepol_policy
+ *
+ * Determine whether the object is the owner of its string pool (if
+ * it has one).
+ *
+ * @param o object to check
+ *
+ * \retval 0 object does not own or does not have a string pool
+ * \retval 1 object owns its string pool
+ */
+extern char sepol_object_is_strpool_owner(struct sepol_object *o);
+
+
+/**
+ * \ingroup sepol_policy
+ *
+ * Return the typeid for the object.
+ *
+ * @param o object from which to return the type id.
+ *
+ * \retval >0 typeid for the object
+ */
+extern uint32_t sepol_object_get_typeid(struct sepol_object *o);
+
+/**
+ * \ingroup sepol_policy
+ *
+ * Determine whether the object is an instance of the object type
+ * represented by a typeid. This function checks both the specific
+ * object type (as returned by sepol_object_get_typeid) and the
+ * parent type for the object.
+ *
+ * @param o object to check
+ * @param typeid typeid
+ *
+ * \retval 0 object is not an instance of the type
+ * \retval 1 object is an instance of the type
+ */
+extern char sepol_object_isinstance(struct sepol_object *o, uint32_t typeid);
+
+/**
+ * \ingroup sepol_policy
+ *
+ * Return the parent of this object (if any).
+ *
+ * @param o object for which to return parent
+ *
+ * \retval non-NULL pointer to parent object
+ * \retval NULL object has no parent
+ */
+extern struct sepol_parent *sepol_object_get_parent(struct sepol_object *o);
+
+/**
+ * \ingroup sepol_policy
+ *
+ * Specify the output for various sepol_*_tostring functions.
+ */
+enum sepol_tostring_style {
+ SEPOL_TOSTRING_RAW, /** raw policy language */
+ SEPOL_TOSTRING_REFPOL, /** refpol style output */
+ SEPOL_TOSTRING_DEBUG /** debugging output */
+};
+
+/**
+ * \ingroup sepol_policy
+ *
+ * Convert an sepol_object into a string representation. If the
+ * returned string is of 0 length (return is 0), str will be an
+ * allocated, 0 length string that should be freed by the caller.
+ *
+ * @param h sepol_handle (may be NULL)
+ * @param o object to convert to a string
+ * @param style style of the output - see sepol_tostring_style
+ * @param str output string - this string is allocated by the function
+ * and should be freed by the caller using free()
+ *
+ * \retval >=0 Success - the size of the string is returned
+ * \retval <0 Failure - str will be undefined and does not need to be freed.
+ */
+extern int sepol_object_tostring(struct sepol_handle *h, struct sepol_object *o,
+ int style, char **str);
+
+/**
+ * \ingroup sepol_policy
+ *
+ * Convert an sepol_object into a string representation for the
+ * closure of that object. Some objects - typically that contain
+ * other objects - need a string to represent the beginning _and_
+ * the end of that object. For example:
+ *
+ * \code
+ * if (foo) {
+ * allow foo bar : file read;
+ * }
+ * \endcode
+ *
+ * In this example "if (foo) }" would be printed by
+ * sepol_object_tostring and "}} printed by
+ * sepol_object_tostring_close on the same conditional object. If the
+ * returned string is of 0 length (return is 0), str will be an
+ * allocated, 0 length string that should be freed by the caller.
+ *
+ * @param h sepol_handle (may be NULL)
+ * @param o object to convert to a string
+ * @param style style of the output - see sepol_tostring_style
+ * @param str output string - this string is allocated by the function
+ * and should be freed by the caller using free()
+ *
+ * \retval >=0 Success - the size of the string is returned
+ * \retval <0 Failure - str will be undefined and does not need to be freed.
+ */
+extern int sepol_object_tostring_close(struct sepol_handle *h, struct sepol_object *o,
+ int style, char **str);
+
+/**
+ * \ingroup sepol_policy
+ * \struct sepol_parent
+ *
+ * sepol_parent is the parent class of all objects that can contain
+ * other objects in the tree. Having a single base class for all parent
+ * objects allows writing functions that can traverse the tree without
+ * knowing the details about most of the objects in the tree.
+ */
+struct sepol_parent;
+
+/**
+ * \ingroup sepol_policy
+ *
+ * Convert an object to an sepol_parent
+ *
+ * @param x object
+ */
+#define SEPOL_PARENT(x) ((struct sepol_parent *)x)
+
+/**
+ * \ingroup sepol_policy
+ *
+ * Free a parent object and all of its children (if any). This
+ * function traverses a policy tree starting at the parent node passed
+ * in destroy each object it encounters (by (calling
+ * sepol_object_free).
+ *
+ * @param h sepol_handle (may be NULL)
+ * @param p sepol_parent object
+ *
+ * \retval SEPOL_OK success
+ * \retval SEPOL_ENOMEM out of memory
+ */
+extern int sepol_parent_free_tree(struct sepol_handle *h, struct sepol_parent *p);
+
+/**
+ * \ingroup sepol_policy
+ *
+ * Append an object as a child of this parent. An object can only
+ * be the child of a single parent - to move an object from one
+ * part of the tree to another (and change the parent), remove the
+ * child from the current parent first before appending to the new
+ * parent.
+ *
+ * @param h sepol_handle (may be NULL)
+ * @param p sepol_parent to which to append child object
+ * @param o object to append (parent will be set)
+ *
+ * \retval SEPOL_OK success
+ * \retval SEPOL_EEXIST object is already a child of another parent
+ * \retval SEPOL_ENOMEM out of memory
+ */
+extern int sepol_parent_append(struct sepol_handle *h, struct sepol_parent *p,
+ struct sepol_object *o);
+
+/**
+ * \ingroup sepol_policy
+ *
+ * Extend the children of an sepol_parent with the objects returned by
+ * an iterator. Each object will be appended using
+ * sepol_parent_append. If there is an error from adding any of the
+ * children some of the objects may have been added. The iterator will
+ * be left in the position of the object that caused an error.
+ *
+ * @param h sepol_handle (may be NULL)
+ * @param p sepol_parent to which to add children
+ * @param iter iterator from which to add children
+ *
+ * \retval SEPOL_OK success
+ * \retval SEPOL_EEXIST object is already a child of another parent
+ * \retval SEPOL_ENOMEM out of memory
+ */
+extern int sepol_parent_extend(struct sepol_handle *h, struct sepol_parent *p,
+ struct sepol_iter *iter);
+
+/**
+ * \ingroup sepol_policy
+ *
+ * Convenience function similar to sepol_parent_extend that takes a
+ * list instead of an interator.
+ *
+ * @param h sepol_handle (may be NULL)
+ * @param p sepol_parent to which to add objects
+ * @param list sepol_list from which to add objects
+ *
+ * \retval SEPOL_OK success
+ * \retval SEPOL_EEXIST object is already a child of another parent
+ * \retval SEPOL_ENOMEM out of memory
+ */
+extern int sepol_parent_extend_list(struct sepol_handle *h, struct sepol_parent *p,
+ struct sepol_list *list);
+
+/**
+ * \ingroup sepol_policy
+ *
+ * Delete a child object from the sepol_parent. Like sepol_list_del,
+ * the iterator will not be valid after a call to this function.
+ *
+ * @param h sepol_handle (may be NULL)
+ * @param p sepol_parent from which to delete child
+ * @param iter iterator pointing to a child object of p
+ *
+ * \retval SEPOL_OK success
+ */
+extern int sepol_parent_del(struct sepol_handle *h, struct sepol_parent *p,
+ struct sepol_iter *iter);
+
+/**
+ * \ingroup sepol_policy
+ *
+ * Insert a child object into the list of children for the
+ * sepol_parent. See sepol_list_insert for more information on the
+ * semantics of this insert.
+ *
+ * @param h sepol_handle (may be NULL)
+ * @param p sepol_parent to which to insert child object
+ * @param iter iterator representing the position to insert the child object
+ * @param o child object to insert
+ *
+ * \retval SEPOL_OK success
+ * \retval SEPOL_EEXIST object is already a child of another parent
+ * \retval SEPOL_ENOMEM out of memory
+ */
+extern int sepol_parent_insert(struct sepol_handle *h, struct sepol_parent *p,
+ struct sepol_iter *iter, struct sepol_object *o);
+
+/**
+ * \ingroup sepol_policy
+ *
+ * Set an iterator to iterate over the children of an sepol_parent.
+ *
+ * @param h sepol_handle (may be NULL)
+ * @param p sepol_parent
+ * @param iter iterator to set to iterate over children
+ *
+ * \retval SEPOL_OK success
+ * \retval SEPOL_ENOMEM out of memory
+ */
+extern int sepol_parent_children(struct sepol_handle *h, struct sepol_parent *p,
+ struct sepol_iter *iter);
+
+/**
+ * \ingroup sepol_policy
+ *
+ * Return the list containing the children of the sepol_parent
+ * object. This is the actual list used to store children of the
+ * object, so changes will be reflected in the sepol_parent. It is
+ * important that deletions and insertions use sepol_parent_del and
+ * sepol_parent_insert or that the parent property of the objects
+ * is properly set.
+ *
+ * @param p sepol_parent
+ *
+ * \retval non-NULL pointer to the list of children
+ */
+struct sepol_list *sepol_parent_get_children(struct sepol_parent *parent);
+
+
+/**
+ * \ingroup sepol_policy
+ *
+ * Traversal of a policy tree rooted at a sepol_parent can take many
+ * forms. This enumeration is used to set the traversal strategy. See
+ * http://en.wikipedia.org/wiki/Tree_traversal for more information.
+ *
+ * The hybrid strategy combines both preorder and postorder
+ * traversal. This means that each parent node will be visited twice:
+ * once before its children are traversed and once afterward. The
+ * second traversal can be detected by checking the flag indicating
+ * that the parent has been visited (see sepol_parent_isvisited).
+ */
+enum sepol_parent_traverse_strategy {
+ SEPOL_TRAVERSE_POSTORDER, /** traverse the tree in postorder */
+ SEPOL_TRAVERSE_PREORDER, /** traverse the tree in preorder */
+ SEPOL_TRAVERSE_HYBRID /** traverse the tree combining preorder and postorder */
+};
+
+/**
+ * \ingroup sepol_policy
+ *
+ * Traverse a policy tree using parent as the root node of the tree. The traversal
+ * strategy is controlled by sepol_parent_traverse_strategy.
+ *
+ * @param h sepol_handle (may be null)
+ * @param parent sepol_parent
+ * @param iter iterator to represent traversal state
+ * @param strategy traversal strategy - see sepol_parent_traverse_strategy
+ *
+ * \retval SEPOL_OK success
+ * \retval SEPOL_ENOMEM out of memory
+ */
+extern int sepol_parent_traverse(struct sepol_handle *h, struct sepol_parent *parent,
+ struct sepol_iter *iter, int strategy);
+
+/**
+ * \ingroup sepol_policy
+ *
+ * Return whether an object has already been visited before during this tree
+ * traversal. See sepol_parent_traverse_strategy for more information.
+ *
+ * @param iter iterator
+ *
+ * \retval 0 object has not been previously visited
+ * \retval 1 object has been previously visited
+ */
+char sepol_parent_isvisited(struct sepol_iter *iter);
+
+struct sepol_policy;
+
+extern int sepol_policy_free(struct sepol_handle *h, struct sepol_policy *o);
+extern int sepol_policy_create(struct sepol_handle *h,
+ struct sepol_policy **policy);
+
+extern char sepol_policy_get_mls(struct sepol_policy *o);
+extern int sepol_policy_set_mls(struct sepol_policy *o, char mls);
+
+struct sepol_module;
+
+extern int sepol_module_free(struct sepol_handle *h, struct sepol_module *o);
+extern int sepol_module_create(struct sepol_handle *h,
+ struct sepol_module **module);
+extern int sepol_module_create_tree(struct sepol_handle *h,
+ struct sepol_module **module,
+ struct sepol_parent *root);
+
+int sepol_module_set_name(struct sepol_module *module, char *name);
+const char *sepol_module_get_name(struct sepol_module *module);
+
+int sepol_module_set_version(struct sepol_module *module, char *version);
+const char *sepol_module_get_version(struct sepol_module *module);
+
+int sepol_module_set_isbase(struct sepol_module *module, char isbase);
+char sepol_module_get_isbase(struct sepol_module *module);
+
+#endif
diff -r cacdf4377ebf -r bd4ee6e00a63 libsepol/src/policy.c
--- a/libsepol/src/policy.c Mon May 07 15:50:27 2007 -0400
+++ b/libsepol/src/policy.c Mon May 07 18:03:03 2007 -0400
@@ -0,0 +1,638 @@
+/*
+ * Author : Karl MacMillan <kmacmillan@mentalrootkit.com>
+ *
+ * Copyright (C) 2007 Red Hat, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include "policy_internal.h"
+#include "debug.h"
+#include "dso.h"
+
+#include <stdio.h>
+#include <string.h>
+#include <assert.h>
+
+/*
+ * SEPOL_OBJECT
+ */
+
+static char *typeid_strings[] = {
+ "none",
+ "object",
+ "parent",
+ "policy",
+ "module",
+ "block",
+ "cond",
+ "optional",
+ "type",
+ "class",
+ "attribute",
+ "typealias",
+ "boolean",
+ "avrule",
+ "typerule",
+ "security context",
+ "initial sid",
+ "typeattribute",
+ "conditional expression",
+ "sensitivity",
+ "dominance",
+ "category",
+ "role dominance",
+ "role"
+};
+
+const char *sepol_typeid_tostring(int typeid)
+{
+ assert(typeid < sizeof(typeid_strings));
+ return typeid_strings[typeid];
+}
+hidden_def(sepol_typeid_tostring)
+
+int sepol_object_free(struct sepol_handle *h, struct sepol_object *o)
+{
+ assert(o->methods->free);
+
+ return o->methods->free(h, o);
+}
+hidden_def(sepol_object_free)
+
+#define SEPOL_STRPOOL_SIZE 64
+int sepol_object_create_strpool(struct sepol_handle *h, struct sepol_object *o)
+{
+ int ret;
+
+ ret = sepol_objpool_create(h, &o->strpool, (sepol_objpool_hash_t)sepol_symhash,
+ (sepol_objpool_cmp_t)sepol_symcmp, free,
+ SEPOL_STRPOOL_SIZE);
+ ret_check(ret);
+ o->flags |= SEPOL_OBJECT_STRPOOL_OWNER;
+
+ return ret;
+}
+hidden_def(sepol_object_create_strpool)
+
+struct sepol_objpool *sepol_object_get_strpool(struct sepol_object *o)
+{
+ return o->strpool;
+}
+hidden_def(sepol_object_get_strpool)
+
+char sepol_object_is_strpool_owner(struct sepol_object *o)
+{
+ return (o->flags & SEPOL_OBJECT_STRPOOL_OWNER) != 0;
+}
+hidden_def(sepol_object_is_strpool_owner)
+
+uint32_t sepol_object_get_typeid(struct sepol_object *o)
+{
+ return o->typeid;
+}
+hidden_def(sepol_object_get_typeid)
+
+char sepol_object_isinstance(struct sepol_object *o, uint32_t typeid)
+{
+ if (o->typeid == typeid || o->sclass_typeid == typeid)
+ return 1;
+ else return 0;
+}
+hidden_def(sepol_object_isinstance)
+
+struct sepol_parent *sepol_object_get_parent(struct sepol_object *o)
+{
+ return o->parent;
+}
+hidden_def(sepol_object_get_parent)
+
+int sepol_object_tostring(struct sepol_handle *h, struct sepol_object *o,
+ int style, char **str)
+{
+ if (o->methods->tostring) {
+ return o->methods->tostring(h, o, style, str);
+ } else {
+ if (style == SEPOL_TOSTRING_DEBUG) {
+ return asprintf(str, "[sepol_object(%s) at %p]",
+ sepol_typeid_tostring(o->typeid), o);
+ }
+
+ /* Even though we are returning an empty string, we still
+ * need to allocated an empty string to return. This
+ * matches the behavior of asprintf.
+ */
+ *str = strdup("");
+ if (*str == NULL)
+ return -1;
+ return 0;
+ }
+}
+hidden_def(sepol_object_tostring)
+
+int sepol_object_tostring_close(struct sepol_handle *h, struct sepol_object *o,
+ int style, char **str)
+{
+ if (o->methods->tostring_close) {
+ return o->methods->tostring_close(h, o, style, str);
+ } else {
+ if (style == SEPOL_TOSTRING_DEBUG) {
+ return asprintf(str, "[close: sepol_object(%s) at %p]",
+ sepol_typeid_tostring(o->typeid), o);
+ }
+
+ /* Even though we are returning an empty string, we still
+ * need to allocated an empty string to return. This
+ * matches the behavior of asprintf.
+ */
+ *str = strdup("");
+ if (*str == NULL)
+ return -1;
+ return 0;
+ }
+}
+hidden_def(sepol_object_tostring_close)
+
+/*
+ * SEPOL_PARENT
+ */
+
+int sepol_parent_free_tree(struct sepol_handle *h, struct sepol_parent *p)
+{
+ int ret;
+ struct sepol_iter *iter;
+ struct sepol_object *cur;
+
+ ret = sepol_iter_create(h, &iter);
+ if (ret < 0)
+ goto out;
+
+ ret = sepol_parent_traverse(h, p, iter, SEPOL_TRAVERSE_POSTORDER);
+ if (ret < 0)
+ goto out;
+
+ sepol_foreach(h, ret, cur, iter) {
+ int ret2;
+ char *str;
+ ret2 = sepol_object_tostring(h, cur, SEPOL_TOSTRING_DEBUG, &str);
+ assert(ret2 >= 0);
+ printf("freeing %s", str);
+ sepol_object_free(h, cur);
+ free(str);
+ }
+ if (ret != SEPOL_ITERSTOP)
+ goto out;
+
+ ret = SEPOL_OK;
+out:
+ sepol_iter_free(h, iter);
+ return ret;
+}
+hidden_def(sepol_parent_free_tree)
+
+int sepol_parent_append(struct sepol_handle *h, struct sepol_parent *p, struct sepol_object *o)
+{
+ if (o->parent)
+ return SEPOL_EEXIST;
+ o->parent = p;
+ return sepol_list_append(h, p->children, o);
+}
+hidden_def(sepol_parent_append)
+
+int sepol_parent_extend(struct sepol_handle *h, struct sepol_parent *p, struct sepol_iter *iter)
+{
+ int ret = SEPOL_OK;
+ struct sepol_object *cur;
+
+ sepol_foreach(h, ret, cur, iter) {
+ ret = sepol_parent_append(h, p, cur);
+ if (ret < 0) {
+ return ret;
+ }
+ }
+ if (ret != SEPOL_ITERSTOP) {
+ return ret;
+ }
+
+ return SEPOL_OK;
+}
+hidden_def(sepol_parent_extend)
+
+int sepol_parent_extend_list(struct sepol_handle *h, struct sepol_parent *p, struct sepol_list *list)
+{
+ int ret;
+ struct sepol_iter *iter;
+
+ ret = sepol_iter_create(h, &iter);
+ if (ret < 0)
+ return ret;
+ ret = sepol_list_begin(h, list, iter);
+ if (ret < 0) {
+ if (ret == SEPOL_ITERSTOP)
+ return SEPOL_OK;
+ else
+ return ret;
+ }
+ ret = sepol_parent_extend(h, p, iter);
+ sepol_iter_free(h, iter);
+
+ return ret;
+}
+hidden_def(sepol_parent_extend_list)
+
+int sepol_parent_del(struct sepol_handle *h, struct sepol_parent *p, struct sepol_iter *iter)
+{
+ struct sepol_object *o;
+ o = (struct sepol_object*)sepol_iter_get_data(h, iter);
+ if (!o) {
+ ERR(h, "error getting object from iterator");
+ return SEPOL_ERR;
+ }
+ o->parent = NULL;
+ return sepol_list_del(h, p->children, iter);
+}
+hidden_def(sepol_parent_del)
+
+int sepol_parent_insert(struct sepol_handle *h, struct sepol_parent *p,
+ struct sepol_iter *iter, struct sepol_object *o)
+{
+ if (o->parent)
+ return SEPOL_EEXIST;
+ o->parent = p;
+
+ return sepol_list_insert(h, p->children, iter, o);
+}
+hidden_def(sepol_parent_insert)
+
+
+int sepol_parent_children(struct sepol_handle *h, struct sepol_parent *p, struct sepol_iter *iter)
+{
+ return sepol_list_begin(h, p->children, iter);
+}
+hidden_def(sepol_parent_children)
+
+struct sepol_list *sepol_parent_get_children(struct sepol_parent *parent)
+{
+ return parent->children;
+}
+hidden_def(sepol_parent_get_children)
+
+
+struct sepol_parent_traverse_state
+{
+ int strategy;
+ char cur_flags;
+ struct sepol_list *stack;
+ void *object;
+};
+
+static void *sepol_parent_iter_get_data(struct sepol_handle *h, struct sepol_iter *iter)
+{
+ struct sepol_parent_traverse_state *state;
+
+ assert(iter);
+ state = (struct sepol_parent_traverse_state*)
+ sepol_iter_get_state(iter);
+ assert(state);
+
+ return state->object;
+}
+
+static int sepol_parent_iter_free(struct sepol_handle *h, void *data)
+{
+ struct sepol_parent_traverse_state *state =
+ (struct sepol_parent_traverse_state*)data;
+
+ if (state == NULL)
+ return SEPOL_OK;
+
+ if (state->stack)
+ sepol_list_free(state->stack);
+ free(state);
+
+ return SEPOL_OK;
+}
+
+static int sepol_parent_traverse_preorder_next(struct sepol_handle *h, struct sepol_iter *iter)
+{
+ int ret;
+ struct sepol_parent_traverse_state *state;
+ struct sepol_object *object, *cur;
+ struct sepol_iter *child_iter;
+
+ state = sepol_iter_get_state(iter);
+
+ ret = sepol_list_pop_back(h, state->stack, (void**)&object);
+
+ if (ret == SEPOL_ERANGE)
+ return SEPOL_ITERSTOP;
+ else if (ret < 0)
+ return ret;
+
+ state->object = object;
+ state->cur_flags = object->flags;
+
+ if (sepol_object_isinstance(object, SEPOL_TYPEID_PARENT) &&
+ !(object->flags & SEPOL_OBJECT_VISITED)) {
+ if (state->strategy == SEPOL_TRAVERSE_HYBRID) {
+ object->flags |= SEPOL_OBJECT_VISITED;
+ ret = sepol_list_append(h, state->stack, object);
+ ret_check(ret);
+ }
+ ret = sepol_iter_create(h, &child_iter);
+ ret_check(ret);
+ ret = sepol_list_end(h, sepol_parent_get_children(SEPOL_PARENT(object)),
+ child_iter);
+ while (ret == SEPOL_OK) {
+ cur = sepol_iter_get_data(h, child_iter);
+ cur->flags &= ~SEPOL_OBJECT_VISITED;
+ ret = sepol_list_append(h, state->stack, cur);
+ if (ret < 0)
+ break;
+ ret = sepol_iter_prev(h, child_iter);
+ }
+ sepol_iter_free(h, child_iter);
+ if (ret < 0 && ret != SEPOL_ITERSTOP) {
+ return ret;
+ }
+
+ }
+ return SEPOL_OK;
+}
+
+static int sepol_parent_traverse_postorder_next(struct sepol_handle *h, struct sepol_iter *iter)
+{
+ int ret;
+ struct sepol_parent_traverse_state *state;
+ struct sepol_object *object, *cur;
+ struct sepol_iter *child_iter;
+
+ state = sepol_iter_get_state(iter);
+
+ while (1) {
+ ret = sepol_list_pop_back(h, state->stack, (void**)&object);
+
+ if (ret == SEPOL_ERANGE)
+ return SEPOL_ITERSTOP;
+ else if (ret < 0)
+ return ret;
+
+ if (object->flags & SEPOL_OBJECT_VISITED ||
+ !sepol_object_isinstance(object, SEPOL_TYPEID_PARENT)) {
+ state->object = object;
+ break;
+ } else {
+ object->flags |= SEPOL_OBJECT_VISITED;
+ ret = sepol_list_append(h, state->stack, object);
+ ret_check(ret);
+
+ ret = sepol_iter_create(h, &child_iter);
+ ret_check(ret);
+ ret = sepol_list_end(h, sepol_parent_get_children(SEPOL_PARENT(object)),
+ child_iter);
+ while (ret == SEPOL_OK) {
+ cur = sepol_iter_get_data(h, child_iter);
+ cur->flags &= ~SEPOL_OBJECT_VISITED;
+ ret = sepol_list_append(h, state->stack, cur);
+ if (ret < 0)
+ break;
+ ret = sepol_iter_prev(h, child_iter);
+ }
+ sepol_iter_free(h, child_iter);
+ if (ret < 0 && ret != SEPOL_ITERSTOP) {
+ return ret;
+ }
+ }
+ }
+ return SEPOL_OK;
+}
+
+int sepol_parent_traverse(struct sepol_handle *h, struct sepol_parent *parent,
+ struct sepol_iter *iter, int strategy)
+{
+ int ret;
+ struct sepol_parent_traverse_state *state = NULL;
+
+ state = calloc(1, sizeof(struct sepol_parent_traverse_state));
+ if (state == NULL)
+ return SEPOL_ENOMEM;
+
+ ret = sepol_list_create(h, &state->stack);
+ ret_goto(ret, err);
+
+ state->strategy = strategy;
+ sepol_iter_set_state(iter, state);
+
+ if (state->strategy == SEPOL_TRAVERSE_POSTORDER)
+ sepol_iter_set_next(iter, sepol_parent_traverse_postorder_next);
+ else if (state->strategy == SEPOL_TRAVERSE_PREORDER ||
+ state->strategy == SEPOL_TRAVERSE_HYBRID)
+ sepol_iter_set_next(iter, sepol_parent_traverse_preorder_next);
+ else
+ return SEPOL_ERR;
+ sepol_iter_set_free(iter, sepol_parent_iter_free);
+ sepol_iter_set_get_data(iter, sepol_parent_iter_get_data);
+
+
+ parent->sclass.flags &= ~SEPOL_OBJECT_VISITED;
+ ret = sepol_list_append(h, state->stack, parent);
+ ret_goto(ret, err);
+ ret = sepol_iter_next(h, iter);
+ ret_goto(ret, err);
+
+ return SEPOL_OK;
+err:
+ sepol_parent_iter_free(h, state);
+ return ret;
+}
+hidden_def(sepol_parent_traverse)
+
+char sepol_parent_isvisited(struct sepol_iter *iter)
+{
+ struct sepol_parent_traverse_state *state;
+
+ state = sepol_iter_get_state(iter);
+ if (state->cur_flags & SEPOL_OBJECT_VISITED)
+ return 1;
+ else
+ return 0;
+}
+hidden_def(sepol_parent_isvisited)
+
+/*
+ * SEPOL_POLICY
+ */
+
+struct sepol_policy
+{
+ struct sepol_parent sclass;
+ char mls;
+};
+
+int sepol_policy_free(struct sepol_handle *h, struct sepol_policy *o)
+{
+ intern_sepol_parent_free(SEPOL_PARENT(o));
+ free(o);
+
+ return SEPOL_OK;
+}
+
+static int sepol_policy_tostring(struct sepol_handle *h,
+ struct sepol_object * object __attribute__ ((unused)),
+ int style, char **str)
+{
+ if (style == SEPOL_TOSTRING_DEBUG) {
+ return asprintf(str, "POLICY {");
+ } else {
+ *str = strdup("");
+ if (*str)
+ return 0;
+ else
+ return -1;
+ }
+}
+
+static int sepol_policy_tostring_close(struct sepol_handle *h __attribute__ ((unused)),
+ struct sepol_object *object __attribute__ ((unused)),
+ int style, char **str)
+{
+ if (style == SEPOL_TOSTRING_DEBUG) {
+ return asprintf(str, "POLICY {");
+ } else {
+ *str = strdup("");
+ if (*str)
+ return 0;
+ else
+ return -1;
+ }
+}
+
+static struct sepol_object_methods sepol_policy_methods = {
+ .free = (sepol_object_free_t)sepol_policy_free,
+ .tostring = sepol_policy_tostring,
+ .tostring_close = sepol_policy_tostring_close
+};
+
+int sepol_policy_create(struct sepol_handle *h, struct sepol_policy **policy)
+{
+ int ret;
+ struct sepol_policy *x;
+
+ *policy = NULL;
+ x = calloc(1, sizeof(struct sepol_policy));
+ if (x == NULL) {
+ return SEPOL_ENOMEM;
+ }
+
+ ret = intern_sepol_parent_init(h, SEPOL_PARENT(x), SEPOL_TYPEID_POLICY,
+ &sepol_policy_methods, NULL);
+ ret_goto(ret, out);
+
+ /* policy always has a strpool for convenience */
+ ret = sepol_object_create_strpool(h, SEPOL_OBJECT(x));
+ ret_goto(ret, out);
+
+ *policy = x;
+ return SEPOL_OK;
+out:
+ intern_sepol_parent_free(SEPOL_PARENT(x));
+ return ret;
+}
+
+DEFINE_BOOL_PROP(policy, mls)
+
+/*
+ * SEPOL_MODULE
+ */
+
+struct sepol_module
+{
+ struct sepol_parent sclass;
+ char *name;
+ char *version;
+ char isbase;
+};
+
+int sepol_module_free(struct sepol_handle *h, struct sepol_module *o)
+{
+ int ret;
+
+ ret = intern_sepol_object_delstr(h, o, o->name);
+ ret_check(ret);
+
+ ret = intern_sepol_object_delstr(h, o, o->version);
+ ret_check(ret);
+
+ intern_sepol_parent_free(SEPOL_PARENT(o));
+
+ free(o);
+
+ return SEPOL_OK;
+}
+hidden_def(sepol_module_free)
+
+static int sepol_module_tostring(struct sepol_handle *h, struct sepol_object *object,
+ int style, char **str)
+{
+ struct sepol_module *module = (struct sepol_module *)object;
+
+ if (module->name == NULL || module->version == NULL)
+ return -1;
+
+ if (style == SEPOL_TOSTRING_REFPOL)
+ return asprintf(str, "policy_module(%s %s)", module->name,
+ module->version);
+ else
+ return asprintf(str, "module %s %s;", module->name, module->version);
+}
+
+static struct sepol_object_methods sepol_module_methods = {
+ .free = (sepol_object_free_t)sepol_module_free,
+ .tostring = sepol_module_tostring
+};
+
+int sepol_module_create(struct sepol_handle *h, struct sepol_module **module)
+{
+ return sepol_module_create_tree(h, module, NULL);
+}
+hidden_def(sepol_module_create)
+
+int sepol_module_create_tree(struct sepol_handle *h, struct sepol_module **module,
+ struct sepol_parent *root)
+{
+ int ret;
+ struct sepol_module *x;
+
+ *module = NULL;
+ x = calloc(1, sizeof(struct sepol_module));
+ if (x == NULL) {
+ return SEPOL_ENOMEM;
+ }
+
+ ret = intern_sepol_parent_init(h, SEPOL_PARENT(x), SEPOL_TYPEID_MODULE,
+ &sepol_module_methods, root);
+ ret_goto(ret, out);
+
+ *module = x;
+ return SEPOL_OK;
+out:
+ free(x);
+ return ret;
+}
+hidden_def(sepol_module_create_tree)
+
+DEFINE_STR_PROP(module, name)
+DEFINE_STR_PROP(module, version)
+DEFINE_BOOL_PROP(module, isbase)
diff -r cacdf4377ebf -r bd4ee6e00a63 libsepol/src/policy_internal.c
--- a/libsepol/src/policy_internal.c Mon May 07 15:50:27 2007 -0400
+++ b/libsepol/src/policy_internal.c Mon May 07 18:03:03 2007 -0400
@@ -0,0 +1,102 @@
+/*
+ * Author : Karl MacMillan <kmacmillan@mentalrootkit.com>
+ *
+ * Copyright (C) 2007 Red Hat, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include "policy_internal.h"
+
+int intern_sepol_object_init(struct sepol_handle *h, struct sepol_object *o, uint32_t typeid,
+ struct sepol_object_methods *methods, struct sepol_parent *root)
+{
+ memset(o, 0, sizeof(struct sepol_object));
+ o->sclass_typeid = SEPOL_TYPEID_OBJECT;
+ o->typeid = typeid;
+ o->methods = methods;
+ if (root && sepol_object_get_strpool(SEPOL_OBJECT(root)))
+ o->strpool = sepol_object_get_strpool(SEPOL_OBJECT(root));
+
+
+ return 0;
+}
+
+void intern_sepol_object_free(struct sepol_object *o)
+{
+ if (o == NULL)
+ return;
+
+ if (o->flags & SEPOL_OBJECT_STRPOOL_OWNER)
+ sepol_objpool_free(NULL, o->strpool);
+}
+
+int _intern_sepol_object_addstr(struct sepol_handle *h, struct sepol_object *o, char **str)
+{
+ char *tmp;
+
+ tmp = strdup(*str);
+ if (!tmp)
+ return SEPOL_ENOMEM;
+
+ *str = tmp;
+
+ if (o->strpool) {
+ *str = sepol_objpool_add(h, o->strpool, *str);
+ if (!*str)
+ return SEPOL_ENOMEM;
+ }
+
+ return SEPOL_OK;
+}
+
+int _intern_sepol_object_delstr(struct sepol_handle *h, struct sepol_object *o, char *str)
+{
+ int ret;
+
+ if (str == NULL)
+ return SEPOL_OK;
+
+ if (o->strpool) {
+ ret = sepol_objpool_del(h, o->strpool, str);
+ return ret;
+ } else {
+ free(str);
+ return SEPOL_OK;
+ }
+}
+
+int intern_sepol_parent_init(struct sepol_handle *h, struct sepol_parent *p, uint32_t typeid,
+ struct sepol_object_methods *methods, struct sepol_parent *root)
+{
+ int ret;
+
+ ret = intern_sepol_object_init(h, SEPOL_OBJECT(p), typeid, methods, root);
+ ret_check(ret);
+ p->sclass.sclass_typeid = SEPOL_TYPEID_PARENT;
+
+ ret = sepol_list_create(h, &p->children);
+ if (ret < 0)
+ sepol_object_free(h, SEPOL_OBJECT(p));
+
+ return ret;
+}
+
+void intern_sepol_parent_free(struct sepol_parent *p)
+{
+ intern_sepol_object_free(SEPOL_OBJECT(p));
+
+ sepol_list_free(p->children);
+}
diff -r cacdf4377ebf -r bd4ee6e00a63 libsepol/src/policy_internal.h
--- a/libsepol/src/policy_internal.h Mon May 07 15:50:27 2007 -0400
+++ b/libsepol/src/policy_internal.h Mon May 07 18:03:03 2007 -0400
@@ -0,0 +1,269 @@
+#ifndef __policy_internal_h__
+#define __policy_internal_h__
+
+#include "dso.h"
+
+#include <sepol/policy.h>
+#include <sepol/policydb/policydb.h>
+#include <sepol/policydb/conditional.h>
+
+#include <stdlib.h>
+#include <sys/types.h>
+
+/* Internal structs and functions for the policy object system. In
+ * general, policy objects cannot be created outside of the libsepol
+ * tree. It is possible, but not currently implemented, so there is
+ * quite a lot of internals in this header.
+ *
+ * One of the goals of this object system is to allow polymorphic
+ * methods. That will allow calling , for example, sepol_object_free
+ * on _any_ subclass of sepol_object and have the correct function
+ * called for the specific subclass. This polymorphism is implemented
+ * using an sepol_object_method struct for each class and a pointer to
+ * that struct held in each object instance.
+ *
+ * A subclass is expected to create an sepol_object_methods struct
+ * containing function pointers for the methods that it implements (it
+ * is valid for some of the function pointers to be NULL). Every
+ * instance of an sepol_object object holds a pointer to a single
+ * methods struct - i.e., there is only one struct per class and every
+ * instance holds a pointer to that struct.
+ *
+ * See sepol_object_init for how this pointer is set and sepol_object_free
+ * for how subclass methods are called.
+ */
+
+/* sepol_object_free_t is the type for the free method used in the policy
+ * object system. Implementations of this method should free all of the
+ * memory associated with the object including the struct.
+ */
+typedef int (*sepol_object_free_t)(struct sepol_handle *h, struct sepol_object *o);
+typedef int (*sepol_object_tostring_t)(struct sepol_handle *h, struct sepol_object *o,
+ int style, char **str);
+
+struct sepol_object_methods
+{
+ sepol_object_free_t free;
+ sepol_object_tostring_t tostring;
+ sepol_object_tostring_t tostring_close;
+};
+
+#define SEPOL_OBJECT_STRPOOL_OWNER 1
+#define SEPOL_OBJECT_VISITED 2
+struct sepol_object
+{
+ struct sepol_object_methods *methods;
+ struct sepol_parent *parent;
+ struct sepol_objpool *strpool;
+ uint32_t sclass_typeid;
+ uint32_t typeid;
+ uint32_t lineno;
+ char flags;
+};
+
+/* Private initialization function for all objects. This function only
+ * initializes the generic object properties - the type specific creation
+ * function is responsible for initializing any type specific properties.
+ * If this function fails it will clean up any memory that it allocated. The
+ * calling function is responsible for any type specific memory and for freeing
+ * the object struct.
+ *
+ * params:
+ * o - object to initialize
+ * typeid - typeid of o
+ * methods - pointer to sepol_object_methods struct for this type. Should
+ * be a pointer to a single static struct for all instances of this type.
+ * root - root of the policy tree of which o is a member (may be NULL). If
+ * the root is non-NULL and has a string pool then that string pool is
+ * used for this object.
+ */
+int intern_sepol_object_init(struct sepol_handle *h, struct sepol_object *o, uint32_t typeid,
+ struct sepol_object_methods *methods, struct sepol_parent *root);
+
+/* Free any memory associated with the super class. This should be called
+ * from a type specific free function.
+ */
+void intern_sepol_object_free(struct sepol_object *o);
+
+/* Add a string to the string pool of the object. After a call to this
+ * function the str pointer will point to the correct (and possibly
+ * shared) version of the string to use.
+ */
+#define intern_sepol_object_addstr(h, o, str) _intern_sepol_object_addstr(h, SEPOL_OBJECT(o), str)
+int _intern_sepol_object_addstr(struct sepol_handle *h, struct sepol_object *o, char **str);
+
+/* Delete a string. If the object has a string pool the memory
+ * associated with the string may not be released
+ * immediately. Regardless, the caller should assume that the pointer
+ * is invalid after a call to this function.
+ */
+#define intern_sepol_object_delstr(h, o, str) _intern_sepol_object_delstr(h, SEPOL_OBJECT(o), str)
+int _intern_sepol_object_delstr(struct sepol_handle *h, struct sepol_object *o, char *str);
+
+hidden_proto(sepol_typeid_tostring)
+hidden_proto(sepol_object_free)
+hidden_proto(sepol_object_create_strpool)
+hidden_proto(sepol_object_get_strpool)
+hidden_proto(sepol_object_is_strpool_owner)
+hidden_proto(sepol_object_get_typeid)
+hidden_proto(sepol_object_isinstance)
+hidden_proto(sepol_object_get_parent)
+hidden_proto(sepol_object_tostring)
+hidden_proto(sepol_object_tostring_close)
+
+struct sepol_parent
+{
+ struct sepol_object sclass;
+ struct sepol_list *children;
+};
+
+/* Initialize an sepol_parent object. Same function and general
+ * properties as intern_sepol_object_init but for parent
+ * objects. Objects should only call the init function for their
+ * immediate parent - the parent is responsible for any further
+ * chaining up the type hierarchy.
+ */
+int intern_sepol_parent_init(struct sepol_handle *h, struct sepol_parent *p, uint32_t typeid,
+ struct sepol_object_methods *methods, struct sepol_parent *root);
+
+/* Internal free function for sepol_paren objects. Like the init functions
+ * this chains up the type hierarchy by call inter_sepol_object_free.
+ */
+void intern_sepol_parent_free(struct sepol_parent *p);
+
+hidden_proto(sepol_parent_free_tree)
+hidden_proto(sepol_parent_append)
+hidden_proto(sepol_parent_extend)
+hidden_proto(sepol_parent_extend_list)
+hidden_proto(sepol_parent_del)
+hidden_proto(sepol_parent_insert)
+hidden_proto(sepol_parent_children)
+hidden_proto(sepol_parent_get_children)
+hidden_proto(sepol_parent_traverse)
+hidden_proto(sepol_parent_isvisited)
+
+/* sepol_policy */
+hidden_proto(sepol_policy_free)
+hidden_proto(sepol_policy_get_mls)
+hidden_proto(sepol_policy_set_mls)
+
+/* sepol_module */
+hidden_proto(sepol_module_free)
+hidden_proto(sepol_module_create)
+hidden_proto(sepol_module_create_tree)
+hidden_proto(sepol_module_set_name)
+hidden_proto(sepol_module_get_name)
+hidden_proto(sepol_module_set_version)
+hidden_proto(sepol_module_get_version)
+hidden_proto(sepol_module_set_isbase)
+hidden_proto(sepol_module_get_isbase)
+
+
+/* some convenience macros to check return values */
+#define ret_check(ret) { if (ret < 0) return ret; }
+#define ret_goto(ret, tag) { if (ret < 0) goto tag; }
+
+
+/*
+ * PROPERTY GENERATION MACROS
+ *
+ * Many of the objects are similar and will have almost identical
+ * functions for getting and setting properties. These macros generate
+ * those functions for brevity and correctness.
+ */
+
+/* Initialize an object set for holding strings. This should be used
+ * in an object creation function to initialize a string set. This
+ * handles object pooling.
+ */
+#define INIT_STRSET(obj, set, ret, target) { \
+ if (SEPOL_OBJECT(obj)->strpool) { \
+ ret = sepol_objset_create(&obj->set, sepol_policy_ptrcmp); \
+ ret_goto(ret, target); \
+ } else { \
+ ret = sepol_objset_create(&obj->set, \
+ (sepol_objset_cmp_t)sepol_policy_strcmp); \
+ ret_goto(ret, target); \
+ } }
+
+#define DESTROY_STRSET(obj, set, iter, ret) { \
+ if (obj->set != NULL) { \
+ ret = sepol_iter_create(&iter); \
+ ret_check(ret); \
+ ret = sepol_objset_iter(obj->set, iter); \
+ if (ret < 0 && ret != SEPOL_ITERSTOP) return ret; \
+ while (ret == SEPOL_OK) { \
+ ret = intern_sepol_object_delstr(obj, sepol_iter_get_data(iter)); \
+ ret_check(ret); \
+ ret = sepol_iter_next(iter); \
+ } \
+ sepol_iter_destroy(iter); \
+ if (ret != SEPOL_ITERSTOP) return ret; \
+ } \
+ sepol_objset_destroy(obj->set); }
+
+
+#define DEFINE_STR_PROP(obj, prop) \
+ int sepol_##obj##_set_##prop(struct sepol_##obj *x, char *prop) \
+ { \
+ int ret; \
+ if (x-> prop ) { \
+ ret = intern_sepol_object_delstr(NULL, x, x-> prop ); \
+ ret_check(ret); \
+ } \
+ x-> prop = prop; \
+ return intern_sepol_object_addstr(NULL, x, &x-> prop ); \
+ } \
+ hidden_def(sepol_##obj##_set_##prop) \
+ const char *sepol_##obj##_get_##prop(struct sepol_##obj *x) \
+ { \
+ return x-> prop ; \
+ } \
+ hidden_def(sepol_##obj##_get_##prop)
+
+#define DEFINE_BOOL_PROP(obj, prop) \
+ int sepol_##obj##_set_##prop(struct sepol_##obj *x, char prop) \
+ { \
+ x-> prop = prop; \
+ return SEPOL_OK; \
+ } \
+ hidden_def(sepol_##obj##_set_##prop) \
+ char sepol_##obj##_get_##prop(struct sepol_##obj *x) \
+ { \
+ return x-> prop ; \
+ } \
+ hidden_def(sepol_##obj##_get_##prop)
+
+#define DEFINE_UINT_PROP(obj, prop) \
+ int sepol_##obj##_set_##prop(struct sepol_##obj *x, uint32_t prop) \
+ { \
+ x->prop = prop; \
+ return SEPOL_OK; \
+ } \
+ hidden_def(sepol_##obj##_set_##prop) \
+ uint32_t sepol_##obj##_get_##prop(struct sepol_##obj *x) \
+ { \
+ return x->prop ; \
+ } \
+ hidden_def(sepol_##obj##_get_##prop)
+
+#define DEFINE_STRSET_PROP(obj, prop, set) \
+ int sepol_##obj##_add_##prop(struct sepol_##obj *x, char *prop) \
+ { \
+ int ret; \
+ char *tmp = strdup(prop); \
+ ret = intern_sepol_object_addstr(x, &tmp); \
+ ret_check(ret); \
+ ret = sepol_objset_add(x->set, tmp); \
+ ret_check(ret); \
+ return SEPOL_OK; \
+ } \
+ hidden_def(sepol_##obj##_set_##prop) \
+ struct sepol_objset *sepol_##obj##_get_##set(struct sepol_##obj *x) \
+ { \
+ return x->set; \
+ } \
+ hidden_def(sepol_##obj##_get_##prop)
+
+
+#endif
diff -r cacdf4377ebf -r bd4ee6e00a63 libsepol/tests/libsepol-tests.c
--- a/libsepol/tests/libsepol-tests.c Mon May 07 15:50:27 2007 -0400
+++ b/libsepol/tests/libsepol-tests.c Mon May 07 18:03:03 2007 -0400
@@ -26,6 +26,7 @@
#include "test-hashtab.h"
#include "test-objpool.h"
#include "test-objset.h"
+#include "test-policy.h"
#include <CUnit/Basic.h>
#include <CUnit/Console.h>
@@ -61,14 +62,15 @@ static int do_tests(int interactive, int
if (CUE_SUCCESS != CU_initialize_registry())
return CU_get_error();
- DECLARE_SUITE(cond);
- DECLARE_SUITE(linker);
- DECLARE_SUITE(expander);
- DECLARE_SUITE(deps);
+ //DECLARE_SUITE(cond);
+ //DECLARE_SUITE(linker);
+ //DECLARE_SUITE(expander);
+ //DECLARE_SUITE(deps);
DECLARE_SUITE(list);
DECLARE_SUITE(hashtab);
DECLARE_SUITE(objpool);
DECLARE_SUITE(objset);
+ DECLARE_SUITE(policy);
if (verbose)
CU_basic_set_mode(CU_BRM_VERBOSE);
diff -r cacdf4377ebf -r bd4ee6e00a63 libsepol/tests/test-policy.c
--- a/libsepol/tests/test-policy.c Mon May 07 15:50:27 2007 -0400
+++ b/libsepol/tests/test-policy.c Mon May 07 18:03:03 2007 -0400
@@ -0,0 +1,118 @@
+/*
+ * Author : Karl MacMillan <kmacmillan@mentalrootkit.com>
+ *
+ * Copyright (C) 2007 Red Hat, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include "test-policy.h"
+
+#include <sepol/policy.h>
+#include <sepol/iter.h>
+#include <sepol/errcodes.h>
+
+#include <stdlib.h>
+#include <stdio.h>
+
+int policy_test_init(void)
+{
+ return 0;
+}
+
+int policy_test_cleanup(void)
+{
+ return 0;
+}
+
+static void test_policy(void)
+{
+ int ret;
+ char *str;
+
+ struct sepol_handle *h;
+ struct sepol_iter *iter;
+ struct sepol_object *cur;
+
+ struct sepol_policy *policy;
+ struct sepol_module *module;
+
+ h = sepol_handle_create();
+ CU_ASSERT(h != NULL);
+
+ ret = sepol_policy_create(h, &policy);
+ CU_ASSERT(ret == SEPOL_OK);
+
+ ret = sepol_module_create_tree(h, &module, SEPOL_PARENT(policy));
+ CU_ASSERT(ret == SEPOL_OK);
+
+ ret = sepol_module_set_isbase(module, 0);
+ CU_ASSERT(ret == SEPOL_OK);
+
+ ret = sepol_module_set_name(module, strdup("foo"));
+ CU_ASSERT(ret == SEPOL_OK);
+
+ ret = sepol_module_set_version(module, strdup("1.0"));
+ CU_ASSERT(ret == SEPOL_OK);
+
+ ret = sepol_parent_append(h, SEPOL_PARENT(policy), SEPOL_OBJECT(module));
+ CU_ASSERT(ret == SEPOL_OK);
+
+ ret = sepol_module_create_tree(h, &module, SEPOL_PARENT(policy));
+ CU_ASSERT(ret == SEPOL_OK);
+
+ ret = sepol_module_set_isbase(module, 1);
+ CU_ASSERT(ret == SEPOL_OK);
+
+ ret = sepol_module_set_name(module, strdup("bar"));
+ CU_ASSERT(ret == SEPOL_OK);
+
+ ret = sepol_module_set_version(module, strdup("1.0"));
+ CU_ASSERT(ret == SEPOL_OK);
+
+ ret = sepol_parent_append(h, SEPOL_PARENT(policy), SEPOL_OBJECT(module));
+ CU_ASSERT(ret == SEPOL_OK);
+
+
+ ret = sepol_iter_create(h, &iter);
+ CU_ASSERT(ret == SEPOL_OK);
+ ret = sepol_parent_traverse(h, SEPOL_PARENT(policy), iter, SEPOL_TRAVERSE_POSTORDER);
+ CU_ASSERT(ret == SEPOL_OK);
+
+ sepol_foreach(h, ret, cur, iter) {
+ ret = sepol_object_tostring(h, cur, SEPOL_TOSTRING_DEBUG, &str);
+ CU_ASSERT(ret >= 0);
+ printf("%s\n", str);
+ free(str);
+ }
+ CU_ASSERT(ret == SEPOL_ITERSTOP);
+
+ //ret = sepol_parent_output_tree(SEPOL_PARENT(policy), stdout, SEPOL_DEBUG_OUTPUT);
+
+ ret = sepol_parent_free_tree(h, SEPOL_PARENT(policy));
+ CU_ASSERT(ret == SEPOL_OK);
+ sepol_iter_free(h, iter);
+ sepol_handle_destroy(h);
+}
+
+int policy_add_tests(CU_pSuite suite)
+{
+ if (NULL == CU_add_test(suite, "test_policy",
+ test_policy)) {
+ return -1;
+ }
+
+ return 0;
+}
diff -r cacdf4377ebf -r bd4ee6e00a63 libsepol/tests/test-policy.h
--- a/libsepol/tests/test-policy.h Mon May 07 15:50:27 2007 -0400
+++ b/libsepol/tests/test-policy.h Mon May 07 18:03:03 2007 -0400
@@ -0,0 +1,12 @@
+/* Author : Karl MacMillan <kmacmillan@mentalrootkit.com> */
+
+#ifndef __test_policy_h__
+#define __test_policy_h__
+
+#include <CUnit/Basic.h>
+
+int policy_test_init(void);
+int policy_test_cleanup(void);
+int policy_add_tests(CU_pSuite suite);
+
+#endif
--
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] 25+ messages in thread
* Re: [PATCH] Basic policy representation
2007-05-07 22:06 [PATCH] Basic policy representation Karl MacMillan
@ 2007-05-08 14:45 ` Joshua Brindle
2007-05-08 15:08 ` Karl MacMillan
2007-05-08 16:50 ` Stephen Smalley
2007-05-09 16:24 ` James Antill
2007-05-09 18:35 ` J. Tang
2 siblings, 2 replies; 25+ messages in thread
From: Joshua Brindle @ 2007-05-08 14:45 UTC (permalink / raw)
To: Karl MacMillan; +Cc: selinux
Karl MacMillan wrote:
> Add support for the basic policy object model and the sepol_policy
> and sepol_module objects to libsepol. This version has significant
> changes from the last posted version:
>
> 1) sepol_handle is passed everywhere
> 2) public and private interfaces to the object system are correctly
> split (into policy.[c,h] and policy_internal.[c,h].
> 3) object ouput has been converted from writing to a FILE to returning
> allocated strings. This will help integrate better with scripting
> languages.
> 4) Basic documentation is included for the base objects.
> 5) Enums are used instead of defines - this is a change from the style
> for libsepol, but it makes documenting the enums much easier.
>
> Signed-off-by: User "Karl MacMillan <kmacmillan@mentalrootkit.com>"
> ---
>
> 7 files changed, 1667 insertions(+), 4 deletions(-)
> libsepol/include/sepol/policy.h | 522 +++++++++++++++++++++++++++++++
> libsepol/src/policy.c | 638 +++++++++++++++++++++++++++++++++++++++
> libsepol/src/policy_internal.c | 102 ++++++
> libsepol/src/policy_internal.h | 269 ++++++++++++++++
> libsepol/tests/libsepol-tests.c | 10
> libsepol/tests/test-policy.c | 118 +++++++
> libsepol/tests/test-policy.h | 12
>
>
> diff -r cacdf4377ebf -r bd4ee6e00a63 libsepol/include/sepol/policy.h
> --- a/libsepol/include/sepol/policy.h Mon May 07 15:50:27 2007 -0400
> +++ b/libsepol/include/sepol/policy.h Mon May 07 18:03:03 2007 -0400
> @@ -0,0 +1,522 @@
> +/* Author : Karl MacMillan <kmacmillan@mentalrootkit.com> */
> +
> +#ifndef __sepol_policy_h__
> +#define __sepol_policy_h__
> +
> +#include <sepol/handle.h>
> +
> +#include <sepol/objpool.h>
> +#include <sepol/objset.h>
> +#include <sepol/list.h>
> +
> +#include <sys/types.h>
> +#include <stdint.h>
> +#include <stdio.h>
> +
> +/**
> + * \defgroup sepol_policy sepol_policy: policy representation
> + * Introduction to the policy object system
> + *
> + *
> + * The policy is represented as a tree of objects that loosely
> + * resemble an abstract syntax tree or intermediate representation
> + * commonly found in compilers. This tree representation is used as
> + * the output of the policy parser the format for selinux policy
> + * modules. The data structures are also intended to be flexible
> + * enough to represent an selinux policy for syntax/semantic checking,
> + * analysis, generation, and storage.
> + *
> + * The basic structure is that of a tree holding selinux policy
> + * language components (e.g., type declarations, rules, conditional
> + * blocks, etc.). To implement this tree structure in a form that can
> + * be processed easily, a basic object orientied structure is
> + * implemented in C.
> + *
> + * The object oriented system allows the use of polymorphic functions,
> + * making it possible to process objects in the tree with only limited
> + * informatio about the specific types (e.g., it is possible to
> + * traverse the tree and output all of the objects as strings without
> + * the traversal function knowing detailed type information about each
> + * object - it simple class sepol_object_strout on each object).
> + *
> + * See sepol_object and sepol_parent for more information on this object
> + * oriented type system.
> + *
> + */
> +
> +/**
> + * \ingroup sepol_policy
> + *
> + * Every type in the policy object system is identified
> + * by a numberic typeid.
> + */
> +enum sepol_typeid {
> + SEPOL_TYPEID_NONE, /** special typeid representing no type */
> + SEPOL_TYPEID_OBJECT, /** typeid for base class of all objects */
> + SEPOL_TYPEID_PARENT, /** typeid for base class of objects that contain other objects */
> + SEPOL_TYPEID_POLICY, /** typeid for policy object */
> + SEPOL_TYPEID_MODULE, /** typeid for the module object */
> + SEPOL_TYPEID_BLOCK, /** tyepid for the block object */
> + SEPOL_TYPEID_COND, /** typeid for the cond object */
> + SEPOL_TYPEID_OPTIONAL, /** typeid for the optional object */
> + SEPOL_TYPEID_TYPE, /** typed for the type object */
> + SEPOL_TYPEID_CLASS, /** typeid for the class object */
> + SEPOL_TYPEID_ATTRIBUTE, /** typeid for the attribute object */
> + SEPOL_TYPEID_TYPEALIAS, /** typeid for the typealias object */
> + SEPOL_TYPEID_BOOL, /** typeid for the bool object */
> + SEPOL_TYPEID_AVRULE, /** typeid for the avrule object */
> + SEPOL_TYPEID_TYPERULE, /** typeid for the typerule object */
> + SEPOL_TYPEID_SECURITY_CONTEXT, /** typeid for the securit context object */
> + SEPOL_TYPEID_ISID, /** typeid for the isid object */
> + SEPOL_TYPEID_TYPEATTRIBUTE, /** typeid for the typeattribute object */
> + SEPOL_TYPEID_COND_EXPR, /** typeid for the cond expr object */
> + SEPOL_TYPEID_SENS, /** typeid for the sends object */
> + SEPOL_TYPEID_DOMINANCE, /** typeid for the dominance object */
> + SEPOL_TYPEID_CATEGORY, /** typeid for the category object */
> + SEPOL_TYPEID_ROLE_DOMINANCE, /** typeid for the role dominance object */
> + SEPOL_TYPEID_ROLE /** typeid for the role object */
> +};
>
Do you think typeid is really a good word to use here? This is possibly
very confusing (others have already mentioned to me that it was confusing)
> +
> +/**
> + * \ingroup sepol_policy
> + *
> + * Convert a typeid to a string representation. The returned string
> + * is constant and should not be altered or freed.
> + *
> + * @param typeid typeid to convert to string
> + *
> + * \retval string string representing the typeid
> + */
> +const char *sepol_typeid_tostring(int typeid);
> +
> +/**
> + * \ingroup sepol_policy
> + * \struct sepol_object
> + *
> + * sepol_object is the base class of all objects in this type system.
> + * There is no way to directly create an sepol_object - it is an
> + * abstract base class.
> + *
> + * The type system works by:
> + * - mandating that sepol_object (or one of its subclasses) be the
> + * first entry in every struct. This allows the structs to be
> + * freely cast to an sepol_object or any of the other objects
> + * in the hierarchy of that struct.
> + * - Storing information about the types in the form of IDs. This
> + * allows callers to determine type information at runtime.
> + * - Storing function pointers to class specific function
> + * implementations in each object instance. This allows functions
> + * to have a limited form of polymorphism.
> + *
> + * sepol_object is also the parent class of all objects that are
> + * exclusively leaves in the tree (i.e., objects that cannot contain
> + * other objects).
> + *
> + * Properties that all sepol_objects share:
> + * - string pool (strpool): [optional] an objpool for storing
> + * strings stored in the objects. The object may be the owner of
> + * the string pool (see sepol_object_is_strpool_owner), reference
> + * the string pool of another object (usually the root of a policy
> + * tree), or not have a string pool at all.
> + * - type identifier (typeid): The sepol_typeid for this object.
> + */
> +struct sepol_object;
> +
> +/**
> + * \ingroup sepol_policy
> + *
> + * Convert an object to an sepol_object
> + *
> + * @param x object
> + */
> +#define SEPOL_OBJECT(x) ((struct sepol_object *)x)
> +
> +/**
> + * \ingroup sepol_policy
> + *
> + * Free an sepol_object. This can be called for any
> + * subclass of sepol_object.
> + *
> + * @param n object to free
> + *
> + * \retval SEPOL_OK success
> + * \retval <0 error
> + */
> +extern int sepol_object_free(struct sepol_handle *h, struct sepol_object *o);
> +
> +/**
> + * \ingroup sepol_policy
> + *
> + * Make this object the owner of a string pool. See sepol_object for
> + * more information on string pools.
> + *
> + * @param o object to which to add string pool
> + *
> + * \retval SEPOL_OK success
> + * \retval SEPOL_ENOMEM out of memory
> + */
> +extern int sepol_object_create_strpool(struct sepol_handle *h, struct sepol_object *o);
> +
> +/**
> + * \ingroup sepol_policy
> + *
> + * Return the strpool for this object if any.
> + *
> + * @param o object from which to return string pool.
> + *
> + * \retval non-NULL string pool this object is using.
> + * \retval NULL object does not use string pool.
> + */
> +extern struct sepol_objpool *sepol_object_get_strpool(struct sepol_object *o);
> +
> +/**
> + * \ingroup sepol_policy
> + *
> + * Determine whether the object is the owner of its string pool (if
> + * it has one).
> + *
> + * @param o object to check
> + *
> + * \retval 0 object does not own or does not have a string pool
> + * \retval 1 object owns its string pool
> + */
> +extern char sepol_object_is_strpool_owner(struct sepol_object *o);
> +
> +
> +/**
> + * \ingroup sepol_policy
> + *
> + * Return the typeid for the object.
> + *
> + * @param o object from which to return the type id.
> + *
> + * \retval >0 typeid for the object
> + */
> +extern uint32_t sepol_object_get_typeid(struct sepol_object *o);
> +
> +/**
> + * \ingroup sepol_policy
> + *
> + * Determine whether the object is an instance of the object type
> + * represented by a typeid. This function checks both the specific
> + * object type (as returned by sepol_object_get_typeid) and the
> + * parent type for the object.
> + *
> + * @param o object to check
> + * @param typeid typeid
> + *
> + * \retval 0 object is not an instance of the type
> + * \retval 1 object is an instance of the type
> + */
> +extern char sepol_object_isinstance(struct sepol_object *o, uint32_t typeid);
> +
> +/**
> + * \ingroup sepol_policy
> + *
> + * Return the parent of this object (if any).
> + *
> + * @param o object for which to return parent
> + *
> + * \retval non-NULL pointer to parent object
> + * \retval NULL object has no parent
> + */
> +extern struct sepol_parent *sepol_object_get_parent(struct sepol_object *o);
> +
> +/**
> + * \ingroup sepol_policy
> + *
> + * Specify the output for various sepol_*_tostring functions.
> + */
> +enum sepol_tostring_style {
> + SEPOL_TOSTRING_RAW, /** raw policy language */
> + SEPOL_TOSTRING_REFPOL, /** refpol style output */
> + SEPOL_TOSTRING_DEBUG /** debugging output */
> +};
> +
> +/**
> + * \ingroup sepol_policy
> + *
> + * Convert an sepol_object into a string representation. If the
> + * returned string is of 0 length (return is 0), str will be an
> + * allocated, 0 length string that should be freed by the caller.
> + *
> + * @param h sepol_handle (may be NULL)
> + * @param o object to convert to a string
> + * @param style style of the output - see sepol_tostring_style
> + * @param str output string - this string is allocated by the function
> + * and should be freed by the caller using free()
> + *
> + * \retval >=0 Success - the size of the string is returned
> + * \retval <0 Failure - str will be undefined and does not need to be freed.
> + */
> +extern int sepol_object_tostring(struct sepol_handle *h, struct sepol_object *o,
> + int style, char **str);
> +
> +/**
> + * \ingroup sepol_policy
> + *
> + * Convert an sepol_object into a string representation for the
> + * closure of that object. Some objects - typically that contain
> + * other objects - need a string to represent the beginning _and_
> + * the end of that object. For example:
> + *
> + * \code
> + * if (foo) {
> + * allow foo bar : file read;
> + * }
> + * \endcode
> + *
> + * In this example "if (foo) }" would be printed by
> + * sepol_object_tostring and "}} printed by
> + * sepol_object_tostring_close on the same conditional object. If the
> + * returned string is of 0 length (return is 0), str will be an
> + * allocated, 0 length string that should be freed by the caller.
> + *
> + * @param h sepol_handle (may be NULL)
> + * @param o object to convert to a string
> + * @param style style of the output - see sepol_tostring_style
> + * @param str output string - this string is allocated by the function
> + * and should be freed by the caller using free()
> + *
> + * \retval >=0 Success - the size of the string is returned
> + * \retval <0 Failure - str will be undefined and does not need to be freed.
> + */
> +extern int sepol_object_tostring_close(struct sepol_handle *h, struct sepol_object *o,
> + int style, char **str);
> +
> +/**
> + * \ingroup sepol_policy
> + * \struct sepol_parent
> + *
> + * sepol_parent is the parent class of all objects that can contain
> + * other objects in the tree. Having a single base class for all parent
> + * objects allows writing functions that can traverse the tree without
> + * knowing the details about most of the objects in the tree.
> + */
> +struct sepol_parent;
> +
> +/**
> + * \ingroup sepol_policy
> + *
> + * Convert an object to an sepol_parent
> + *
> + * @param x object
> + */
> +#define SEPOL_PARENT(x) ((struct sepol_parent *)x)
> +
> +/**
> + * \ingroup sepol_policy
> + *
> + * Free a parent object and all of its children (if any). This
> + * function traverses a policy tree starting at the parent node passed
> + * in destroy each object it encounters (by (calling
> + * sepol_object_free).
> + *
> + * @param h sepol_handle (may be NULL)
> + * @param p sepol_parent object
> + *
> + * \retval SEPOL_OK success
> + * \retval SEPOL_ENOMEM out of memory
> + */
> +extern int sepol_parent_free_tree(struct sepol_handle *h, struct sepol_parent *p);
> +
> +/**
> + * \ingroup sepol_policy
> + *
> + * Append an object as a child of this parent. An object can only
> + * be the child of a single parent - to move an object from one
> + * part of the tree to another (and change the parent), remove the
> + * child from the current parent first before appending to the new
> + * parent.
> + *
> + * @param h sepol_handle (may be NULL)
> + * @param p sepol_parent to which to append child object
> + * @param o object to append (parent will be set)
> + *
> + * \retval SEPOL_OK success
> + * \retval SEPOL_EEXIST object is already a child of another parent
> + * \retval SEPOL_ENOMEM out of memory
> + */
> +extern int sepol_parent_append(struct sepol_handle *h, struct sepol_parent *p,
> + struct sepol_object *o);
> +
> +/**
> + * \ingroup sepol_policy
> + *
> + * Extend the children of an sepol_parent with the objects returned by
> + * an iterator. Each object will be appended using
> + * sepol_parent_append. If there is an error from adding any of the
> + * children some of the objects may have been added. The iterator will
> + * be left in the position of the object that caused an error.
> + *
> + * @param h sepol_handle (may be NULL)
> + * @param p sepol_parent to which to add children
> + * @param iter iterator from which to add children
> + *
> + * \retval SEPOL_OK success
> + * \retval SEPOL_EEXIST object is already a child of another parent
> + * \retval SEPOL_ENOMEM out of memory
> + */
> +extern int sepol_parent_extend(struct sepol_handle *h, struct sepol_parent *p,
> + struct sepol_iter *iter);
> +
> +/**
> + * \ingroup sepol_policy
> + *
> + * Convenience function similar to sepol_parent_extend that takes a
> + * list instead of an interator.
> + *
> + * @param h sepol_handle (may be NULL)
> + * @param p sepol_parent to which to add objects
> + * @param list sepol_list from which to add objects
> + *
> + * \retval SEPOL_OK success
> + * \retval SEPOL_EEXIST object is already a child of another parent
> + * \retval SEPOL_ENOMEM out of memory
> + */
> +extern int sepol_parent_extend_list(struct sepol_handle *h, struct sepol_parent *p,
> + struct sepol_list *list);
> +
> +/**
> + * \ingroup sepol_policy
> + *
> + * Delete a child object from the sepol_parent. Like sepol_list_del,
> + * the iterator will not be valid after a call to this function.
> + *
> + * @param h sepol_handle (may be NULL)
> + * @param p sepol_parent from which to delete child
> + * @param iter iterator pointing to a child object of p
> + *
> + * \retval SEPOL_OK success
> + */
> +extern int sepol_parent_del(struct sepol_handle *h, struct sepol_parent *p,
> + struct sepol_iter *iter);
> +
> +/**
> + * \ingroup sepol_policy
> + *
> + * Insert a child object into the list of children for the
> + * sepol_parent. See sepol_list_insert for more information on the
> + * semantics of this insert.
> + *
> + * @param h sepol_handle (may be NULL)
> + * @param p sepol_parent to which to insert child object
> + * @param iter iterator representing the position to insert the child object
> + * @param o child object to insert
> + *
> + * \retval SEPOL_OK success
> + * \retval SEPOL_EEXIST object is already a child of another parent
> + * \retval SEPOL_ENOMEM out of memory
> + */
> +extern int sepol_parent_insert(struct sepol_handle *h, struct sepol_parent *p,
> + struct sepol_iter *iter, struct sepol_object *o);
> +
> +/**
> + * \ingroup sepol_policy
> + *
> + * Set an iterator to iterate over the children of an sepol_parent.
> + *
> + * @param h sepol_handle (may be NULL)
> + * @param p sepol_parent
> + * @param iter iterator to set to iterate over children
> + *
> + * \retval SEPOL_OK success
> + * \retval SEPOL_ENOMEM out of memory
> + */
> +extern int sepol_parent_children(struct sepol_handle *h, struct sepol_parent *p,
> + struct sepol_iter *iter);
> +
> +/**
> + * \ingroup sepol_policy
> + *
> + * Return the list containing the children of the sepol_parent
> + * object. This is the actual list used to store children of the
> + * object, so changes will be reflected in the sepol_parent. It is
> + * important that deletions and insertions use sepol_parent_del and
> + * sepol_parent_insert or that the parent property of the objects
> + * is properly set.
> + *
> + * @param p sepol_parent
> + *
> + * \retval non-NULL pointer to the list of children
> + */
> +struct sepol_list *sepol_parent_get_children(struct sepol_parent *parent);
> +
> +
> +/**
> + * \ingroup sepol_policy
> + *
> + * Traversal of a policy tree rooted at a sepol_parent can take many
> + * forms. This enumeration is used to set the traversal strategy. See
> + * http://en.wikipedia.org/wiki/Tree_traversal for more information.
> + *
> + * The hybrid strategy combines both preorder and postorder
> + * traversal. This means that each parent node will be visited twice:
> + * once before its children are traversed and once afterward. The
> + * second traversal can be detected by checking the flag indicating
> + * that the parent has been visited (see sepol_parent_isvisited).
> + */
> +enum sepol_parent_traverse_strategy {
> + SEPOL_TRAVERSE_POSTORDER, /** traverse the tree in postorder */
> + SEPOL_TRAVERSE_PREORDER, /** traverse the tree in preorder */
> + SEPOL_TRAVERSE_HYBRID /** traverse the tree combining preorder and postorder */
> +};
> +
> +/**
> + * \ingroup sepol_policy
> + *
> + * Traverse a policy tree using parent as the root node of the tree. The traversal
> + * strategy is controlled by sepol_parent_traverse_strategy.
> + *
> + * @param h sepol_handle (may be null)
> + * @param parent sepol_parent
> + * @param iter iterator to represent traversal state
> + * @param strategy traversal strategy - see sepol_parent_traverse_strategy
> + *
> + * \retval SEPOL_OK success
> + * \retval SEPOL_ENOMEM out of memory
> + */
> +extern int sepol_parent_traverse(struct sepol_handle *h, struct sepol_parent *parent,
> + struct sepol_iter *iter, int strategy);
> +
> +/**
> + * \ingroup sepol_policy
> + *
> + * Return whether an object has already been visited before during this tree
> + * traversal. See sepol_parent_traverse_strategy for more information.
> + *
> + * @param iter iterator
> + *
> + * \retval 0 object has not been previously visited
> + * \retval 1 object has been previously visited
> + */
> +char sepol_parent_isvisited(struct sepol_iter *iter);
> +
>
is it really necessary to use a char here? granted its smaller but it
also doesn't really convey to someone new to the code what is going on.
Perhaps a bool typemap? or short int?
> +struct sepol_policy;
> +
> +extern int sepol_policy_free(struct sepol_handle *h, struct sepol_policy *o);
> +extern int sepol_policy_create(struct sepol_handle *h,
> + struct sepol_policy **policy);
> +
> +extern char sepol_policy_get_mls(struct sepol_policy *o);
> +extern int sepol_policy_set_mls(struct sepol_policy *o, char mls);
> +
> +struct sepol_module;
> +
> +extern int sepol_module_free(struct sepol_handle *h, struct sepol_module *o);
> +extern int sepol_module_create(struct sepol_handle *h,
> + struct sepol_module **module);
> +extern int sepol_module_create_tree(struct sepol_handle *h,
> + struct sepol_module **module,
> + struct sepol_parent *root);
> +
> +int sepol_module_set_name(struct sepol_module *module, char *name);
> +const char *sepol_module_get_name(struct sepol_module *module);
> +
> +int sepol_module_set_version(struct sepol_module *module, char *version);
> +const char *sepol_module_get_version(struct sepol_module *module);
> +
> +int sepol_module_set_isbase(struct sepol_module *module, char isbase);
> +char sepol_module_get_isbase(struct sepol_module *module);
> +
> +#endif
> diff -r cacdf4377ebf -r bd4ee6e00a63 libsepol/src/policy.c
> --- a/libsepol/src/policy.c Mon May 07 15:50:27 2007 -0400
> +++ b/libsepol/src/policy.c Mon May 07 18:03:03 2007 -0400
> @@ -0,0 +1,638 @@
> +/*
> + * Author : Karl MacMillan <kmacmillan@mentalrootkit.com>
> + *
> + * Copyright (C) 2007 Red Hat, Inc.
> + *
> + * This library is free software; you can redistribute it and/or
> + * modify it under the terms of the GNU Lesser General Public
> + * License as published by the Free Software Foundation; either
> + * version 2.1 of the License, or (at your option) any later version.
> + *
> + * This library is distributed in the hope that it will be useful,
> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
> + * Lesser General Public License for more details.
> + *
> + * You should have received a copy of the GNU Lesser General Public
> + * License along with this library; if not, write to the Free Software
> + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
> + */
> +
> +#include "policy_internal.h"
> +#include "debug.h"
> +#include "dso.h"
> +
> +#include <stdio.h>
> +#include <string.h>
> +#include <assert.h>
> +
> +/*
> + * SEPOL_OBJECT
> + */
> +
> +static char *typeid_strings[] = {
> + "none",
> + "object",
> + "parent",
> + "policy",
> + "module",
> + "block",
> + "cond",
> + "optional",
> + "type",
> + "class",
> + "attribute",
> + "typealias",
> + "boolean",
> + "avrule",
> + "typerule",
> + "security context",
> + "initial sid",
> + "typeattribute",
> + "conditional expression",
> + "sensitivity",
> + "dominance",
> + "category",
> + "role dominance",
> + "role"
> +};
> +
>
It would be nice if these were in the same place as the enum so they
could be updated easier, but I understand that the strings are private
and the enum is exported :\
> +const char *sepol_typeid_tostring(int typeid)
> +{
> + assert(typeid < sizeof(typeid_strings));
> + return typeid_strings[typeid];
> +}
> +hidden_def(sepol_typeid_tostring)
> +
> +int sepol_object_free(struct sepol_handle *h, struct sepol_object *o)
> +{
> + assert(o->methods->free);
> +
> + return o->methods->free(h, o);
> +}
> +hidden_def(sepol_object_free)
> +
> +#define SEPOL_STRPOOL_SIZE 64
> +int sepol_object_create_strpool(struct sepol_handle *h, struct sepol_object *o)
> +{
> + int ret;
> +
> + ret = sepol_objpool_create(h, &o->strpool, (sepol_objpool_hash_t)sepol_symhash,
> + (sepol_objpool_cmp_t)sepol_symcmp, free,
> + SEPOL_STRPOOL_SIZE);
> + ret_check(ret);
> + o->flags |= SEPOL_OBJECT_STRPOOL_OWNER;
> +
> + return ret;
> +}
> +hidden_def(sepol_object_create_strpool)
> +
> +struct sepol_objpool *sepol_object_get_strpool(struct sepol_object *o)
> +{
> + return o->strpool;
> +}
> +hidden_def(sepol_object_get_strpool)
> +
> +char sepol_object_is_strpool_owner(struct sepol_object *o)
> +{
> + return (o->flags & SEPOL_OBJECT_STRPOOL_OWNER) != 0;
> +}
> +hidden_def(sepol_object_is_strpool_owner)
> +
> +uint32_t sepol_object_get_typeid(struct sepol_object *o)
> +{
> + return o->typeid;
> +}
> +hidden_def(sepol_object_get_typeid)
> +
> +char sepol_object_isinstance(struct sepol_object *o, uint32_t typeid)
> +{
> + if (o->typeid == typeid || o->sclass_typeid == typeid)
> + return 1;
> + else return 0;
> +}
> +hidden_def(sepol_object_isinstance)
> +
> +struct sepol_parent *sepol_object_get_parent(struct sepol_object *o)
> +{
> + return o->parent;
> +}
> +hidden_def(sepol_object_get_parent)
> +
> +int sepol_object_tostring(struct sepol_handle *h, struct sepol_object *o,
> + int style, char **str)
> +{
> + if (o->methods->tostring) {
> + return o->methods->tostring(h, o, style, str);
> + } else {
> + if (style == SEPOL_TOSTRING_DEBUG) {
> + return asprintf(str, "[sepol_object(%s) at %p]",
> + sepol_typeid_tostring(o->typeid), o);
> + }
> +
> + /* Even though we are returning an empty string, we still
> + * need to allocated an empty string to return. This
> + * matches the behavior of asprintf.
> + */
> + *str = strdup("");
> + if (*str == NULL)
> + return -1;
> + return 0;
> + }
> +}
> +hidden_def(sepol_object_tostring)
> +
> +int sepol_object_tostring_close(struct sepol_handle *h, struct sepol_object *o,
> + int style, char **str)
> +{
> + if (o->methods->tostring_close) {
> + return o->methods->tostring_close(h, o, style, str);
> + } else {
> + if (style == SEPOL_TOSTRING_DEBUG) {
> + return asprintf(str, "[close: sepol_object(%s) at %p]",
> + sepol_typeid_tostring(o->typeid), o);
> + }
> +
> + /* Even though we are returning an empty string, we still
> + * need to allocated an empty string to return. This
> + * matches the behavior of asprintf.
> + */
> + *str = strdup("");
> + if (*str == NULL)
> + return -1;
> + return 0;
> + }
> +}
> +hidden_def(sepol_object_tostring_close)
> +
> +/*
> + * SEPOL_PARENT
> + */
> +
> +int sepol_parent_free_tree(struct sepol_handle *h, struct sepol_parent *p)
> +{
> + int ret;
> + struct sepol_iter *iter;
> + struct sepol_object *cur;
> +
> + ret = sepol_iter_create(h, &iter);
> + if (ret < 0)
> + goto out;
> +
> + ret = sepol_parent_traverse(h, p, iter, SEPOL_TRAVERSE_POSTORDER);
> + if (ret < 0)
> + goto out;
> +
> + sepol_foreach(h, ret, cur, iter) {
> + int ret2;
> + char *str;
> + ret2 = sepol_object_tostring(h, cur, SEPOL_TOSTRING_DEBUG, &str);
> + assert(ret2 >= 0);
> + printf("freeing %s", str);
> + sepol_object_free(h, cur);
> + free(str);
> + }
> + if (ret != SEPOL_ITERSTOP)
> + goto out;
> +
> + ret = SEPOL_OK;
> +out:
> + sepol_iter_free(h, iter);
> + return ret;
> +}
> +hidden_def(sepol_parent_free_tree)
> +
> +int sepol_parent_append(struct sepol_handle *h, struct sepol_parent *p, struct sepol_object *o)
> +{
> + if (o->parent)
> + return SEPOL_EEXIST;
> + o->parent = p;
> + return sepol_list_append(h, p->children, o);
> +}
> +hidden_def(sepol_parent_append)
> +
> +int sepol_parent_extend(struct sepol_handle *h, struct sepol_parent *p, struct sepol_iter *iter)
> +{
> + int ret = SEPOL_OK;
> + struct sepol_object *cur;
> +
> + sepol_foreach(h, ret, cur, iter) {
> + ret = sepol_parent_append(h, p, cur);
> + if (ret < 0) {
> + return ret;
> + }
> + }
> + if (ret != SEPOL_ITERSTOP) {
> + return ret;
> + }
> +
> + return SEPOL_OK;
> +}
> +hidden_def(sepol_parent_extend)
> +
> +int sepol_parent_extend_list(struct sepol_handle *h, struct sepol_parent *p, struct sepol_list *list)
> +{
> + int ret;
> + struct sepol_iter *iter;
> +
> + ret = sepol_iter_create(h, &iter);
> + if (ret < 0)
> + return ret;
> + ret = sepol_list_begin(h, list, iter);
> + if (ret < 0) {
> + if (ret == SEPOL_ITERSTOP)
> + return SEPOL_OK;
> + else
> + return ret;
> + }
> + ret = sepol_parent_extend(h, p, iter);
> + sepol_iter_free(h, iter);
> +
> + return ret;
> +}
> +hidden_def(sepol_parent_extend_list)
> +
> +int sepol_parent_del(struct sepol_handle *h, struct sepol_parent *p, struct sepol_iter *iter)
> +{
> + struct sepol_object *o;
> + o = (struct sepol_object*)sepol_iter_get_data(h, iter);
> + if (!o) {
> + ERR(h, "error getting object from iterator");
> + return SEPOL_ERR;
> + }
> + o->parent = NULL;
> + return sepol_list_del(h, p->children, iter);
> +}
> +hidden_def(sepol_parent_del)
> +
> +int sepol_parent_insert(struct sepol_handle *h, struct sepol_parent *p,
> + struct sepol_iter *iter, struct sepol_object *o)
> +{
> + if (o->parent)
> + return SEPOL_EEXIST;
> + o->parent = p;
> +
> + return sepol_list_insert(h, p->children, iter, o);
> +}
> +hidden_def(sepol_parent_insert)
> +
> +
> +int sepol_parent_children(struct sepol_handle *h, struct sepol_parent *p, struct sepol_iter *iter)
> +{
> + return sepol_list_begin(h, p->children, iter);
> +}
> +hidden_def(sepol_parent_children)
> +
> +struct sepol_list *sepol_parent_get_children(struct sepol_parent *parent)
> +{
> + return parent->children;
> +}
> +hidden_def(sepol_parent_get_children)
> +
> +
> +struct sepol_parent_traverse_state
> +{
> + int strategy;
> + char cur_flags;
> + struct sepol_list *stack;
> + void *object;
> +};
> +
> +static void *sepol_parent_iter_get_data(struct sepol_handle *h, struct sepol_iter *iter)
> +{
> + struct sepol_parent_traverse_state *state;
> +
> + assert(iter);
> + state = (struct sepol_parent_traverse_state*)
> + sepol_iter_get_state(iter);
> + assert(state);
> +
> + return state->object;
> +}
> +
> +static int sepol_parent_iter_free(struct sepol_handle *h, void *data)
> +{
> + struct sepol_parent_traverse_state *state =
> + (struct sepol_parent_traverse_state*)data;
> +
> + if (state == NULL)
> + return SEPOL_OK;
> +
> + if (state->stack)
> + sepol_list_free(state->stack);
> + free(state);
> +
> + return SEPOL_OK;
> +}
> +
> +static int sepol_parent_traverse_preorder_next(struct sepol_handle *h, struct sepol_iter *iter)
> +{
> + int ret;
> + struct sepol_parent_traverse_state *state;
> + struct sepol_object *object, *cur;
> + struct sepol_iter *child_iter;
> +
> + state = sepol_iter_get_state(iter);
> +
> + ret = sepol_list_pop_back(h, state->stack, (void**)&object);
> +
> + if (ret == SEPOL_ERANGE)
> + return SEPOL_ITERSTOP;
> + else if (ret < 0)
> + return ret;
> +
> + state->object = object;
> + state->cur_flags = object->flags;
> +
> + if (sepol_object_isinstance(object, SEPOL_TYPEID_PARENT) &&
> + !(object->flags & SEPOL_OBJECT_VISITED)) {
> + if (state->strategy == SEPOL_TRAVERSE_HYBRID) {
> + object->flags |= SEPOL_OBJECT_VISITED;
> + ret = sepol_list_append(h, state->stack, object);
> + ret_check(ret);
> + }
> + ret = sepol_iter_create(h, &child_iter);
> + ret_check(ret);
> + ret = sepol_list_end(h, sepol_parent_get_children(SEPOL_PARENT(object)),
> + child_iter);
> + while (ret == SEPOL_OK) {
> + cur = sepol_iter_get_data(h, child_iter);
> + cur->flags &= ~SEPOL_OBJECT_VISITED;
> + ret = sepol_list_append(h, state->stack, cur);
> + if (ret < 0)
> + break;
> + ret = sepol_iter_prev(h, child_iter);
> + }
> + sepol_iter_free(h, child_iter);
> + if (ret < 0 && ret != SEPOL_ITERSTOP) {
> + return ret;
> + }
> +
> + }
> + return SEPOL_OK;
> +}
> +
> +static int sepol_parent_traverse_postorder_next(struct sepol_handle *h, struct sepol_iter *iter)
> +{
> + int ret;
> + struct sepol_parent_traverse_state *state;
> + struct sepol_object *object, *cur;
> + struct sepol_iter *child_iter;
> +
> + state = sepol_iter_get_state(iter);
> +
> + while (1) {
> + ret = sepol_list_pop_back(h, state->stack, (void**)&object);
> +
> + if (ret == SEPOL_ERANGE)
> + return SEPOL_ITERSTOP;
> + else if (ret < 0)
> + return ret;
> +
> + if (object->flags & SEPOL_OBJECT_VISITED ||
> + !sepol_object_isinstance(object, SEPOL_TYPEID_PARENT)) {
> + state->object = object;
> + break;
> + } else {
> + object->flags |= SEPOL_OBJECT_VISITED;
> + ret = sepol_list_append(h, state->stack, object);
> + ret_check(ret);
> +
> + ret = sepol_iter_create(h, &child_iter);
> + ret_check(ret);
> + ret = sepol_list_end(h, sepol_parent_get_children(SEPOL_PARENT(object)),
> + child_iter);
> + while (ret == SEPOL_OK) {
> + cur = sepol_iter_get_data(h, child_iter);
> + cur->flags &= ~SEPOL_OBJECT_VISITED;
> + ret = sepol_list_append(h, state->stack, cur);
> + if (ret < 0)
> + break;
> + ret = sepol_iter_prev(h, child_iter);
> + }
> + sepol_iter_free(h, child_iter);
> + if (ret < 0 && ret != SEPOL_ITERSTOP) {
> + return ret;
> + }
> + }
> + }
> + return SEPOL_OK;
> +}
> +
> +int sepol_parent_traverse(struct sepol_handle *h, struct sepol_parent *parent,
> + struct sepol_iter *iter, int strategy)
> +{
> + int ret;
> + struct sepol_parent_traverse_state *state = NULL;
> +
> + state = calloc(1, sizeof(struct sepol_parent_traverse_state));
>
> + if (state == NULL)
> + return SEPOL_ENOMEM;
> +
> + ret = sepol_list_create(h, &state->stack);
> + ret_goto(ret, err);
> +
> + state->strategy = strategy;
> + sepol_iter_set_state(iter, state);
> +
> + if (state->strategy == SEPOL_TRAVERSE_POSTORDER)
> + sepol_iter_set_next(iter, sepol_parent_traverse_postorder_next);
> + else if (state->strategy == SEPOL_TRAVERSE_PREORDER ||
> + state->strategy == SEPOL_TRAVERSE_HYBRID)
> + sepol_iter_set_next(iter, sepol_parent_traverse_preorder_next);
> + else
> + return SEPOL_ERR;
> + sepol_iter_set_free(iter, sepol_parent_iter_free);
> + sepol_iter_set_get_data(iter, sepol_parent_iter_get_data);
> +
> +
> + parent->sclass.flags &= ~SEPOL_OBJECT_VISITED;
> + ret = sepol_list_append(h, state->stack, parent);
> + ret_goto(ret, err);
> + ret = sepol_iter_next(h, iter);
> + ret_goto(ret, err);
> +
> + return SEPOL_OK;
> +err:
> + sepol_parent_iter_free(h, state);
> + return ret;
> +}
> +hidden_def(sepol_parent_traverse)
> +
> +char sepol_parent_isvisited(struct sepol_iter *iter)
> +{
> + struct sepol_parent_traverse_state *state;
> +
> + state = sepol_iter_get_state(iter);
> + if (state->cur_flags & SEPOL_OBJECT_VISITED)
> + return 1;
> + else
> + return 0;
> +}
> +hidden_def(sepol_parent_isvisited)
> +
> +/*
> + * SEPOL_POLICY
> + */
> +
> +struct sepol_policy
> +{
> + struct sepol_parent sclass;
> + char mls;
> +};
> +
> +int sepol_policy_free(struct sepol_handle *h, struct sepol_policy *o)
> +{
> + intern_sepol_parent_free(SEPOL_PARENT(o));
> + free(o);
> +
> + return SEPOL_OK;
> +}
> +
> +static int sepol_policy_tostring(struct sepol_handle *h,
> + struct sepol_object * object __attribute__ ((unused)),
> + int style, char **str)
> +{
> + if (style == SEPOL_TOSTRING_DEBUG) {
> + return asprintf(str, "POLICY {");
>
Why are these strings hard coded?
> + } else {
> + *str = strdup("");
> + if (*str)
> + return 0;
> + else
> + return -1;
> + }
> +}
> +
> +static int sepol_policy_tostring_close(struct sepol_handle *h __attribute__ ((unused)),
> + struct sepol_object *object __attribute__ ((unused)),
> + int style, char **str)
> +{
> + if (style == SEPOL_TOSTRING_DEBUG) {
> + return asprintf(str, "POLICY {");
> + } else {
> + *str = strdup("");
> + if (*str)
> + return 0;
> + else
> + return -1;
> + }
> +}
> +
> +static struct sepol_object_methods sepol_policy_methods = {
> + .free = (sepol_object_free_t)sepol_policy_free,
> + .tostring = sepol_policy_tostring,
> + .tostring_close = sepol_policy_tostring_close
> +};
> +
> +int sepol_policy_create(struct sepol_handle *h, struct sepol_policy **policy)
> +{
> + int ret;
> + struct sepol_policy *x;
> +
> + *policy = NULL;
> + x = calloc(1, sizeof(struct sepol_policy));
>
I am adverse to calloc used on structs, this implicitly initializes the
struct and makes it harder to update the initial state. Why not have an
explicit initializer?
> + if (x == NULL) {
> + return SEPOL_ENOMEM;
> + }
> +
> + ret = intern_sepol_parent_init(h, SEPOL_PARENT(x), SEPOL_TYPEID_POLICY,
> + &sepol_policy_methods, NULL);
> + ret_goto(ret, out);
> +
> + /* policy always has a strpool for convenience */
> + ret = sepol_object_create_strpool(h, SEPOL_OBJECT(x));
> + ret_goto(ret, out);
> +
> + *policy = x;
> + return SEPOL_OK;
> +out:
> + intern_sepol_parent_free(SEPOL_PARENT(x));
> + return ret;
> +}
> +
> +DEFINE_BOOL_PROP(policy, mls)
> +
> +/*
> + * SEPOL_MODULE
> + */
> +
> +struct sepol_module
> +{
> + struct sepol_parent sclass;
> + char *name;
> + char *version;
> + char isbase;
> +};
> +
> +int sepol_module_free(struct sepol_handle *h, struct sepol_module *o)
> +{
> + int ret;
> +
> + ret = intern_sepol_object_delstr(h, o, o->name);
> + ret_check(ret);
> +
> + ret = intern_sepol_object_delstr(h, o, o->version);
> + ret_check(ret);
> +
> + intern_sepol_parent_free(SEPOL_PARENT(o));
> +
> + free(o);
> +
> + return SEPOL_OK;
> +}
> +hidden_def(sepol_module_free)
> +
> +static int sepol_module_tostring(struct sepol_handle *h, struct sepol_object *object,
> + int style, char **str)
> +{
> + struct sepol_module *module = (struct sepol_module *)object;
> +
> + if (module->name == NULL || module->version == NULL)
> + return -1;
> +
> + if (style == SEPOL_TOSTRING_REFPOL)
> + return asprintf(str, "policy_module(%s %s)", module->name,
>
So we now have 2 syntaxes for policy modules? One here and one in the
lexer/parser?
> + module->version);
> + else
> + return asprintf(str, "module %s %s;", module->name, module->version);
> +}
> +
> +static struct sepol_object_methods sepol_module_methods = {
> + .free = (sepol_object_free_t)sepol_module_free,
> + .tostring = sepol_module_tostring
> +};
> +
> +int sepol_module_create(struct sepol_handle *h, struct sepol_module **module)
> +{
> + return sepol_module_create_tree(h, module, NULL);
> +}
> +hidden_def(sepol_module_create)
> +
> +int sepol_module_create_tree(struct sepol_handle *h, struct sepol_module **module,
> + struct sepol_parent *root)
> +{
> + int ret;
> + struct sepol_module *x;
> +
> + *module = NULL;
> + x = calloc(1, sizeof(struct sepol_module));
> + if (x == NULL) {
> + return SEPOL_ENOMEM;
> + }
> +
> + ret = intern_sepol_parent_init(h, SEPOL_PARENT(x), SEPOL_TYPEID_MODULE,
> + &sepol_module_methods, root);
> + ret_goto(ret, out);
> +
> + *module = x;
> + return SEPOL_OK;
> +out:
> + free(x);
> + return ret;
> +}
> +hidden_def(sepol_module_create_tree)
> +
> +DEFINE_STR_PROP(module, name)
> +DEFINE_STR_PROP(module, version)
> +DEFINE_BOOL_PROP(module, isbase)
> diff -r cacdf4377ebf -r bd4ee6e00a63 libsepol/src/policy_internal.c
> --- a/libsepol/src/policy_internal.c Mon May 07 15:50:27 2007 -0400
> +++ b/libsepol/src/policy_internal.c Mon May 07 18:03:03 2007 -0400
> @@ -0,0 +1,102 @@
> +/*
> + * Author : Karl MacMillan <kmacmillan@mentalrootkit.com>
> + *
> + * Copyright (C) 2007 Red Hat, Inc.
> + *
> + * This library is free software; you can redistribute it and/or
> + * modify it under the terms of the GNU Lesser General Public
> + * License as published by the Free Software Foundation; either
> + * version 2.1 of the License, or (at your option) any later version.
> + *
> + * This library is distributed in the hope that it will be useful,
> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
> + * Lesser General Public License for more details.
> + *
> + * You should have received a copy of the GNU Lesser General Public
> + * License along with this library; if not, write to the Free Software
> + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
> + */
> +
> +#include "policy_internal.h"
> +
> +int intern_sepol_object_init(struct sepol_handle *h, struct sepol_object *o, uint32_t typeid,
> + struct sepol_object_methods *methods, struct sepol_parent *root)
> +{
> + memset(o, 0, sizeof(struct sepol_object));
> + o->sclass_typeid = SEPOL_TYPEID_OBJECT;
> + o->typeid = typeid;
> + o->methods = methods;
> + if (root && sepol_object_get_strpool(SEPOL_OBJECT(root)))
> + o->strpool = sepol_object_get_strpool(SEPOL_OBJECT(root));
> +
> +
> + return 0;
> +}
> +
> +void intern_sepol_object_free(struct sepol_object *o)
> +{
> + if (o == NULL)
> + return;
> +
> + if (o->flags & SEPOL_OBJECT_STRPOOL_OWNER)
> + sepol_objpool_free(NULL, o->strpool);
> +}
> +
> +int _intern_sepol_object_addstr(struct sepol_handle *h, struct sepol_object *o, char **str)
> +{
> + char *tmp;
> +
> + tmp = strdup(*str);
> + if (!tmp)
> + return SEPOL_ENOMEM;
> +
> + *str = tmp;
> +
> + if (o->strpool) {
> + *str = sepol_objpool_add(h, o->strpool, *str);
> + if (!*str)
> + return SEPOL_ENOMEM;
> + }
> +
> + return SEPOL_OK;
> +}
> +
> +int _intern_sepol_object_delstr(struct sepol_handle *h, struct sepol_object *o, char *str)
>
Why do some of these start with _ and others don't?
> +{
> + int ret;
> +
> + if (str == NULL)
> + return SEPOL_OK;
> +
> + if (o->strpool) {
> + ret = sepol_objpool_del(h, o->strpool, str);
> + return ret;
> + } else {
> + free(str);
> + return SEPOL_OK;
> + }
> +}
> +
> +int intern_sepol_parent_init(struct sepol_handle *h, struct sepol_parent *p, uint32_t typeid,
> + struct sepol_object_methods *methods, struct sepol_parent *root)
> +{
> + int ret;
> +
> + ret = intern_sepol_object_init(h, SEPOL_OBJECT(p), typeid, methods, root);
> + ret_check(ret);
> + p->sclass.sclass_typeid = SEPOL_TYPEID_PARENT;
> +
> + ret = sepol_list_create(h, &p->children);
> + if (ret < 0)
> + sepol_object_free(h, SEPOL_OBJECT(p));
> +
> + return ret;
> +}
> +
> +void intern_sepol_parent_free(struct sepol_parent *p)
> +{
> + intern_sepol_object_free(SEPOL_OBJECT(p));
> +
> + sepol_list_free(p->children);
> +}
> diff -r cacdf4377ebf -r bd4ee6e00a63 libsepol/src/policy_internal.h
> --- a/libsepol/src/policy_internal.h Mon May 07 15:50:27 2007 -0400
> +++ b/libsepol/src/policy_internal.h Mon May 07 18:03:03 2007 -0400
> @@ -0,0 +1,269 @@
> +#ifndef __policy_internal_h__
> +#define __policy_internal_h__
> +
> +#include "dso.h"
> +
> +#include <sepol/policy.h>
> +#include <sepol/policydb/policydb.h>
> +#include <sepol/policydb/conditional.h>
> +
> +#include <stdlib.h>
> +#include <sys/types.h>
> +
> +/* Internal structs and functions for the policy object system. In
> + * general, policy objects cannot be created outside of the libsepol
> + * tree. It is possible, but not currently implemented, so there is
> + * quite a lot of internals in this header.
> + *
> + * One of the goals of this object system is to allow polymorphic
> + * methods. That will allow calling , for example, sepol_object_free
> + * on _any_ subclass of sepol_object and have the correct function
> + * called for the specific subclass. This polymorphism is implemented
> + * using an sepol_object_method struct for each class and a pointer to
> + * that struct held in each object instance.
> + *
> + * A subclass is expected to create an sepol_object_methods struct
> + * containing function pointers for the methods that it implements (it
> + * is valid for some of the function pointers to be NULL). Every
> + * instance of an sepol_object object holds a pointer to a single
> + * methods struct - i.e., there is only one struct per class and every
> + * instance holds a pointer to that struct.
> + *
> + * See sepol_object_init for how this pointer is set and sepol_object_free
> + * for how subclass methods are called.
> + */
> +
> +/* sepol_object_free_t is the type for the free method used in the policy
> + * object system. Implementations of this method should free all of the
> + * memory associated with the object including the struct.
> + */
> +typedef int (*sepol_object_free_t)(struct sepol_handle *h, struct sepol_object *o);
> +typedef int (*sepol_object_tostring_t)(struct sepol_handle *h, struct sepol_object *o,
> + int style, char **str);
> +
> +struct sepol_object_methods
> +{
> + sepol_object_free_t free;
> + sepol_object_tostring_t tostring;
> + sepol_object_tostring_t tostring_close;
> +};
> +
> +#define SEPOL_OBJECT_STRPOOL_OWNER 1
> +#define SEPOL_OBJECT_VISITED 2
>
Why aren't these in an enum?
> +struct sepol_object
> +{
> + struct sepol_object_methods *methods;
> + struct sepol_parent *parent;
> + struct sepol_objpool *strpool;
> + uint32_t sclass_typeid;
>
What is this field? Please make it less ambiguous/confusing.
> + uint32_t typeid;
> + uint32_t lineno;
> + char flags;
> +};
> +
> +/* Private initialization function for all objects. This function only
> + * initializes the generic object properties - the type specific creation
> + * function is responsible for initializing any type specific properties.
> + * If this function fails it will clean up any memory that it allocated. The
> + * calling function is responsible for any type specific memory and for freeing
> + * the object struct.
> + *
> + * params:
> + * o - object to initialize
> + * typeid - typeid of o
> + * methods - pointer to sepol_object_methods struct for this type. Should
> + * be a pointer to a single static struct for all instances of this type.
> + * root - root of the policy tree of which o is a member (may be NULL). If
> + * the root is non-NULL and has a string pool then that string pool is
> + * used for this object.
> + */
> +int intern_sepol_object_init(struct sepol_handle *h, struct sepol_object *o, uint32_t typeid,
> + struct sepol_object_methods *methods, struct sepol_parent *root);
> +
> +/* Free any memory associated with the super class. This should be called
> + * from a type specific free function.
> + */
> +void intern_sepol_object_free(struct sepol_object *o);
> +
> +/* Add a string to the string pool of the object. After a call to this
> + * function the str pointer will point to the correct (and possibly
> + * shared) version of the string to use.
> + */
> +#define intern_sepol_object_addstr(h, o, str) _intern_sepol_object_addstr(h, SEPOL_OBJECT(o), str)
> +int _intern_sepol_object_addstr(struct sepol_handle *h, struct sepol_object *o, char **str);
> +
> +/* Delete a string. If the object has a string pool the memory
> + * associated with the string may not be released
> + * immediately. Regardless, the caller should assume that the pointer
> + * is invalid after a call to this function.
> + */
> +#define intern_sepol_object_delstr(h, o, str) _intern_sepol_object_delstr(h, SEPOL_OBJECT(o), str)
> +int _intern_sepol_object_delstr(struct sepol_handle *h, struct sepol_object *o, char *str);
> +
> +hidden_proto(sepol_typeid_tostring)
> +hidden_proto(sepol_object_free)
> +hidden_proto(sepol_object_create_strpool)
> +hidden_proto(sepol_object_get_strpool)
> +hidden_proto(sepol_object_is_strpool_owner)
> +hidden_proto(sepol_object_get_typeid)
> +hidden_proto(sepol_object_isinstance)
> +hidden_proto(sepol_object_get_parent)
> +hidden_proto(sepol_object_tostring)
> +hidden_proto(sepol_object_tostring_close)
> +
> +struct sepol_parent
> +{
> + struct sepol_object sclass;
> + struct sepol_list *children;
> +};
> +
> +/* Initialize an sepol_parent object. Same function and general
> + * properties as intern_sepol_object_init but for parent
> + * objects. Objects should only call the init function for their
> + * immediate parent - the parent is responsible for any further
> + * chaining up the type hierarchy.
> + */
> +int intern_sepol_parent_init(struct sepol_handle *h, struct sepol_parent *p, uint32_t typeid,
> + struct sepol_object_methods *methods, struct sepol_parent *root);
> +
> +/* Internal free function for sepol_paren objects. Like the init functions
> + * this chains up the type hierarchy by call inter_sepol_object_free.
> + */
> +void intern_sepol_parent_free(struct sepol_parent *p);
> +
> +hidden_proto(sepol_parent_free_tree)
> +hidden_proto(sepol_parent_append)
> +hidden_proto(sepol_parent_extend)
> +hidden_proto(sepol_parent_extend_list)
> +hidden_proto(sepol_parent_del)
> +hidden_proto(sepol_parent_insert)
> +hidden_proto(sepol_parent_children)
> +hidden_proto(sepol_parent_get_children)
> +hidden_proto(sepol_parent_traverse)
> +hidden_proto(sepol_parent_isvisited)
> +
>
Hrm. IIRC hidden_proto is only needed if the function is going to be
exported from the shared library and also used internally, are these
really exported? I didn't see any map updates with this patch.
> +/* sepol_policy */
> +hidden_proto(sepol_policy_free)
> +hidden_proto(sepol_policy_get_mls)
> +hidden_proto(sepol_policy_set_mls)
> +
> +/* sepol_module */
> +hidden_proto(sepol_module_free)
> +hidden_proto(sepol_module_create)
> +hidden_proto(sepol_module_create_tree)
> +hidden_proto(sepol_module_set_name)
> +hidden_proto(sepol_module_get_name)
> +hidden_proto(sepol_module_set_version)
> +hidden_proto(sepol_module_get_version)
> +hidden_proto(sepol_module_set_isbase)
> +hidden_proto(sepol_module_get_isbase)
> +
> +
> +/* some convenience macros to check return values */
> +#define ret_check(ret) { if (ret < 0) return ret; }
> +#define ret_goto(ret, tag) { if (ret < 0) goto tag; }
> +
> +
> +/*
> + * PROPERTY GENERATION MACROS
> + *
> + * Many of the objects are similar and will have almost identical
> + * functions for getting and setting properties. These macros generate
> + * those functions for brevity and correctness.
> + */
> +
> +/* Initialize an object set for holding strings. This should be used
> + * in an object creation function to initialize a string set. This
> + * handles object pooling.
>
I understand the argument for using these but its my experience that
they make everything harder to understand like the libselinux macros..
> + */
> +#define INIT_STRSET(obj, set, ret, target) { \
> + if (SEPOL_OBJECT(obj)->strpool) { \
> + ret = sepol_objset_create(&obj->set, sepol_policy_ptrcmp); \
> + ret_goto(ret, target); \
> + } else { \
> + ret = sepol_objset_create(&obj->set, \
> + (sepol_objset_cmp_t)sepol_policy_strcmp); \
> + ret_goto(ret, target); \
> + } }
> +
> +#define DESTROY_STRSET(obj, set, iter, ret) { \
> + if (obj->set != NULL) { \
> + ret = sepol_iter_create(&iter); \
> + ret_check(ret); \
> + ret = sepol_objset_iter(obj->set, iter); \
> + if (ret < 0 && ret != SEPOL_ITERSTOP) return ret; \
> + while (ret == SEPOL_OK) { \
> + ret = intern_sepol_object_delstr(obj, sepol_iter_get_data(iter)); \
> + ret_check(ret); \
> + ret = sepol_iter_next(iter); \
> + } \
> + sepol_iter_destroy(iter); \
> + if (ret != SEPOL_ITERSTOP) return ret; \
> + } \
> + sepol_objset_destroy(obj->set); }
> +
> +
> +#define DEFINE_STR_PROP(obj, prop) \
> + int sepol_##obj##_set_##prop(struct sepol_##obj *x, char *prop) \
> + { \
> + int ret; \
> + if (x-> prop ) { \
> + ret = intern_sepol_object_delstr(NULL, x, x-> prop ); \
> + ret_check(ret); \
> + } \
> + x-> prop = prop; \
> + return intern_sepol_object_addstr(NULL, x, &x-> prop ); \
> + } \
> + hidden_def(sepol_##obj##_set_##prop) \
> + const char *sepol_##obj##_get_##prop(struct sepol_##obj *x) \
> + { \
> + return x-> prop ; \
> + } \
> + hidden_def(sepol_##obj##_get_##prop)
> +
> +#define DEFINE_BOOL_PROP(obj, prop) \
> + int sepol_##obj##_set_##prop(struct sepol_##obj *x, char prop) \
> + { \
> + x-> prop = prop; \
> + return SEPOL_OK; \
> + } \
> + hidden_def(sepol_##obj##_set_##prop) \
> + char sepol_##obj##_get_##prop(struct sepol_##obj *x) \
> + { \
> + return x-> prop ; \
> + } \
> + hidden_def(sepol_##obj##_get_##prop)
> +
> +#define DEFINE_UINT_PROP(obj, prop) \
> + int sepol_##obj##_set_##prop(struct sepol_##obj *x, uint32_t prop) \
> + { \
> + x->prop = prop; \
> + return SEPOL_OK; \
> + } \
> + hidden_def(sepol_##obj##_set_##prop) \
> + uint32_t sepol_##obj##_get_##prop(struct sepol_##obj *x) \
> + { \
> + return x->prop ; \
> + } \
> + hidden_def(sepol_##obj##_get_##prop)
> +
> +#define DEFINE_STRSET_PROP(obj, prop, set) \
> + int sepol_##obj##_add_##prop(struct sepol_##obj *x, char *prop) \
> + { \
> + int ret; \
> + char *tmp = strdup(prop); \
> + ret = intern_sepol_object_addstr(x, &tmp); \
> + ret_check(ret); \
> + ret = sepol_objset_add(x->set, tmp); \
> + ret_check(ret); \
> + return SEPOL_OK; \
> + } \
> + hidden_def(sepol_##obj##_set_##prop) \
> + struct sepol_objset *sepol_##obj##_get_##set(struct sepol_##obj *x) \
> + { \
> + return x->set; \
> + } \
> + hidden_def(sepol_##obj##_get_##prop)
> +
> +
> +#endif
>
--
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] 25+ messages in thread
* Re: [PATCH] Basic policy representation
2007-05-08 14:45 ` Joshua Brindle
@ 2007-05-08 15:08 ` Karl MacMillan
2007-05-08 15:48 ` Joshua Brindle
2007-05-08 16:50 ` Stephen Smalley
1 sibling, 1 reply; 25+ messages in thread
From: Karl MacMillan @ 2007-05-08 15:08 UTC (permalink / raw)
To: Joshua Brindle; +Cc: selinux
On Tue, 2007-05-08 at 10:45 -0400, Joshua Brindle wrote:
> Karl MacMillan wrote:
<snip>
> > +enum sepol_typeid {
> > + SEPOL_TYPEID_NONE, /** special typeid representing no type */
> > + SEPOL_TYPEID_OBJECT, /** typeid for base class of all objects */
> > + SEPOL_TYPEID_PARENT, /** typeid for base class of objects that contain other objects */
> > + SEPOL_TYPEID_POLICY, /** typeid for policy object */
> > + SEPOL_TYPEID_MODULE, /** typeid for the module object */
> > + SEPOL_TYPEID_BLOCK, /** tyepid for the block object */
> > + SEPOL_TYPEID_COND, /** typeid for the cond object */
> > + SEPOL_TYPEID_OPTIONAL, /** typeid for the optional object */
> > + SEPOL_TYPEID_TYPE, /** typed for the type object */
> > + SEPOL_TYPEID_CLASS, /** typeid for the class object */
> > + SEPOL_TYPEID_ATTRIBUTE, /** typeid for the attribute object */
> > + SEPOL_TYPEID_TYPEALIAS, /** typeid for the typealias object */
> > + SEPOL_TYPEID_BOOL, /** typeid for the bool object */
> > + SEPOL_TYPEID_AVRULE, /** typeid for the avrule object */
> > + SEPOL_TYPEID_TYPERULE, /** typeid for the typerule object */
> > + SEPOL_TYPEID_SECURITY_CONTEXT, /** typeid for the securit context object */
> > + SEPOL_TYPEID_ISID, /** typeid for the isid object */
> > + SEPOL_TYPEID_TYPEATTRIBUTE, /** typeid for the typeattribute object */
> > + SEPOL_TYPEID_COND_EXPR, /** typeid for the cond expr object */
> > + SEPOL_TYPEID_SENS, /** typeid for the sends object */
> > + SEPOL_TYPEID_DOMINANCE, /** typeid for the dominance object */
> > + SEPOL_TYPEID_CATEGORY, /** typeid for the category object */
> > + SEPOL_TYPEID_ROLE_DOMINANCE, /** typeid for the role dominance object */
> > + SEPOL_TYPEID_ROLE /** typeid for the role object */
> > +};
> >
> Do you think typeid is really a good word to use here? This is possibly
> very confusing (others have already mentioned to me that it was confusing)
>
I'm fine with something else. Why is it confusing though? And what would
you suggest as a less confusing alternative?
<snip>
> > +char sepol_parent_isvisited(struct sepol_iter *iter);
> > +
> >
>
> is it really necessary to use a char here? granted its smaller but it
> also doesn't really convey to someone new to the code what is going on.
> Perhaps a bool typemap? or short int?
>
Char isn't necessary, though I think it is a common idiom to use char as
boolean in C programs. What do you mean by typemap (typedef?). I don't
really think that short int is any better.
I try to use "is" in the name to indicate a boolean (and I will change
sepol_policy_mls to sepol_policy_ismls to be consistent).
<snip>
> > +
> > +static char *typeid_strings[] = {
> > + "none",
> > + "object",
> > + "parent",
> > + "policy",
> > + "module",
> > + "block",
> > + "cond",
> > + "optional",
> > + "type",
> > + "class",
> > + "attribute",
> > + "typealias",
> > + "boolean",
> > + "avrule",
> > + "typerule",
> > + "security context",
> > + "initial sid",
> > + "typeattribute",
> > + "conditional expression",
> > + "sensitivity",
> > + "dominance",
> > + "category",
> > + "role dominance",
> > + "role"
> > +};
> > +
> >
> It would be nice if these were in the same place as the enum so they
> could be updated easier, but I understand that the strings are private
> and the enum is exported :\
>
Yeah - and I've already screwed this up once. Unless you feel strongly,
though, I'd prefer to leave this in the C file.
<snip>
> > +static int sepol_policy_tostring(struct sepol_handle *h,
> > + struct sepol_object * object __attribute__ ((unused)),
> > + int style, char **str)
> > +{
> > + if (style == SEPOL_TOSTRING_DEBUG) {
> > + return asprintf(str, "POLICY {");
> >
>
> Why are these strings hard coded?
>
What is the alternative? I could use defines, but I don't think it would
help readability. Is that what you mean?
> > + } else {
> > + *str = strdup("");
> > + if (*str)
> > + return 0;
> > + else
> > + return -1;
> > + }
> > +}
> > +
> > +static int sepol_policy_tostring_close(struct sepol_handle *h __attribute__ ((unused)),
> > + struct sepol_object *object __attribute__ ((unused)),
> > + int style, char **str)
> > +{
> > + if (style == SEPOL_TOSTRING_DEBUG) {
> > + return asprintf(str, "POLICY {");
> > + } else {
> > + *str = strdup("");
> > + if (*str)
> > + return 0;
> > + else
> > + return -1;
> > + }
> > +}
> > +
> > +static struct sepol_object_methods sepol_policy_methods = {
> > + .free = (sepol_object_free_t)sepol_policy_free,
> > + .tostring = sepol_policy_tostring,
> > + .tostring_close = sepol_policy_tostring_close
> > +};
> > +
> > +int sepol_policy_create(struct sepol_handle *h, struct sepol_policy **policy)
> > +{
> > + int ret;
> > + struct sepol_policy *x;
> > +
> > + *policy = NULL;
> > + x = calloc(1, sizeof(struct sepol_policy));
> >
>
> I am adverse to calloc used on structs, this implicitly initializes the
> struct and makes it harder to update the initial state. Why not have an
> explicit initializer?
>
I like calloc because you don't have to explicitly set all of the
members and the code tends (in my experience) to be more reliable in the
face of change because of this. I don't have a strong opinion though -
what do others think?
<snip>
> > +
> > +static int sepol_module_tostring(struct sepol_handle *h, struct sepol_object *object,
> > + int style, char **str)
> > +{
> > + struct sepol_module *module = (struct sepol_module *)object;
> > +
> > + if (module->name == NULL || module->version == NULL)
> > + return -1;
> > +
> > + if (style == SEPOL_TOSTRING_REFPOL)
> > + return asprintf(str, "policy_module(%s %s)", module->name,
> >
>
> So we now have 2 syntaxes for policy modules? One here and one in the
> lexer/parser?
>
You mean that we will have to maintain information about the syntax in 2
places? Sure - is there an alternative?
<snip>
> > +#include "policy_internal.h"
> > +
> > +int intern_sepol_object_init(struct sepol_handle *h, struct sepol_object *o, uint32_t typeid,
> > + struct sepol_object_methods *methods, struct sepol_parent *root)
> > +{
> > + memset(o, 0, sizeof(struct sepol_object));
> > + o->sclass_typeid = SEPOL_TYPEID_OBJECT;
> > + o->typeid = typeid;
> > + o->methods = methods;
> > + if (root && sepol_object_get_strpool(SEPOL_OBJECT(root)))
> > + o->strpool = sepol_object_get_strpool(SEPOL_OBJECT(root));
> > +
> > +
> > + return 0;
> > +}
> > +
> > +void intern_sepol_object_free(struct sepol_object *o)
> > +{
> > + if (o == NULL)
> > + return;
> > +
> > + if (o->flags & SEPOL_OBJECT_STRPOOL_OWNER)
> > + sepol_objpool_free(NULL, o->strpool);
> > +}
> > +
> > +int _intern_sepol_object_addstr(struct sepol_handle *h, struct sepol_object *o, char **str)
> > +{
> > + char *tmp;
> > +
> > + tmp = strdup(*str);
> > + if (!tmp)
> > + return SEPOL_ENOMEM;
> > +
> > + *str = tmp;
> > +
> > + if (o->strpool) {
> > + *str = sepol_objpool_add(h, o->strpool, *str);
> > + if (!*str)
> > + return SEPOL_ENOMEM;
> > + }
> > +
> > + return SEPOL_OK;
> > +}
> > +
> > +int _intern_sepol_object_delstr(struct sepol_handle *h, struct sepol_object *o, char *str)
> >
>
> Why do some of these start with _ and others don't?
>
The two prefixed with _ have a macro in policy_internal to wrap them. It
just does an automatic cast to SEPOL_OBJECT to make them easier to call
from the generation macros.
<snip>
> > +
> > +struct sepol_object_methods
> > +{
> > + sepol_object_free_t free;
> > + sepol_object_tostring_t tostring;
> > + sepol_object_tostring_t tostring_close;
> > +};
> > +
> > +#define SEPOL_OBJECT_STRPOOL_OWNER 1
> > +#define SEPOL_OBJECT_VISITED 2
> >
>
> Why aren't these in an enum?
>
Mainly because I didn't document them so didn't think to make the
change. The other issue is that they are bit flags - so the defines
might be clearer. I've changed it to an enum though.
> > +struct sepol_object
> > +{
> > + struct sepol_object_methods *methods;
> > + struct sepol_parent *parent;
> > + struct sepol_objpool *strpool;
> > + uint32_t sclass_typeid;
> >
>
> What is this field? Please make it less ambiguous/confusing.
>
sclass = super class typeid. Would you prefer super_class_typeid?
<snip>
> > +
> > +hidden_proto(sepol_parent_free_tree)
> > +hidden_proto(sepol_parent_append)
> > +hidden_proto(sepol_parent_extend)
> > +hidden_proto(sepol_parent_extend_list)
> > +hidden_proto(sepol_parent_del)
> > +hidden_proto(sepol_parent_insert)
> > +hidden_proto(sepol_parent_children)
> > +hidden_proto(sepol_parent_get_children)
> > +hidden_proto(sepol_parent_traverse)
> > +hidden_proto(sepol_parent_isvisited)
> > +
> >
>
> Hrm. IIRC hidden_proto is only needed if the function is going to be
> exported from the shared library and also used internally, are these
> really exported? I didn't see any map updates with this patch.
>
They should have been exported - I thought there was a glob in the map
general enough to catch them. I've updated the map.
<snip>
> > +
> > +/*
> > + * PROPERTY GENERATION MACROS
> > + *
> > + * Many of the objects are similar and will have almost identical
> > + * functions for getting and setting properties. These macros generate
> > + * those functions for brevity and correctness.
> > + */
> > +
> > +/* Initialize an object set for holding strings. This should be used
> > + * in an object creation function to initialize a string set. This
> > + * handles object pooling.
> >
>
> I understand the argument for using these but its my experience that
> they make everything harder to understand like the libselinux macros..
>
I'd really prefer to keep them - they have already made development much
easier. They generate a _lot_ of code that really is exactly the same.
Also, I've already fixed bugs in the macros several times that would
have resulted in painful changes otherwise.
I understand that CPP is not particularly readable, but I think the
alternative is worse.
Karl
--
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] 25+ messages in thread
* Re: [PATCH] Basic policy representation
2007-05-08 15:08 ` Karl MacMillan
@ 2007-05-08 15:48 ` Joshua Brindle
2007-05-08 16:11 ` Karl MacMillan
0 siblings, 1 reply; 25+ messages in thread
From: Joshua Brindle @ 2007-05-08 15:48 UTC (permalink / raw)
To: Karl MacMillan; +Cc: selinux
Karl MacMillan wrote:
> On Tue, 2007-05-08 at 10:45 -0400, Joshua Brindle wrote:
>
>> Karl MacMillan wrote:
>>
>
> <snip>
>
>
>>> +enum sepol_typeid {
>>> + SEPOL_TYPEID_NONE, /** special typeid representing no type */
>>> + SEPOL_TYPEID_OBJECT, /** typeid for base class of all objects */
>>> + SEPOL_TYPEID_PARENT, /** typeid for base class of objects that contain other objects */
>>> + SEPOL_TYPEID_POLICY, /** typeid for policy object */
>>> + SEPOL_TYPEID_MODULE, /** typeid for the module object */
>>> + SEPOL_TYPEID_BLOCK, /** tyepid for the block object */
>>> + SEPOL_TYPEID_COND, /** typeid for the cond object */
>>> + SEPOL_TYPEID_OPTIONAL, /** typeid for the optional object */
>>> + SEPOL_TYPEID_TYPE, /** typed for the type object */
>>> + SEPOL_TYPEID_CLASS, /** typeid for the class object */
>>> + SEPOL_TYPEID_ATTRIBUTE, /** typeid for the attribute object */
>>> + SEPOL_TYPEID_TYPEALIAS, /** typeid for the typealias object */
>>> + SEPOL_TYPEID_BOOL, /** typeid for the bool object */
>>> + SEPOL_TYPEID_AVRULE, /** typeid for the avrule object */
>>> + SEPOL_TYPEID_TYPERULE, /** typeid for the typerule object */
>>> + SEPOL_TYPEID_SECURITY_CONTEXT, /** typeid for the securit context object */
>>> + SEPOL_TYPEID_ISID, /** typeid for the isid object */
>>> + SEPOL_TYPEID_TYPEATTRIBUTE, /** typeid for the typeattribute object */
>>> + SEPOL_TYPEID_COND_EXPR, /** typeid for the cond expr object */
>>> + SEPOL_TYPEID_SENS, /** typeid for the sends object */
>>> + SEPOL_TYPEID_DOMINANCE, /** typeid for the dominance object */
>>> + SEPOL_TYPEID_CATEGORY, /** typeid for the category object */
>>> + SEPOL_TYPEID_ROLE_DOMINANCE, /** typeid for the role dominance object */
>>> + SEPOL_TYPEID_ROLE /** typeid for the role object */
>>> +};
>>>
>>>
>> Do you think typeid is really a good word to use here? This is possibly
>> very confusing (others have already mentioned to me that it was confusing)
>>
>>
>
> I'm fine with something else. Why is it confusing though? And what would
> you suggest as a less confusing alternative?
>
>
ILK? :P
how about objid? Its confusing because of the use of type and id, both
of which are heavily used in the current compiler (and type being used
in selinux)
> <snip>
>
>
>>> +char sepol_parent_isvisited(struct sepol_iter *iter);
>>> +
>>>
>>>
>> is it really necessary to use a char here? granted its smaller but it
>> also doesn't really convey to someone new to the code what is going on.
>> Perhaps a bool typemap? or short int?
>>
>>
>
> Char isn't necessary, though I think it is a common idiom to use char as
> boolean in C programs. What do you mean by typemap (typedef?). I don't
> really think that short int is any better.
>
>
oops, I meant typedef.
> I try to use "is" in the name to indicate a boolean (and I will change
> sepol_policy_mls to sepol_policy_ismls to be consistent).
>
> <snip>
>
>
Ok.
>>> +
>>> +static char *typeid_strings[] = {
>>> + "none",
>>> + "object",
>>> + "parent",
>>> + "policy",
>>> + "module",
>>> + "block",
>>> + "cond",
>>> + "optional",
>>> + "type",
>>> + "class",
>>> + "attribute",
>>> + "typealias",
>>> + "boolean",
>>> + "avrule",
>>> + "typerule",
>>> + "security context",
>>> + "initial sid",
>>> + "typeattribute",
>>> + "conditional expression",
>>> + "sensitivity",
>>> + "dominance",
>>> + "category",
>>> + "role dominance",
>>> + "role"
>>> +};
>>> +
>>>
>>>
>> It would be nice if these were in the same place as the enum so they
>> could be updated easier, but I understand that the strings are private
>> and the enum is exported :\
>>
>>
>
> Yeah - and I've already screwed this up once. Unless you feel strongly,
> though, I'd prefer to leave this in the C file.
>
>
I don't feel strongly.
> <snip>
>
>
>>> +static int sepol_policy_tostring(struct sepol_handle *h,
>>> + struct sepol_object * object __attribute__ ((unused)),
>>> + int style, char **str)
>>> +{
>>> + if (style == SEPOL_TOSTRING_DEBUG) {
>>> + return asprintf(str, "POLICY {");
>>>
>>>
>> Why are these strings hard coded?
>>
>>
>
> What is the alternative? I could use defines, but I don't think it would
> help readability. Is that what you mean?
>
>
I suppose not it wouldn't help readability much..
>>> + } else {
>>> + *str = strdup("");
>>> + if (*str)
>>> + return 0;
>>> + else
>>> + return -1;
>>> + }
>>> +}
>>> +
>>> +static int sepol_policy_tostring_close(struct sepol_handle *h __attribute__ ((unused)),
>>> + struct sepol_object *object __attribute__ ((unused)),
>>> + int style, char **str)
>>> +{
>>> + if (style == SEPOL_TOSTRING_DEBUG) {
>>> + return asprintf(str, "POLICY {");
>>> + } else {
>>> + *str = strdup("");
>>> + if (*str)
>>> + return 0;
>>> + else
>>> + return -1;
>>> + }
>>> +}
>>> +
>>> +static struct sepol_object_methods sepol_policy_methods = {
>>> + .free = (sepol_object_free_t)sepol_policy_free,
>>> + .tostring = sepol_policy_tostring,
>>> + .tostring_close = sepol_policy_tostring_close
>>> +};
>>> +
>>> +int sepol_policy_create(struct sepol_handle *h, struct sepol_policy **policy)
>>> +{
>>> + int ret;
>>> + struct sepol_policy *x;
>>> +
>>> + *policy = NULL;
>>> + x = calloc(1, sizeof(struct sepol_policy));
>>>
>>>
>> I am adverse to calloc used on structs, this implicitly initializes the
>> struct and makes it harder to update the initial state. Why not have an
>> explicit initializer?
>>
>>
>
> I like calloc because you don't have to explicitly set all of the
> members and the code tends (in my experience) to be more reliable in the
> face of change because of this. I don't have a strong opinion though -
> what do others think?
>
>
an initializer that does memset would be just as reliable in the face of
change and have the additional advantage of being maintainable when
initial state changes.
> <snip>
>
>
>>> +
>>> +static int sepol_module_tostring(struct sepol_handle *h, struct sepol_object *object,
>>> + int style, char **str)
>>> +{
>>> + struct sepol_module *module = (struct sepol_module *)object;
>>> +
>>> + if (module->name == NULL || module->version == NULL)
>>> + return -1;
>>> +
>>> + if (style == SEPOL_TOSTRING_REFPOL)
>>> + return asprintf(str, "policy_module(%s %s)", module->name,
>>>
>>>
>> So we now have 2 syntaxes for policy modules? One here and one in the
>> lexer/parser?
>>
>>
>
> You mean that we will have to maintain information about the syntax in 2
> places? Sure - is there an alternative?
>
> <snip>
>
>
It would be nice if there was a way to keep a consistent syntax between
these components, it may not be possible though. There is a small
difference in this syntax and the policy source syntax, what is the
benefit of making them different? Won't it be more confusing when
looking at the serialized version from here vs. the source? I thought
you wanted to be able to generate source from the library for generation
tools like sepolgen?
>>> +#include "policy_internal.h"
>>> +
>>> +int intern_sepol_object_init(struct sepol_handle *h, struct sepol_object *o, uint32_t typeid,
>>> + struct sepol_object_methods *methods, struct sepol_parent *root)
>>> +{
>>> + memset(o, 0, sizeof(struct sepol_object));
>>> + o->sclass_typeid = SEPOL_TYPEID_OBJECT;
>>> + o->typeid = typeid;
>>> + o->methods = methods;
>>> + if (root && sepol_object_get_strpool(SEPOL_OBJECT(root)))
>>> + o->strpool = sepol_object_get_strpool(SEPOL_OBJECT(root));
>>> +
>>> +
>>> + return 0;
>>> +}
>>> +
>>> +void intern_sepol_object_free(struct sepol_object *o)
>>> +{
>>> + if (o == NULL)
>>> + return;
>>> +
>>> + if (o->flags & SEPOL_OBJECT_STRPOOL_OWNER)
>>> + sepol_objpool_free(NULL, o->strpool);
>>> +}
>>> +
>>> +int _intern_sepol_object_addstr(struct sepol_handle *h, struct sepol_object *o, char **str)
>>> +{
>>> + char *tmp;
>>> +
>>> + tmp = strdup(*str);
>>> + if (!tmp)
>>> + return SEPOL_ENOMEM;
>>> +
>>> + *str = tmp;
>>> +
>>> + if (o->strpool) {
>>> + *str = sepol_objpool_add(h, o->strpool, *str);
>>> + if (!*str)
>>> + return SEPOL_ENOMEM;
>>> + }
>>> +
>>> + return SEPOL_OK;
>>> +}
>>> +
>>> +int _intern_sepol_object_delstr(struct sepol_handle *h, struct sepol_object *o, char *str)
>>>
>>>
>> Why do some of these start with _ and others don't?
>>
>>
>
> The two prefixed with _ have a macro in policy_internal to wrap them. It
> just does an automatic cast to SEPOL_OBJECT to make them easier to call
> from the generation macros.
>
>
ok.
> <snip>
>
>
>>> +
>>> +struct sepol_object_methods
>>> +{
>>> + sepol_object_free_t free;
>>> + sepol_object_tostring_t tostring;
>>> + sepol_object_tostring_t tostring_close;
>>> +};
>>> +
>>> +#define SEPOL_OBJECT_STRPOOL_OWNER 1
>>> +#define SEPOL_OBJECT_VISITED 2
>>>
>>>
>> Why aren't these in an enum?
>>
>>
>
> Mainly because I didn't document them so didn't think to make the
> change. The other issue is that they are bit flags - so the defines
> might be clearer. I've changed it to an enum though.
>
>
>>> +struct sepol_object
>>> +{
>>> + struct sepol_object_methods *methods;
>>> + struct sepol_parent *parent;
>>> + struct sepol_objpool *strpool;
>>> + uint32_t sclass_typeid;
>>>
>>>
>> What is this field? Please make it less ambiguous/confusing.
>>
>>
>
> sclass = super class typeid. Would you prefer super_class_typeid?
>
>
Still not sure what it means.
> <snip>
>
>
>>> +
>>> +hidden_proto(sepol_parent_free_tree)
>>> +hidden_proto(sepol_parent_append)
>>> +hidden_proto(sepol_parent_extend)
>>> +hidden_proto(sepol_parent_extend_list)
>>> +hidden_proto(sepol_parent_del)
>>> +hidden_proto(sepol_parent_insert)
>>> +hidden_proto(sepol_parent_children)
>>> +hidden_proto(sepol_parent_get_children)
>>> +hidden_proto(sepol_parent_traverse)
>>> +hidden_proto(sepol_parent_isvisited)
>>> +
>>>
>>>
>> Hrm. IIRC hidden_proto is only needed if the function is going to be
>> exported from the shared library and also used internally, are these
>> really exported? I didn't see any map updates with this patch.
>>
>>
>
> They should have been exported - I thought there was a glob in the map
> general enough to catch them. I've updated the map.
>
>
So this is the new exported API? I'd like to see what the intentions for
the shared API are going to be since its going to have to be stable for
the foreseeable future.
> <snip>
>
>
>>> +
>>> +/*
>>> + * PROPERTY GENERATION MACROS
>>> + *
>>> + * Many of the objects are similar and will have almost identical
>>> + * functions for getting and setting properties. These macros generate
>>> + * those functions for brevity and correctness.
>>> + */
>>> +
>>> +/* Initialize an object set for holding strings. This should be used
>>> + * in an object creation function to initialize a string set. This
>>> + * handles object pooling.
>>>
>>>
>> I understand the argument for using these but its my experience that
>> they make everything harder to understand like the libselinux macros..
>>
>>
>
> I'd really prefer to keep them - they have already made development much
> easier. They generate a _lot_ of code that really is exactly the same.
> Also, I've already fixed bugs in the macros several times that would
> have resulted in painful changes otherwise.
>
> I understand that CPP is not particularly readable, but I think the
> alternative is worse.
>
>
fair enough.
--
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] 25+ messages in thread
* Re: [PATCH] Basic policy representation
2007-05-08 15:48 ` Joshua Brindle
@ 2007-05-08 16:11 ` Karl MacMillan
2007-05-08 16:47 ` Brian Pomerantz
2007-05-08 17:13 ` Stephen Smalley
0 siblings, 2 replies; 25+ messages in thread
From: Karl MacMillan @ 2007-05-08 16:11 UTC (permalink / raw)
To: Joshua Brindle; +Cc: selinux
On Tue, 2007-05-08 at 11:48 -0400, Joshua Brindle wrote:
> Karl MacMillan wrote:
> > On Tue, 2007-05-08 at 10:45 -0400, Joshua Brindle wrote:
> >
> >> Karl MacMillan wrote:
> >>
> >
> > <snip>
> >
> >
> >>> +enum sepol_typeid {
> >>> + SEPOL_TYPEID_NONE, /** special typeid representing no type */
> >>> + SEPOL_TYPEID_OBJECT, /** typeid for base class of all objects */
> >>> + SEPOL_TYPEID_PARENT, /** typeid for base class of objects that contain other objects */
> >>> + SEPOL_TYPEID_POLICY, /** typeid for policy object */
> >>> + SEPOL_TYPEID_MODULE, /** typeid for the module object */
> >>> + SEPOL_TYPEID_BLOCK, /** tyepid for the block object */
> >>> + SEPOL_TYPEID_COND, /** typeid for the cond object */
> >>> + SEPOL_TYPEID_OPTIONAL, /** typeid for the optional object */
> >>> + SEPOL_TYPEID_TYPE, /** typed for the type object */
> >>> + SEPOL_TYPEID_CLASS, /** typeid for the class object */
> >>> + SEPOL_TYPEID_ATTRIBUTE, /** typeid for the attribute object */
> >>> + SEPOL_TYPEID_TYPEALIAS, /** typeid for the typealias object */
> >>> + SEPOL_TYPEID_BOOL, /** typeid for the bool object */
> >>> + SEPOL_TYPEID_AVRULE, /** typeid for the avrule object */
> >>> + SEPOL_TYPEID_TYPERULE, /** typeid for the typerule object */
> >>> + SEPOL_TYPEID_SECURITY_CONTEXT, /** typeid for the securit context object */
> >>> + SEPOL_TYPEID_ISID, /** typeid for the isid object */
> >>> + SEPOL_TYPEID_TYPEATTRIBUTE, /** typeid for the typeattribute object */
> >>> + SEPOL_TYPEID_COND_EXPR, /** typeid for the cond expr object */
> >>> + SEPOL_TYPEID_SENS, /** typeid for the sends object */
> >>> + SEPOL_TYPEID_DOMINANCE, /** typeid for the dominance object */
> >>> + SEPOL_TYPEID_CATEGORY, /** typeid for the category object */
> >>> + SEPOL_TYPEID_ROLE_DOMINANCE, /** typeid for the role dominance object */
> >>> + SEPOL_TYPEID_ROLE /** typeid for the role object */
> >>> +};
> >>>
> >>>
> >> Do you think typeid is really a good word to use here? This is possibly
> >> very confusing (others have already mentioned to me that it was confusing)
> >>
> >>
> >
> > I'm fine with something else. Why is it confusing though? And what would
> > you suggest as a less confusing alternative?
> >
> >
>
> ILK? :P
>
NOOOOOOO - not again!
> how about objid? Its confusing because of the use of type and id, both
> of which are heavily used in the current compiler (and type being used
> in selinux)
>
The problem with objid is that it - to me - implies that it is a
per-instance identifier rather than a per-type identifier. I could
change it to classid :) Actually classid might be more consistent
overall.
Any other alternatives?
> > <snip>
> >
> >
> >>> +char sepol_parent_isvisited(struct sepol_iter *iter);
> >>> +
> >>>
> >>>
> >> is it really necessary to use a char here? granted its smaller but it
> >> also doesn't really convey to someone new to the code what is going on.
> >> Perhaps a bool typemap? or short int?
> >>
> >>
> >
> > Char isn't necessary, though I think it is a common idiom to use char as
> > boolean in C programs. What do you mean by typemap (typedef?). I don't
> > really think that short int is any better.
> >
> >
>
> oops, I meant typedef.
>
I've worked on codebases with and without boolean typedefs and
personally prefer to not have a typedef. Any other opinions?
> >>> +int sepol_policy_create(struct sepol_handle *h, struct sepol_policy **policy)
> >>> +{
> >>> + int ret;
> >>> + struct sepol_policy *x;
> >>> +
> >>> + *policy = NULL;
> >>> + x = calloc(1, sizeof(struct sepol_policy));
> >>>
> >>>
> >> I am adverse to calloc used on structs, this implicitly initializes the
> >> struct and makes it harder to update the initial state. Why not have an
> >> explicit initializer?
> >>
> >>
> >
> > I like calloc because you don't have to explicitly set all of the
> > members and the code tends (in my experience) to be more reliable in the
> > face of change because of this. I don't have a strong opinion though -
> > what do others think?
> >
> >
>
> an initializer that does memset would be just as reliable in the face of
> change and have the additional advantage of being maintainable when
> initial state changes.
>
I think I'm missing something - what is the difference between malloc +
memset and calloc? And what do you mean by initializer?
> > <snip>
> >
> >
> >>> +
> >>> +static int sepol_module_tostring(struct sepol_handle *h, struct sepol_object *object,
> >>> + int style, char **str)
> >>> +{
> >>> + struct sepol_module *module = (struct sepol_module *)object;
> >>> +
> >>> + if (module->name == NULL || module->version == NULL)
> >>> + return -1;
> >>> +
> >>> + if (style == SEPOL_TOSTRING_REFPOL)
> >>> + return asprintf(str, "policy_module(%s %s)", module->name,
> >>>
> >>>
> >> So we now have 2 syntaxes for policy modules? One here and one in the
> >> lexer/parser?
> >>
> >>
> >
> > You mean that we will have to maintain information about the syntax in 2
> > places? Sure - is there an alternative?
> >
> > <snip>
> >
> >
>
> It would be nice if there was a way to keep a consistent syntax between
> these components, it may not be possible though.
I agree it would be better, but don't know of a way to do this.
> There is a small
> difference in this syntax and the policy source syntax, what is the
> benefit of making them different?
What difference?
> Won't it be more confusing when
> looking at the serialized version from here vs. the source? I thought
> you wanted to be able to generate source from the library for generation
> tools like sepolgen?
>
I'm intending that be used for policy generation - what difference are
you talking about?
> >
> >>> +struct sepol_object
> >>> +{
> >>> + struct sepol_object_methods *methods;
> >>> + struct sepol_parent *parent;
> >>> + struct sepol_objpool *strpool;
> >>> + uint32_t sclass_typeid;
> >>>
> >>>
> >> What is this field? Please make it less ambiguous/confusing.
> >>
> >>
> >
> > sclass = super class typeid. Would you prefer super_class_typeid?
> >
> >
>
> Still not sure what it means.
Super class means the class that this class inherits from. So
sepol_policy is inherited from sepol_parent while sepol_bool is
inherited from sepol_object. The field stores this information for
sepol_object_isinstance.
Sometimes super class is called parent class, but I wanted to avoid that
since I'm using sepol_parent to mean an object that can contain other
objects (not that I really like that term, but it works).
So - that is why I think that changing typeid to classid might be better
because this would become sclass_classid, which doesn't mix terms.
Does that clear things up? What name seems clearer?
> >
> >
> >>> +
> >>> +hidden_proto(sepol_parent_free_tree)
> >>> +hidden_proto(sepol_parent_append)
> >>> +hidden_proto(sepol_parent_extend)
> >>> +hidden_proto(sepol_parent_extend_list)
> >>> +hidden_proto(sepol_parent_del)
> >>> +hidden_proto(sepol_parent_insert)
> >>> +hidden_proto(sepol_parent_children)
> >>> +hidden_proto(sepol_parent_get_children)
> >>> +hidden_proto(sepol_parent_traverse)
> >>> +hidden_proto(sepol_parent_isvisited)
> >>> +
> >>>
> >>>
> >> Hrm. IIRC hidden_proto is only needed if the function is going to be
> >> exported from the shared library and also used internally, are these
> >> really exported? I didn't see any map updates with this patch.
> >>
> >>
> >
> > They should have been exported - I thought there was a glob in the map
> > general enough to catch them. I've updated the map.
> >
> >
>
> So this is the new exported API?
Yes.
> I'd like to see what the intentions for
> the shared API are going to be since its going to have to be stable for
> the foreseeable future.
>
My plan is to export things that look very much like sepol_policy and
sepol_module. If you look at sepol_bool and the changes I have made in
this patch set you can see how I'm making those APIs match. The next
patch will be for sepol_bool, so you can see how I reconcile those APIs
(though there is still a need to break compatibility slightly).
Karl
--
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] 25+ messages in thread
* Re: [PATCH] Basic policy representation
2007-05-08 16:11 ` Karl MacMillan
@ 2007-05-08 16:47 ` Brian Pomerantz
2007-05-08 19:41 ` Karl MacMillan
2007-05-08 17:13 ` Stephen Smalley
1 sibling, 1 reply; 25+ messages in thread
From: Brian Pomerantz @ 2007-05-08 16:47 UTC (permalink / raw)
To: selinux
On Tue, May 08, 2007 at 12:11:11PM -0400, Karl MacMillan wrote:
> On Tue, 2007-05-08 at 11:48 -0400, Joshua Brindle wrote:
> > Karl MacMillan wrote:
> > > On Tue, 2007-05-08 at 10:45 -0400, Joshua Brindle wrote:
> > >
> > >> Karl MacMillan wrote:
<snip>
> > >> is it really necessary to use a char here? granted its smaller but it
> > >> also doesn't really convey to someone new to the code what is going on.
> > >> Perhaps a bool typemap? or short int?
> > >>
> > >>
> > >
> > > Char isn't necessary, though I think it is a common idiom to use char as
> > > boolean in C programs. What do you mean by typemap (typedef?). I don't
> > > really think that short int is any better.
> > >
> > >
> >
> > oops, I meant typedef.
> >
>
> I've worked on codebases with and without boolean typedefs and
> personally prefer to not have a typedef. Any other opinions?
>
Using the standard *nix form of returning int is always safe and
consistent.
BAPper
--
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] 25+ messages in thread
* Re: [PATCH] Basic policy representation
2007-05-08 14:45 ` Joshua Brindle
2007-05-08 15:08 ` Karl MacMillan
@ 2007-05-08 16:50 ` Stephen Smalley
1 sibling, 0 replies; 25+ messages in thread
From: Stephen Smalley @ 2007-05-08 16:50 UTC (permalink / raw)
To: Joshua Brindle; +Cc: Karl MacMillan, selinux
On Tue, 2007-05-08 at 10:45 -0400, Joshua Brindle wrote:
> Karl MacMillan wrote:
>snip>
> > +static char *typeid_strings[] = {
> > + "none",
> > + "object",
> > + "parent",
> > + "policy",
> > + "module",
> > + "block",
> > + "cond",
> > + "optional",
> > + "type",
> > + "class",
> > + "attribute",
> > + "typealias",
> > + "boolean",
> > + "avrule",
> > + "typerule",
> > + "security context",
> > + "initial sid",
> > + "typeattribute",
> > + "conditional expression",
> > + "sensitivity",
> > + "dominance",
> > + "category",
> > + "role dominance",
> > + "role"
> > +};
> > +
> >
> It would be nice if these were in the same place as the enum so they
> could be updated easier, but I understand that the strings are private
> and the enum is exported :\
One thing that would make them nicer for maintenance and readability
would be explicit indices in the array definition here, ala:
static char *typeid_strings[] = {
[SEPOL_TYPEID_NONE] = "none",
[SEPOL_TYPEID_OBJECT] = "object",
...
--
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] 25+ messages in thread
* Re: [PATCH] Basic policy representation
2007-05-08 16:11 ` Karl MacMillan
2007-05-08 16:47 ` Brian Pomerantz
@ 2007-05-08 17:13 ` Stephen Smalley
2007-05-08 18:37 ` Joshua Brindle
1 sibling, 1 reply; 25+ messages in thread
From: Stephen Smalley @ 2007-05-08 17:13 UTC (permalink / raw)
To: Karl MacMillan; +Cc: Joshua Brindle, selinux
On Tue, 2007-05-08 at 12:11 -0400, Karl MacMillan wrote:
> On Tue, 2007-05-08 at 11:48 -0400, Joshua Brindle wrote:
<snip>
> > >>> +int sepol_policy_create(struct sepol_handle *h, struct sepol_policy **policy)
> > >>> +{
> > >>> + int ret;
> > >>> + struct sepol_policy *x;
> > >>> +
> > >>> + *policy = NULL;
> > >>> + x = calloc(1, sizeof(struct sepol_policy));
> > >>>
> > >>>
> > >> I am adverse to calloc used on structs, this implicitly initializes the
> > >> struct and makes it harder to update the initial state. Why not have an
> > >> explicit initializer?
> > >>
> > >>
> > >
> > > I like calloc because you don't have to explicitly set all of the
> > > members and the code tends (in my experience) to be more reliable in the
> > > face of change because of this. I don't have a strong opinion though -
> > > what do others think?
> > >
> > >
> >
> > an initializer that does memset would be just as reliable in the face of
> > change and have the additional advantage of being maintainable when
> > initial state changes.
> >
>
> I think I'm missing something - what is the difference between malloc +
> memset and calloc? And what do you mean by initializer?
I'd say stay with calloc here.
--
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] 25+ messages in thread
* Re: [PATCH] Basic policy representation
2007-05-08 17:13 ` Stephen Smalley
@ 2007-05-08 18:37 ` Joshua Brindle
2007-05-08 19:05 ` Stephen Smalley
0 siblings, 1 reply; 25+ messages in thread
From: Joshua Brindle @ 2007-05-08 18:37 UTC (permalink / raw)
To: Stephen Smalley; +Cc: Karl MacMillan, selinux
Stephen Smalley wrote:
> On Tue, 2007-05-08 at 12:11 -0400, Karl MacMillan wrote:
>
>> On Tue, 2007-05-08 at 11:48 -0400, Joshua Brindle wrote:
>>
> <snip>
>
>>>>>> +int sepol_policy_create(struct sepol_handle *h, struct sepol_policy **policy)
>>>>>> +{
>>>>>> + int ret;
>>>>>> + struct sepol_policy *x;
>>>>>> +
>>>>>> + *policy = NULL;
>>>>>> + x = calloc(1, sizeof(struct sepol_policy));
>>>>>>
>>>>>>
>>>>>>
>>>>> I am adverse to calloc used on structs, this implicitly initializes the
>>>>> struct and makes it harder to update the initial state. Why not have an
>>>>> explicit initializer?
>>>>>
>>>>>
>>>>>
>>>> I like calloc because you don't have to explicitly set all of the
>>>> members and the code tends (in my experience) to be more reliable in the
>>>> face of change because of this. I don't have a strong opinion though -
>>>> what do others think?
>>>>
>>>>
>>>>
>>> an initializer that does memset would be just as reliable in the face of
>>> change and have the additional advantage of being maintainable when
>>> initial state changes.
>>>
>>>
>> I think I'm missing something - what is the difference between malloc +
>> memset and calloc? And what do you mean by initializer?
>>
>
> I'd say stay with calloc here.
>
>
Umm, and then when the initial state changes we have to audit every user
of the struct to make sure its initialized correctly instead of just
doing it from the beginning and using an initialization function?
--
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] 25+ messages in thread
* Re: [PATCH] Basic policy representation
2007-05-08 18:37 ` Joshua Brindle
@ 2007-05-08 19:05 ` Stephen Smalley
2007-05-08 19:28 ` Joshua Brindle
0 siblings, 1 reply; 25+ messages in thread
From: Stephen Smalley @ 2007-05-08 19:05 UTC (permalink / raw)
To: Joshua Brindle; +Cc: Karl MacMillan, selinux
On Tue, 2007-05-08 at 14:37 -0400, Joshua Brindle wrote:
> Stephen Smalley wrote:
> > On Tue, 2007-05-08 at 12:11 -0400, Karl MacMillan wrote:
> >
> >> On Tue, 2007-05-08 at 11:48 -0400, Joshua Brindle wrote:
> >>
> > <snip>
> >
> >>>>>> +int sepol_policy_create(struct sepol_handle *h, struct sepol_policy **policy)
> >>>>>> +{
> >>>>>> + int ret;
> >>>>>> + struct sepol_policy *x;
> >>>>>> +
> >>>>>> + *policy = NULL;
> >>>>>> + x = calloc(1, sizeof(struct sepol_policy));
> >>>>>>
> >>>>>>
> >>>>>>
> >>>>> I am adverse to calloc used on structs, this implicitly initializes the
> >>>>> struct and makes it harder to update the initial state. Why not have an
> >>>>> explicit initializer?
> >>>>>
> >>>>>
> >>>>>
> >>>> I like calloc because you don't have to explicitly set all of the
> >>>> members and the code tends (in my experience) to be more reliable in the
> >>>> face of change because of this. I don't have a strong opinion though -
> >>>> what do others think?
> >>>>
> >>>>
> >>>>
> >>> an initializer that does memset would be just as reliable in the face of
> >>> change and have the additional advantage of being maintainable when
> >>> initial state changes.
> >>>
> >>>
> >> I think I'm missing something - what is the difference between malloc +
> >> memset and calloc? And what do you mean by initializer?
> >>
> >
> > I'd say stay with calloc here.
> >
> >
>
> Umm, and then when the initial state changes we have to audit every user
> of the struct to make sure its initialized correctly instead of just
> doing it from the beginning and using an initialization function?
This is the initialization (and allocation) function for struct
sepol_policy.
--
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] 25+ messages in thread
* Re: [PATCH] Basic policy representation
2007-05-08 19:05 ` Stephen Smalley
@ 2007-05-08 19:28 ` Joshua Brindle
2007-05-08 19:36 ` Karl MacMillan
0 siblings, 1 reply; 25+ messages in thread
From: Joshua Brindle @ 2007-05-08 19:28 UTC (permalink / raw)
To: Stephen Smalley; +Cc: Karl MacMillan, selinux
Stephen Smalley wrote:
> On Tue, 2007-05-08 at 14:37 -0400, Joshua Brindle wrote:
>
>> Stephen Smalley wrote:
>>
>>> On Tue, 2007-05-08 at 12:11 -0400, Karl MacMillan wrote:
>>>
>>>
>>>> On Tue, 2007-05-08 at 11:48 -0400, Joshua Brindle wrote:
>>>>
>>>>
>>> <snip>
>>>
>>>
>>>>>>>> +int sepol_policy_create(struct sepol_handle *h, struct sepol_policy **policy)
>>>>>>>> +{
>>>>>>>> + int ret;
>>>>>>>> + struct sepol_policy *x;
>>>>>>>> +
>>>>>>>> + *policy = NULL;
>>>>>>>> + x = calloc(1, sizeof(struct sepol_policy));
>>>>>>>>
>>>>>>>>
>>>>>>>>
>>>>>>>>
>>>>>>> I am adverse to calloc used on structs, this implicitly initializes the
>>>>>>> struct and makes it harder to update the initial state. Why not have an
>>>>>>> explicit initializer?
>>>>>>>
>>>>>>>
>>>>>>>
>>>>>>>
>>>>>> I like calloc because you don't have to explicitly set all of the
>>>>>> members and the code tends (in my experience) to be more reliable in the
>>>>>> face of change because of this. I don't have a strong opinion though -
>>>>>> what do others think?
>>>>>>
>>>>>>
>>>>>>
>>>>>>
>>>>> an initializer that does memset would be just as reliable in the face of
>>>>> change and have the additional advantage of being maintainable when
>>>>> initial state changes.
>>>>>
>>>>>
>>>>>
>>>> I think I'm missing something - what is the difference between malloc +
>>>> memset and calloc? And what do you mean by initializer?
>>>>
>>>>
>>> I'd say stay with calloc here.
>>>
>>>
>>>
>> Umm, and then when the initial state changes we have to audit every user
>> of the struct to make sure its initialized correctly instead of just
>> doing it from the beginning and using an initialization function?
>>
>
> This is the initialization (and allocation) function for struct
> sepol_policy.
>
err, so it is. I'm not use to allocating and initializing in the same
function since we don't do that much in this library.
--
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] 25+ messages in thread
* Re: [PATCH] Basic policy representation
2007-05-08 19:28 ` Joshua Brindle
@ 2007-05-08 19:36 ` Karl MacMillan
0 siblings, 0 replies; 25+ messages in thread
From: Karl MacMillan @ 2007-05-08 19:36 UTC (permalink / raw)
To: Joshua Brindle; +Cc: Stephen Smalley, selinux
On Tue, 2007-05-08 at 15:28 -0400, Joshua Brindle wrote:
> Stephen Smalley wrote:
> > On Tue, 2007-05-08 at 14:37 -0400, Joshua Brindle wrote:
> >
> >> Stephen Smalley wrote:
> >>
> >>> On Tue, 2007-05-08 at 12:11 -0400, Karl MacMillan wrote:
> >>>
> >>>
> >>>> On Tue, 2007-05-08 at 11:48 -0400, Joshua Brindle wrote:
> >>>>
> >>>>
> >>> <snip>
> >>>
> >>>
> >>>>>>>> +int sepol_policy_create(struct sepol_handle *h, struct sepol_policy **policy)
> >>>>>>>> +{
> >>>>>>>> + int ret;
> >>>>>>>> + struct sepol_policy *x;
> >>>>>>>> +
> >>>>>>>> + *policy = NULL;
> >>>>>>>> + x = calloc(1, sizeof(struct sepol_policy));
> >>>>>>>>
> >>>>>>>>
> >>>>>>>>
> >>>>>>>>
> >>>>>>> I am adverse to calloc used on structs, this implicitly initializes the
> >>>>>>> struct and makes it harder to update the initial state. Why not have an
> >>>>>>> explicit initializer?
> >>>>>>>
> >>>>>>>
> >>>>>>>
> >>>>>>>
> >>>>>> I like calloc because you don't have to explicitly set all of the
> >>>>>> members and the code tends (in my experience) to be more reliable in the
> >>>>>> face of change because of this. I don't have a strong opinion though -
> >>>>>> what do others think?
> >>>>>>
> >>>>>>
> >>>>>>
> >>>>>>
> >>>>> an initializer that does memset would be just as reliable in the face of
> >>>>> change and have the additional advantage of being maintainable when
> >>>>> initial state changes.
> >>>>>
> >>>>>
> >>>>>
> >>>> I think I'm missing something - what is the difference between malloc +
> >>>> memset and calloc? And what do you mean by initializer?
> >>>>
> >>>>
> >>> I'd say stay with calloc here.
> >>>
> >>>
> >>>
> >> Umm, and then when the initial state changes we have to audit every user
> >> of the struct to make sure its initialized correctly instead of just
> >> doing it from the beginning and using an initialization function?
> >>
> >
> > This is the initialization (and allocation) function for struct
> > sepol_policy.
> >
> err, so it is. I'm not use to allocating and initializing in the same
> function since we don't do that much in this library.
No point in separating them because the struct is opaque. You can't put
them on the stack or use them in an array, so a separate init function
is not useful.
Karl
--
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] 25+ messages in thread
* Re: [PATCH] Basic policy representation
2007-05-08 16:47 ` Brian Pomerantz
@ 2007-05-08 19:41 ` Karl MacMillan
2007-05-09 14:03 ` Karl MacMillan
0 siblings, 1 reply; 25+ messages in thread
From: Karl MacMillan @ 2007-05-08 19:41 UTC (permalink / raw)
To: Brian Pomerantz; +Cc: selinux
On Tue, 2007-05-08 at 09:47 -0700, Brian Pomerantz wrote:
> On Tue, May 08, 2007 at 12:11:11PM -0400, Karl MacMillan wrote:
> > On Tue, 2007-05-08 at 11:48 -0400, Joshua Brindle wrote:
> > > Karl MacMillan wrote:
> > > > On Tue, 2007-05-08 at 10:45 -0400, Joshua Brindle wrote:
> > > >
> > > >> Karl MacMillan wrote:
> <snip>
> > > >> is it really necessary to use a char here? granted its smaller but it
> > > >> also doesn't really convey to someone new to the code what is going on.
> > > >> Perhaps a bool typemap? or short int?
> > > >>
> > > >>
> > > >
> > > > Char isn't necessary, though I think it is a common idiom to use char as
> > > > boolean in C programs. What do you mean by typemap (typedef?). I don't
> > > > really think that short int is any better.
> > > >
> > > >
> > >
> > > oops, I meant typedef.
> > >
> >
> > I've worked on codebases with and without boolean typedefs and
> > personally prefer to not have a typedef. Any other opinions?
> >
>
> Using the standard *nix form of returning int is always safe and
> consistent.
>
I actually prefer returning char instead - to me that is a common way to
indicate that the returned value has a limited range of values (2 in
this case). But maybe that is just the code bases I've worked on. I
don't care either way - this seems like a bike shed discussion . . .
Karl
--
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] 25+ messages in thread
* Re: [PATCH] Basic policy representation
2007-05-08 19:41 ` Karl MacMillan
@ 2007-05-09 14:03 ` Karl MacMillan
2007-05-11 15:27 ` Joshua Brindle
0 siblings, 1 reply; 25+ messages in thread
From: Karl MacMillan @ 2007-05-09 14:03 UTC (permalink / raw)
To: Brian Pomerantz; +Cc: selinux
On Tue, 2007-05-08 at 15:41 -0400, Karl MacMillan wrote:
> On Tue, 2007-05-08 at 09:47 -0700, Brian Pomerantz wrote:
> > On Tue, May 08, 2007 at 12:11:11PM -0400, Karl MacMillan wrote:
> > > On Tue, 2007-05-08 at 11:48 -0400, Joshua Brindle wrote:
> > > > Karl MacMillan wrote:
> > > > > On Tue, 2007-05-08 at 10:45 -0400, Joshua Brindle wrote:
> > > > >
> > > > >> Karl MacMillan wrote:
> > <snip>
> > > > >> is it really necessary to use a char here? granted its smaller but it
> > > > >> also doesn't really convey to someone new to the code what is going on.
> > > > >> Perhaps a bool typemap? or short int?
> > > > >>
> > > > >>
> > > > >
> > > > > Char isn't necessary, though I think it is a common idiom to use char as
> > > > > boolean in C programs. What do you mean by typemap (typedef?). I don't
> > > > > really think that short int is any better.
> > > > >
> > > > >
> > > >
> > > > oops, I meant typedef.
> > > >
> > >
> > > I've worked on codebases with and without boolean typedefs and
> > > personally prefer to not have a typedef. Any other opinions?
> > >
> >
> > Using the standard *nix form of returning int is always safe and
> > consistent.
> >
>
> I actually prefer returning char instead - to me that is a common way to
> indicate that the returned value has a limited range of values (2 in
> this case). But maybe that is just the code bases I've worked on. I
> don't care either way - this seems like a bike shed discussion . . .
>
On the other hand, the existing code (for things like sepol_bool) uses
int for boolean values. So I'll change to using int everywhere.
Ahh . . . the bike shed looks much nicer painted blue rather than green.
Karl
--
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] 25+ messages in thread
* Re: [PATCH] Basic policy representation
2007-05-07 22:06 [PATCH] Basic policy representation Karl MacMillan
2007-05-08 14:45 ` Joshua Brindle
@ 2007-05-09 16:24 ` James Antill
2007-05-09 18:31 ` Karl MacMillan
2007-05-09 18:35 ` J. Tang
2 siblings, 1 reply; 25+ messages in thread
From: James Antill @ 2007-05-09 16:24 UTC (permalink / raw)
To: Karl MacMillan; +Cc: selinux
[-- Attachment #1: Type: text/plain, Size: 20953 bytes --]
On Mon, 2007-05-07 at 18:06 -0400, Karl MacMillan wrote:
> Add support for the basic policy object model and the sepol_policy
> and sepol_module objects to libsepol. This version has significant
> changes from the last posted version:
>
> 1) sepol_handle is passed everywhere
> 2) public and private interfaces to the object system are correctly
> split (into policy.[c,h] and policy_internal.[c,h].
> 3) object ouput has been converted from writing to a FILE to returning
> allocated strings. This will help integrate better with scripting
> languages.
> 4) Basic documentation is included for the base objects.
> 5) Enums are used instead of defines - this is a change from the style
> for libsepol, but it makes documenting the enums much easier.
One idiom that is often used is:
enum {
FOO = 0,
#define FOO FOO
[...]
};
> Signed-off-by: User "Karl MacMillan <kmacmillan@mentalrootkit.com>"
> ---
>
> 7 files changed, 1667 insertions(+), 4 deletions(-)
> libsepol/include/sepol/policy.h | 522 +++++++++++++++++++++++++++++++
> libsepol/src/policy.c | 638 +++++++++++++++++++++++++++++++++++++++
> libsepol/src/policy_internal.c | 102 ++++++
> libsepol/src/policy_internal.h | 269 ++++++++++++++++
> libsepol/tests/libsepol-tests.c | 10
> libsepol/tests/test-policy.c | 118 +++++++
> libsepol/tests/test-policy.h | 12
[...]
> diff -r cacdf4377ebf -r bd4ee6e00a63 libsepol/src/policy.c
> --- a/libsepol/src/policy.c Mon May 07 15:50:27 2007 -0400
> +++ b/libsepol/src/policy.c Mon May 07 18:03:03 2007 -0400
> +/*
> + * SEPOL_OBJECT
> + */
> +
> +static char *typeid_strings[] = {
> + "none",
[...]
> + "role"
> +};
> +
> +const char *sepol_typeid_tostring(int typeid)
> +{
> + assert(typeid < sizeof(typeid_strings));
This assert is wrong.
> + return typeid_strings[typeid];
> +}
> +hidden_def(sepol_typeid_tostring)
> +
> +int sepol_object_free(struct sepol_handle *h, struct sepol_object *o)
> +{
> + assert(o->methods->free);
> +
> + return o->methods->free(h, o);
> +}
> +hidden_def(sepol_object_free)
Personally I find it's almost always a good idea to retain the
semantics of free(NULL) in free'ing functions (as it often cleans up the
deallocation paths).
> +#define SEPOL_STRPOOL_SIZE 64
> +int sepol_object_create_strpool(struct sepol_handle *h, struct sepol_object *o)
> +{
> + int ret;
> +
> + ret = sepol_objpool_create(h, &o->strpool, (sepol_objpool_hash_t)sepol_symhash,
> + (sepol_objpool_cmp_t)sepol_symcmp, free,
> + SEPOL_STRPOOL_SIZE);
> + ret_check(ret);
> + o->flags |= SEPOL_OBJECT_STRPOOL_OWNER;
> +
> + return ret;
> +}
> +hidden_def(sepol_object_create_strpool)
> +
> +struct sepol_objpool *sepol_object_get_strpool(struct sepol_object *o)
> +{
> + return o->strpool;
> +}
> +hidden_def(sepol_object_get_strpool)
> +
> +char sepol_object_is_strpool_owner(struct sepol_object *o)
> +{
> + return (o->flags & SEPOL_OBJECT_STRPOOL_OWNER) != 0;
> +}
> +hidden_def(sepol_object_is_strpool_owner)
This confused me, why would the base call for all objects need a
strpool?
> +
> +uint32_t sepol_object_get_typeid(struct sepol_object *o)
> +{
> + return o->typeid;
> +}
> +hidden_def(sepol_object_get_typeid)
> +
> +char sepol_object_isinstance(struct sepol_object *o, uint32_t typeid)
> +{
> + if (o->typeid == typeid || o->sclass_typeid == typeid)
> + return 1;
> + else return 0;
> +}
> +hidden_def(sepol_object_isinstance)
You can only have one layer of inheritance?
> +struct sepol_parent *sepol_object_get_parent(struct sepol_object *o)
> +{
> + return o->parent;
> +}
> +hidden_def(sepol_object_get_parent)
> +
> +int sepol_object_tostring(struct sepol_handle *h, struct sepol_object *o,
> + int style, char **str)
> +{
Why don't you just return the string?
> + if (o->methods->tostring) {
> + return o->methods->tostring(h, o, style, str);
> + } else {
> + if (style == SEPOL_TOSTRING_DEBUG) {
> + return asprintf(str, "[sepol_object(%s) at %p]",
> + sepol_typeid_tostring(o->typeid), o);
> + }
Given that sepol_typeid_tostring() can/is being called as above, it
seems like a bad idea to just return allocaed memory here.
The obvious fix is to save the result into o->store_tostring ...
free()'ing that when the object is destroyed, or _tostring is called
again (although possibly just re-using it, for a speed benefit, might be
worthwhile).
> +
> + /* Even though we are returning an empty string, we still
> + * need to allocated an empty string to return. This
> + * matches the behavior of asprintf.
> + */
> + *str = strdup("");
> + if (*str == NULL)
> + return -1;
> + return 0;
> + }
> +}
> +hidden_def(sepol_object_tostring)
> +
> +int sepol_object_tostring_close(struct sepol_handle *h, struct sepol_object *o,
> + int style, char **str)
> +{
> + if (o->methods->tostring_close) {
> + return o->methods->tostring_close(h, o, style, str);
> + } else {
> + if (style == SEPOL_TOSTRING_DEBUG) {
> + return asprintf(str, "[close: sepol_object(%s) at %p]",
> + sepol_typeid_tostring(o->typeid), o);
> + }
> +
> + /* Even though we are returning an empty string, we still
> + * need to allocated an empty string to return. This
> + * matches the behavior of asprintf.
> + */
> + *str = strdup("");
> + if (*str == NULL)
> + return -1;
> + return 0;
> + }
> +}
> +hidden_def(sepol_object_tostring_close)
> +
> +/*
> + * SEPOL_PARENT
> + */
> +
> +int sepol_parent_free_tree(struct sepol_handle *h, struct sepol_parent *p)
> +{
> + int ret;
> + struct sepol_iter *iter;
> + struct sepol_object *cur;
> +
> + ret = sepol_iter_create(h, &iter);
> + if (ret < 0)
> + goto out;
> +
> + ret = sepol_parent_traverse(h, p, iter, SEPOL_TRAVERSE_POSTORDER);
> + if (ret < 0)
> + goto out;
> +
> + sepol_foreach(h, ret, cur, iter) {
> + int ret2;
> + char *str;
> + ret2 = sepol_object_tostring(h, cur, SEPOL_TOSTRING_DEBUG, &str);
> + assert(ret2 >= 0);
ret2 is malloc()'d data.
> + printf("freeing %s", str);
printf??
> + sepol_object_free(h, cur);
> + free(str);
> + }
> + if (ret != SEPOL_ITERSTOP)
> + goto out;
> +
> + ret = SEPOL_OK;
> +out:
> + sepol_iter_free(h, iter);
> + return ret;
> +}
> +hidden_def(sepol_parent_free_tree)
> +
> +int sepol_parent_append(struct sepol_handle *h, struct sepol_parent *p, struct sepol_object *o)
> +{
> + if (o->parent)
> + return SEPOL_EEXIST;
> + o->parent = p;
> + return sepol_list_append(h, p->children, o);
> +}
This seems like a bad name, the task you are really doing is "attaching
a parent to an object" not "appending a child to a parent". Also what
happens if list_append() fails ... ->parent is set, how can you recover?
> +hidden_def(sepol_parent_append)
> +
> +int sepol_parent_extend(struct sepol_handle *h, struct sepol_parent *p, struct sepol_iter *iter)
> +{
> + int ret = SEPOL_OK;
> + struct sepol_object *cur;
> +
> + sepol_foreach(h, ret, cur, iter) {
> + ret = sepol_parent_append(h, p, cur);
Even if you leave it with the parent POV, I think you really want
"append one object", "append iter of objects" and "append list of
objects" to all have a prefix.
> + if (ret < 0) {
> + return ret;
> + }
> + }
> + if (ret != SEPOL_ITERSTOP) {
> + return ret;
> + }
> +
> + return SEPOL_OK;
> +}
> +hidden_def(sepol_parent_extend)
> +
> +int sepol_parent_extend_list(struct sepol_handle *h, struct sepol_parent *p, struct sepol_list *list)
> +{
> + int ret;
> + struct sepol_iter *iter;
> +
> + ret = sepol_iter_create(h, &iter);
> + if (ret < 0)
> + return ret;
> + ret = sepol_list_begin(h, list, iter);
> + if (ret < 0) {
> + if (ret == SEPOL_ITERSTOP)
> + return SEPOL_OK;
> + else
> + return ret;
> + }
> + ret = sepol_parent_extend(h, p, iter);
> + sepol_iter_free(h, iter);
> +
> + return ret;
> +}
> +hidden_def(sepol_parent_extend_list)
> +
> +int sepol_parent_del(struct sepol_handle *h, struct sepol_parent *p, struct sepol_iter *iter)
> +{
> + struct sepol_object *o;
> + o = (struct sepol_object*)sepol_iter_get_data(h, iter);
> + if (!o) {
> + ERR(h, "error getting object from iterator");
> + return SEPOL_ERR;
> + }
> + o->parent = NULL;
> + return sepol_list_del(h, p->children, iter);
> +}
sepoll_list_del can't fail here, right?
> +hidden_def(sepol_parent_del)
> +
> +int sepol_parent_insert(struct sepol_handle *h, struct sepol_parent *p,
> + struct sepol_iter *iter, struct sepol_object *o)
> +{
> + if (o->parent)
> + return SEPOL_EEXIST;
> + o->parent = p;
> +
> + return sepol_list_insert(h, p->children, iter, o);
> +}
> +hidden_def(sepol_parent_insert)
Why do you have insert and append? Dito problem if list_insert fails.
> +
> +int sepol_parent_children(struct sepol_handle *h, struct sepol_parent *p, struct sepol_iter *iter)
> +{
> + return sepol_list_begin(h, p->children, iter);
> +}
> +hidden_def(sepol_parent_children)
Putting something to do with "iter" in the name would probably be a
good idea.
> +struct sepol_list *sepol_parent_get_children(struct sepol_parent *parent)
> +{
> + return parent->children;
> +}
> +hidden_def(sepol_parent_get_children)
> +
> +
> +struct sepol_parent_traverse_state
> +{
> + int strategy;
> + char cur_flags;
> + struct sepol_list *stack;
> + void *object;
> +};
> +
> +static void *sepol_parent_iter_get_data(struct sepol_handle *h, struct sepol_iter *iter)
> +{
> + struct sepol_parent_traverse_state *state;
> +
> + assert(iter);
Is it possible to use the GCC nonnull attributes? It also seems really
bizarre how much sepol_handle is passed around but never used.
> + state = (struct sepol_parent_traverse_state*)
> + sepol_iter_get_state(iter);
> + assert(state);
> +
> + return state->object;
> +}
> +
> +static int sepol_parent_iter_free(struct sepol_handle *h, void *data)
> +{
> + struct sepol_parent_traverse_state *state =
> + (struct sepol_parent_traverse_state*)data;
You don't need the cast in C, only in C++.
> +static int sepol_policy_tostring(struct sepol_handle *h,
> + struct sepol_object * object __attribute__ ((unused)),
> + int style, char **str)
> +{
> + if (style == SEPOL_TOSTRING_DEBUG) {
> + return asprintf(str, "POLICY {");
> + } else {
> + *str = strdup("");
> + if (*str)
> + return 0;
> + else
> + return -1;
> + }
> +}
> +
> +static int sepol_policy_tostring_close(struct sepol_handle *h __attribute__ ((unused)),
> + struct sepol_object *object __attribute__ ((unused)),
> + int style, char **str)
> +{
> + if (style == SEPOL_TOSTRING_DEBUG) {
> + return asprintf(str, "POLICY {");
== strdup
> + } else {
> + *str = strdup("");
> + if (*str)
> + return 0;
> + else
> + return -1;
> + }
> +}
[...]
> +/* Internal structs and functions for the policy object system. In
> + * general, policy objects cannot be created outside of the libsepol
> + * tree. It is possible, but not currently implemented, so there is
> + * quite a lot of internals in this header.
> + *
> + * One of the goals of this object system is to allow polymorphic
> + * methods. That will allow calling , for example, sepol_object_free
> + * on _any_ subclass of sepol_object and have the correct function
> + * called for the specific subclass. This polymorphism is implemented
> + * using an sepol_object_method struct for each class and a pointer to
> + * that struct held in each object instance.
> + *
> + * A subclass is expected to create an sepol_object_methods struct
> + * containing function pointers for the methods that it implements (it
> + * is valid for some of the function pointers to be NULL). Every
> + * instance of an sepol_object object holds a pointer to a single
> + * methods struct - i.e., there is only one struct per class and every
> + * instance holds a pointer to that struct.
> + *
> + * See sepol_object_init for how this pointer is set and sepol_object_free
> + * for how subclass methods are called.
> + */
> +
> +/* sepol_object_free_t is the type for the free method used in the policy
> + * object system. Implementations of this method should free all of the
> + * memory associated with the object including the struct.
> + */
> +typedef int (*sepol_object_free_t)(struct sepol_handle *h, struct sepol_object *o);
> +typedef int (*sepol_object_tostring_t)(struct sepol_handle *h, struct sepol_object *o,
> + int style, char **str);
> +
> +struct sepol_object_methods
> +{
> + sepol_object_free_t free;
> + sepol_object_tostring_t tostring;
> + sepol_object_tostring_t tostring_close;
> +};
> +
> +#define SEPOL_OBJECT_STRPOOL_OWNER 1
> +#define SEPOL_OBJECT_VISITED 2
> +struct sepol_object
> +{
> + struct sepol_object_methods *methods;
> + struct sepol_parent *parent;
> + struct sepol_objpool *strpool;
> + uint32_t sclass_typeid;
> + uint32_t typeid;
> + uint32_t lineno;
> + char flags;
using char here seems iffy, the compiler is almost certainly going to
expand to uint size anyway due to padding.
> +};
> +
> +/* Private initialization function for all objects. This function only
> + * initializes the generic object properties - the type specific creation
> + * function is responsible for initializing any type specific properties.
> + * If this function fails it will clean up any memory that it allocated. The
> + * calling function is responsible for any type specific memory and for freeing
> + * the object struct.
> + *
> + * params:
> + * o - object to initialize
> + * typeid - typeid of o
> + * methods - pointer to sepol_object_methods struct for this type. Should
> + * be a pointer to a single static struct for all instances of this type.
> + * root - root of the policy tree of which o is a member (may be NULL). If
> + * the root is non-NULL and has a string pool then that string pool is
> + * used for this object.
> + */
> +int intern_sepol_object_init(struct sepol_handle *h, struct sepol_object *o, uint32_t typeid,
> + struct sepol_object_methods *methods, struct sepol_parent *root);
> +
> +/* Free any memory associated with the super class. This should be called
> + * from a type specific free function.
> + */
> +void intern_sepol_object_free(struct sepol_object *o);
> +
> +/* Add a string to the string pool of the object. After a call to this
> + * function the str pointer will point to the correct (and possibly
> + * shared) version of the string to use.
> + */
> +#define intern_sepol_object_addstr(h, o, str) _intern_sepol_object_addstr(h, SEPOL_OBJECT(o), str)
> +int _intern_sepol_object_addstr(struct sepol_handle *h, struct sepol_object *o, char **str);
> +
> +/* Delete a string. If the object has a string pool the memory
> + * associated with the string may not be released
> + * immediately. Regardless, the caller should assume that the pointer
> + * is invalid after a call to this function.
> + */
> +#define intern_sepol_object_delstr(h, o, str) _intern_sepol_object_delstr(h, SEPOL_OBJECT(o), str)
> +int _intern_sepol_object_delstr(struct sepol_handle *h, struct sepol_object *o, char *str);
> +
> +hidden_proto(sepol_typeid_tostring)
> +hidden_proto(sepol_object_free)
> +hidden_proto(sepol_object_create_strpool)
> +hidden_proto(sepol_object_get_strpool)
> +hidden_proto(sepol_object_is_strpool_owner)
> +hidden_proto(sepol_object_get_typeid)
> +hidden_proto(sepol_object_isinstance)
> +hidden_proto(sepol_object_get_parent)
> +hidden_proto(sepol_object_tostring)
> +hidden_proto(sepol_object_tostring_close)
> +
> +struct sepol_parent
> +{
> + struct sepol_object sclass;
> + struct sepol_list *children;
> +};
> +
> +/* Initialize an sepol_parent object. Same function and general
> + * properties as intern_sepol_object_init but for parent
> + * objects. Objects should only call the init function for their
> + * immediate parent - the parent is responsible for any further
> + * chaining up the type hierarchy.
> + */
> +int intern_sepol_parent_init(struct sepol_handle *h, struct sepol_parent *p, uint32_t typeid,
> + struct sepol_object_methods *methods, struct sepol_parent *root);
> +
> +/* Internal free function for sepol_paren objects. Like the init functions
> + * this chains up the type hierarchy by call inter_sepol_object_free.
> + */
> +void intern_sepol_parent_free(struct sepol_parent *p);
> +
> +hidden_proto(sepol_parent_free_tree)
> +hidden_proto(sepol_parent_append)
> +hidden_proto(sepol_parent_extend)
> +hidden_proto(sepol_parent_extend_list)
> +hidden_proto(sepol_parent_del)
> +hidden_proto(sepol_parent_insert)
> +hidden_proto(sepol_parent_children)
> +hidden_proto(sepol_parent_get_children)
> +hidden_proto(sepol_parent_traverse)
> +hidden_proto(sepol_parent_isvisited)
> +
> +/* sepol_policy */
> +hidden_proto(sepol_policy_free)
> +hidden_proto(sepol_policy_get_mls)
> +hidden_proto(sepol_policy_set_mls)
> +
> +/* sepol_module */
> +hidden_proto(sepol_module_free)
> +hidden_proto(sepol_module_create)
> +hidden_proto(sepol_module_create_tree)
> +hidden_proto(sepol_module_set_name)
> +hidden_proto(sepol_module_get_name)
> +hidden_proto(sepol_module_set_version)
> +hidden_proto(sepol_module_get_version)
> +hidden_proto(sepol_module_set_isbase)
> +hidden_proto(sepol_module_get_isbase)
> +
> +
> +/* some convenience macros to check return values */
> +#define ret_check(ret) { if (ret < 0) return ret; }
> +#define ret_goto(ret, tag) { if (ret < 0) goto tag; }
These are just evil, and I don't mind invisible returns in macros when
it's kind of obvious that's what they do.
They should be in CAPS, have the "do {} while" idiom, the name isn't
great as check == return is not obvious and you should use (ret) instead
of ret. Maybe:
#define RC_FAIL_RETURN(ret) do { if ((ret) < 0) return (ret); } while (FALSE)
#define RC_FAIL_GOTO(ret, tag) do { if ((ret) < 0) goto tag; } while (FALSE)
...but I'm also unconvinced they help, for instance you have:
ret = foo();
RC_FAIL_RETURN(ret);
...instead of:
if ((ret = foo()) < 0)
return (ret);
...even if you split the assignment out of the condition, it's only one
extra line ... so it doesn't seem like they are doing enough.
> +/*
> + * PROPERTY GENERATION MACROS
> + *
> + * Many of the objects are similar and will have almost identical
> + * functions for getting and setting properties. These macros generate
> + * those functions for brevity and correctness.
> + */
> +
> +/* Initialize an object set for holding strings. This should be used
> + * in an object creation function to initialize a string set. This
> + * handles object pooling.
> + */
> +#define INIT_STRSET(obj, set, ret, target) { \
> + if (SEPOL_OBJECT(obj)->strpool) { \
> + ret = sepol_objset_create(&obj->set, sepol_policy_ptrcmp); \
> + ret_goto(ret, target); \
> + } else { \
> + ret = sepol_objset_create(&obj->set, \
> + (sepol_objset_cmp_t)sepol_policy_strcmp); \
> + ret_goto(ret, target); \
> + } }
do/while idiom, plus you should combine the error handling.
> +#define DESTROY_STRSET(obj, set, iter, ret) { \
> + if (obj->set != NULL) { \
> + ret = sepol_iter_create(&iter); \
> + ret_check(ret); \
> + ret = sepol_objset_iter(obj->set, iter); \
> + if (ret < 0 && ret != SEPOL_ITERSTOP) return ret; \
> + while (ret == SEPOL_OK) { \
> + ret = intern_sepol_object_delstr(obj, sepol_iter_get_data(iter)); \
> + ret_check(ret); \
Leaked the iter.
> + ret = sepol_iter_next(iter); \
> + } \
> + sepol_iter_destroy(iter); \
> + if (ret != SEPOL_ITERSTOP) return ret; \
> + } \
> + sepol_objset_destroy(obj->set); }
> +
[...]
> +#define DEFINE_BOOL_PROP(obj, prop) \
> +#define DEFINE_UINT_PROP(obj, prop) \
These two are identical apart from char/uint.
> +#define DEFINE_STRSET_PROP(obj, prop, set) \
> + int sepol_##obj##_add_##prop(struct sepol_##obj *x, char *prop) \
> + { \
> + int ret; \
> + char *tmp = strdup(prop); \
> + ret = intern_sepol_object_addstr(x, &tmp); \
> + ret_check(ret); \
Leaked tmp, no?
> + ret = sepol_objset_add(x->set, tmp); \
> + ret_check(ret); \
> + return SEPOL_OK; \
> + } \
> + hidden_def(sepol_##obj##_set_##prop) \
> + struct sepol_objset *sepol_##obj##_get_##set(struct sepol_##obj *x) \
> + { \
> + return x->set; \
> + } \
> + hidden_def(sepol_##obj##_get_##prop)
> +
--
James Antill <jantill@redhat.com>
[-- Attachment #2: This is a digitally signed message part --]
[-- Type: application/pgp-signature, Size: 189 bytes --]
^ permalink raw reply [flat|nested] 25+ messages in thread
* Re: [PATCH] Basic policy representation
2007-05-09 16:24 ` James Antill
@ 2007-05-09 18:31 ` Karl MacMillan
0 siblings, 0 replies; 25+ messages in thread
From: Karl MacMillan @ 2007-05-09 18:31 UTC (permalink / raw)
To: James Antill; +Cc: selinux
On Wed, 2007-05-09 at 12:24 -0400, James Antill wrote:
> On Mon, 2007-05-07 at 18:06 -0400, Karl MacMillan wrote:
> > Add support for the basic policy object model and the sepol_policy
> > and sepol_module objects to libsepol. This version has significant
> > changes from the last posted version:
> >
> > 1) sepol_handle is passed everywhere
> > 2) public and private interfaces to the object system are correctly
> > split (into policy.[c,h] and policy_internal.[c,h].
> > 3) object ouput has been converted from writing to a FILE to returning
> > allocated strings. This will help integrate better with scripting
> > languages.
> > 4) Basic documentation is included for the base objects.
> > 5) Enums are used instead of defines - this is a change from the style
> > for libsepol, but it makes documenting the enums much easier.
>
> One idiom that is often used is:
>
> enum {
> FOO = 0,
> #define FOO FOO
> [...]
> };
>
Why though?
>
> > Signed-off-by: User "Karl MacMillan <kmacmillan@mentalrootkit.com>"
> > ---
> >
> > 7 files changed, 1667 insertions(+), 4 deletions(-)
> > libsepol/include/sepol/policy.h | 522 +++++++++++++++++++++++++++++++
> > libsepol/src/policy.c | 638 +++++++++++++++++++++++++++++++++++++++
> > libsepol/src/policy_internal.c | 102 ++++++
> > libsepol/src/policy_internal.h | 269 ++++++++++++++++
> > libsepol/tests/libsepol-tests.c | 10
> > libsepol/tests/test-policy.c | 118 +++++++
> > libsepol/tests/test-policy.h | 12
>
> [...]
>
> > diff -r cacdf4377ebf -r bd4ee6e00a63 libsepol/src/policy.c
> > --- a/libsepol/src/policy.c Mon May 07 15:50:27 2007 -0400
> > +++ b/libsepol/src/policy.c Mon May 07 18:03:03 2007 -0400
> > +/*
> > + * SEPOL_OBJECT
> > + */
> > +
> > +static char *typeid_strings[] = {
> > + "none",
> [...]
> > + "role"
> > +};
> > +
> > +const char *sepol_typeid_tostring(int typeid)
> > +{
> > + assert(typeid < sizeof(typeid_strings));
>
> This assert is wrong.
>
Ooops.
> > + return typeid_strings[typeid];
> > +}
> > +hidden_def(sepol_typeid_tostring)
> > +
> > +int sepol_object_free(struct sepol_handle *h, struct sepol_object *o)
> > +{
> > + assert(o->methods->free);
> > +
> > + return o->methods->free(h, o);
> > +}
> > +hidden_def(sepol_object_free)
>
> Personally I find it's almost always a good idea to retain the
> semantics of free(NULL) in free'ing functions (as it often cleans up the
> deallocation paths).
>
I'm going to make that change - this is just getting irritating.
> > +#define SEPOL_STRPOOL_SIZE 64
> > +int sepol_object_create_strpool(struct sepol_handle *h, struct sepol_object *o)
> > +{
> > + int ret;
> > +
> > + ret = sepol_objpool_create(h, &o->strpool, (sepol_objpool_hash_t)sepol_symhash,
> > + (sepol_objpool_cmp_t)sepol_symcmp, free,
> > + SEPOL_STRPOOL_SIZE);
> > + ret_check(ret);
> > + o->flags |= SEPOL_OBJECT_STRPOOL_OWNER;
> > +
> > + return ret;
> > +}
> > +hidden_def(sepol_object_create_strpool)
> > +
> > +struct sepol_objpool *sepol_object_get_strpool(struct sepol_object *o)
> > +{
> > + return o->strpool;
> > +}
> > +hidden_def(sepol_object_get_strpool)
> > +
> > +char sepol_object_is_strpool_owner(struct sepol_object *o)
> > +{
> > + return (o->flags & SEPOL_OBJECT_STRPOOL_OWNER) != 0;
> > +}
> > +hidden_def(sepol_object_is_strpool_owner)
>
> This confused me, why would the base call for all objects need a
> strpool?
>
Why wouldn't it? It seems unlikely that you would want string pooling
for a single object, but it doesn't seem necessary to prevent it. I
guess it adds a pointer to every child. *shrug* - I'll think about it.
> > +
> > +uint32_t sepol_object_get_typeid(struct sepol_object *o)
> > +{
> > + return o->typeid;
> > +}
> > +hidden_def(sepol_object_get_typeid)
> > +
> > +char sepol_object_isinstance(struct sepol_object *o, uint32_t typeid)
> > +{
> > + if (o->typeid == typeid || o->sclass_typeid == typeid)
> > + return 1;
> > + else return 0;
> > +}
> > +hidden_def(sepol_object_isinstance)
>
> You can only have one layer of inheritance?
>
For now - I assume that if / when we want more we can change this to
traverse the type tree. We'll have to do some more book keeping to make
that work, which is why I didn't want to do it unless it was used.
> > +struct sepol_parent *sepol_object_get_parent(struct sepol_object *o)
> > +{
> > + return o->parent;
> > +}
> > +hidden_def(sepol_object_get_parent)
> > +
> > +int sepol_object_tostring(struct sepol_handle *h, struct sepol_object *o,
> > + int style, char **str)
> > +{
>
> Why don't you just return the string?
>
Allow for error returns. There are other possible errors besides
allocation - if the object is in an inconsistent state.
Actually - I hate that some of these objects can be in inconsistent
states. Perhaps I should change that.
> > + if (o->methods->tostring) {
> > + return o->methods->tostring(h, o, style, str);
> > + } else {
> > + if (style == SEPOL_TOSTRING_DEBUG) {
> > + return asprintf(str, "[sepol_object(%s) at %p]",
> > + sepol_typeid_tostring(o->typeid), o);
> > + }
>
> Given that sepol_typeid_tostring() can/is being called as above, it
> seems like a bad idea to just return allocaed memory here.
> The obvious fix is to save the result into o->store_tostring ...
> free()'ing that when the object is destroyed, or _tostring is called
> again
I'm ok with that - though for a large object tree it could use quite a
bit of memory.
> (although possibly just re-using it, for a speed benefit, might be
> worthwhile).
>
We'd have to track whether the object had changed to get that speedup.
Certainly possible.
> > +
> > + /* Even though we are returning an empty string, we still
> > + * need to allocated an empty string to return. This
> > + * matches the behavior of asprintf.
> > + */
> > + *str = strdup("");
> > + if (*str == NULL)
> > + return -1;
> > + return 0;
> > + }
> > +}
> > +hidden_def(sepol_object_tostring)
> > +
> > +int sepol_object_tostring_close(struct sepol_handle *h, struct sepol_object *o,
> > + int style, char **str)
> > +{
> > + if (o->methods->tostring_close) {
> > + return o->methods->tostring_close(h, o, style, str);
> > + } else {
> > + if (style == SEPOL_TOSTRING_DEBUG) {
> > + return asprintf(str, "[close: sepol_object(%s) at %p]",
> > + sepol_typeid_tostring(o->typeid), o);
> > + }
> > +
> > + /* Even though we are returning an empty string, we still
> > + * need to allocated an empty string to return. This
> > + * matches the behavior of asprintf.
> > + */
> > + *str = strdup("");
> > + if (*str == NULL)
> > + return -1;
> > + return 0;
> > + }
> > +}
> > +hidden_def(sepol_object_tostring_close)
> > +
> > +/*
> > + * SEPOL_PARENT
> > + */
> > +
> > +int sepol_parent_free_tree(struct sepol_handle *h, struct sepol_parent *p)
> > +{
> > + int ret;
> > + struct sepol_iter *iter;
> > + struct sepol_object *cur;
> > +
> > + ret = sepol_iter_create(h, &iter);
> > + if (ret < 0)
> > + goto out;
> > +
> > + ret = sepol_parent_traverse(h, p, iter, SEPOL_TRAVERSE_POSTORDER);
> > + if (ret < 0)
> > + goto out;
> > +
> > + sepol_foreach(h, ret, cur, iter) {
> > + int ret2;
> > + char *str;
> > + ret2 = sepol_object_tostring(h, cur, SEPOL_TOSTRING_DEBUG, &str);
> > + assert(ret2 >= 0);
>
> ret2 is malloc()'d data.
>
> > + printf("freeing %s", str);
>
> printf??
>
Debugging output that I forgot to remove.
> > + sepol_object_free(h, cur);
> > + free(str);
> > + }
> > + if (ret != SEPOL_ITERSTOP)
> > + goto out;
> > +
> > + ret = SEPOL_OK;
> > +out:
> > + sepol_iter_free(h, iter);
> > + return ret;
> > +}
> > +hidden_def(sepol_parent_free_tree)
> > +
> > +int sepol_parent_append(struct sepol_handle *h, struct sepol_parent *p, struct sepol_object *o)
> > +{
> > + if (o->parent)
> > + return SEPOL_EEXIST;
> > + o->parent = p;
> > + return sepol_list_append(h, p->children, o);
> > +}
>
> This seems like a bad name, the task you are really doing is "attaching
> a parent to an object" not "appending a child to a parent".
I'm not real fond of the name, but I think that we are appending a child
to a parent as much as the other way. I could change to
sepol_parent_append_child - but that doesn't seem to help. Anybody else
have an opinion.
> Also what
> happens if list_append() fails ... ->parent is set, how can you recover?
>
I'll fix.
> > +hidden_def(sepol_parent_append)
> > +
> > +int sepol_parent_extend(struct sepol_handle *h, struct sepol_parent *p, struct sepol_iter *iter)
> > +{
> > + int ret = SEPOL_OK;
> > + struct sepol_object *cur;
> > +
> > + sepol_foreach(h, ret, cur, iter) {
> > + ret = sepol_parent_append(h, p, cur);
>
> Even if you leave it with the parent POV, I think you really want
> "append one object", "append iter of objects" and "append list of
> objects" to all have a prefix.
>
To ease finding them? These make the corresponding list functions so
anyone familiar with the library should expect them I would hope. Again
- I don't feel strongly and would appreciate other opinions (as naming
is only useful if it is intuitive to most people).
> > + if (ret < 0) {
> > + return ret;
> > + }
> > + }
> > + if (ret != SEPOL_ITERSTOP) {
> > + return ret;
> > + }
> > +
> > + return SEPOL_OK;
> > +}
> > +hidden_def(sepol_parent_extend)
> > +
> > +int sepol_parent_extend_list(struct sepol_handle *h, struct sepol_parent *p, struct sepol_list *list)
> > +{
> > + int ret;
> > + struct sepol_iter *iter;
> > +
> > + ret = sepol_iter_create(h, &iter);
> > + if (ret < 0)
> > + return ret;
> > + ret = sepol_list_begin(h, list, iter);
> > + if (ret < 0) {
> > + if (ret == SEPOL_ITERSTOP)
> > + return SEPOL_OK;
> > + else
> > + return ret;
> > + }
> > + ret = sepol_parent_extend(h, p, iter);
> > + sepol_iter_free(h, iter);
> > +
> > + return ret;
> > +}
> > +hidden_def(sepol_parent_extend_list)
> > +
> > +int sepol_parent_del(struct sepol_handle *h, struct sepol_parent *p, struct sepol_iter *iter)
> > +{
> > + struct sepol_object *o;
> > + o = (struct sepol_object*)sepol_iter_get_data(h, iter);
> > + if (!o) {
> > + ERR(h, "error getting object from iterator");
> > + return SEPOL_ERR;
> > + }
> > + o->parent = NULL;
> > + return sepol_list_del(h, p->children, iter);
> > +}
>
> sepoll_list_del can't fail here, right?
>
It currently has a return - so it could at some point in the future.
> > +hidden_def(sepol_parent_del)
> > +
> > +int sepol_parent_insert(struct sepol_handle *h, struct sepol_parent *p,
> > + struct sepol_iter *iter, struct sepol_object *o)
> > +{
> > + if (o->parent)
> > + return SEPOL_EEXIST;
> > + o->parent = p;
> > +
> > + return sepol_list_insert(h, p->children, iter, o);
> > +}
> > +hidden_def(sepol_parent_insert)
>
> Why do you have insert and append?
Insert is at a specific point - append is, well, append. These mirror
the list functions. I was intending to preserve the ordering of the
children - it's useful for policy generation.
> Dito problem if list_insert fails.
>
got it.
> > +
> > +int sepol_parent_children(struct sepol_handle *h, struct sepol_parent *p, struct sepol_iter *iter)
> > +{
> > + return sepol_list_begin(h, p->children, iter);
> > +}
> > +hidden_def(sepol_parent_children)
>
> Putting something to do with "iter" in the name would probably be a
> good idea.
>
ok.
> > +struct sepol_list *sepol_parent_get_children(struct sepol_parent *parent)
> > +{
> > + return parent->children;
> > +}
> > +hidden_def(sepol_parent_get_children)
> > +
> > +
> > +struct sepol_parent_traverse_state
> > +{
> > + int strategy;
> > + char cur_flags;
> > + struct sepol_list *stack;
> > + void *object;
> > +};
> > +
> > +static void *sepol_parent_iter_get_data(struct sepol_handle *h, struct sepol_iter *iter)
> > +{
> > + struct sepol_parent_traverse_state *state;
> > +
> > + assert(iter);
>
> Is it possible to use the GCC nonnull attributes?
You mean
> It also seems really
> bizarre how much sepol_handle is passed around but never used.
>
This is for consistency and to make it easier to maintain a stable API /
ABI. Since the idiom is that the handle is passed whenever an error is
possible, it gets passed a lot. I sometimes don't use error messages
when a lower level is going to provide one or when the error code gives
all of the information (e.g., "out of memory" is pretty useless when you
return SEPOL_ENOMEM).
So - I'm prioritizing consistency, but I'm open to other ideas. Anyone
have any?
> > + state = (struct sepol_parent_traverse_state*)
> > + sepol_iter_get_state(iter);
> > + assert(state);
> > +
> > + return state->object;
> > +}
> > +
> > +static int sepol_parent_iter_free(struct sepol_handle *h, void *data)
> > +{
> > + struct sepol_parent_traverse_state *state =
> > + (struct sepol_parent_traverse_state*)data;
>
> You don't need the cast in C, only in C++.
>
Oops - some habits die hard.
> > +static int sepol_policy_tostring(struct sepol_handle *h,
> > + struct sepol_object * object __attribute__ ((unused)),
> > + int style, char **str)
> > +{
> > + if (style == SEPOL_TOSTRING_DEBUG) {
> > + return asprintf(str, "POLICY {");
> > + } else {
> > + *str = strdup("");
> > + if (*str)
> > + return 0;
> > + else
> > + return -1;
> > + }
> > +}
> > +
> > +static int sepol_policy_tostring_close(struct sepol_handle *h __attribute__ ((unused)),
> > + struct sepol_object *object __attribute__ ((unused)),
> > + int style, char **str)
> > +{
> > + if (style == SEPOL_TOSTRING_DEBUG) {
> > + return asprintf(str, "POLICY {");
>
> == strdup
>
:)
> > + } else {
> > + *str = strdup("");
> > + if (*str)
> > + return 0;
> > + else
> > + return -1;
> > + }
> > +}
>
> [...]
> > +/* Internal structs and functions for the policy object system. In
> > + * general, policy objects cannot be created outside of the libsepol
> > + * tree. It is possible, but not currently implemented, so there is
> > + * quite a lot of internals in this header.
> > + *
> > + * One of the goals of this object system is to allow polymorphic
> > + * methods. That will allow calling , for example, sepol_object_free
> > + * on _any_ subclass of sepol_object and have the correct function
> > + * called for the specific subclass. This polymorphism is implemented
> > + * using an sepol_object_method struct for each class and a pointer to
> > + * that struct held in each object instance.
> > + *
> > + * A subclass is expected to create an sepol_object_methods struct
> > + * containing function pointers for the methods that it implements (it
> > + * is valid for some of the function pointers to be NULL). Every
> > + * instance of an sepol_object object holds a pointer to a single
> > + * methods struct - i.e., there is only one struct per class and every
> > + * instance holds a pointer to that struct.
> > + *
> > + * See sepol_object_init for how this pointer is set and sepol_object_free
> > + * for how subclass methods are called.
> > + */
> > +
> > +/* sepol_object_free_t is the type for the free method used in the policy
> > + * object system. Implementations of this method should free all of the
> > + * memory associated with the object including the struct.
> > + */
> > +typedef int (*sepol_object_free_t)(struct sepol_handle *h, struct sepol_object *o);
> > +typedef int (*sepol_object_tostring_t)(struct sepol_handle *h, struct sepol_object *o,
> > + int style, char **str);
> > +
> > +struct sepol_object_methods
> > +{
> > + sepol_object_free_t free;
> > + sepol_object_tostring_t tostring;
> > + sepol_object_tostring_t tostring_close;
> > +};
> > +
> > +#define SEPOL_OBJECT_STRPOOL_OWNER 1
> > +#define SEPOL_OBJECT_VISITED 2
> > +struct sepol_object
> > +{
> > + struct sepol_object_methods *methods;
> > + struct sepol_parent *parent;
> > + struct sepol_objpool *strpool;
> > + uint32_t sclass_typeid;
> > + uint32_t typeid;
> > + uint32_t lineno;
> > + char flags;
>
> using char here seems iffy, the compiler is almost certainly going to
> expand to uint size anyway due to padding.
>
ok.
> > +};
> > +
> > +/* Private initialization function for all objects. This function only
> > + * initializes the generic object properties - the type specific creation
> > + * function is responsible for initializing any type specific properties.
> > + * If this function fails it will clean up any memory that it allocated. The
> > + * calling function is responsible for any type specific memory and for freeing
> > + * the object struct.
> > + *
> > + * params:
> > + * o - object to initialize
> > + * typeid - typeid of o
> > + * methods - pointer to sepol_object_methods struct for this type. Should
> > + * be a pointer to a single static struct for all instances of this type.
> > + * root - root of the policy tree of which o is a member (may be NULL). If
> > + * the root is non-NULL and has a string pool then that string pool is
> > + * used for this object.
> > + */
> > +int intern_sepol_object_init(struct sepol_handle *h, struct sepol_object *o, uint32_t typeid,
> > + struct sepol_object_methods *methods, struct sepol_parent *root);
> > +
> > +/* Free any memory associated with the super class. This should be called
> > + * from a type specific free function.
> > + */
> > +void intern_sepol_object_free(struct sepol_object *o);
> > +
> > +/* Add a string to the string pool of the object. After a call to this
> > + * function the str pointer will point to the correct (and possibly
> > + * shared) version of the string to use.
> > + */
> > +#define intern_sepol_object_addstr(h, o, str) _intern_sepol_object_addstr(h, SEPOL_OBJECT(o), str)
> > +int _intern_sepol_object_addstr(struct sepol_handle *h, struct sepol_object *o, char **str);
> > +
> > +/* Delete a string. If the object has a string pool the memory
> > + * associated with the string may not be released
> > + * immediately. Regardless, the caller should assume that the pointer
> > + * is invalid after a call to this function.
> > + */
> > +#define intern_sepol_object_delstr(h, o, str) _intern_sepol_object_delstr(h, SEPOL_OBJECT(o), str)
> > +int _intern_sepol_object_delstr(struct sepol_handle *h, struct sepol_object *o, char *str);
> > +
> > +hidden_proto(sepol_typeid_tostring)
> > +hidden_proto(sepol_object_free)
> > +hidden_proto(sepol_object_create_strpool)
> > +hidden_proto(sepol_object_get_strpool)
> > +hidden_proto(sepol_object_is_strpool_owner)
> > +hidden_proto(sepol_object_get_typeid)
> > +hidden_proto(sepol_object_isinstance)
> > +hidden_proto(sepol_object_get_parent)
> > +hidden_proto(sepol_object_tostring)
> > +hidden_proto(sepol_object_tostring_close)
> > +
> > +struct sepol_parent
> > +{
> > + struct sepol_object sclass;
> > + struct sepol_list *children;
> > +};
> > +
> > +/* Initialize an sepol_parent object. Same function and general
> > + * properties as intern_sepol_object_init but for parent
> > + * objects. Objects should only call the init function for their
> > + * immediate parent - the parent is responsible for any further
> > + * chaining up the type hierarchy.
> > + */
> > +int intern_sepol_parent_init(struct sepol_handle *h, struct sepol_parent *p, uint32_t typeid,
> > + struct sepol_object_methods *methods, struct sepol_parent *root);
> > +
> > +/* Internal free function for sepol_paren objects. Like the init functions
> > + * this chains up the type hierarchy by call inter_sepol_object_free.
> > + */
> > +void intern_sepol_parent_free(struct sepol_parent *p);
> > +
> > +hidden_proto(sepol_parent_free_tree)
> > +hidden_proto(sepol_parent_append)
> > +hidden_proto(sepol_parent_extend)
> > +hidden_proto(sepol_parent_extend_list)
> > +hidden_proto(sepol_parent_del)
> > +hidden_proto(sepol_parent_insert)
> > +hidden_proto(sepol_parent_children)
> > +hidden_proto(sepol_parent_get_children)
> > +hidden_proto(sepol_parent_traverse)
> > +hidden_proto(sepol_parent_isvisited)
> > +
> > +/* sepol_policy */
> > +hidden_proto(sepol_policy_free)
> > +hidden_proto(sepol_policy_get_mls)
> > +hidden_proto(sepol_policy_set_mls)
> > +
> > +/* sepol_module */
> > +hidden_proto(sepol_module_free)
> > +hidden_proto(sepol_module_create)
> > +hidden_proto(sepol_module_create_tree)
> > +hidden_proto(sepol_module_set_name)
> > +hidden_proto(sepol_module_get_name)
> > +hidden_proto(sepol_module_set_version)
> > +hidden_proto(sepol_module_get_version)
> > +hidden_proto(sepol_module_set_isbase)
> > +hidden_proto(sepol_module_get_isbase)
> > +
> > +
> > +/* some convenience macros to check return values */
> > +#define ret_check(ret) { if (ret < 0) return ret; }
> > +#define ret_goto(ret, tag) { if (ret < 0) goto tag; }
>
> These are just evil,
Thanks :) To be fair - they are meant to only be used internally.
> and I don't mind invisible returns in macros when
> it's kind of obvious that's what they do.
> They should be in CAPS, have the "do {} while" idiom,
Is the do {} while thing really needed - it's just to introduce a new
scope, right?
> the name isn't
> great as check == return is not obvious and you should use (ret) instead
> of ret. Maybe:
>
> #define RC_FAIL_RETURN(ret) do { if ((ret) < 0) return (ret); } while (FALSE)
> #define RC_FAIL_GOTO(ret, tag) do { if ((ret) < 0) goto tag; } while (FALSE)
>
That looks better.
> ...but I'm also unconvinced they help, for instance you have:
>
> ret = foo();
> RC_FAIL_RETURN(ret);
>
> ...instead of:
>
> if ((ret = foo()) < 0)
> return (ret);
>
> ...even if you split the assignment out of the condition, it's only one
> extra line ... so it doesn't seem like they are doing enough.
>
I started it with the generation macros where adding a line was more of
a pain. I can ditch them though.
> > +/*
> > + * PROPERTY GENERATION MACROS
> > + *
> > + * Many of the objects are similar and will have almost identical
> > + * functions for getting and setting properties. These macros generate
> > + * those functions for brevity and correctness.
> > + */
> > +
> > +/* Initialize an object set for holding strings. This should be used
> > + * in an object creation function to initialize a string set. This
> > + * handles object pooling.
> > + */
> > +#define INIT_STRSET(obj, set, ret, target) { \
> > + if (SEPOL_OBJECT(obj)->strpool) { \
> > + ret = sepol_objset_create(&obj->set, sepol_policy_ptrcmp); \
> > + ret_goto(ret, target); \
> > + } else { \
> > + ret = sepol_objset_create(&obj->set, \
> > + (sepol_objset_cmp_t)sepol_policy_strcmp); \
> > + ret_goto(ret, target); \
> > + } }
>
> do/while idiom, plus you should combine the error handling.
>
> > +#define DESTROY_STRSET(obj, set, iter, ret) { \
> > + if (obj->set != NULL) { \
> > + ret = sepol_iter_create(&iter); \
> > + ret_check(ret); \
> > + ret = sepol_objset_iter(obj->set, iter); \
> > + if (ret < 0 && ret != SEPOL_ITERSTOP) return ret; \
> > + while (ret == SEPOL_OK) { \
> > + ret = intern_sepol_object_delstr(obj, sepol_iter_get_data(iter)); \
> > + ret_check(ret); \
>
> Leaked the iter.
>
> > + ret = sepol_iter_next(iter); \
> > + } \
> > + sepol_iter_destroy(iter); \
> > + if (ret != SEPOL_ITERSTOP) return ret; \
> > + } \
> > + sepol_objset_destroy(obj->set); }
> > +
> [...]
> > +#define DEFINE_BOOL_PROP(obj, prop) \
> > +#define DEFINE_UINT_PROP(obj, prop) \
>
> These two are identical apart from char/uint.
>
> > +#define DEFINE_STRSET_PROP(obj, prop, set) \
> > + int sepol_##obj##_add_##prop(struct sepol_##obj *x, char *prop) \
> > + { \
> > + int ret; \
> > + char *tmp = strdup(prop); \
> > + ret = intern_sepol_object_addstr(x, &tmp); \
> > + ret_check(ret); \
>
> Leaked tmp, no?
>
Yeah - that was because of a change (intern_sepol_object_addstr didn't
used to copy).
Karl
> > + ret = sepol_objset_add(x->set, tmp); \
> > + ret_check(ret); \
> > + return SEPOL_OK; \
> > + } \
> > + hidden_def(sepol_##obj##_set_##prop) \
> > + struct sepol_objset *sepol_##obj##_get_##set(struct sepol_##obj *x) \
> > + { \
> > + return x->set; \
> > + } \
> > + hidden_def(sepol_##obj##_get_##prop)
> > +
>
--
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] 25+ messages in thread
* Re: [PATCH] Basic policy representation
2007-05-07 22:06 [PATCH] Basic policy representation Karl MacMillan
2007-05-08 14:45 ` Joshua Brindle
2007-05-09 16:24 ` James Antill
@ 2007-05-09 18:35 ` J. Tang
2007-05-09 19:22 ` Karl MacMillan
2 siblings, 1 reply; 25+ messages in thread
From: J. Tang @ 2007-05-09 18:35 UTC (permalink / raw)
To: Karl MacMillan; +Cc: selinux
On Mon, 2007-05-07 at 18:06 -0400, Karl MacMillan wrote:
> +/**
> + * \ingroup sepol_policy
> + *
> + * Every type in the policy object system is identified
> + * by a numberic typeid.
> + */
There seems to be some things missing from this enumeration. What about
common object classes, users, (role) allow, constraints, validate
transitions, and range transitions?
>From the code you posted, I was unable to determine a few things. How
do you plan on handling these situations?
1. What about aliases for categories and levels?
2. How does this differentiate between symbols declared versus symbols
required within modules? Recall that modules can have require
statements currently.
3. How does this differentiate between symbols declared versus symbols
required within optional blocks?
4. What are the steps to determine if all of a module's dependencies
have been met?
5. If all strings are being stored in the object pool, does that also
mean permissions are instances of sepol_objpool as well?
6. Where is the definition of struct sepol_objpool?
It is unclear how semantic analysis and code generation will operate.
For example, how does one determine if the strings within the source of
an AV allow rule are valid attributes, types, or aliases? For each
string lookup, is there a linear search through all sepol_objects to
find a sepol_object whose sepol_typeid is SEPOL_TYPEID_ATTRIBUTE or
SEPOL_TYPEID_TYPE, and whose sepol_objpool's name matches the string?
Or is there a way to ask the object pool for a matching sepol_objpool
and from there dereference back to its sepol_object?
Do SEPOL_TYPEID_TYPEALIAS objects represent the statement:
typealias lib_t alias shlib_t;
or just the symbol shlib_t?
> + * The hybrid strategy combines both preorder and postorder
> + * traversal. This means that each parent node will be visited twice:
> + * once before its children are traversed and once afterward. The
> + * second traversal can be detected by checking the flag indicating
> + * that the parent has been visited (see sepol_parent_isvisited).
> + */
It is unclear why a hybrid traversal is needed, from the public API's
point of view.
> + * Traverse a policy tree using parent as the root node of the tree. The traversal
> + * strategy is controlled by sepol_parent_traverse_strategy.
> + *
> + * @param h sepol_handle (may be null)
> + * @param parent sepol_parent
> + * @param iter iterator to represent traversal state
Perhaps this should be appended with, "Iterator will be updated to point
to the next node"?
> + * @param strategy traversal strategy - see sepol_parent_traverse_strategy
> + *
> + * \retval SEPOL_OK success
> + * \retval SEPOL_ENOMEM out of memory
> + */
> +extern int sepol_parent_traverse(struct sepol_handle *h, struct sepol_parent *parent,
> + struct sepol_iter *iter, int strategy);
Should not this last parameter be an enum
sepol_policy_traverse_strategy?
> +char sepol_parent_isvisited(struct sepol_iter *iter);
How do you envision this function being used, from a public API's point
of view?
> +extern int sepol_policy_free(struct sepol_handle *h, struct sepol_policy *o);
What happens if a NULL is passed as the second parameter? Users of the
library do not necessarily have the library's source code to consult.
> +extern int sepol_module_create_tree(struct sepol_handle *h,
> + struct sepol_module **module,
> + struct sepol_parent *root);
What does the second parameter represent? A list of sepol_module
pointers, an out parameter to a sepol_module, or something else? Users
of the library do not necessarily have the library's source code to
consult.
--
Jason Tang / jtang@tresys.com
--
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] 25+ messages in thread
* Re: [PATCH] Basic policy representation
2007-05-09 18:35 ` J. Tang
@ 2007-05-09 19:22 ` Karl MacMillan
2007-05-09 22:46 ` J. Tang
0 siblings, 1 reply; 25+ messages in thread
From: Karl MacMillan @ 2007-05-09 19:22 UTC (permalink / raw)
To: J. Tang; +Cc: selinux
On Wed, 2007-05-09 at 14:35 -0400, J. Tang wrote:
> On Mon, 2007-05-07 at 18:06 -0400, Karl MacMillan wrote:
> > +/**
> > + * \ingroup sepol_policy
> > + *
> > + * Every type in the policy object system is identified
> > + * by a numberic typeid.
> > + */
>
> There seems to be some things missing from this enumeration. What about
> common object classes, users, (role) allow, constraints, validate
> transitions, and range transitions?
>
The only things included are those that I had gotten to in my previous
patch set. We can add the remaining types as we go.
> >From the code you posted, I was unable to determine a few things. How
> do you plan on handling these situations?
>
> 1. What about aliases for categories and levels?
Not certain what you are asking.
> 2. How does this differentiate between symbols declared versus symbols
> required within modules? Recall that modules can have require
> statements currently.
Requires are going to be removed entirely - I thought that this had been
discussed on-list, but perhaps not. So far they are only a source of
bugs - no reason to keep them.
> 3. How does this differentiate between symbols declared versus symbols
> required within optional blocks?
Same as above - no requires. To determine whether an optional block can
be activated you will have to check the scope for that block for
declarations (by walking the tree - but I assume that the code that does
this will cache declarations to make this simpler). See policy_check.c
in the other patches I have posted for RFC.
> 4. What are the steps to determine if all of a module's dependencies
> have been met?
Walk the tree looking at declarations. Again, see policy_check.c.
> 5. If all strings are being stored in the object pool, does that also
> mean permissions are instances of sepol_objpool as well?
No - permissions will just be strings. There must be some
misunderstanding as this question makes no sense to me.
> 6. Where is the definition of struct sepol_objpool?
>
In objpool.c - see the previously merged patches.
> It is unclear how semantic analysis and code generation will operate.
> For example, how does one determine if the strings within the source of
> an AV allow rule are valid attributes, types, or aliases?
Walking the tree that represents the scope for the block looking for
declarations. As I mentioned in a previous discussion - an explicit goal
of this work is to remove duplicate storage of information. That means
that scoping information is represented _only_ by the tree structure,
valid symbols _only_ by declarations, etc., etc.
I'm fine with some code caching parts of this information, but I don't
want it pushed into the basic representation. The current code base has
suffered greatly because making changes to the policy is difficult. This
is both because of the use of ids and because of the duplicate storage
of information.
> For each
> string lookup, is there a linear search through all sepol_objects to
> find a sepol_object whose sepol_typeid is SEPOL_TYPEID_ATTRIBUTE or
> SEPOL_TYPEID_TYPE, and whose sepol_objpool's name matches the string?
At least for the initial search, yes.
> Or is there a way to ask the object pool for a matching sepol_objpool
> and from there dereference back to its sepol_object?
>
You probably need to look at objpool.[c,h] - I think you misunderstand
their purpose. Also look at policy_check.c in the old patch set.
> Do SEPOL_TYPEID_TYPEALIAS objects represent the statement:
>
> typealias lib_t alias shlib_t;
>
Yes.
> or just the symbol shlib_t?
>
It stores both.
> > + * The hybrid strategy combines both preorder and postorder
> > + * traversal. This means that each parent node will be visited twice:
> > + * once before its children are traversed and once afterward. The
> > + * second traversal can be detected by checking the flag indicating
> > + * that the parent has been visited (see sepol_parent_isvisited).
> > + */
>
> It is unclear why a hybrid traversal is needed, from the public API's
> point of view.
>
There is no way to easily track the level in the tree without seeing
both the opening and closing of a parent - hence the hybrid traversal
strategy. I think that information is generally useful.
> > + * Traverse a policy tree using parent as the root node of the tree. The traversal
> > + * strategy is controlled by sepol_parent_traverse_strategy.
> > + *
> > + * @param h sepol_handle (may be null)
> > + * @param parent sepol_parent
> > + * @param iter iterator to represent traversal state
>
> Perhaps this should be appended with, "Iterator will be updated to point
> to the next node"?
>
What do you mean? The iterator will be set to point to the initial node.
That is how all of the iterators work.
> > + * @param strategy traversal strategy - see sepol_parent_traverse_strategy
> > + *
> > + * \retval SEPOL_OK success
> > + * \retval SEPOL_ENOMEM out of memory
> > + */
> > +extern int sepol_parent_traverse(struct sepol_handle *h, struct sepol_parent *parent,
> > + struct sepol_iter *iter, int strategy);
>
> Should not this last parameter be an enum
> sepol_policy_traverse_strategy?
>
Sure.
> > +char sepol_parent_isvisited(struct sepol_iter *iter);
>
> How do you envision this function being used, from a public API's point
> of view?
>
It is needed for the hybrid traversal to make sense - otherwise you
can't tell whether this is the opening or closing of a parent object.
> > +extern int sepol_policy_free(struct sepol_handle *h, struct sepol_policy *o);
>
> What happens if a NULL is passed as the second parameter?
Should be a no-op. I could document it everywhere I guess, but it won't
be a priority any time soon. Feel free to send a patch.
> Users of the
> library do not necessarily have the library's source code to consult.
>
Of course they do - this is open source. Documentation is just a
bonus :)
> > +extern int sepol_module_create_tree(struct sepol_handle *h,
> > + struct sepol_module **module,
> > + struct sepol_parent *root);
>
> What does the second parameter represent? A list of sepol_module
> pointers, an out parameter to a sepol_module, or something else?
Out parameter - just liked every other create function.
> Users
> of the library do not necessarily have the library's source code to
> consult.
>
Again - of course they do.
Karl
--
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] 25+ messages in thread
* Re: [PATCH] Basic policy representation
2007-05-09 19:22 ` Karl MacMillan
@ 2007-05-09 22:46 ` J. Tang
2007-05-09 23:26 ` Karl MacMillan
0 siblings, 1 reply; 25+ messages in thread
From: J. Tang @ 2007-05-09 22:46 UTC (permalink / raw)
To: Karl MacMillan; +Cc: selinux
On Wed, 2007-05-09 at 15:22 -0400, Karl MacMillan wrote:
> > 1. What about aliases for categories and levels?
> Not certain what you are asking.
Categories and levels can have aliases. Is this addressed?
> Requires are going to be removed entirely - I thought that this had
Current modules have requirements. If it is true that policyrep must be
able to accept all existing policies, then there must be some way to
represent module requirements.
> No - permissions will just be strings. There must be some
> misunderstanding as this question makes no sense to me.
Does this mean:
allow A B : C d;
allow x y : z d;
will have two instances within memory of the string "d"?
> > For each
> > string lookup, is there a linear search through all sepol_objects to
> > find a sepol_object whose sepol_typeid is SEPOL_TYPEID_ATTRIBUTE or
> > SEPOL_TYPEID_TYPE, and whose sepol_objpool's name matches the
> string?
> At least for the initial search, yes.
This does not seem correct. Given the following:
optional {
typealias a alias b;
}
optional {
type a;
allow a x : y z; # type x is never declared anywhere
}
It appears that the proposed algorithm will incorrectly mark the first
optional's requirements as being met.
> > Do SEPOL_TYPEID_TYPEALIAS objects represent the statement:
> > typealias lib_t alias shlib_t;
> Yes.
> > or just the symbol shlib_t?
> It stores both.
In the statement:
type A alias {B C D E F};
will this create five instances of a SEPOL_TYPEID_TYPEALIAS or just one?
> There is no way to easily track the level in the tree without seeing
> both the opening and closing of a parent - hence the hybrid traversal
> strategy. I think that information is generally useful.
Why does a public user of this API need to track levels? If a user
really wanted to know at what level a node is, he could always walk up
the tree by way of the node's parent.
> > > +extern int sepol_module_create_tree(struct sepol_handle *h,
> > > + struct sepol_module **module,
> > > + struct sepol_parent *root);
> > What does the second parameter represent? A list of sepol_module
> > pointers, an out parameter to a sepol_module, or something else?
> Out parameter - just liked every other create function.
Function prototypes such as these may be difficult to wrap via SWIG.
> +const char *sepol_typeid_tostring(int typeid)
Should not this take an enum sepol_typeid instead?
> +uint32_t sepol_object_get_typeid(struct sepol_object *o)
Why does this return a uint32_t, sepol_typeid_tostring() take a signed
integer, and type identifiers are declared as an enumeration?
> +char sepol_object_isinstance(struct sepol_object *o, uint32_t typeid)
Ibid.
> +int sepol_object_tostring(struct sepol_handle *h, struct sepol_object
*o,
> + int style, char **str)
Should not the third parameter be of type enum sepol_tostring_style?
It would be convenient if the debugging style were to report line
numbers and the name of the module from which the object originated.
Where within the proposed design are line numbers and filenames stored?
> + * Insert a child object into the list of children for the
> + * sepol_parent. See sepol_list_insert for more information on the
> + * semantics of this insert.
> + *
> + * @param h sepol_handle (may be NULL)
> + * @param p sepol_parent to which to insert child object
> + * @param iter iterator representing the position to insert the child
object
> + * @param o child object to insert
It is unclear by the given documentation if the given iterator should
point to the parent or to a location within the parent node's children.
Where within the proposed design are order dependent statements
recorded? Given the string MLS level "a:b.c", how are the actual
categories determined?
--
Jason Tang / jtang@tresys.com
--
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] 25+ messages in thread
* Re: [PATCH] Basic policy representation
2007-05-09 22:46 ` J. Tang
@ 2007-05-09 23:26 ` Karl MacMillan
2007-05-10 19:42 ` J. Tang
0 siblings, 1 reply; 25+ messages in thread
From: Karl MacMillan @ 2007-05-09 23:26 UTC (permalink / raw)
To: J. Tang; +Cc: selinux
On Wed, 2007-05-09 at 18:46 -0400, J. Tang wrote:
> On Wed, 2007-05-09 at 15:22 -0400, Karl MacMillan wrote:
> > > 1. What about aliases for categories and levels?
> > Not certain what you are asking.
>
> Categories and levels can have aliases. Is this addressed?
>
Not yet.
> > Requires are going to be removed entirely - I thought that this had
>
> Current modules have requirements. If it is true that policyrep must be
> able to accept all existing policies, then there must be some way to
> represent module requirements.
>
I don't see why - the import function will just create the bare rules
and declarations and the normal resolution functions can work. The
requirements would just be thrown out.
> > No - permissions will just be strings. There must be some
> > misunderstanding as this question makes no sense to me.
>
> Does this mean:
>
> allow A B : C d;
> allow x y : z d;
>
> will have two instances within memory of the string "d"?
>
Perhaps - it depends on whether there is a string pool at the root of
the tree the object is in. If there is a string pool, however, there
will only be one instance.
> > > For each
> > > string lookup, is there a linear search through all sepol_objects to
> > > find a sepol_object whose sepol_typeid is SEPOL_TYPEID_ATTRIBUTE or
> > > SEPOL_TYPEID_TYPE, and whose sepol_objpool's name matches the
> > string?
> > At least for the initial search, yes.
>
> This does not seem correct. Given the following:
>
> optional {
> typealias a alias b;
> }
>
> optional {
> type a;
> allow a x : y z; # type x is never declared anywhere
> }
>
> It appears that the proposed algorithm will incorrectly mark the first
> optional's requirements as being met.
>
What makes you conclude that? The algorithm will still have to correctly
resolve dependencies - there is nothing about the tree structure
preventing that.
> > > Do SEPOL_TYPEID_TYPEALIAS objects represent the statement:
> > > typealias lib_t alias shlib_t;
> > Yes.
> > > or just the symbol shlib_t?
> > It stores both.
>
> In the statement:
>
> type A alias {B C D E F};
>
> will this create five instances of a SEPOL_TYPEID_TYPEALIAS or just one?
>
The code I posted for comments would create 0 - you would just have a
type declaration. The goal is to represent the policy in the same
structure as the source - it helps for policy generation.
> > There is no way to easily track the level in the tree without seeing
> > both the opening and closing of a parent - hence the hybrid traversal
> > strategy. I think that information is generally useful.
>
> Why does a public user of this API need to track levels? If a user
> really wanted to know at what level a node is, he could always walk up
> the tree by way of the node's parent.
>
If you want to print out the tree structure you need this. Is there some
reason to not export this?
> > > > +extern int sepol_module_create_tree(struct sepol_handle *h,
> > > > + struct sepol_module **module,
> > > > + struct sepol_parent *root);
> > > What does the second parameter represent? A list of sepol_module
> > > pointers, an out parameter to a sepol_module, or something else?
> > Out parameter - just liked every other create function.
>
> Function prototypes such as these may be difficult to wrap via SWIG.
>
Why? What is going to be harder is to always convert sepol_object and
sepol_parent to the most specific type when returned I think. That and
mapping the iterators to python iterators.
I'm considering wrapping by hand if it will make the python code more
idiomatic.
> > +const char *sepol_typeid_tostring(int typeid)
>
> Should not this take an enum sepol_typeid instead?
>
Yes.
> > +uint32_t sepol_object_get_typeid(struct sepol_object *o)
>
> Why does this return a uint32_t, sepol_typeid_tostring() take a signed
> integer, and type identifiers are declared as an enumeration?
>
Because they will end up being serialized and sent over the wire. This
function will make certain that the ids can be represented as a uint32
if necessary.
> > +char sepol_object_isinstance(struct sepol_object *o, uint32_t typeid)
>
> Ibid.
>
Changed.
> > +int sepol_object_tostring(struct sepol_handle *h, struct sepol_object
> *o,
> > + int style, char **str)
>
> Should not the third parameter be of type enum sepol_tostring_style?
>
Changed.
> It would be convenient if the debugging style were to report line
> numbers and the name of the module from which the object originated.
> Where within the proposed design are line numbers and filenames stored?
>
Nowhere yet - send patches.
> > + * Insert a child object into the list of children for the
> > + * sepol_parent. See sepol_list_insert for more information on the
> > + * semantics of this insert.
> > + *
> > + * @param h sepol_handle (may be NULL)
> > + * @param p sepol_parent to which to insert child object
> > + * @param iter iterator representing the position to insert the child
> object
> > + * @param o child object to insert
>
> It is unclear by the given documentation if the given iterator should
> point to the parent or to a location within the parent node's children.
>
Point within parents list of children.
> Where within the proposed design are order dependent statements
> recorded? Given the string MLS level "a:b.c", how are the actual
> categories determined?
>
I haven't finished the MLS portion - feel free to start on that if you
want.
Karl
--
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] 25+ messages in thread
* [PATCH] Basic policy representation
@ 2007-05-10 17:56 Karl MacMillan
0 siblings, 0 replies; 25+ messages in thread
From: Karl MacMillan @ 2007-05-10 17:56 UTC (permalink / raw)
To: selinux; +Cc: kmacmill
Add support for the basic policy object model and the sepol_policy
and sepol_module objects to libsepol. This version has significant
changes from the last posted version:
1) sepol_handle is passed everywhere
2) public and private interfaces to the object system are correctly
split (into policy.[c,h] and policy_internal.[c,h].
3) object ouput has been converted from writing to a FILE to returning
allocated strings. This will help integrate better with scripting
languages.
4) Basic documentation is included for the base objects.
5) Enums are used instead of defines - this is a change from the style
for libsepol, but it makes documenting the enums much easier.
This version includes updates based on comments from Josh Brindle, Stephen Smalley,
James Antill, and Jason Tang.
Signed-off-by: User "Karl MacMillan <kmacmillan@mentalrootkit.com>"
---
8 files changed, 1750 insertions(+)
libsepol/include/sepol/policy.h | 541 ++++++++++++++++++++++++++++++
libsepol/src/libsepol.map | 4
libsepol/src/policy.c | 690 +++++++++++++++++++++++++++++++++++++++
libsepol/src/policy_internal.c | 103 +++++
libsepol/src/policy_internal.h | 281 +++++++++++++++
libsepol/tests/libsepol-tests.c | 2
libsepol/tests/test-policy.c | 117 ++++++
libsepol/tests/test-policy.h | 12
diff -r 1d04713e6b39 -r 18a337232eef libsepol/include/sepol/policy.h
--- a/libsepol/include/sepol/policy.h Thu May 10 13:43:00 2007 -0400
+++ b/libsepol/include/sepol/policy.h Thu May 10 13:56:28 2007 -0400
@@ -0,0 +1,541 @@
+/* Author : Karl MacMillan <kmacmillan@mentalrootkit.com> */
+
+#ifndef __sepol_policy_h__
+#define __sepol_policy_h__
+
+#include <sepol/handle.h>
+
+#include <sepol/objpool.h>
+#include <sepol/objset.h>
+#include <sepol/list.h>
+
+#include <sys/types.h>
+#include <stdint.h>
+#include <stdio.h>
+
+/**
+ * \defgroup sepol_policy sepol_policy: policy representation
+ * Introduction to the policy object system
+ *
+ *
+ * The policy is represented as a tree of objects that loosely
+ * resemble an abstract syntax tree or intermediate representation
+ * commonly found in compilers. This tree representation is used as
+ * the output of the policy parser the format for selinux policy
+ * modules. The data structures are also intended to be flexible
+ * enough to represent an selinux policy for syntax/semantic checking,
+ * analysis, generation, and storage.
+ *
+ * The basic structure is that of a tree holding selinux policy
+ * language components (e.g., type declarations, rules, conditional
+ * blocks, etc.). To implement this tree structure in a form that can
+ * be processed easily, a basic object orientied structure is
+ * implemented in C.
+ *
+ * The object oriented system allows the use of polymorphic functions,
+ * making it possible to process objects in the tree with only limited
+ * informatio about the specific types (e.g., it is possible to
+ * traverse the tree and output all of the objects as strings without
+ * the traversal function knowing detailed type information about each
+ * object - it simple class sepol_object_strout on each object).
+ *
+ * See sepol_object and sepol_parent for more information on this object
+ * oriented type system.
+ *
+ */
+
+/**
+ * \ingroup sepol_policy
+ *
+ * Every type in the policy object system is identified
+ * by a numberic typeid.
+ */
+enum sepol_typeid {
+ SEPOL_TYPEID_NONE, /** special typeid representing no type */
+ SEPOL_TYPEID_OBJECT, /** typeid for base class of all objects */
+ SEPOL_TYPEID_PARENT, /** typeid for base class of objects that contain other objects */
+ SEPOL_TYPEID_POLICY, /** typeid for policy object */
+ SEPOL_TYPEID_MODULE, /** typeid for the module object */
+ SEPOL_TYPEID_BLOCK, /** tyepid for the block object */
+ SEPOL_TYPEID_COND, /** typeid for the cond object */
+ SEPOL_TYPEID_OPTIONAL, /** typeid for the optional object */
+ SEPOL_TYPEID_TYPE, /** typed for the type object */
+ SEPOL_TYPEID_CLASS, /** typeid for the class object */
+ SEPOL_TYPEID_ATTRIBUTE, /** typeid for the attribute object */
+ SEPOL_TYPEID_TYPEALIAS, /** typeid for the typealias object */
+ SEPOL_TYPEID_BOOL, /** typeid for the bool object */
+ SEPOL_TYPEID_AVRULE, /** typeid for the avrule object */
+ SEPOL_TYPEID_TYPERULE, /** typeid for the typerule object */
+ SEPOL_TYPEID_SECURITY_CONTEXT, /** typeid for the securit context object */
+ SEPOL_TYPEID_ISID, /** typeid for the isid object */
+ SEPOL_TYPEID_TYPEATTRIBUTE, /** typeid for the typeattribute object */
+ SEPOL_TYPEID_COND_EXPR, /** typeid for the cond expr object */
+ SEPOL_TYPEID_SENS, /** typeid for the sends object */
+ SEPOL_TYPEID_DOMINANCE, /** typeid for the dominance object */
+ SEPOL_TYPEID_CATEGORY, /** typeid for the category object */
+ SEPOL_TYPEID_ROLE_DOMINANCE, /** typeid for the role dominance object */
+ SEPOL_TYPEID_ROLE /** typeid for the role object */
+};
+
+/**
+ * \ingroup sepol_policy
+ *
+ * Convert a typeid to a string representation. The returned string
+ * is constant and should not be altered or freed.
+ *
+ * @param typeid typeid to convert to string
+ *
+ * \retval string string representing the typeid
+ */
+const char *sepol_typeid_tostring(enum sepol_typeid typeid);
+
+/**
+ * \ingroup sepol_policy
+ * \struct sepol_object
+ *
+ * sepol_object is the base class of all objects in this type system.
+ * There is no way to directly create an sepol_object - it is an
+ * abstract base class.
+ *
+ * The type system works by:
+ * - mandating that sepol_object (or one of its subclasses) be the
+ * first entry in every struct. This allows the structs to be
+ * freely cast to an sepol_object or any of the other objects
+ * in the hierarchy of that struct.
+ * - Storing information about the types in the form of IDs. This
+ * allows callers to determine type information at runtime.
+ * - Storing function pointers to class specific function
+ * implementations in each object instance. This allows functions
+ * to have a limited form of polymorphism.
+ *
+ * sepol_object is also the parent class of all objects that are
+ * exclusively leaves in the tree (i.e., objects that cannot contain
+ * other objects).
+ *
+ * Properties that all sepol_objects share:
+ * - string pool (strpool): [optional] an objpool for storing
+ * strings stored in the objects. The object may be the owner of
+ * the string pool (see sepol_object_is_strpool_owner), reference
+ * the string pool of another object (usually the root of a policy
+ * tree), or not have a string pool at all.
+ * - type identifier (typeid): The sepol_typeid for this object.
+ */
+struct sepol_object;
+
+/**
+ * \ingroup sepol_policy
+ *
+ * Convert an object to an sepol_object
+ *
+ * @param x object
+ */
+#define SEPOL_OBJECT(x) ((struct sepol_object *)x)
+
+/**
+ * \ingroup sepol_policy
+ *
+ * Free an sepol_object. This can be called for any
+ * subclass of sepol_object.
+ *
+ * @param n object to free
+ *
+ * \retval SEPOL_OK success
+ * \retval <0 error
+ */
+extern void sepol_object_free(struct sepol_object *o);
+
+/**
+ * \ingroup sepol_policy
+ *
+ * Return the typeid for the object.
+ *
+ * @param o object from which to return the type id.
+ *
+ * \retval >0 typeid for the object
+ */
+extern uint32_t sepol_object_get_typeid(struct sepol_object *o);
+
+/**
+ * \ingroup sepol_policy
+ *
+ * Determine whether the object is an instance of the object type
+ * represented by a typeid. This function checks both the specific
+ * object type (as returned by sepol_object_get_typeid) and the
+ * parent type for the object.
+ *
+ * @param o object to check
+ * @param typeid typeid
+ *
+ * \retval 0 object is not an instance of the type
+ * \retval 1 object is an instance of the type
+ */
+extern int sepol_object_isinstance(struct sepol_object *o, uint32_t typeid);
+
+/**
+ * \ingroup sepol_policy
+ *
+ * Make this object the owner of a string pool. See sepol_object for
+ * more information on string pools.
+ *
+ * @param o object to which to add string pool
+ *
+ * \retval SEPOL_OK success
+ * \retval SEPOL_ENOMEM out of memory
+ */
+extern int sepol_object_create_strpool(struct sepol_handle *h, struct sepol_object *o);
+
+/**
+ * \ingroup sepol_policy
+ *
+ * Return the strpool for this object if any.
+ *
+ * @param o object from which to return string pool.
+ *
+ * \retval non-NULL string pool this object is using.
+ * \retval NULL object does not use string pool.
+ */
+extern struct sepol_objpool *sepol_object_get_strpool(struct sepol_object *o);
+
+/**
+ * \ingroup sepol_policy
+ *
+ * Determine whether the object is the owner of its string pool (if
+ * it has one).
+ *
+ * @param o object to check
+ *
+ * \retval 0 object does not own or does not have a string pool
+ * \retval 1 object owns its string pool
+ */
+extern int sepol_object_is_strpool_owner(struct sepol_object *o);
+
+/**
+ * \ingroup sepol_policy
+ *
+ * Return the parent of this object (if any).
+ *
+ * @param o object for which to return parent
+ *
+ * \retval non-NULL pointer to parent object
+ * \retval NULL object has no parent
+ */
+extern struct sepol_parent *sepol_object_get_parent(struct sepol_object *o);
+
+/**
+ * \ingroup sepol_policy
+ *
+ * Specify the output for various sepol_*_tostring functions.
+ */
+enum sepol_tostring_style {
+ SEPOL_TOSTRING_RAW, /** raw policy language */
+ SEPOL_TOSTRING_REFPOL, /** refpol style output */
+ SEPOL_TOSTRING_DEBUG /** debugging output */
+};
+
+/**
+ * \ingroup sepol_policy
+ *
+ * Convert an sepol_object into a string representation. If the
+ * returned string is of 0 length (return is 0), str will be an
+ * allocated, 0 length string that should be freed by the caller.
+ *
+ * @param h sepol_handle (may be NULL)
+ * @param o object to convert to a string
+ * @param style style of the output - see sepol_tostring_style
+ * @param str output string - this string is allocated by the function
+ * and should be freed by the caller using free()
+ *
+ * \retval >=0 Success - the size of the string is returned
+ * \retval <0 Failure - str will be undefined and does not need to be freed.
+ */
+extern int sepol_object_tostring(struct sepol_handle *h, struct sepol_object *o,
+ enum sepol_tostring_style style, char **str);
+
+/**
+ * \ingroup sepol_policy
+ *
+ * Convert an sepol_object into a string representation for the
+ * closure of that object. Some objects - typically that contain
+ * other objects - need a string to represent the beginning _and_
+ * the end of that object. For example:
+ *
+ * \code
+ * if (foo) {
+ * allow foo bar : file read;
+ * }
+ * \endcode
+ *
+ * In this example "if (foo) }" would be printed by
+ * sepol_object_tostring and "}} printed by
+ * sepol_object_tostring_close on the same conditional object. If the
+ * returned string is of 0 length (return is 0), str will be an
+ * allocated, 0 length string that should be freed by the caller.
+ *
+ * @param h sepol_handle (may be NULL)
+ * @param o object to convert to a string
+ * @param style style of the output - see sepol_tostring_style
+ * @param str output string - this string is allocated by the function
+ * and should be freed by the caller using free()
+ *
+ * \retval >=0 Success - the size of the string is returned
+ * \retval <0 Failure - str will be undefined and does not need to be freed.
+ */
+extern int sepol_object_tostring_close(struct sepol_handle *h, struct sepol_object *o,
+ enum sepol_tostring_style style, char **str);
+
+/**
+ * \ingroup sepol_policy
+ * \struct sepol_parent
+ *
+ * sepol_parent is the parent class of all objects that can contain
+ * other objects in the tree. Having a single base class for all parent
+ * objects allows writing functions that can traverse the tree without
+ * knowing the details about most of the objects in the tree.
+ */
+struct sepol_parent;
+
+/**
+ * \ingroup sepol_policy
+ *
+ * Convert an object to an sepol_parent
+ *
+ * @param x object
+ */
+#define SEPOL_PARENT(x) ((struct sepol_parent *)x)
+
+/**
+ * \ingroup sepol_policy
+ *
+ * Free a parent object and all of its children (if any). This
+ * function traverses a policy tree starting at the parent node passed
+ * in destroy each object it encounters (by (calling
+ * sepol_object_free).
+ *
+ * @param h sepol_handle (may be NULL)
+ * @param p sepol_parent object
+ *
+ * \retval SEPOL_OK success
+ * \retval SEPOL_ENOMEM out of memory
+ */
+extern void sepol_parent_free_tree(struct sepol_parent *p);
+
+/**
+ * \ingroup sepol_policy
+ *
+ * Append an object as a child of this parent. An object can only
+ * be the child of a single parent - to move an object from one
+ * part of the tree to another (and change the parent), remove the
+ * child from the current parent first before appending to the new
+ * parent.
+ *
+ * @param h sepol_handle (may be NULL)
+ * @param p sepol_parent to which to append child object
+ * @param o object to append (parent will be set)
+ *
+ * \retval SEPOL_OK success
+ * \retval SEPOL_EEXIST object is already a child of another parent
+ * \retval SEPOL_ENOMEM out of memory
+ */
+extern int sepol_parent_append(struct sepol_handle *h, struct sepol_parent *p,
+ struct sepol_object *o);
+
+/**
+ * \ingroup sepol_policy
+ *
+ * Extend the children of an sepol_parent with the objects returned by
+ * an iterator. Each object will be appended using
+ * sepol_parent_append. If there is an error from adding any of the
+ * children some of the objects may have been added. The iterator will
+ * be left in the position of the object that caused an error.
+ *
+ * @param h sepol_handle (may be NULL)
+ * @param p sepol_parent to which to add children
+ * @param iter iterator from which to add children
+ *
+ * \retval SEPOL_OK success
+ * \retval SEPOL_EEXIST object is already a child of another parent
+ * \retval SEPOL_ENOMEM out of memory
+ */
+extern int sepol_parent_extend(struct sepol_handle *h, struct sepol_parent *p,
+ struct sepol_iter *iter);
+
+/**
+ * \ingroup sepol_policy
+ *
+ * Convenience function similar to sepol_parent_extend that takes a
+ * list instead of an interator.
+ *
+ * @param h sepol_handle (may be NULL)
+ * @param p sepol_parent to which to add objects
+ * @param list sepol_list from which to add objects
+ *
+ * \retval SEPOL_OK success
+ * \retval SEPOL_EEXIST object is already a child of another parent
+ * \retval SEPOL_ENOMEM out of memory
+ */
+extern int sepol_parent_extend_list(struct sepol_handle *h, struct sepol_parent *p,
+ struct sepol_list *list);
+
+/**
+ * \ingroup sepol_policy
+ *
+ * Delete a child object from the sepol_parent. Like sepol_list_del,
+ * the iterator will not be valid after a call to this function.
+ *
+ * @param h sepol_handle (may be NULL)
+ * @param p sepol_parent from which to delete child
+ * @param iter iterator pointing to a child object of p
+ *
+ * \retval SEPOL_OK success
+ */
+extern void sepol_parent_del(struct sepol_parent *p, struct sepol_iter *iter);
+
+/**
+ * \ingroup sepol_policy
+ *
+ * Insert a child object into the list of children for the
+ * sepol_parent. See sepol_list_insert for more information on the
+ * semantics of this insert.
+ *
+ * @param h sepol_handle (may be NULL)
+ * @param p sepol_parent to which to insert child object
+ * @param iter iterator representing the position to insert the child object
+ * @param o child object to insert
+ *
+ * \retval SEPOL_OK success
+ * \retval SEPOL_EEXIST object is already a child of another parent
+ * \retval SEPOL_ENOMEM out of memory
+ */
+extern int sepol_parent_insert(struct sepol_handle *h, struct sepol_parent *p,
+ struct sepol_iter *iter, struct sepol_object *o);
+
+/**
+ * \ingroup sepol_policy
+ *
+ * Set an iterator to iterate over the children of an sepol_parent.
+ *
+ * @param h sepol_handle (may be NULL)
+ * @param p sepol_parent
+ * @param iter iterator to set to iterate over children
+ *
+ * \retval SEPOL_OK success
+ * \retval SEPOL_ENOMEM out of memory
+ */
+extern int sepol_parent_children_begin(struct sepol_handle *h, struct sepol_parent *p,
+ struct sepol_iter *iter);
+
+/**
+ * \ingroup sepol_policy
+ *
+ * Return the list containing the children of the sepol_parent
+ * object. This is the actual list used to store children of the
+ * object, so changes will be reflected in the sepol_parent. It is
+ * important that deletions and insertions use sepol_parent_del and
+ * sepol_parent_insert or that the parent property of the objects
+ * is properly set.
+ *
+ * @param p sepol_parent
+ *
+ * \retval non-NULL pointer to the list of children
+ */
+struct sepol_list *sepol_parent_get_children(struct sepol_parent *parent);
+
+
+/**
+ * \ingroup sepol_policy
+ *
+ * Traversal of a policy tree rooted at a sepol_parent can take many
+ * forms. This enumeration is used to set the traversal strategy. See
+ * http://en.wikipedia.org/wiki/Tree_traversal for more information.
+ *
+ * The hybrid strategy combines both preorder and postorder
+ * traversal. This means that each parent node will be visited twice:
+ * once before its children are traversed and once afterward. The
+ * second traversal can be detected by checking the flag indicating
+ * that the parent has been visited (see sepol_parent_isvisited).
+ */
+enum sepol_parent_traverse_strategy {
+ SEPOL_TRAVERSE_POSTORDER, /** traverse the tree in postorder */
+ SEPOL_TRAVERSE_PREORDER, /** traverse the tree in preorder */
+ SEPOL_TRAVERSE_HYBRID /** traverse the tree combining preorder and postorder */
+};
+
+/**
+ * \ingroup sepol_policy
+ *
+ * Traverse a policy tree using parent as the root node of the tree. The traversal
+ * strategy is controlled by sepol_parent_traverse_strategy.
+ *
+ * @param h sepol_handle (may be null)
+ * @param parent sepol_parent
+ * @param iter iterator to represent traversal state
+ * @param strategy traversal strategy - see sepol_parent_traverse_strategy
+ *
+ * \retval SEPOL_OK success
+ * \retval SEPOL_ENOMEM out of memory
+ */
+extern int sepol_parent_traverse(struct sepol_handle *h, struct sepol_parent *parent,
+ struct sepol_iter *iter, int strategy);
+
+/**
+ * \ingroup sepol_policy
+ *
+ * Return whether an object has already been visited before during this tree
+ * traversal. See sepol_parent_traverse_strategy for more information.
+ *
+ * @param iter iterator
+ *
+ * \retval 0 object has not been previously visited
+ * \retval 1 object has been previously visited
+ */
+int sepol_parent_isvisited(struct sepol_iter *iter);
+
+/**
+ * \ingroup sepol_policy
+ *
+ * Output a formatted, string representation of a policy tree
+ * to a file descriptor.
+ *
+ * @param h sepol_handle (may be null)
+ * @param p root of policy tree to output
+ * @param style output style
+ * @param fp file point to which to output
+ *
+ * \retval SEPOL_OK success
+ * \retval SEPOL_ENOMEM out of memory
+ */
+int sepol_parent_output_tree(struct sepol_handle *h, struct sepol_parent *p,
+ int style, FILE *fp);
+
+struct sepol_policy;
+
+extern void sepol_policy_free(struct sepol_policy *o);
+extern int sepol_policy_create(struct sepol_handle *h,
+ struct sepol_policy **policy);
+
+extern int sepol_policy_get_ismls(struct sepol_policy *o);
+extern int sepol_policy_set_ismls(struct sepol_handle *h, struct sepol_policy *o,
+ int mls);
+
+struct sepol_module;
+
+extern void sepol_module_free(struct sepol_module *o);
+extern int sepol_module_create(struct sepol_handle *h,
+ struct sepol_module **module);
+extern int sepol_module_create_tree(struct sepol_handle *h,
+ struct sepol_module **module,
+ struct sepol_parent *root);
+
+int sepol_module_set_name(struct sepol_handle *h, struct sepol_module *module,
+ char *name);
+const char *sepol_module_get_name(struct sepol_module *module);
+
+int sepol_module_set_version(struct sepol_handle *h, struct sepol_module *module,
+ char *version);
+const char *sepol_module_get_version(struct sepol_module *module);
+
+int sepol_module_set_isbase(struct sepol_handle *h, struct sepol_module *module,
+ int isbase);
+int sepol_module_get_isbase(struct sepol_module *module);
+
+#endif
diff -r 1d04713e6b39 -r 18a337232eef libsepol/src/libsepol.map
--- a/libsepol/src/libsepol.map Thu May 10 13:43:00 2007 -0400
+++ b/libsepol/src/libsepol.map Thu May 10 13:56:28 2007 -0400
@@ -12,5 +12,9 @@ LIBSEPOL_2.0 {
sepol_policydb_*; sepol_set_policydb_from_file;
sepol_policy_kern_*;
sepol_policy_file_*;
+ sepol_object_*;
+ sepol_parent_*;
+ sepol_policy_*;
+ sepol_module_*;
local: *;
};
diff -r 1d04713e6b39 -r 18a337232eef libsepol/src/policy.c
--- a/libsepol/src/policy.c Thu May 10 13:43:00 2007 -0400
+++ b/libsepol/src/policy.c Thu May 10 13:56:28 2007 -0400
@@ -0,0 +1,690 @@
+/*
+ * Author : Karl MacMillan <kmacmillan@mentalrootkit.com>
+ *
+ * Copyright (C) 2007 Red Hat, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include "policy_internal.h"
+#include "debug.h"
+#include "dso.h"
+
+#include <stdio.h>
+#include <string.h>
+#include <assert.h>
+
+/*
+ * SEPOL_OBJECT
+ */
+
+static char *typeid_strings[] = {
+ [SEPOL_TYPEID_NONE] = "none",
+ [SEPOL_TYPEID_OBJECT] = "object",
+ [SEPOL_TYPEID_PARENT] = "parent",
+ [SEPOL_TYPEID_POLICY] = "policy",
+ [SEPOL_TYPEID_MODULE] = "module",
+ [SEPOL_TYPEID_BLOCK] = "block",
+ [SEPOL_TYPEID_COND] = "cond",
+ [SEPOL_TYPEID_OPTIONAL] = "optional",
+ [SEPOL_TYPEID_TYPE] = "type",
+ [SEPOL_TYPEID_CLASS] = "class",
+ [SEPOL_TYPEID_ATTRIBUTE] = "attribute",
+ [SEPOL_TYPEID_TYPEALIAS] = "typealias",
+ [SEPOL_TYPEID_BOOL] = "boolean",
+ [SEPOL_TYPEID_AVRULE] = "avrule",
+ [SEPOL_TYPEID_TYPERULE] = "typerule",
+ [SEPOL_TYPEID_SECURITY_CONTEXT] = "security context",
+ [SEPOL_TYPEID_ISID] = "initial sid",
+ [SEPOL_TYPEID_TYPEATTRIBUTE] = "typeattribute",
+ [SEPOL_TYPEID_COND_EXPR] = "conditional expression",
+ [SEPOL_TYPEID_SENS] = "sensitivity",
+ [SEPOL_TYPEID_DOMINANCE] = "dominance",
+ [SEPOL_TYPEID_CATEGORY] = "category",
+ [SEPOL_TYPEID_ROLE_DOMINANCE] = "role dominance",
+ [SEPOL_TYPEID_ROLE] = "role"
+};
+
+const char *sepol_typeid_tostring(enum sepol_typeid typeid)
+{
+ assert(typeid < (sizeof(typeid_strings) / sizeof(typeid_strings[0])));
+ return typeid_strings[typeid];
+}
+hidden_def(sepol_typeid_tostring)
+
+void sepol_object_free(struct sepol_object *o)
+{
+ assert(o->methods->free);
+ o->methods->free(o);
+}
+hidden_def(sepol_object_free)
+
+uint32_t sepol_object_get_typeid(struct sepol_object *o)
+{
+ return o->typeid;
+}
+hidden_def(sepol_object_get_typeid)
+
+int sepol_object_isinstance(struct sepol_object *o, uint32_t typeid)
+{
+ if (o->typeid == typeid || o->sclass_typeid == typeid)
+ return 1;
+ else return 0;
+}
+hidden_def(sepol_object_isinstance)
+
+#define SEPOL_STRPOOL_SIZE 64
+int sepol_object_create_strpool(struct sepol_handle *h, struct sepol_object *o)
+{
+ int ret;
+
+ ret = sepol_objpool_create(h, &o->strpool, (sepol_objpool_hash_t)sepol_symhash,
+ (sepol_objpool_cmp_t)sepol_symcmp, free,
+ SEPOL_STRPOOL_SIZE);
+ if (ret < 0)
+ return ret;
+ o->flags |= SEPOL_OBJECT_STRPOOL_OWNER;
+
+ return ret;
+}
+hidden_def(sepol_object_create_strpool)
+
+struct sepol_objpool *sepol_object_get_strpool(struct sepol_object *o)
+{
+ return o->strpool;
+}
+hidden_def(sepol_object_get_strpool)
+
+int sepol_object_is_strpool_owner(struct sepol_object *o)
+{
+ return (o->flags & SEPOL_OBJECT_STRPOOL_OWNER) != 0;
+}
+hidden_def(sepol_object_is_strpool_owner)
+
+struct sepol_parent *sepol_object_get_parent(struct sepol_object *o)
+{
+ return o->parent;
+}
+hidden_def(sepol_object_get_parent)
+
+int sepol_object_tostring(struct sepol_handle *h, struct sepol_object *o,
+ enum sepol_tostring_style style, char **str)
+{
+ if (o->methods->tostring) {
+ return o->methods->tostring(h, o, style, str);
+ } else {
+ if (style == SEPOL_TOSTRING_DEBUG) {
+ return asprintf(str, "[sepol_object(%s) at %p]",
+ sepol_typeid_tostring(o->typeid), o);
+ }
+
+ /* Even though we are returning an empty string, we still
+ * need to allocated an empty string to return. This
+ * matches the behavior of asprintf.
+ */
+ *str = strdup("");
+ if (*str == NULL)
+ return -1;
+ return 0;
+ }
+}
+hidden_def(sepol_object_tostring)
+
+int sepol_object_tostring_close(struct sepol_handle *h, struct sepol_object *o,
+ enum sepol_tostring_style style, char **str)
+{
+ if (o->methods->tostring_close) {
+ return o->methods->tostring_close(h, o, style, str);
+ } else {
+ if (style == SEPOL_TOSTRING_DEBUG) {
+ return asprintf(str, "[close: sepol_object(%s) at %p]",
+ sepol_typeid_tostring(o->typeid), o);
+ }
+
+ /* Even though we are returning an empty string, we still
+ * need to allocated an empty string to return. This
+ * matches the behavior of asprintf.
+ */
+ *str = strdup("");
+ if (*str == NULL)
+ return -1;
+ return 0;
+ }
+}
+hidden_def(sepol_object_tostring_close)
+
+/*
+ * SEPOL_PARENT
+ */
+
+void sepol_parent_free_tree(struct sepol_parent *p)
+{
+ int ret;
+ struct sepol_iter *iter;
+ struct sepol_object *cur;
+
+ ret = sepol_iter_create(NULL, &iter);
+ if (ret < 0)
+ goto out;
+
+ ret = sepol_parent_traverse(NULL, p, iter, SEPOL_TRAVERSE_POSTORDER);
+ if (ret < 0)
+ goto out;
+
+ sepol_foreach(NULL, ret, cur, iter) {
+ sepol_object_free(cur);
+ }
+out:
+ sepol_iter_free(iter);
+}
+hidden_def(sepol_parent_free_tree)
+
+int sepol_parent_append(struct sepol_handle *h, struct sepol_parent *p, struct sepol_object *o)
+{
+ if (o->parent)
+ return SEPOL_EEXIST;
+ o->parent = p;
+ return sepol_list_append(h, p->children, o);
+}
+hidden_def(sepol_parent_append)
+
+int sepol_parent_extend(struct sepol_handle *h, struct sepol_parent *p, struct sepol_iter *iter)
+{
+ int ret = SEPOL_OK;
+ struct sepol_object *cur;
+
+ sepol_foreach(h, ret, cur, iter) {
+ ret = sepol_parent_append(h, p, cur);
+ if (ret < 0)
+ return ret;
+ }
+ if (ret != SEPOL_ITERSTOP) {
+ return ret;
+ }
+
+ return SEPOL_OK;
+}
+hidden_def(sepol_parent_extend)
+
+int sepol_parent_extend_list(struct sepol_handle *h, struct sepol_parent *p, struct sepol_list *list)
+{
+ int ret;
+ struct sepol_iter *iter;
+
+ ret = sepol_iter_create(h, &iter);
+ if (ret < 0)
+ return ret;
+ ret = sepol_list_begin(h, list, iter);
+ if (ret < 0) {
+ if (ret == SEPOL_ITERSTOP)
+ return SEPOL_OK;
+ else
+ return ret;
+ }
+ ret = sepol_parent_extend(h, p, iter);
+ sepol_iter_free(iter);
+
+ return ret;
+}
+hidden_def(sepol_parent_extend_list)
+
+void sepol_parent_del(struct sepol_parent *p, struct sepol_iter *iter)
+{
+ struct sepol_object *o;
+ o = (struct sepol_object*)sepol_iter_get_data(iter);
+ assert(o);
+
+ o->parent = NULL;
+ sepol_list_del(p->children, iter);
+}
+hidden_def(sepol_parent_del)
+
+int sepol_parent_insert(struct sepol_handle *h, struct sepol_parent *p,
+ struct sepol_iter *iter, struct sepol_object *o)
+{
+ int ret;
+
+ if (o->parent)
+ return SEPOL_EEXIST;
+ o->parent = p;
+
+ ret = sepol_list_insert(h, p->children, iter, o);
+ if (ret < 0)
+ o->parent = NULL;
+
+ return ret;
+}
+hidden_def(sepol_parent_insert)
+
+
+int sepol_parent_children_begin(struct sepol_handle *h, struct sepol_parent *p, struct sepol_iter *iter)
+{
+ return sepol_list_begin(h, p->children, iter);
+}
+hidden_def(sepol_parent_children_begin)
+
+struct sepol_list *sepol_parent_get_children(struct sepol_parent *parent)
+{
+ return parent->children;
+}
+hidden_def(sepol_parent_get_children)
+
+
+struct sepol_parent_traverse_state
+{
+ int strategy;
+ char cur_flags;
+ struct sepol_list *stack;
+ void *object;
+};
+
+static void *sepol_parent_iter_get_data(struct sepol_iter *iter)
+{
+ struct sepol_parent_traverse_state *state;
+
+ assert(iter);
+ state = (struct sepol_parent_traverse_state*)
+ sepol_iter_get_state(iter);
+ assert(state);
+
+ return state->object;
+}
+
+static void sepol_parent_iter_free(void *data)
+{
+ struct sepol_parent_traverse_state *state = data;
+
+ if (state == NULL)
+ return;
+
+ if (state->stack)
+ sepol_list_free(state->stack);
+ free(state);
+}
+
+static int sepol_parent_traverse_preorder_next(struct sepol_handle *h, struct sepol_iter *iter)
+{
+ int ret;
+ struct sepol_parent_traverse_state *state;
+ struct sepol_object *object, *cur;
+ struct sepol_iter *child_iter;
+
+ state = sepol_iter_get_state(iter);
+
+ ret = sepol_list_pop_back(h, state->stack, (void**)&object);
+
+ if (ret == SEPOL_ERANGE)
+ return SEPOL_ITERSTOP;
+ else if (ret < 0)
+ return ret;
+
+ state->object = object;
+ state->cur_flags = object->flags;
+
+ if (sepol_object_isinstance(object, SEPOL_TYPEID_PARENT) &&
+ !(object->flags & SEPOL_OBJECT_VISITED)) {
+ if (state->strategy == SEPOL_TRAVERSE_HYBRID) {
+ object->flags |= SEPOL_OBJECT_VISITED;
+ ret = sepol_list_append(h, state->stack, object);
+ if (ret < 0) return ret;
+ }
+ ret = sepol_iter_create(h, &child_iter);
+ if (ret < 0)
+ return ret;
+ ret = sepol_list_end(h, sepol_parent_get_children(SEPOL_PARENT(object)),
+ child_iter);
+ while (ret == SEPOL_OK) {
+ cur = sepol_iter_get_data(child_iter);
+ cur->flags &= ~SEPOL_OBJECT_VISITED;
+ ret = sepol_list_append(h, state->stack, cur);
+ if (ret < 0)
+ break;
+ ret = sepol_iter_prev(h, child_iter);
+ }
+ sepol_iter_free(child_iter);
+ if (ret < 0 && ret != SEPOL_ITERSTOP) {
+ return ret;
+ }
+
+ }
+ return SEPOL_OK;
+}
+
+static int sepol_parent_traverse_postorder_next(struct sepol_handle *h, struct sepol_iter *iter)
+{
+ int ret;
+ struct sepol_parent_traverse_state *state;
+ struct sepol_object *object, *cur;
+ struct sepol_iter *child_iter;
+
+ state = sepol_iter_get_state(iter);
+
+ while (1) {
+ ret = sepol_list_pop_back(h, state->stack, (void**)&object);
+
+ if (ret == SEPOL_ERANGE)
+ return SEPOL_ITERSTOP;
+ else if (ret < 0)
+ return ret;
+
+ if (object->flags & SEPOL_OBJECT_VISITED ||
+ !sepol_object_isinstance(object, SEPOL_TYPEID_PARENT)) {
+ state->object = object;
+ break;
+ } else {
+ object->flags |= SEPOL_OBJECT_VISITED;
+ ret = sepol_list_append(h, state->stack, object);
+ if (ret < 0)
+ return ret;
+
+ ret = sepol_iter_create(h, &child_iter);
+ if (ret < 0)
+ return ret;
+ ret = sepol_list_end(h, sepol_parent_get_children(SEPOL_PARENT(object)),
+ child_iter);
+ while (ret == SEPOL_OK) {
+ cur = sepol_iter_get_data(child_iter);
+ cur->flags &= ~SEPOL_OBJECT_VISITED;
+ ret = sepol_list_append(h, state->stack, cur);
+ if (ret < 0)
+ break;
+ ret = sepol_iter_prev(h, child_iter);
+ }
+ sepol_iter_free(child_iter);
+ if (ret < 0 && ret != SEPOL_ITERSTOP) {
+ return ret;
+ }
+ }
+ }
+ return SEPOL_OK;
+}
+
+int sepol_parent_traverse(struct sepol_handle *h, struct sepol_parent *parent,
+ struct sepol_iter *iter, int strategy)
+{
+ int ret;
+ struct sepol_parent_traverse_state *state = NULL;
+
+ state = calloc(1, sizeof(struct sepol_parent_traverse_state));
+ if (state == NULL)
+ return SEPOL_ENOMEM;
+
+ ret = sepol_list_create(h, &state->stack);
+ if (ret < 0)
+ goto err;
+
+ state->strategy = strategy;
+ sepol_iter_set_state(iter, state);
+
+ if (state->strategy == SEPOL_TRAVERSE_POSTORDER)
+ sepol_iter_set_next(iter, sepol_parent_traverse_postorder_next);
+ else if (state->strategy == SEPOL_TRAVERSE_PREORDER ||
+ state->strategy == SEPOL_TRAVERSE_HYBRID)
+ sepol_iter_set_next(iter, sepol_parent_traverse_preorder_next);
+ else
+ return SEPOL_ERR;
+ sepol_iter_set_free(iter, sepol_parent_iter_free);
+ sepol_iter_set_get_data(iter, sepol_parent_iter_get_data);
+
+
+ parent->sclass.flags &= ~SEPOL_OBJECT_VISITED;
+ ret = sepol_list_append(h, state->stack, parent);
+ if (ret < 0)
+ goto err;
+ ret = sepol_iter_next(h, iter);
+ if (ret < 0)
+ goto err;
+
+ return SEPOL_OK;
+err:
+ sepol_parent_iter_free(state);
+ return ret;
+}
+hidden_def(sepol_parent_traverse)
+
+int sepol_parent_isvisited(struct sepol_iter *iter)
+{
+ struct sepol_parent_traverse_state *state;
+
+ state = sepol_iter_get_state(iter);
+ if (state->cur_flags & SEPOL_OBJECT_VISITED)
+ return 1;
+ else
+ return 0;
+}
+hidden_def(sepol_parent_isvisited)
+
+static void sepol_print_tabs(FILE *fp, int tabs)
+{
+ int i = tabs;
+
+ assert(i >= 0);
+ while (i--) {
+ fprintf(fp, " ");
+ }
+}
+
+int sepol_parent_output_tree(struct sepol_handle *h, struct sepol_parent *p,
+ int style, FILE *fp)
+{
+ int ret, indent;
+ char *str;
+
+ struct sepol_object *cur;
+ struct sepol_iter *iter;
+
+ indent = 0;
+
+ ret = sepol_iter_create(h, &iter);
+ if (ret < 0)
+ return ret;
+ ret = sepol_parent_traverse(h, p, iter, SEPOL_TRAVERSE_HYBRID);
+ sepol_foreach (h, ret, cur, iter) {
+ if (sepol_parent_isvisited(iter)) {
+ if (sepol_object_isinstance(cur, SEPOL_TYPEID_PARENT)) {
+ indent--;
+ ret = sepol_object_tostring_close(h, cur, style, &str);
+ if (ret < 0)
+ goto out;
+ sepol_print_tabs(fp, indent);
+ fprintf(fp, "%s\n", str);
+ free(str);
+ }
+
+ } else {
+ ret = sepol_object_tostring(h, cur, style, &str);
+ if (ret < 0)
+ goto out;
+ sepol_print_tabs(fp, indent);
+ fprintf(fp, "%s\n", str);
+ free(str);
+ if (sepol_object_isinstance(cur, SEPOL_TYPEID_PARENT))
+ indent++;
+ }
+ }
+ if (ret == SEPOL_ITERSTOP)
+ ret = SEPOL_OK;
+out:
+ sepol_iter_free(iter);
+
+ return ret;
+}
+hidden_def(sepol_parent_output_tree);
+
+/*
+ * SEPOL_POLICY
+ */
+
+struct sepol_policy
+{
+ struct sepol_parent sclass;
+ int ismls;
+};
+
+void sepol_policy_free(struct sepol_policy *o)
+{
+ intern_sepol_parent_free(SEPOL_PARENT(o));
+ free(o);
+}
+
+static int sepol_policy_tostring(struct sepol_handle *h,
+ struct sepol_object * object __attribute__ ((unused)),
+ int style, char **str)
+{
+ if (style == SEPOL_TOSTRING_DEBUG) {
+ *str = strdup("POLICY {");
+ if (*str)
+ return 0;
+ else
+ return -1;
+ } else {
+ *str = strdup("");
+ if (*str)
+ return 0;
+ else
+ return -1;
+ }
+}
+
+static int sepol_policy_tostring_close(struct sepol_handle *h __attribute__ ((unused)),
+ struct sepol_object *object __attribute__ ((unused)),
+ int style, char **str)
+{
+ if (style == SEPOL_TOSTRING_DEBUG) {
+ *str = strdup("} [POLICY]");
+ if (*str)
+ return 0;
+ else
+ return -1;
+ } else {
+ *str = strdup("");
+ if (*str)
+ return 0;
+ else
+ return -1;
+ }
+}
+
+static struct sepol_object_methods sepol_policy_methods = {
+ .free = (sepol_object_free_t)sepol_policy_free,
+ .tostring = sepol_policy_tostring,
+ .tostring_close = sepol_policy_tostring_close
+};
+
+int sepol_policy_create(struct sepol_handle *h, struct sepol_policy **policy)
+{
+ int ret;
+ struct sepol_policy *x;
+
+ *policy = NULL;
+ x = calloc(1, sizeof(struct sepol_policy));
+ if (x == NULL) {
+ return SEPOL_ENOMEM;
+ }
+
+ ret = intern_sepol_parent_init(h, SEPOL_PARENT(x), SEPOL_TYPEID_POLICY,
+ &sepol_policy_methods, NULL);
+ if (ret < 0)
+ goto out;
+
+ /* policy always has a strpool for convenience */
+ ret = sepol_object_create_strpool(h, SEPOL_OBJECT(x));
+ if (ret < 0)
+ goto out;
+
+ *policy = x;
+ return SEPOL_OK;
+out:
+ intern_sepol_parent_free(SEPOL_PARENT(x));
+ return ret;
+}
+
+DEFINE_BOOL_PROP(policy, ismls)
+
+/*
+ * SEPOL_MODULE
+ */
+
+struct sepol_module
+{
+ struct sepol_parent sclass;
+ char *name;
+ char *version;
+ char isbase;
+};
+
+void sepol_module_free(struct sepol_module *o)
+{
+ intern_sepol_object_delstr(NULL, o, o->name);
+ intern_sepol_object_delstr(NULL, o, o->version);
+ intern_sepol_parent_free(SEPOL_PARENT(o));
+ free(o);
+}
+hidden_def(sepol_module_free)
+
+static int sepol_module_tostring(struct sepol_handle *h, struct sepol_object *object,
+ int style, char **str)
+{
+ struct sepol_module *module = (struct sepol_module *)object;
+
+ if (module->name == NULL || module->version == NULL)
+ return -1;
+
+ if (style == SEPOL_TOSTRING_REFPOL)
+ return asprintf(str, "policy_module(%s %s)", module->name,
+ module->version);
+ else
+ return asprintf(str, "module %s %s;", module->name, module->version);
+}
+
+static struct sepol_object_methods sepol_module_methods = {
+ .free = (sepol_object_free_t)sepol_module_free,
+ .tostring = sepol_module_tostring
+};
+
+int sepol_module_create(struct sepol_handle *h, struct sepol_module **module)
+{
+ return sepol_module_create_tree(h, module, NULL);
+}
+hidden_def(sepol_module_create)
+
+int sepol_module_create_tree(struct sepol_handle *h, struct sepol_module **module,
+ struct sepol_parent *root)
+{
+ int ret;
+ struct sepol_module *x;
+
+ *module = NULL;
+ x = calloc(1, sizeof(struct sepol_module));
+ if (x == NULL) {
+ return SEPOL_ENOMEM;
+ }
+
+ ret = intern_sepol_parent_init(h, SEPOL_PARENT(x), SEPOL_TYPEID_MODULE,
+ &sepol_module_methods, root);
+ if (ret < 0)
+ goto out;
+
+ *module = x;
+ return SEPOL_OK;
+out:
+ free(x);
+ return ret;
+}
+hidden_def(sepol_module_create_tree)
+
+DEFINE_STR_PROP(module, name)
+DEFINE_STR_PROP(module, version)
+DEFINE_BOOL_PROP(module, isbase)
diff -r 1d04713e6b39 -r 18a337232eef libsepol/src/policy_internal.c
--- a/libsepol/src/policy_internal.c Thu May 10 13:43:00 2007 -0400
+++ b/libsepol/src/policy_internal.c Thu May 10 13:56:28 2007 -0400
@@ -0,0 +1,103 @@
+/*
+ * Author : Karl MacMillan <kmacmillan@mentalrootkit.com>
+ *
+ * Copyright (C) 2007 Red Hat, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include "policy_internal.h"
+
+int intern_sepol_object_init(struct sepol_handle *h, struct sepol_object *o, uint32_t typeid,
+ struct sepol_object_methods *methods, struct sepol_parent *root)
+{
+ memset(o, 0, sizeof(struct sepol_object));
+ o->sclass_typeid = SEPOL_TYPEID_OBJECT;
+ o->typeid = typeid;
+ o->methods = methods;
+ if (root && sepol_object_get_strpool(SEPOL_OBJECT(root)))
+ o->strpool = sepol_object_get_strpool(SEPOL_OBJECT(root));
+
+
+ return 0;
+}
+
+void intern_sepol_object_free(struct sepol_object *o)
+{
+ if (o == NULL)
+ return;
+
+ if (o->flags & SEPOL_OBJECT_STRPOOL_OWNER)
+ sepol_objpool_free(o->strpool);
+}
+
+int _intern_sepol_object_addstr(struct sepol_handle *h, struct sepol_object *o, char **str)
+{
+ char *tmp;
+
+ tmp = strdup(*str);
+ if (!tmp)
+ return SEPOL_ENOMEM;
+
+ *str = tmp;
+
+ if (o->strpool) {
+ *str = sepol_objpool_add(h, o->strpool, *str);
+ if (!*str)
+ return SEPOL_ENOMEM;
+ }
+
+ return SEPOL_OK;
+}
+
+int _intern_sepol_object_delstr(struct sepol_handle *h, struct sepol_object *o, char *str)
+{
+ int ret;
+
+ if (str == NULL)
+ return SEPOL_OK;
+
+ if (o->strpool) {
+ ret = sepol_objpool_del(h, o->strpool, str);
+ return ret;
+ } else {
+ free(str);
+ return SEPOL_OK;
+ }
+}
+
+int intern_sepol_parent_init(struct sepol_handle *h, struct sepol_parent *p, uint32_t typeid,
+ struct sepol_object_methods *methods, struct sepol_parent *root)
+{
+ int ret;
+
+ ret = intern_sepol_object_init(h, SEPOL_OBJECT(p), typeid, methods, root);
+ if (ret < 0)
+ return ret;
+ p->sclass.sclass_typeid = SEPOL_TYPEID_PARENT;
+
+ ret = sepol_list_create(h, &p->children);
+ if (ret < 0)
+ sepol_object_free(SEPOL_OBJECT(p));
+
+ return ret;
+}
+
+void intern_sepol_parent_free(struct sepol_parent *p)
+{
+ intern_sepol_object_free(SEPOL_OBJECT(p));
+
+ sepol_list_free(p->children);
+}
diff -r 1d04713e6b39 -r 18a337232eef libsepol/src/policy_internal.h
--- a/libsepol/src/policy_internal.h Thu May 10 13:43:00 2007 -0400
+++ b/libsepol/src/policy_internal.h Thu May 10 13:56:28 2007 -0400
@@ -0,0 +1,281 @@
+#ifndef __policy_internal_h__
+#define __policy_internal_h__
+
+#include "dso.h"
+
+#include <sepol/policy.h>
+#include <sepol/policydb/policydb.h>
+#include <sepol/policydb/conditional.h>
+
+#include <stdlib.h>
+#include <sys/types.h>
+
+/* Internal structs and functions for the policy object system. In
+ * general, policy objects cannot be created outside of the libsepol
+ * tree. It is possible, but not currently implemented, so there is
+ * quite a lot of internals in this header.
+ *
+ * One of the goals of this object system is to allow polymorphic
+ * methods. That will allow calling , for example, sepol_object_free
+ * on _any_ subclass of sepol_object and have the correct function
+ * called for the specific subclass. This polymorphism is implemented
+ * using an sepol_object_method struct for each class and a pointer to
+ * that struct held in each object instance.
+ *
+ * A subclass is expected to create an sepol_object_methods struct
+ * containing function pointers for the methods that it implements (it
+ * is valid for some of the function pointers to be NULL). Every
+ * instance of an sepol_object object holds a pointer to a single
+ * methods struct - i.e., there is only one struct per class and every
+ * instance holds a pointer to that struct.
+ *
+ * See sepol_object_init for how this pointer is set and sepol_object_free
+ * for how subclass methods are called.
+ */
+
+/* sepol_object_free_t is the type for the free method used in the policy
+ * object system. Implementations of this method should free all of the
+ * memory associated with the object including the struct.
+ */
+typedef void (*sepol_object_free_t)(struct sepol_object *o);
+typedef int (*sepol_object_tostring_t)(struct sepol_handle *h, struct sepol_object *o,
+ int style, char **str);
+
+struct sepol_object_methods
+{
+ sepol_object_free_t free;
+ sepol_object_tostring_t tostring;
+ sepol_object_tostring_t tostring_close;
+};
+
+enum sepol_object_flags {
+ SEPOL_OBJECT_STRPOOL_OWNER = 1,
+ SEPOL_OBJECT_VISITED = 2
+};
+
+struct sepol_object
+{
+ struct sepol_object_methods *methods;
+ struct sepol_parent *parent;
+ struct sepol_objpool *strpool;
+ int flags;
+ uint32_t sclass_typeid;
+ uint32_t typeid;
+ uint32_t lineno;
+};
+
+/* Private initialization function for all objects. This function only
+ * initializes the generic object properties - the type specific creation
+ * function is responsible for initializing any type specific properties.
+ * If this function fails it will clean up any memory that it allocated. The
+ * calling function is responsible for any type specific memory and for freeing
+ * the object struct.
+ *
+ * params:
+ * o - object to initialize
+ * typeid - typeid of o
+ * methods - pointer to sepol_object_methods struct for this type. Should
+ * be a pointer to a single static struct for all instances of this type.
+ * root - root of the policy tree of which o is a member (may be NULL). If
+ * the root is non-NULL and has a string pool then that string pool is
+ * used for this object.
+ */
+int intern_sepol_object_init(struct sepol_handle *h, struct sepol_object *o, uint32_t typeid,
+ struct sepol_object_methods *methods, struct sepol_parent *root);
+
+/* Free any memory associated with the super class. This should be called
+ * from a type specific free function.
+ */
+void intern_sepol_object_free(struct sepol_object *o);
+
+/* Add a string to the string pool of the object. After a call to this
+ * function the str pointer will point to the correct (and possibly
+ * shared) version of the string to use.
+ */
+#define intern_sepol_object_addstr(h, o, str) _intern_sepol_object_addstr(h, SEPOL_OBJECT(o), str)
+int _intern_sepol_object_addstr(struct sepol_handle *h, struct sepol_object *o, char **str);
+
+/* Delete a string. If the object has a string pool the memory
+ * associated with the string may not be released
+ * immediately. Regardless, the caller should assume that the pointer
+ * is invalid after a call to this function.
+ */
+#define intern_sepol_object_delstr(h, o, str) _intern_sepol_object_delstr(h, SEPOL_OBJECT(o), str)
+int _intern_sepol_object_delstr(struct sepol_handle *h, struct sepol_object *o, char *str);
+
+hidden_proto(sepol_typeid_tostring)
+hidden_proto(sepol_object_free)
+hidden_proto(sepol_object_get_typeid)
+hidden_proto(sepol_object_isinstance)
+hidden_proto(sepol_object_create_strpool)
+hidden_proto(sepol_object_get_strpool)
+hidden_proto(sepol_object_is_strpool_owner)
+hidden_proto(sepol_object_get_parent)
+hidden_proto(sepol_object_tostring)
+hidden_proto(sepol_object_tostring_close)
+
+struct sepol_parent
+{
+ struct sepol_object sclass;
+ struct sepol_list *children;
+};
+
+/* Initialize an sepol_parent object. Same function and general
+ * properties as intern_sepol_object_init but for parent
+ * objects. Objects should only call the init function for their
+ * immediate parent - the parent is responsible for any further
+ * chaining up the type hierarchy.
+ */
+int intern_sepol_parent_init(struct sepol_handle *h, struct sepol_parent *p, uint32_t typeid,
+ struct sepol_object_methods *methods, struct sepol_parent *root);
+
+/* Internal free function for sepol_paren objects. Like the init functions
+ * this chains up the type hierarchy by call inter_sepol_object_free.
+ */
+void intern_sepol_parent_free(struct sepol_parent *p);
+
+hidden_proto(sepol_parent_free_tree)
+hidden_proto(sepol_parent_append)
+hidden_proto(sepol_parent_extend)
+hidden_proto(sepol_parent_extend_list)
+hidden_proto(sepol_parent_del)
+hidden_proto(sepol_parent_insert)
+hidden_proto(sepol_parent_children_begin)
+hidden_proto(sepol_parent_get_children)
+hidden_proto(sepol_parent_traverse)
+hidden_proto(sepol_parent_isvisited)
+hidden_proto(sepol_parent_output_tree)
+
+
+/* sepol_policy */
+hidden_proto(sepol_policy_free)
+hidden_proto(sepol_policy_get_ismls)
+hidden_proto(sepol_policy_set_ismls)
+
+/* sepol_module */
+hidden_proto(sepol_module_free)
+hidden_proto(sepol_module_create)
+hidden_proto(sepol_module_create_tree)
+hidden_proto(sepol_module_set_name)
+hidden_proto(sepol_module_get_name)
+hidden_proto(sepol_module_set_version)
+hidden_proto(sepol_module_get_version)
+hidden_proto(sepol_module_set_isbase)
+hidden_proto(sepol_module_get_isbase)
+
+/*
+ * PROPERTY GENERATION MACROS
+ *
+ * Many of the objects are similar and will have almost identical
+ * functions for getting and setting properties. These macros generate
+ * those functions for brevity and correctness.
+ */
+
+/* Initialize an object set for holding strings. This should be used
+ * in an object creation function to initialize a string set. This
+ * handles object pooling.
+ */
+#define INIT_STRSET(obj, set, ret, target) \
+ do { \
+ if (SEPOL_OBJECT(obj)->strpool) { \
+ ret = sepol_objset_create(&obj->set, sepol_policy_ptrcmp); \
+ } else { \
+ ret = sepol_objset_create(&obj->set, \
+ (sepol_objset_cmp_t)sepol_policy_strcmp); \
+ } \
+ if (ret < 0) goto target; \
+ } while (0);
+
+#define DESTROY_STRSET(obj, set, iter, ret) \
+ do { \
+ if (obj->set != NULL) { \
+ ret = sepol_iter_create(&iter); \
+ if (ret < 0) return ret;; \
+ ret = sepol_objset_iter(obj->set, iter); \
+ if (ret < 0 && ret != SEPOL_ITERSTOP) return ret; \
+ while (ret == SEPOL_OK) { \
+ ret = intern_sepol_object_delstr(obj, sepol_iter_get_data(iter)); \
+ if (ret < 0) { \
+ sepol_iter_destroy(iter); \
+ return ret; \
+ } \
+ ret = sepol_iter_next(iter); \
+ } \
+ sepol_iter_destroy(iter); \
+ if (ret != SEPOL_ITERSTOP) return ret; \
+ } \
+ sepol_objset_destroy(obj->set); \
+ } while (0);
+
+
+#define DEFINE_STR_PROP(obj, prop) \
+ int sepol_##obj##_set_##prop(struct sepol_handle *h, \
+ struct sepol_##obj *x, char *prop) \
+ { \
+ int ret; \
+ if (x-> prop ) { \
+ ret = intern_sepol_object_delstr(h, x, x-> prop ); \
+ if (ret < 0) return ret;; \
+ } \
+ x-> prop = prop; \
+ return intern_sepol_object_addstr(h, x, &x-> prop ); \
+ } \
+ hidden_def(sepol_##obj##_set_##prop) \
+ const char *sepol_##obj##_get_##prop(struct sepol_##obj *x) \
+ { \
+ return x-> prop ; \
+ } \
+ hidden_def(sepol_##obj##_get_##prop)
+
+#define DEFINE_BOOL_PROP(obj, prop) \
+ int sepol_##obj##_set_##prop(struct sepol_handle *h, \
+ struct sepol_##obj *x, int prop) \
+ { \
+ if (prop != 0 && prop != 1) { \
+ ERR(h, "boolean properties can only be 1 and 0"); \
+ return SEPOL_ERR; \
+ } \
+ x-> prop = prop; \
+ return SEPOL_OK; \
+ } \
+ hidden_def(sepol_##obj##_set_##prop) \
+ int sepol_##obj##_get_##prop(struct sepol_##obj *x) \
+ { \
+ return x->prop ; \
+ } \
+ hidden_def(sepol_##obj##_get_##prop)
+
+#define DEFINE_UINT_PROP(obj, prop) \
+ int sepol_##obj##_set_##prop(struct sepol_handle *h, \
+ struct sepol_##obj *x, uint32_t prop) \
+ { \
+ x->prop = prop; \
+ return SEPOL_OK; \
+ } \
+ hidden_def(sepol_##obj##_set_##prop) \
+ uint32_t sepol_##obj##_get_##prop(struct sepol_##obj *x) \
+ { \
+ return x->prop ; \
+ } \
+ hidden_def(sepol_##obj##_get_##prop)
+
+#define DEFINE_STRSET_PROP(obj, prop, set) \
+ int sepol_##obj##_add_##prop(struct sepol_handle *h, \
+ struct sepol_##obj *x, char *prop) \
+ { \
+ int ret; \
+ ret = intern_sepol_object_addstr(x, &tmp); \
+ if (ret < 0) return ret;; \
+ ret = sepol_objset_add(h, x->set, tmp); \
+ if (ret < 0) return ret;; \
+ return SEPOL_OK; \
+ } \
+ hidden_def(sepol_##obj##_set_##prop) \
+ struct sepol_objset *sepol_##obj##_get_##set(struct sepol_##obj *x) \
+ { \
+ return x->set; \
+ } \
+ hidden_def(sepol_##obj##_get_##prop)
+
+
+#endif
diff -r 1d04713e6b39 -r 18a337232eef libsepol/tests/libsepol-tests.c
--- a/libsepol/tests/libsepol-tests.c Thu May 10 13:43:00 2007 -0400
+++ b/libsepol/tests/libsepol-tests.c Thu May 10 13:56:28 2007 -0400
@@ -26,6 +26,7 @@
#include "test-hashtab.h"
#include "test-objpool.h"
#include "test-objset.h"
+#include "test-policy.h"
#include <CUnit/Basic.h>
#include <CUnit/Console.h>
@@ -69,6 +70,7 @@ static int do_tests(int interactive, int
DECLARE_SUITE(hashtab);
DECLARE_SUITE(objpool);
DECLARE_SUITE(objset);
+ DECLARE_SUITE(policy);
if (verbose)
CU_basic_set_mode(CU_BRM_VERBOSE);
diff -r 1d04713e6b39 -r 18a337232eef libsepol/tests/test-policy.c
--- a/libsepol/tests/test-policy.c Thu May 10 13:43:00 2007 -0400
+++ b/libsepol/tests/test-policy.c Thu May 10 13:56:28 2007 -0400
@@ -0,0 +1,117 @@
+/*
+ * Author : Karl MacMillan <kmacmillan@mentalrootkit.com>
+ *
+ * Copyright (C) 2007 Red Hat, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include "test-policy.h"
+
+#include <sepol/policy.h>
+#include <sepol/iter.h>
+#include <sepol/errcodes.h>
+
+#include <stdlib.h>
+#include <stdio.h>
+
+int policy_test_init(void)
+{
+ return 0;
+}
+
+int policy_test_cleanup(void)
+{
+ return 0;
+}
+
+static void test_policy(void)
+{
+ int ret;
+ char *str;
+
+ struct sepol_handle *h;
+ struct sepol_iter *iter;
+ struct sepol_object *cur;
+
+ struct sepol_policy *policy;
+ struct sepol_module *module;
+
+ h = sepol_handle_create();
+ CU_ASSERT(h != NULL);
+
+ ret = sepol_policy_create(h, &policy);
+ CU_ASSERT(ret == SEPOL_OK);
+
+ ret = sepol_module_create_tree(h, &module, SEPOL_PARENT(policy));
+ CU_ASSERT(ret == SEPOL_OK);
+
+ ret = sepol_module_set_isbase(h, module, 0);
+ CU_ASSERT(ret == SEPOL_OK);
+
+ ret = sepol_module_set_name(h, module, "foo");
+ CU_ASSERT(ret == SEPOL_OK);
+
+ ret = sepol_module_set_version(h, module, "1.1");
+ CU_ASSERT(ret == SEPOL_OK);
+
+ ret = sepol_parent_append(h, SEPOL_PARENT(policy), SEPOL_OBJECT(module));
+ CU_ASSERT(ret == SEPOL_OK);
+
+ ret = sepol_module_create_tree(h, &module, SEPOL_PARENT(policy));
+ CU_ASSERT(ret == SEPOL_OK);
+
+ ret = sepol_module_set_isbase(h, module, 1);
+ CU_ASSERT(ret == SEPOL_OK);
+
+ ret = sepol_module_set_name(h, module, "bar");
+ CU_ASSERT(ret == SEPOL_OK);
+
+ ret = sepol_module_set_version(h, module, "1.0");
+ CU_ASSERT(ret == SEPOL_OK);
+
+ ret = sepol_parent_append(h, SEPOL_PARENT(policy), SEPOL_OBJECT(module));
+ CU_ASSERT(ret == SEPOL_OK);
+
+
+ ret = sepol_iter_create(h, &iter);
+ CU_ASSERT(ret == SEPOL_OK);
+ ret = sepol_parent_traverse(h, SEPOL_PARENT(policy), iter, SEPOL_TRAVERSE_POSTORDER);
+ CU_ASSERT(ret == SEPOL_OK);
+
+ sepol_foreach(h, ret, cur, iter) {
+ ret = sepol_object_tostring(h, cur, SEPOL_TOSTRING_DEBUG, &str);
+ CU_ASSERT(ret >= 0);
+ printf("%s\n", str);
+ free(str);
+ }
+ CU_ASSERT(ret == SEPOL_ITERSTOP);
+
+ ret = sepol_parent_output_tree(h, SEPOL_PARENT(policy), SEPOL_TOSTRING_DEBUG, stdout);
+
+ sepol_parent_free_tree(SEPOL_PARENT(policy));
+ sepol_iter_free(iter);
+ sepol_handle_destroy(h);
+}
+
+int policy_add_tests(CU_pSuite suite)
+{
+ if (NULL == CU_add_test(suite, "test_policy",
+ test_policy)) {
+ return -1;
+ }
+
+ return 0;
+}
diff -r 1d04713e6b39 -r 18a337232eef libsepol/tests/test-policy.h
--- a/libsepol/tests/test-policy.h Thu May 10 13:43:00 2007 -0400
+++ b/libsepol/tests/test-policy.h Thu May 10 13:56:28 2007 -0400
@@ -0,0 +1,12 @@
+/* Author : Karl MacMillan <kmacmillan@mentalrootkit.com> */
+
+#ifndef __test_policy_h__
+#define __test_policy_h__
+
+#include <CUnit/Basic.h>
+
+int policy_test_init(void);
+int policy_test_cleanup(void);
+int policy_add_tests(CU_pSuite suite);
+
+#endif
--
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] 25+ messages in thread
* Re: [PATCH] Basic policy representation
2007-05-09 23:26 ` Karl MacMillan
@ 2007-05-10 19:42 ` J. Tang
2007-05-10 20:00 ` Karl MacMillan
0 siblings, 1 reply; 25+ messages in thread
From: J. Tang @ 2007-05-10 19:42 UTC (permalink / raw)
To: Karl MacMillan; +Cc: selinux
On Wed, 2007-05-09 at 19:26 -0400, Karl MacMillan wrote:
> I don't see why - the import function will just create the bare rules
> and declarations and the normal resolution functions can work. The
> requirements would just be thrown out.
An existing module could have this:
optional o {
type A, B, C; # type A is not used by this optional
allow B C: d e;
}
Within the proposed design, how is type A represented? It is neither
used within a rule nor is it a definition. It is a declaration, under
classic compiler terminology. The given design does not seem to make a
distinction between declarations and definitions.
> > allow A B : C d;
> > allow x y : z d;
> Perhaps - it depends on whether there is a string pool at the root of
> the tree the object is in. If there is a string pool, however, there
> will only be one instance.
Here are three scenarios:
1. Both rules are declared unconditionally. This is a monolithic
policy.
2. First allow rule is declared unconditonally, the second rule within
a conditional. This is a monolithic policy.
3. The two rules are from different modules. Their respective ASTs are
presumably joined during linking.
For which of these scenario(s) is there a string pool "at the root of
the tree the [rules are] in"? If so, it holds that there is only one
instance of "d", and thus am I correct in saying that permissions are
indeed instances of sepol_objpools?
> > In the statement
> > type A alias {B C D E F}
> > will this create five instances of a SEPOL_TYPEID_TYPEALIAS or just
> one?
> The code I posted for comments would create 0 - you would just have a
> type declaration. The goal is to represent the policy in the same
> structure as the source - it helps for policy generation.
Follow-up question: In the statement
typealias A alias {B C D E F};
will this create five instances of a SEPOL_TYPEID_TYPEALIAS or just one?
It is unclear by the supplied documentation what the intended behavior
is.
> If you want to print out the tree structure you need this. Is there
> some
> reason to not export this?
Why would not the user call sepol_object_tostring() from the topmost
node?
--
Jason Tang / jtang@tresys.com
--
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] 25+ messages in thread
* Re: [PATCH] Basic policy representation
2007-05-10 19:42 ` J. Tang
@ 2007-05-10 20:00 ` Karl MacMillan
0 siblings, 0 replies; 25+ messages in thread
From: Karl MacMillan @ 2007-05-10 20:00 UTC (permalink / raw)
To: J. Tang; +Cc: selinux
On Thu, 2007-05-10 at 15:42 -0400, J. Tang wrote:
> On Wed, 2007-05-09 at 19:26 -0400, Karl MacMillan wrote:
> > I don't see why - the import function will just create the bare rules
> > and declarations and the normal resolution functions can work. The
> > requirements would just be thrown out.
>
> An existing module could have this:
>
> optional o {
> type A, B, C; # type A is not used by this optional
> allow B C: d e;
> }
>
> Within the proposed design, how is type A represented? It is neither
> used within a rule nor is it a definition.
Perhaps you mean (as the syntax above is not supported):
require {
type A, B, C;
}
Otherwise this is just a plain type declaration / definition (not
certain there is a difference for types).
So for the proposed design the require statement would be a no-op, while
the type declarations would be represented by sepol_type objects.
> It is a declaration, under
> classic compiler terminology. The given design does not seem to make a
> distinction between declarations and definitions.
>
Not certain there is a real differences - we basically have:
1) type declarations - introduce a symbol into the type namespace (no
difference between declaration and definition)
2) type alias - introduce a alternative symbol into the type namespace
(no difference between declaration and definition)
3) attributes - here there is a distinction between the declaration and
the distributed definition, but you could likely just remove the
declaration.
Regardless - what are you getting at? As far as I can see the tree
structure can represent the required semantics correctly. I'm also
confident that any shortcomings can be addressed by tweaks to the basic
design I've proposed.
It seems like you are obliquely hinting that there is an overall design
problem. If so, please stop and just state any concerns you have about
the design directly.
> > > allow A B : C d;
> > > allow x y : z d;
> > Perhaps - it depends on whether there is a string pool at the root of
> > the tree the object is in. If there is a string pool, however, there
> > will only be one instance.
>
> Here are three scenarios:
>
> 1. Both rules are declared unconditionally. This is a monolithic
> policy.
>
> 2. First allow rule is declared unconditonally, the second rule within
> a conditional. This is a monolithic policy.
>
> 3. The two rules are from different modules. Their respective ASTs are
> presumably joined during linking.
>
> For which of these scenario(s) is there a string pool "at the root of
> the tree the [rules are] in"? If so, it holds that there is only one
> instance of "d", and thus am I correct in saying that permissions are
> indeed instances of sepol_objpools?
>
For all cases there may or may not be a string pool at the root of the
policy tree (sepol_policy).
I don't know what else to say other than you need to read the patches
more closely - you are not understanding the string pools. They are
simply an optimization - everything in all of the objects can safely be
assumed to simply be strings (or bools, or sets of strings, etc). You
would never instantiate an sepol_objpool as a permission - it just
doesn't make sense.
> > > In the statement
> > > type A alias {B C D E F}
> > > will this create five instances of a SEPOL_TYPEID_TYPEALIAS or just
> > one?
> > The code I posted for comments would create 0 - you would just have a
> > type declaration. The goal is to represent the policy in the same
> > structure as the source - it helps for policy generation.
>
> Follow-up question: In the statement
>
> typealias A alias {B C D E F};
>
> will this create five instances of a SEPOL_TYPEID_TYPEALIAS or just one?
Just one.
> It is unclear by the supplied documentation what the intended behavior
> is.
>
Please read the code more closely - both the current patches and the old
RFCs.
> > If you want to print out the tree structure you need this. Is there
> > some
> > reason to not export this?
>
> Why would not the user call sepol_object_tostring() from the topmost
> node?
>
The tostring functions only print a single node in the tree. To answer
your more general question, though, they might want to do special
formatting, export the nodes in some way, or any of a million other
things. Again, why not export this?
Karl
--
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] 25+ messages in thread
* Re: [PATCH] Basic policy representation
2007-05-09 14:03 ` Karl MacMillan
@ 2007-05-11 15:27 ` Joshua Brindle
2007-05-11 18:45 ` Karl MacMillan
0 siblings, 1 reply; 25+ messages in thread
From: Joshua Brindle @ 2007-05-11 15:27 UTC (permalink / raw)
To: Karl MacMillan; +Cc: Brian Pomerantz, selinux
Karl MacMillan wrote:
> On Tue, 2007-05-08 at 15:41 -0400, Karl MacMillan wrote:
>
>> I actually prefer returning char instead - to me that is a common way to
>> indicate that the returned value has a limited range of values (2 in
>> this case). But maybe that is just the code bases I've worked on. I
>> don't care either way - this seems like a bike shed discussion . . .
>>
>>
>
> On the other hand, the existing code (for things like sepol_bool) uses
> int for boolean values. So I'll change to using int everywhere.
> Ahh . . . the bike shed looks much nicer painted blue rather than green.
>
Not to drag this mostly irrelevant discussion out longer but the setools
guys have decided to move to using stdbool.h and proper bool types for
all their boolean functions, is there a reason we can't do that? I was
surprised to find out that setting a bool value to anything other than 0
would cause it to be 1, so it really behaves like a boolean (strange..
I'm not use to C doing things the way you'd expect them to :P )
Also the bikeshed should be red.
--
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] 25+ messages in thread
* Re: [PATCH] Basic policy representation
2007-05-11 15:27 ` Joshua Brindle
@ 2007-05-11 18:45 ` Karl MacMillan
0 siblings, 0 replies; 25+ messages in thread
From: Karl MacMillan @ 2007-05-11 18:45 UTC (permalink / raw)
To: Joshua Brindle; +Cc: Brian Pomerantz, selinux
On Fri, 2007-05-11 at 11:27 -0400, Joshua Brindle wrote:
> Karl MacMillan wrote:
> > On Tue, 2007-05-08 at 15:41 -0400, Karl MacMillan wrote:
> >
> >> I actually prefer returning char instead - to me that is a common way to
> >> indicate that the returned value has a limited range of values (2 in
> >> this case). But maybe that is just the code bases I've worked on. I
> >> don't care either way - this seems like a bike shed discussion . . .
> >>
> >>
> >
> > On the other hand, the existing code (for things like sepol_bool) uses
> > int for boolean values. So I'll change to using int everywhere.
> > Ahh . . . the bike shed looks much nicer painted blue rather than green.
> >
> Not to drag this mostly irrelevant discussion out longer but the setools
> guys have decided to move to using stdbool.h and proper bool types for
> all their boolean functions, is there a reason we can't do that? I was
> surprised to find out that setting a bool value to anything other than 0
> would cause it to be 1, so it really behaves like a boolean (strange..
> I'm not use to C doing things the way you'd expect them to :P )
>
I'm fine with that - actually I'm fine with any C99 usage in libsepol as
long as Steve agrees. Will you send a patch?
> Also the bikeshed should be red.
>
Sure :)
Karl
--
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] 25+ messages in thread
end of thread, other threads:[~2007-05-11 18:46 UTC | newest]
Thread overview: 25+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2007-05-07 22:06 [PATCH] Basic policy representation Karl MacMillan
2007-05-08 14:45 ` Joshua Brindle
2007-05-08 15:08 ` Karl MacMillan
2007-05-08 15:48 ` Joshua Brindle
2007-05-08 16:11 ` Karl MacMillan
2007-05-08 16:47 ` Brian Pomerantz
2007-05-08 19:41 ` Karl MacMillan
2007-05-09 14:03 ` Karl MacMillan
2007-05-11 15:27 ` Joshua Brindle
2007-05-11 18:45 ` Karl MacMillan
2007-05-08 17:13 ` Stephen Smalley
2007-05-08 18:37 ` Joshua Brindle
2007-05-08 19:05 ` Stephen Smalley
2007-05-08 19:28 ` Joshua Brindle
2007-05-08 19:36 ` Karl MacMillan
2007-05-08 16:50 ` Stephen Smalley
2007-05-09 16:24 ` James Antill
2007-05-09 18:31 ` Karl MacMillan
2007-05-09 18:35 ` J. Tang
2007-05-09 19:22 ` Karl MacMillan
2007-05-09 22:46 ` J. Tang
2007-05-09 23:26 ` Karl MacMillan
2007-05-10 19:42 ` J. Tang
2007-05-10 20:00 ` Karl MacMillan
-- strict thread matches above, loose matches on Subject: below --
2007-05-10 17:56 Karl MacMillan
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.