diff options
author | Nick Kralevich <nnk@google.com> | 2016-12-12 09:14:06 -0800 |
---|---|---|
committer | Nick Kralevich <nnk@google.com> | 2016-12-12 09:16:22 -0800 |
commit | ff1beaccf2997a56b83fe49172623984be7a3221 (patch) | |
tree | 4b825dc642cb6eb9a060e54bf8d69288fbee4904 | |
parent | d4828b3ba449355aa2d1751026e5f1d1129cedcf (diff) | |
download | libselinux-android-n-iot-release-smart-display.tar.gz |
external/libselinux: Delete all filesHEADandroid-n-mr2-preview-2android-n-mr2-preview-1android-n-iot-release-smart-display-r2android-n-iot-release-smart-displayandroid-n-iot-release-polk-at1android-n-iot-release-lg-thinq-wk7android-n-iot-release-ihome-igv1android-n-iot-preview-4nougat-iot-releasen-iot-preview-4mastermain
This repository was removed from the manifest in
https://android-review.googlesource.com/293506. The files in
this stale manifest are polluting search results.
Test: unneeded. Deleting stale files.
Change-Id: I067c23b991b0da88bb61b179c9e00f6c405f5ad1
59 files changed, 0 insertions, 10373 deletions
diff --git a/MODULE_LICENSE_PUBLIC_DOMAIN b/MODULE_LICENSE_PUBLIC_DOMAIN deleted file mode 100644 index e69de29..0000000 --- a/MODULE_LICENSE_PUBLIC_DOMAIN +++ /dev/null @@ -1,21 +0,0 @@ -This library (libselinux) is public domain software, i.e. not copyrighted. - -Warranty Exclusion ------------------- -You agree that this software is a -non-commercially developed program that may contain "bugs" (as that -term is used in the industry) and that it may not function as intended. -The software is licensed "as is". NSA makes no, and hereby expressly -disclaims all, warranties, express, implied, statutory, or otherwise -with respect to the software, including noninfringement and the implied -warranties of merchantability and fitness for a particular purpose. - -Limitation of Liability ------------------------ -In no event will NSA be liable for any damages, including loss of data, -lost profits, cost of cover, or other special, incidental, -consequential, direct or indirect damages arising from the software or -the use thereof, however caused and on any theory of liability. This -limitation will apply even if NSA has been advised of the possibility -of such damage. You acknowledge that this is a reasonable allocation of -risk. diff --git a/README.android b/README.android deleted file mode 100644 index e01f889..0000000 --- a/README.android +++ /dev/null @@ -1,62 +0,0 @@ -This directory contains a small port of libselinux for Android. -It was originally forked in mid-2011, circa libselinux 2.1.0. -Some changes have been cherry-picked from the upstream libselinux. -Upstream git repository is https://github.com/SELinuxProject/selinux -(libselinux subdirectory) and official releases are available from -https://github.com/SELinuxProject/selinux/wiki/Releases. - -This fork differs from upstream libselinux in at least the following ways: - -* Dependencies on glibc-specific features have been removed/replaced -in order to work with bionic, - -* Legacy code and compatibility interfaces have been removed, - -* Many interfaces, functions, and files are omitted since they are -unused in Android, - -* The python bindings are omitted since they are unused in Android, - -* The setrans (context translation) support has been removed since -there is no need for MLS label translation in Android and the support -imposes extra overhead on calls passing security contexts, - -* The SELinux policy files are all located in / rather than under -/etc/selinux since /etc is not available in Android until /system -is mounted and use fixed paths, not dependent on /etc/selinux/config, - -* The kernel policy file (sepolicy in Android, policy.N in Linux) does -not include a version suffix since Android does not need to support -booting multiple kernels, - -* The policy loading logic does not support automatic downgrading of -the kernel policy file to a version known to the kernel, since this -requires libsepol on the device and is only needed to support mixing -and matching kernels and userspace easily, - -* The selabel interface and label_file backend have been extended to -support label-by-symlink and partial matching support for use by ueventd -in labeling device nodes based on stable symlink names and by init for -optimizing its restorecon_recursive of /sys, - -* Since the fork, upstream libselinux has switched the label_file -backend to use a binary version of the file_contexts file -(file_contexts.bin) that contains precompiled versions of the pcre -regexes. This reduces the time to load the file_contexts -configuration, which in Linux can be significant due to the large -number of entries (> 5000). As Android has far fewer entries (~400), -this has not yet seemed necessary. - -* restorecon functionality, including recursive restorecon, has been -fully implemented within new libselinux functions, along with optimizations -to prune the tree walk if no change has occurred in file_contexts since -the last restorecon, - -* Support for new Android-specific SELinux configuration files, such -as seapp_contexts, property_contexts, and service_contexts, has been -added. - -New files added for Android: -* libselinux/include/selinux/android.h -* libselinux/src/android.c -* libselinux/src/label_android_property.c (later added upstream) diff --git a/include/selinux/android.h b/include/selinux/android.h deleted file mode 100644 index 21a41a0..0000000 --- a/include/selinux/android.h +++ /dev/null @@ -1,56 +0,0 @@ -#ifndef _SELINUX_ANDROID_H_ -#define _SELINUX_ANDROID_H_ - -#include <stdbool.h> -#include <sys/types.h> -#include <unistd.h> - -#include <selinux/label.h> - -#ifdef __cplusplus -extern "C" { -#endif - -extern struct selabel_handle* selinux_android_file_context_handle(void); - -extern struct selabel_handle* selinux_android_prop_context_handle(void); - -extern struct selabel_handle* selinux_android_service_context_handle(void); - -extern void selinux_android_set_sehandle(const struct selabel_handle *hndl); - -extern int selinux_android_load_policy(void); - -extern int selinux_android_setcon(const char *con); - -extern int selinux_android_setcontext(uid_t uid, - bool isSystemServer, - const char *seinfo, - const char *name); - -extern int selinux_android_setfilecon(const char *pkgdir, - const char *pkgname, - const char *seinfo, - uid_t uid); - -extern int selinux_log_callback(int type, const char *fmt, ...) - __attribute__ ((format(printf, 2, 3))); - -#define SELINUX_ANDROID_RESTORECON_NOCHANGE 1 -#define SELINUX_ANDROID_RESTORECON_VERBOSE 2 -#define SELINUX_ANDROID_RESTORECON_RECURSE 4 -#define SELINUX_ANDROID_RESTORECON_FORCE 8 -#define SELINUX_ANDROID_RESTORECON_DATADATA 16 -extern int selinux_android_restorecon(const char *file, unsigned int flags); - -extern int selinux_android_restorecon_pkgdir(const char *pkgdir, - const char *seinfo, - uid_t uid, - unsigned int flags); - -extern int selinux_android_seapp_context_reload(void); - -#ifdef __cplusplus -} -#endif -#endif diff --git a/include/selinux/avc.h b/include/selinux/avc.h deleted file mode 100644 index 8a1a6df..0000000 --- a/include/selinux/avc.h +++ /dev/null @@ -1,507 +0,0 @@ -/* - * Access vector cache interface for object managers. - * - * Author : Eamon Walsh <ewalsh@epoch.ncsc.mil> - */ -#ifndef _SELINUX_AVC_H_ -#define _SELINUX_AVC_H_ - -#include <stdint.h> -#include <errno.h> -#include <stdlib.h> -#include <selinux/selinux.h> - -#ifdef __cplusplus -extern "C" { -#endif - -/* - * SID format and operations - */ -struct security_id { - char * ctx; - unsigned int refcnt; -}; -typedef struct security_id *security_id_t; - -#define SECSID_WILD (security_id_t)NULL /* unspecified SID */ - -/** - * avc_sid_to_context - get copy of context corresponding to SID. - * @sid: input SID - * @ctx: pointer to context reference - * - * Return a copy of the security context corresponding to the input - * @sid in the memory referenced by @ctx. The caller is expected to - * free the context with freecon(). Return %0 on success, -%1 on - * failure, with @errno set to %ENOMEM if insufficient memory was - * available to make the copy, or %EINVAL if the input SID is invalid. - */ -int avc_sid_to_context(security_id_t sid, char ** ctx); -int avc_sid_to_context_raw(security_id_t sid, char ** ctx); - -/** - * avc_context_to_sid - get SID for context. - * @ctx: input security context - * @sid: pointer to SID reference - * - * Look up security context @ctx in SID table, making - * a new entry if @ctx is not found. Increment the - * reference counter for the SID. Store a pointer - * to the SID structure into the memory referenced by @sid, - * returning %0 on success or -%1 on error with @errno set. - */ -int avc_context_to_sid(const char * ctx, security_id_t * sid); -int avc_context_to_sid_raw(const char * ctx, security_id_t * sid); - -/** - * sidget - increment SID reference counter. - * @sid: SID reference - * - * Increment the reference counter for @sid, indicating that - * @sid is in use by an (additional) object. Return the - * new reference count, or zero if @sid is invalid (has zero - * reference count). Note that avc_context_to_sid() also - * increments reference counts. - */ -int sidget(security_id_t sid); - -/** - * sidput - decrement SID reference counter. - * @sid: SID reference - * - * Decrement the reference counter for @sid, indicating that - * a reference to @sid is no longer in use. Return the - * new reference count. When the reference count reaches - * zero, the SID is invalid, and avc_context_to_sid() must - * be called to obtain a new SID for the security context. - */ -int sidput(security_id_t sid); - -/** - * avc_get_initial_sid - get SID for an initial kernel security identifier - * @name: input name of initial kernel security identifier - * @sid: pointer to a SID reference - * - * Get the context for an initial kernel security identifier specified by - * @name using security_get_initial_context() and then call - * avc_context_to_sid() to get the corresponding SID. - */ -int avc_get_initial_sid(const char *name, security_id_t * sid); - -/* - * AVC entry - */ -struct avc_entry; -struct avc_entry_ref { - struct avc_entry *ae; -}; - -/** - * avc_entry_ref_init - initialize an AVC entry reference. - * @aeref: pointer to avc entry reference structure - * - * Use this macro to initialize an avc entry reference structure - * before first use. These structures are passed to avc_has_perm(), - * which stores cache entry references in them. They can increase - * performance on repeated queries. - */ -#define avc_entry_ref_init(aeref) ((aeref)->ae = NULL) - -/* - * User-provided callbacks for memory, auditing, and locking - */ - -/* These structures are passed by reference to avc_init(). Passing - * a NULL reference will cause the AVC to use a default. The default - * memory callbacks are malloc() and free(). The default logging method - * is to print on stderr. If no thread callbacks are passed, a separate - * listening thread won't be started for kernel policy change messages. - * If no locking callbacks are passed, no locking will take place. - */ -struct avc_memory_callback { - /* malloc() equivalent. */ - void *(*func_malloc) (size_t size); - /* free() equivalent. */ - void (*func_free) (void *ptr); - /* Note that these functions should set errno on failure. - If not, some avc routines may return -1 without errno set. */ -}; - -struct avc_log_callback { - /* log the printf-style format and arguments. */ - void (*func_log) (const char *fmt, ...); - /* store a string representation of auditdata (corresponding - to the given security class) into msgbuf. */ - void (*func_audit) (void *auditdata, security_class_t cls, - char *msgbuf, size_t msgbufsize); -}; - -struct avc_thread_callback { - /* create and start a thread, returning an opaque pointer to it; - the thread should run the given function. */ - void *(*func_create_thread) (void (*run) (void)); - /* cancel a given thread and free its resources. */ - void (*func_stop_thread) (void *thread); -}; - -struct avc_lock_callback { - /* create a lock and return an opaque pointer to it. */ - void *(*func_alloc_lock) (void); - /* obtain a given lock, blocking if necessary. */ - void (*func_get_lock) (void *lock); - /* release a given lock. */ - void (*func_release_lock) (void *lock); - /* destroy a given lock (free memory, etc.) */ - void (*func_free_lock) (void *lock); -}; - -/* - * Available options - */ - -/* no-op option, useful for unused slots in an array of options */ -#define AVC_OPT_UNUSED 0 -/* override kernel enforcing mode (boolean value) */ -#define AVC_OPT_SETENFORCE 1 - -/* - * AVC operations - */ - -/** - * avc_init - Initialize the AVC. - * @msgprefix: prefix for log messages - * @mem_callbacks: user-supplied memory callbacks - * @log_callbacks: user-supplied logging callbacks - * @thread_callbacks: user-supplied threading callbacks - * @lock_callbacks: user-supplied locking callbacks - * - * Initialize the access vector cache. Return %0 on - * success or -%1 with @errno set on failure. - * If @msgprefix is NULL, use "uavc". If any callback - * structure references are NULL, use default methods - * for those callbacks (see the definition of the callback - * structures above). - */ -int avc_init(const char *msgprefix, - const struct avc_memory_callback *mem_callbacks, - const struct avc_log_callback *log_callbacks, - const struct avc_thread_callback *thread_callbacks, - const struct avc_lock_callback *lock_callbacks); - -/** - * avc_open - Initialize the AVC. - * @opts: array of selabel_opt structures specifying AVC options or NULL. - * @nopts: number of elements in opts array or zero for no options. - * - * This function is identical to avc_init(), except the message prefix - * is set to "avc" and any callbacks desired should be specified via - * selinux_set_callback(). Available options are listed above. - */ -int avc_open(struct selinux_opt *opts, unsigned nopts); - -/** - * avc_cleanup - Remove unused SIDs and AVC entries. - * - * Search the SID table for SID structures with zero - * reference counts, and remove them along with all - * AVC entries that reference them. This can be used - * to return memory to the system. - */ -void avc_cleanup(void); - -/** - * avc_reset - Flush the cache and reset statistics. - * - * Remove all entries from the cache and reset all access - * statistics (as returned by avc_cache_stats()) to zero. - * The SID mapping is not affected. Return %0 on success, - * -%1 with @errno set on error. - */ -int avc_reset(void); - -/** - * avc_destroy - Free all AVC structures. - * - * Destroy all AVC structures and free all allocated - * memory. User-supplied locking, memory, and audit - * callbacks will be retained, but security-event - * callbacks will not. All SID's will be invalidated. - * User must call avc_init() if further use of AVC is desired. - */ -void avc_destroy(void); - -/** - * avc_has_perm_noaudit - Check permissions but perform no auditing. - * @ssid: source security identifier - * @tsid: target security identifier - * @tclass: target security class - * @requested: requested permissions, interpreted based on @tclass - * @aeref: AVC entry reference - * @avd: access vector decisions - * - * Check the AVC to determine whether the @requested permissions are granted - * for the SID pair (@ssid, @tsid), interpreting the permissions - * based on @tclass, and call the security server on a cache miss to obtain - * a new decision and add it to the cache. Update @aeref to refer to an AVC - * entry with the resulting decisions, and return a copy of the decisions - * in @avd. Return %0 if all @requested permissions are granted, -%1 with - * @errno set to %EACCES if any permissions are denied, or to another value - * upon other errors. This function is typically called by avc_has_perm(), - * but may also be called directly to separate permission checking from - * auditing, e.g. in cases where a lock must be held for the check but - * should be released for the auditing. - */ -int avc_has_perm_noaudit(security_id_t ssid, - security_id_t tsid, - security_class_t tclass, - access_vector_t requested, - struct avc_entry_ref *aeref, struct av_decision *avd); - -/** - * avc_has_perm - Check permissions and perform any appropriate auditing. - * @ssid: source security identifier - * @tsid: target security identifier - * @tclass: target security class - * @requested: requested permissions, interpreted based on @tclass - * @aeref: AVC entry reference - * @auditdata: auxiliary audit data - * - * Check the AVC to determine whether the @requested permissions are granted - * for the SID pair (@ssid, @tsid), interpreting the permissions - * based on @tclass, and call the security server on a cache miss to obtain - * a new decision and add it to the cache. Update @aeref to refer to an AVC - * entry with the resulting decisions. Audit the granting or denial of - * permissions in accordance with the policy. Return %0 if all @requested - * permissions are granted, -%1 with @errno set to %EACCES if any permissions - * are denied or to another value upon other errors. - */ -int avc_has_perm(security_id_t ssid, security_id_t tsid, - security_class_t tclass, access_vector_t requested, - struct avc_entry_ref *aeref, void *auditdata); - -/** - * avc_audit - Audit the granting or denial of permissions. - * @ssid: source security identifier - * @tsid: target security identifier - * @tclass: target security class - * @requested: requested permissions - * @avd: access vector decisions - * @result: result from avc_has_perm_noaudit - * @auditdata: auxiliary audit data - * - * Audit the granting or denial of permissions in accordance - * with the policy. This function is typically called by - * avc_has_perm() after a permission check, but can also be - * called directly by callers who use avc_has_perm_noaudit() - * in order to separate the permission check from the auditing. - * For example, this separation is useful when the permission check must - * be performed under a lock, to allow the lock to be released - * before calling the auditing code. - */ -void avc_audit(security_id_t ssid, security_id_t tsid, - security_class_t tclass, access_vector_t requested, - struct av_decision *avd, int result, void *auditdata); - -/** - * avc_compute_create - Compute SID for labeling a new object. - * @ssid: source security identifier - * @tsid: target security identifier - * @tclass: target security class - * @newsid: pointer to SID reference - * - * Call the security server to obtain a context for labeling a - * new object. Look up the context in the SID table, making - * a new entry if not found. Increment the reference counter - * for the SID. Store a pointer to the SID structure into the - * memory referenced by @newsid, returning %0 on success or -%1 on - * error with @errno set. - */ -int avc_compute_create(security_id_t ssid, - security_id_t tsid, - security_class_t tclass, security_id_t * newsid); - -/** - * avc_compute_member - Compute SID for polyinstantation. - * @ssid: source security identifier - * @tsid: target security identifier - * @tclass: target security class - * @newsid: pointer to SID reference - * - * Call the security server to obtain a context for labeling an - * object instance. Look up the context in the SID table, making - * a new entry if not found. Increment the reference counter - * for the SID. Store a pointer to the SID structure into the - * memory referenced by @newsid, returning %0 on success or -%1 on - * error with @errno set. - */ -int avc_compute_member(security_id_t ssid, - security_id_t tsid, - security_class_t tclass, security_id_t * newsid); - -/* - * security event callback facility - */ - -/* security events */ -#define AVC_CALLBACK_GRANT 1 -#define AVC_CALLBACK_TRY_REVOKE 2 -#define AVC_CALLBACK_REVOKE 4 -#define AVC_CALLBACK_RESET 8 -#define AVC_CALLBACK_AUDITALLOW_ENABLE 16 -#define AVC_CALLBACK_AUDITALLOW_DISABLE 32 -#define AVC_CALLBACK_AUDITDENY_ENABLE 64 -#define AVC_CALLBACK_AUDITDENY_DISABLE 128 - -/** - * avc_add_callback - Register a callback for security events. - * @callback: callback function - * @events: bitwise OR of desired security events - * @ssid: source security identifier or %SECSID_WILD - * @tsid: target security identifier or %SECSID_WILD - * @tclass: target security class - * @perms: permissions - * - * Register a callback function for events in the set @events - * related to the SID pair (@ssid, @tsid) and - * and the permissions @perms, interpreting - * @perms based on @tclass. Returns %0 on success or - * -%1 if insufficient memory exists to add the callback. - */ -int avc_add_callback(int (*callback) - (uint32_t event, security_id_t ssid, - security_id_t tsid, security_class_t tclass, - access_vector_t perms, - access_vector_t * out_retained), - uint32_t events, security_id_t ssid, - security_id_t tsid, security_class_t tclass, - access_vector_t perms); - -/* - * AVC statistics - */ - -/* If set, cache statistics are tracked. This may - * become a compile-time option in the future. - */ -#define AVC_CACHE_STATS 1 - -struct avc_cache_stats { - unsigned entry_lookups; - unsigned entry_hits; - unsigned entry_misses; - unsigned entry_discards; - unsigned cav_lookups; - unsigned cav_hits; - unsigned cav_probes; - unsigned cav_misses; -}; - -/** - * avc_cache_stats - get cache access statistics. - * @stats: reference to statistics structure - * - * Fill the supplied structure with information about AVC - * activity since the last call to avc_init() or - * avc_reset(). See the structure definition for - * details. - */ -void avc_cache_stats(struct avc_cache_stats *stats); - -/** - * avc_av_stats - log av table statistics. - * - * Log a message with information about the size and - * distribution of the access vector table. The audit - * callback is used to print the message. - */ -void avc_av_stats(void); - -/** - * avc_sid_stats - log SID table statistics. - * - * Log a message with information about the size and - * distribution of the SID table. The audit callback - * is used to print the message. - */ -void avc_sid_stats(void); - -/** - * avc_netlink_open - Create a netlink socket and connect to the kernel. - */ -int avc_netlink_open(int blocking); - -/** - * avc_netlink_loop - Wait for netlink messages from the kernel - */ -void avc_netlink_loop(void); - -/** - * avc_netlink_close - Close the netlink socket - */ -void avc_netlink_close(void); - -/** - * avc_netlink_acquire_fd - Acquire netlink socket fd. - * - * Allows the application to manage messages from the netlink socket in - * its own main loop. - */ -int avc_netlink_acquire_fd(void); - -/** - * avc_netlink_release_fd - Release netlink socket fd. - * - * Returns ownership of the netlink socket to the library. - */ -void avc_netlink_release_fd(void); - -/** - * avc_netlink_check_nb - Check netlink socket for new messages. - * - * Called by the application when using avc_netlink_acquire_fd() to - * process kernel netlink events. - */ -int avc_netlink_check_nb(void); - -/** - * selinux_status_open - Open and map SELinux kernel status page - * - */ -int selinux_status_open(int fallback); - -/** - * selinux_status_close - Unmap and close SELinux kernel status page - * - */ -void selinux_status_close(void); - -/** - * selinux_status_updated - Inform us whether the kernel status has been updated - * - */ -int selinux_status_updated(void); - -/** - * selinux_status_getenforce - Get the enforce flag value - * - */ -int selinux_status_getenforce(void); - -/** - * selinux_status_policyload - Get the number of policy reloaded - * - */ -int selinux_status_policyload(void); - -/** - * selinux_status_deny_unknown - Get the behavior for undefined classes/permissions - * - */ -int selinux_status_deny_unknown(void); - -#ifdef __cplusplus -} -#endif -#endif /* _SELINUX_AVC_H_ */ diff --git a/include/selinux/context.h b/include/selinux/context.h deleted file mode 100644 index 949fb1e..0000000 --- a/include/selinux/context.h +++ /dev/null @@ -1,50 +0,0 @@ -#ifndef _SELINUX_CONTEXT_H_ -#define _SELINUX_CONTEXT_H_ - -#ifdef __cplusplus -extern "C" { -#endif - -/* - * Functions to deal with security contexts in user space. - */ - - typedef struct { - void *ptr; - } context_s_t; - - typedef context_s_t *context_t; - -/* Return a new context initialized to a context string */ - - extern context_t context_new(const char *); - -/* - * Return a pointer to the string value of the context_t - * Valid until the next call to context_str or context_free - * for the same context_t* - */ - - extern char *context_str(context_t); - -/* Free the storage used by a context */ - extern void context_free(context_t); - -/* Get a pointer to the string value of a context component */ - - extern const char *context_type_get(context_t); - extern const char *context_range_get(context_t); - extern const char *context_role_get(context_t); - extern const char *context_user_get(context_t); - -/* Set a context component. Returns nonzero if unsuccessful */ - - extern int context_type_set(context_t, const char *); - extern int context_range_set(context_t, const char *); - extern int context_role_set(context_t, const char *); - extern int context_user_set(context_t, const char *); - -#ifdef __cplusplus -} -#endif -#endif diff --git a/include/selinux/label.h b/include/selinux/label.h deleted file mode 100644 index 07eff74..0000000 --- a/include/selinux/label.h +++ /dev/null @@ -1,167 +0,0 @@ -/* - * Labeling interface for userspace object managers and others. - * - * Author : Eamon Walsh <ewalsh@tycho.nsa.gov> - */ -#ifndef _SELABEL_H_ -#define _SELABEL_H_ - -#include <stdbool.h> -#include <sys/types.h> -#include <selinux/selinux.h> - -#ifdef __cplusplus -extern "C" { -#endif - -/* - * Opaque type used for all label handles. - */ - -struct selabel_handle; - -/* - * Available backends. - */ - -/* file contexts */ -#define SELABEL_CTX_FILE 0 -/* media contexts */ -#define SELABEL_CTX_MEDIA 1 -/* x contexts */ -#define SELABEL_CTX_X 2 -/* db objects */ -#define SELABEL_CTX_DB 3 -/* Android property contexts */ -#define SELABEL_CTX_ANDROID_PROP 4 -/* Android service contexts */ -#define SELABEL_CTX_ANDROID_SERVICE 5 - -/* - * Available options - */ - -/* no-op option, useful for unused slots in an array of options */ -#define SELABEL_OPT_UNUSED 0 -/* validate contexts before returning them (boolean value) */ -#define SELABEL_OPT_VALIDATE 1 -/* don't use local customizations to backend data (boolean value) */ -#define SELABEL_OPT_BASEONLY 2 -/* specify an alternate path to use when loading backend data */ -#define SELABEL_OPT_PATH 3 -/* select a subset of the search space as an optimization (file backend) */ -#define SELABEL_OPT_SUBSET 4 -/* total number of options */ -#define SELABEL_NOPT 5 - -/* - * Label operations - */ - -/** - * selabel_open - Create a labeling handle. - * @backend: one of the constants specifying a supported labeling backend. - * @opts: array of selabel_opt structures specifying label options or NULL. - * @nopts: number of elements in opts array or zero for no options. - * - * Open a labeling backend for use. The available backend identifiers are - * listed above. Options may be provided via the opts parameter; available - * options are listed above. Not all options may be supported by every - * backend. Return value is the created handle on success or NULL with - * @errno set on failure. - */ -struct selabel_handle *selabel_open(unsigned int backend, - const struct selinux_opt *opts, - unsigned nopts); - -/** - * selabel_close - Close a labeling handle. - * @handle: specifies handle to close - * - * Destroy the specified handle, closing files, freeing allocated memory, - * etc. The handle may not be further used after it has been closed. - */ -void selabel_close(struct selabel_handle *handle); - -/** - * selabel_lookup - Perform labeling lookup operation. - * @handle: specifies backend instance to query - * @con: returns the appropriate context with which to label the object - * @key: string input to lookup operation - * @type: numeric input to the lookup operation - * - * Perform a labeling lookup operation. Return %0 on success, -%1 with - * @errno set on failure. The key and type arguments are the inputs to the - * lookup operation; appropriate values are dictated by the backend in use. - * The result is returned in the memory pointed to by @con and must be freed - * by the user with freecon(). - */ -int selabel_lookup(struct selabel_handle *handle, char **con, - const char *key, int type); -int selabel_lookup_raw(struct selabel_handle *handle, char **con, - const char *key, int type); - -bool selabel_partial_match(struct selabel_handle *handle, const char *key); - -int selabel_lookup_best_match(struct selabel_handle *rec, char **con, - const char *key, const char **aliases, int type); - -enum selabel_cmp_result { - SELABEL_SUBSET, - SELABEL_EQUAL, - SELABEL_SUPERSET, - SELABEL_INCOMPARABLE -}; - -/** - * selabel_cmp - Compare two label configurations. - * @h1: handle for the first label configuration - * @h2: handle for the first label configuration - * - * Compare two label configurations. - * Return %SELABEL_SUBSET if @h1 is a subset of @h2, %SELABEL_EQUAL - * if @h1 is identical to @h2, %SELABEL_SUPERSET if @h1 is a superset - * of @h2, and %SELABEL_INCOMPARABLE if @h1 and @h2 are incomparable. - */ -enum selabel_cmp_result selabel_cmp(struct selabel_handle *h1, - struct selabel_handle *h2); - -/** - * selabel_stats - log labeling operation statistics. - * @handle: specifies backend instance to query - * - * Log a message with information about the number of queries performed, - * number of unused matching entries, or other operational statistics. - * Message is backend-specific, some backends may not output a message. - */ -void selabel_stats(struct selabel_handle *handle); - -/* - * Type codes used by specific backends - */ - -/* X backend */ -#define SELABEL_X_PROP 1 -#define SELABEL_X_EXT 2 -#define SELABEL_X_CLIENT 3 -#define SELABEL_X_EVENT 4 -#define SELABEL_X_SELN 5 -#define SELABEL_X_POLYPROP 6 -#define SELABEL_X_POLYSELN 7 - -/* DB backend */ -#define SELABEL_DB_DATABASE 1 -#define SELABEL_DB_SCHEMA 2 -#define SELABEL_DB_TABLE 3 -#define SELABEL_DB_COLUMN 4 -#define SELABEL_DB_SEQUENCE 5 -#define SELABEL_DB_VIEW 6 -#define SELABEL_DB_PROCEDURE 7 -#define SELABEL_DB_BLOB 8 -#define SELABEL_DB_TUPLE 9 -#define SELABEL_DB_LANGUAGE 10 - -#ifdef __cplusplus -} -#endif -#endif /* _SELABEL_H_ */ diff --git a/include/selinux/selinux.h b/include/selinux/selinux.h deleted file mode 100644 index 8827da8..0000000 --- a/include/selinux/selinux.h +++ /dev/null @@ -1,291 +0,0 @@ -#ifndef _SELINUX_H_ -#define _SELINUX_H_ - -#include <sys/types.h> -#include <stdarg.h> - -#ifdef __cplusplus -extern "C" { -#endif - -/* Return 1 if we are running on a SELinux kernel, or 0 if not or -1 if we get an error. */ -extern int is_selinux_enabled(void); -/* Return 1 if we are running on a SELinux MLS kernel, or 0 otherwise. */ -extern int is_selinux_mls_enabled(void); - -/* No longer used; here for compatibility with legacy callers. */ -typedef char *security_context_t; - -/* Free the memory allocated for a context by any of the below get* calls. */ -extern void freecon(char * con); - -/* Free the memory allocated for a context array by security_compute_user. */ -extern void freeconary(char ** con); - -/* Wrappers for the /proc/pid/attr API. */ - -/* Get current context, and set *con to refer to it. - Caller must free via freecon. */ -extern int getcon(char ** con); - -/* Set the current security context to con. - Note that use of this function requires that the entire application - be trusted to maintain any desired separation between the old and new - security contexts, unlike exec-based transitions performed via setexeccon. - When possible, decompose your application and use setexeccon()+execve() - instead. Note that the application may lose access to its open descriptors - as a result of a setcon() unless policy allows it to use descriptors opened - by the old context. */ -extern int setcon(const char * con); - -/* Get context of process identified by pid, and - set *con to refer to it. Caller must free via freecon. */ -extern int getpidcon(pid_t pid, char ** con); - -/* Get previous context (prior to last exec), and set *con to refer to it. - Caller must free via freecon. */ -extern int getprevcon(char ** con); - -/* Get exec context, and set *con to refer to it. - Sets *con to NULL if no exec context has been set, i.e. using default. - If non-NULL, caller must free via freecon. */ -extern int getexeccon(char ** con); - -/* Set exec security context for the next execve. - Call with NULL if you want to reset to the default. */ -extern int setexeccon(const char * con); - -/* Get fscreate context, and set *con to refer to it. - Sets *con to NULL if no fs create context has been set, i.e. using default. - If non-NULL, caller must free via freecon. */ -extern int getfscreatecon(char ** con); - -/* Set the fscreate security context for subsequent file creations. - Call with NULL if you want to reset to the default. */ -extern int setfscreatecon(const char * context); - -/* Get keycreate context, and set *con to refer to it. - Sets *con to NULL if no key create context has been set, i.e. using default. - If non-NULL, caller must free via freecon. */ -extern int getkeycreatecon(char ** con); - -/* Set the keycreate security context for subsequent key creations. - Call with NULL if you want to reset to the default. */ -extern int setkeycreatecon(const char * context); - -/* Get sockcreate context, and set *con to refer to it. - Sets *con to NULL if no socket create context has been set, i.e. using default. - If non-NULL, caller must free via freecon. */ -extern int getsockcreatecon(char ** con); - -/* Set the sockcreate security context for subsequent socket creations. - Call with NULL if you want to reset to the default. */ -extern int setsockcreatecon(const char * context); - -/* Wrappers for the xattr API. */ - -/* Get file context, and set *con to refer to it. - Caller must free via freecon. */ -extern int getfilecon(const char *path, char ** con); -extern int lgetfilecon(const char *path, char ** con); -extern int fgetfilecon(int fd, char ** con); - -/* Set file context */ -extern int setfilecon(const char *path, const char *con); -extern int lsetfilecon(const char *path, const char *con); -extern int fsetfilecon(int fd, const char *con); - -/* Wrappers for the socket API */ - -/* Get context of peer socket, and set *con to refer to it. - Caller must free via freecon. */ -extern int getpeercon(int fd, char ** con); - -/* Wrappers for the selinuxfs (policy) API. */ - -typedef unsigned int access_vector_t; -typedef unsigned short security_class_t; - -struct av_decision { - access_vector_t allowed; - access_vector_t decided; - access_vector_t auditallow; - access_vector_t auditdeny; - unsigned int seqno; - unsigned int flags; -}; - -/* Definitions of av_decision.flags */ -#define SELINUX_AVD_FLAGS_PERMISSIVE 0x0001 - -/* Structure for passing options, used by AVC and label subsystems */ -struct selinux_opt { - int type; - const char *value; -}; - -/* Callback facilities */ -union selinux_callback { - /* log the printf-style format and arguments, - with the type code indicating the type of message */ - int -#ifdef __GNUC__ -__attribute__ ((format(printf, 2, 3))) -#endif - (*func_log) (int type, const char *fmt, ...); - /* store a string representation of auditdata (corresponding - to the given security class) into msgbuf. */ - int (*func_audit) (void *auditdata, security_class_t cls, - char *msgbuf, size_t msgbufsize); - /* validate the supplied context, modifying if necessary */ - int (*func_validate) (char **ctx); - /* netlink callback for setenforce message */ - int (*func_setenforce) (int enforcing); - /* netlink callback for policyload message */ - int (*func_policyload) (int seqno); -}; - -#define SELINUX_CB_LOG 0 -#define SELINUX_CB_AUDIT 1 -#define SELINUX_CB_VALIDATE 2 -#define SELINUX_CB_SETENFORCE 3 -#define SELINUX_CB_POLICYLOAD 4 - -extern union selinux_callback selinux_get_callback(int type); -extern void selinux_set_callback(int type, union selinux_callback cb); - - /* Logging type codes, passed to the logging callback */ -#define SELINUX_ERROR 0 -#define SELINUX_WARNING 1 -#define SELINUX_INFO 2 -#define SELINUX_AVC 3 - -/* Compute an access decision. */ -extern int security_compute_av(const char * scon, - const char * tcon, - security_class_t tclass, - access_vector_t requested, - struct av_decision *avd); - -/* Compute a labeling decision and set *newcon to refer to it. - Caller must free via freecon. */ -extern int security_compute_create(const char * scon, - const char * tcon, - security_class_t tclass, - char ** newcon); - -/* Compute a relabeling decision and set *newcon to refer to it. - Caller must free via freecon. */ -extern int security_compute_relabel(const char * scon, - const char * tcon, - security_class_t tclass, - char ** newcon); - -/* Compute a polyinstantiation member decision and set *newcon to refer to it. - Caller must free via freecon. */ -extern int security_compute_member(const char * scon, - const char * tcon, - security_class_t tclass, - char ** newcon); - -/* Compute the set of reachable user contexts and set *con to refer to - the NULL-terminated array of contexts. Caller must free via freeconary. */ -extern int security_compute_user(const char * scon, - const char *username, - char *** con); - -/* Load a policy configuration. */ -extern int security_load_policy(void *data, size_t len); - -/* Get the context of an initial kernel security identifier by name. - Caller must free via freecon */ -extern int security_get_initial_context(const char *name, - char ** con); - -/* Translate boolean strict to name value pair. */ -typedef struct { - const char *name; - int value; -} SELboolean; -/* save a list of booleans in a single transaction. */ -extern int security_set_boolean_list(size_t boolcnt, - SELboolean * const boollist, int permanent); - -/* Check the validity of a security context. */ -extern int security_check_context(const char * con); - -/* Canonicalize a security context. */ -extern int security_canonicalize_context(const char * con, - char ** canoncon); - -/* Get the enforce flag value. */ -extern int security_getenforce(void); - -/* Set the enforce flag value. */ -extern int security_setenforce(int value); - -/* Get the behavior for undefined classes/permissions */ -extern int security_deny_unknown(void); - -/* Disable SELinux at runtime (must be done prior to initial policy load). */ -extern int security_disable(void); - -/* Get the policy version number. */ -extern int security_policyvers(void); - -/* Get the boolean names */ -extern int security_get_boolean_names(char ***names, int *len); - -/* Get the pending value for the boolean */ -extern int security_get_boolean_pending(const char *name); - -/* Get the active value for the boolean */ -extern int security_get_boolean_active(const char *name); - -/* Set the pending value for the boolean */ -extern int security_set_boolean(const char *name, int value); - -/* Commit the pending values for the booleans */ -extern int security_commit_booleans(void); - -/* Userspace class mapping support */ -struct security_class_mapping { - const char *name; - const char *perms[sizeof(access_vector_t) * 8 + 1]; -}; - -extern int selinux_set_mapping(struct security_class_mapping *map); - -/* Common helpers */ - -/* Convert between security class values and string names */ -extern security_class_t string_to_security_class(const char *name); -extern const char *security_class_to_string(security_class_t cls); - -/* Convert between individual access vector permissions and string names */ -extern const char *security_av_perm_to_string(security_class_t tclass, - access_vector_t perm); -extern access_vector_t string_to_av_perm(security_class_t tclass, - const char *name); - -/* Returns an access vector in a string representation. User must free the - * returned string via free(). */ -extern int security_av_string(security_class_t tclass, - access_vector_t av, char **result); - -/* Check permissions and perform appropriate auditing. */ -extern int selinux_check_access(const char * scon, - const char * tcon, - const char *tclass, - const char *perm, void *aux); - -/* Set the path to the selinuxfs mount point explicitly. - Normally, this is determined automatically during libselinux - initialization, but this is not always possible, e.g. for /sbin/init - which performs the initial mount of selinuxfs. */ -void set_selinuxmnt(const char *mnt); - -#ifdef __cplusplus -} -#endif -#endif diff --git a/src/android.c b/src/android.c deleted file mode 100644 index ff3a277..0000000 --- a/src/android.c +++ /dev/null @@ -1,1538 +0,0 @@ -#include <sys/types.h> -#include <unistd.h> -#include <string.h> -#include <stdio.h> -#include <stdlib.h> -#include <stdbool.h> -#include <ctype.h> -#include <errno.h> -#include <pwd.h> -#include <grp.h> -#include <sys/mman.h> -#include <sys/mount.h> -#include <sys/types.h> -#include <sys/stat.h> -#include <sys/xattr.h> -#include <fcntl.h> -#include <fts.h> -#include <selinux/selinux.h> -#include <selinux/context.h> -#include <selinux/android.h> -#include <selinux/label.h> -#include <selinux/avc.h> -#include <openssl/sha.h> -#include <private/android_filesystem_config.h> -#include <log/log.h> -#include "policy.h" -#include "callbacks.h" -#include "selinux_internal.h" -#include "label_internal.h" -#include <fnmatch.h> -#include <limits.h> -#include <sys/vfs.h> -#include <linux/magic.h> -#include <libgen.h> -#include <packagelistparser/packagelistparser.h> - -#define _REALLY_INCLUDE_SYS__SYSTEM_PROPERTIES_H_ -#include <sys/_system_properties.h> - -/* - * XXX Where should this configuration file be located? - * Needs to be accessible by zygote and installd when - * setting credentials for app processes and setting permissions - * on app data directories. - */ -static char const * const seapp_contexts_file = "/seapp_contexts"; - -static const struct selinux_opt seopts = - { SELABEL_OPT_PATH, "/file_contexts.bin" }; - -static const char *const sepolicy_file = "/sepolicy"; - -static const struct selinux_opt seopts_prop = - { SELABEL_OPT_PATH, "/property_contexts" }; - -static const struct selinux_opt seopts_service = - { SELABEL_OPT_PATH, "/service_contexts" }; - -enum levelFrom { - LEVELFROM_NONE, - LEVELFROM_APP, - LEVELFROM_USER, - LEVELFROM_ALL -}; - -#if DEBUG -static char const * const levelFromName[] = { - "none", - "app", - "user", - "all" -}; -#endif - -struct prefix_str { - size_t len; - char *str; - char is_prefix; -}; - -static void free_prefix_str(struct prefix_str *p) -{ - if (!p) - return; - free(p->str); -} - -struct seapp_context { - /* input selectors */ - bool isSystemServer; - bool isEphemeralAppSet; - bool isEphemeralApp; - bool isOwnerSet; - bool isOwner; - struct prefix_str user; - char *seinfo; - struct prefix_str name; - struct prefix_str path; - bool isPrivAppSet; - bool isPrivApp; - /* outputs */ - char *domain; - char *type; - char *level; - enum levelFrom levelFrom; -}; - -static void free_seapp_context(struct seapp_context *s) -{ - if (!s) - return; - - free_prefix_str(&s->user); - free(s->seinfo); - free_prefix_str(&s->name); - free_prefix_str(&s->path); - free(s->domain); - free(s->type); - free(s->level); -} - -static bool seapp_contexts_dup = false; - -static int seapp_context_cmp(const void *A, const void *B) -{ - const struct seapp_context *const *sp1 = (const struct seapp_context *const *) A; - const struct seapp_context *const *sp2 = (const struct seapp_context *const *) B; - const struct seapp_context *s1 = *sp1, *s2 = *sp2; - bool dup; - - /* Give precedence to isSystemServer=true. */ - if (s1->isSystemServer != s2->isSystemServer) - return (s1->isSystemServer ? -1 : 1); - - /* Give precedence to a specified isEphemeral= over an - * unspecified isEphemeral=. */ - if (s1->isEphemeralAppSet != s2->isEphemeralAppSet) - return (s1->isEphemeralAppSet ? -1 : 1); - - - /* Give precedence to a specified isOwner= over an unspecified isOwner=. */ - if (s1->isOwnerSet != s2->isOwnerSet) - return (s1->isOwnerSet ? -1 : 1); - - /* Give precedence to a specified user= over an unspecified user=. */ - if (s1->user.str && !s2->user.str) - return -1; - if (!s1->user.str && s2->user.str) - return 1; - - if (s1->user.str) { - /* Give precedence to a fixed user= string over a prefix. */ - if (s1->user.is_prefix != s2->user.is_prefix) - return (s2->user.is_prefix ? -1 : 1); - - /* Give precedence to a longer prefix over a shorter prefix. */ - if (s1->user.is_prefix && s1->user.len != s2->user.len) - return (s1->user.len > s2->user.len) ? -1 : 1; - } - - /* Give precedence to a specified seinfo= over an unspecified seinfo=. */ - if (s1->seinfo && !s2->seinfo) - return -1; - if (!s1->seinfo && s2->seinfo) - return 1; - - /* Give precedence to a specified name= over an unspecified name=. */ - if (s1->name.str && !s2->name.str) - return -1; - if (!s1->name.str && s2->name.str) - return 1; - - if (s1->name.str) { - /* Give precedence to a fixed name= string over a prefix. */ - if (s1->name.is_prefix != s2->name.is_prefix) - return (s2->name.is_prefix ? -1 : 1); - - /* Give precedence to a longer prefix over a shorter prefix. */ - if (s1->name.is_prefix && s1->name.len != s2->name.len) - return (s1->name.len > s2->name.len) ? -1 : 1; - } - - /* Give precedence to a specified path= over an unspecified path=. */ - if (s1->path.str && !s2->path.str) - return -1; - if (!s1->path.str && s2->path.str) - return 1; - - if (s1->path.str) { - /* Give precedence to a fixed path= string over a prefix. */ - if (s1->path.is_prefix != s2->path.is_prefix) - return (s2->path.is_prefix ? -1 : 1); - - /* Give precedence to a longer prefix over a shorter prefix. */ - if (s1->path.is_prefix && s1->path.len != s2->path.len) - return (s1->path.len > s2->path.len) ? -1 : 1; - } - - /* Give precedence to a specified isPrivApp= over an unspecified isPrivApp=. */ - if (s1->isPrivAppSet != s2->isPrivAppSet) - return (s1->isPrivAppSet ? -1 : 1); - - /* - * Check for a duplicated entry on the input selectors. - * We already compared isSystemServer, isOwnerSet, and isOwner above. - * We also have already checked that both entries specify the same - * string fields, so if s1 has a non-NULL string, then so does s2. - */ - dup = (!s1->user.str || !strcmp(s1->user.str, s2->user.str)) && - (!s1->seinfo || !strcmp(s1->seinfo, s2->seinfo)) && - (!s1->name.str || !strcmp(s1->name.str, s2->name.str)) && - (!s1->path.str || !strcmp(s1->path.str, s2->path.str)); - if (dup) { - seapp_contexts_dup = true; - selinux_log(SELINUX_ERROR, "seapp_contexts: Duplicated entry\n"); - if (s1->user.str) - selinux_log(SELINUX_ERROR, " user=%s\n", s1->user.str); - if (s1->seinfo) - selinux_log(SELINUX_ERROR, " seinfo=%s\n", s1->seinfo); - if (s1->name.str) - selinux_log(SELINUX_ERROR, " name=%s\n", s1->name.str); - if (s1->path.str) - selinux_log(SELINUX_ERROR, " path=%s\n", s1->path.str); - } - - /* Anything else has equal precedence. */ - return 0; -} - -static struct seapp_context **seapp_contexts = NULL; -static int nspec = 0; - -static void free_seapp_contexts(void) -{ - int n; - - if (!seapp_contexts) - return; - - for (n = 0; n < nspec; n++) - free_seapp_context(seapp_contexts[n]); - - free(seapp_contexts); - seapp_contexts = NULL; - nspec = 0; -} - -int selinux_android_seapp_context_reload(void) -{ - FILE *fp = NULL; - char line_buf[BUFSIZ]; - char *token; - unsigned lineno; - struct seapp_context *cur; - char *p, *name = NULL, *value = NULL, *saveptr; - size_t len; - int n, ret; - - fp = fopen(seapp_contexts_file, "re"); - if (!fp) { - selinux_log(SELINUX_ERROR, "%s: could not open any seapp_contexts file", __FUNCTION__); - return -1; - } - - free_seapp_contexts(); - - nspec = 0; - while (fgets(line_buf, sizeof line_buf - 1, fp)) { - p = line_buf; - while (isspace(*p)) - p++; - if (*p == '#' || *p == 0) - continue; - nspec++; - } - - seapp_contexts = (struct seapp_context **) calloc(nspec, sizeof(struct seapp_context *)); - if (!seapp_contexts) - goto oom; - - rewind(fp); - nspec = 0; - lineno = 1; - while (fgets(line_buf, sizeof line_buf - 1, fp)) { - len = strlen(line_buf); - if (line_buf[len - 1] == '\n') - line_buf[len - 1] = 0; - p = line_buf; - while (isspace(*p)) - p++; - if (*p == '#' || *p == 0) - continue; - - cur = (struct seapp_context *) calloc(1, sizeof(struct seapp_context)); - if (!cur) - goto oom; - - token = strtok_r(p, " \t", &saveptr); - if (!token) { - free_seapp_context(cur); - goto err; - } - - while (1) { - name = token; - value = strchr(name, '='); - if (!value) { - free_seapp_context(cur); - goto err; - } - *value++ = 0; - - if (!strcasecmp(name, "isSystemServer")) { - if (!strcasecmp(value, "true")) - cur->isSystemServer = true; - else if (!strcasecmp(value, "false")) - cur->isSystemServer = false; - else { - free_seapp_context(cur); - goto err; - } - } else if (!strcasecmp(name, "isEphemeralApp")) { - cur->isEphemeralAppSet = true; - if (!strcasecmp(value, "true")) - cur->isEphemeralApp = true; - else if (!strcasecmp(value, "false")) - cur->isEphemeralApp = false; - else { - free_seapp_context(cur); - goto err; - } - } else if (!strcasecmp(name, "isOwner")) { - cur->isOwnerSet = true; - if (!strcasecmp(value, "true")) - cur->isOwner = true; - else if (!strcasecmp(value, "false")) - cur->isOwner = false; - else { - free_seapp_context(cur); - goto err; - } - } else if (!strcasecmp(name, "user")) { - if (cur->user.str) { - free_seapp_context(cur); - goto err; - } - cur->user.str = strdup(value); - if (!cur->user.str) { - free_seapp_context(cur); - goto oom; - } - cur->user.len = strlen(cur->user.str); - if (cur->user.str[cur->user.len-1] == '*') - cur->user.is_prefix = 1; - } else if (!strcasecmp(name, "seinfo")) { - if (cur->seinfo) { - free_seapp_context(cur); - goto err; - } - cur->seinfo = strdup(value); - if (!cur->seinfo) { - free_seapp_context(cur); - goto oom; - } - if (strstr(value, ":")) { - free_seapp_context(cur); - goto err; - } - } else if (!strcasecmp(name, "name")) { - if (cur->name.str) { - free_seapp_context(cur); - goto err; - } - cur->name.str = strdup(value); - if (!cur->name.str) { - free_seapp_context(cur); - goto oom; - } - cur->name.len = strlen(cur->name.str); - if (cur->name.str[cur->name.len-1] == '*') - cur->name.is_prefix = 1; - } else if (!strcasecmp(name, "domain")) { - if (cur->domain) { - free_seapp_context(cur); - goto err; - } - cur->domain = strdup(value); - if (!cur->domain) { - free_seapp_context(cur); - goto oom; - } - } else if (!strcasecmp(name, "type")) { - if (cur->type) { - free_seapp_context(cur); - goto err; - } - cur->type = strdup(value); - if (!cur->type) { - free_seapp_context(cur); - goto oom; - } - } else if (!strcasecmp(name, "levelFromUid")) { - if (cur->levelFrom) { - free_seapp_context(cur); - goto err; - } - if (!strcasecmp(value, "true")) - cur->levelFrom = LEVELFROM_APP; - else if (!strcasecmp(value, "false")) - cur->levelFrom = LEVELFROM_NONE; - else { - free_seapp_context(cur); - goto err; - } - } else if (!strcasecmp(name, "levelFrom")) { - if (cur->levelFrom) { - free_seapp_context(cur); - goto err; - } - if (!strcasecmp(value, "none")) - cur->levelFrom = LEVELFROM_NONE; - else if (!strcasecmp(value, "app")) - cur->levelFrom = LEVELFROM_APP; - else if (!strcasecmp(value, "user")) - cur->levelFrom = LEVELFROM_USER; - else if (!strcasecmp(value, "all")) - cur->levelFrom = LEVELFROM_ALL; - else { - free_seapp_context(cur); - goto err; - } - } else if (!strcasecmp(name, "level")) { - if (cur->level) { - free_seapp_context(cur); - goto err; - } - cur->level = strdup(value); - if (!cur->level) { - free_seapp_context(cur); - goto oom; - } - } else if (!strcasecmp(name, "path")) { - if (cur->path.str) { - free_seapp_context(cur); - goto err; - } - cur->path.str = strdup(value); - if (!cur->path.str) { - free_seapp_context(cur); - goto oom; - } - cur->path.len = strlen(cur->path.str); - if (cur->path.str[cur->path.len-1] == '*') - cur->path.is_prefix = 1; - } else if (!strcasecmp(name, "isPrivApp")) { - cur->isPrivAppSet = true; - if (!strcasecmp(value, "true")) - cur->isPrivApp = true; - else if (!strcasecmp(value, "false")) - cur->isPrivApp = false; - else { - free_seapp_context(cur); - goto err; - } - } else { - free_seapp_context(cur); - goto err; - } - - token = strtok_r(NULL, " \t", &saveptr); - if (!token) - break; - } - - if (cur->name.str && - (!cur->seinfo || !strcmp(cur->seinfo, "default"))) { - selinux_log(SELINUX_ERROR, "%s: No specific seinfo value specified with name=\"%s\", on line %u: insecure configuration!\n", - seapp_contexts_file, cur->name.str, lineno); - free_seapp_context(cur); - goto err; - } - - seapp_contexts[nspec] = cur; - nspec++; - lineno++; - } - - qsort(seapp_contexts, nspec, sizeof(struct seapp_context *), - seapp_context_cmp); - - if (seapp_contexts_dup) - goto err; - -#if DEBUG - { - int i; - for (i = 0; i < nspec; i++) { - cur = seapp_contexts[i]; - selinux_log(SELINUX_INFO, "%s: isSystemServer=%s isEphemeralApp=%s isOwner=%s user=%s seinfo=%s " - "name=%s path=%s isPrivApp=%s -> domain=%s type=%s level=%s levelFrom=%s", - __FUNCTION__, - cur->isSystemServer ? "true" : "false", - cur->isEphemeralAppSet ? (cur->isEphemeralApp ? "true" : "false") : "null", - cur->isOwnerSet ? (cur->isOwner ? "true" : "false") : "null", - cur->user.str, - cur->seinfo, cur->name.str, cur->path.str, - cur->isPrivAppSet ? (cur->isPrivApp ? "true" : "false") : "null", - cur->domain, cur->type, cur->level, - levelFromName[cur->levelFrom]); - } - } -#endif - - ret = 0; - -out: - fclose(fp); - return ret; - -err: - selinux_log(SELINUX_ERROR, "%s: Invalid entry on line %u\n", - seapp_contexts_file, lineno); - free_seapp_contexts(); - ret = -1; - goto out; -oom: - selinux_log(SELINUX_ERROR, - "%s: Out of memory\n", __FUNCTION__); - free_seapp_contexts(); - ret = -1; - goto out; -} - - -static void seapp_context_init(void) -{ - selinux_android_seapp_context_reload(); -} - -static pthread_once_t once = PTHREAD_ONCE_INIT; - -/* - * Max id that can be mapped to category set uniquely - * using the current scheme. - */ -#define CAT_MAPPING_MAX_ID (0x1<<16) - -enum seapp_kind { - SEAPP_TYPE, - SEAPP_DOMAIN -}; - -#define PRIVILEGED_APP_STR ":privapp" -#define EPHEMERAL_APP_STR ":ephemeralapp" - -static int seinfo_parse(char *dest, const char *src, size_t size) -{ - size_t len; - char *p; - - if ((p = strchr(src, ':')) != NULL) - len = p - src; - else - len = strlen(src); - - if (len > size - 1) - return -1; - - strncpy(dest, src, len); - dest[len] = '\0'; - - return 0; -} - -static int seapp_context_lookup(enum seapp_kind kind, - uid_t uid, - bool isSystemServer, - const char *seinfo, - const char *pkgname, - const char *path, - context_t ctx) -{ - struct passwd *pwd; - bool isOwner; - const char *username = NULL; - struct seapp_context *cur = NULL; - int i; - size_t n; - uid_t userid; - uid_t appid; - bool isPrivApp = false; - bool isEphemeralApp = false; - char parsedseinfo[BUFSIZ]; - - __selinux_once(once, seapp_context_init); - - if (seinfo) { - if (seinfo_parse(parsedseinfo, seinfo, BUFSIZ)) - goto err; - isPrivApp = strstr(seinfo, PRIVILEGED_APP_STR) ? true : false; - isEphemeralApp = strstr(seinfo, EPHEMERAL_APP_STR) ? true : false; - seinfo = parsedseinfo; - } - - userid = uid / AID_USER; - isOwner = (userid == 0); - appid = uid % AID_USER; - if (appid < AID_APP) { - /* - * This code is Android specific, bionic guarantees that - * calls to non-reentrant getpwuid() are thread safe. - */ -#ifndef __BIONIC__ -#warning "This code assumes that getpwuid is thread safe, only true with Bionic!" -#endif - pwd = getpwuid(appid); - if (!pwd) - goto err; - - username = pwd->pw_name; - - } else if (appid < AID_ISOLATED_START) { - username = "_app"; - appid -= AID_APP; - } else { - username = "_isolated"; - appid -= AID_ISOLATED_START; - } - - if (appid >= CAT_MAPPING_MAX_ID || userid >= CAT_MAPPING_MAX_ID) - goto err; - - for (i = 0; i < nspec; i++) { - cur = seapp_contexts[i]; - - if (cur->isSystemServer != isSystemServer) - continue; - - if (cur->isEphemeralAppSet && cur->isEphemeralApp != isEphemeralApp) - continue; - - if (cur->isOwnerSet && cur->isOwner != isOwner) - continue; - - if (cur->user.str) { - if (cur->user.is_prefix) { - if (strncasecmp(username, cur->user.str, cur->user.len-1)) - continue; - } else { - if (strcasecmp(username, cur->user.str)) - continue; - } - } - - if (cur->seinfo) { - if (!seinfo || strcasecmp(seinfo, cur->seinfo)) - continue; - } - - if (cur->name.str) { - if(!pkgname) - continue; - - if (cur->name.is_prefix) { - if (strncasecmp(pkgname, cur->name.str, cur->name.len-1)) - continue; - } else { - if (strcasecmp(pkgname, cur->name.str)) - continue; - } - } - - if (cur->isPrivAppSet && cur->isPrivApp != isPrivApp) - continue; - - if (cur->path.str) { - if (!path) - continue; - - if (cur->path.is_prefix) { - if (strncmp(path, cur->path.str, cur->path.len-1)) - continue; - } else { - if (strcmp(path, cur->path.str)) - continue; - } - } - - if (kind == SEAPP_TYPE && !cur->type) - continue; - else if (kind == SEAPP_DOMAIN && !cur->domain) - continue; - - if (kind == SEAPP_TYPE) { - if (context_type_set(ctx, cur->type)) - goto oom; - } else if (kind == SEAPP_DOMAIN) { - if (context_type_set(ctx, cur->domain)) - goto oom; - } - - if (cur->levelFrom != LEVELFROM_NONE) { - char level[255]; - switch (cur->levelFrom) { - case LEVELFROM_APP: - snprintf(level, sizeof level, "s0:c%u,c%u", - appid & 0xff, - 256 + (appid>>8 & 0xff)); - break; - case LEVELFROM_USER: - snprintf(level, sizeof level, "s0:c%u,c%u", - 512 + (userid & 0xff), - 768 + (userid>>8 & 0xff)); - break; - case LEVELFROM_ALL: - snprintf(level, sizeof level, "s0:c%u,c%u,c%u,c%u", - appid & 0xff, - 256 + (appid>>8 & 0xff), - 512 + (userid & 0xff), - 768 + (userid>>8 & 0xff)); - break; - default: - goto err; - } - if (context_range_set(ctx, level)) - goto oom; - } else if (cur->level) { - if (context_range_set(ctx, cur->level)) - goto oom; - } - - break; - } - - if (kind == SEAPP_DOMAIN && i == nspec) { - /* - * No match. - * Fail to prevent staying in the zygote's context. - */ - selinux_log(SELINUX_ERROR, - "%s: No match for app with uid %d, seinfo %s, name %s\n", - __FUNCTION__, uid, seinfo, pkgname); - - if (security_getenforce() == 1) - goto err; - } - - return 0; -err: - return -1; -oom: - return -2; -} - -int selinux_android_setfilecon(const char *pkgdir, - const char *pkgname, - const char *seinfo, - uid_t uid) -{ - char *orig_ctx_str = NULL; - char *ctx_str = NULL; - context_t ctx = NULL; - int rc = -1; - - if (is_selinux_enabled() <= 0) - return 0; - - rc = getfilecon(pkgdir, &ctx_str); - if (rc < 0) - goto err; - - ctx = context_new(ctx_str); - orig_ctx_str = ctx_str; - if (!ctx) - goto oom; - - rc = seapp_context_lookup(SEAPP_TYPE, uid, 0, seinfo, pkgname, NULL, ctx); - if (rc == -1) - goto err; - else if (rc == -2) - goto oom; - - ctx_str = context_str(ctx); - if (!ctx_str) - goto oom; - - rc = security_check_context(ctx_str); - if (rc < 0) - goto err; - - if (strcmp(ctx_str, orig_ctx_str)) { - rc = setfilecon(pkgdir, ctx_str); - if (rc < 0) - goto err; - } - - rc = 0; -out: - freecon(orig_ctx_str); - context_free(ctx); - return rc; -err: - selinux_log(SELINUX_ERROR, "%s: Error setting context for pkgdir %s, uid %d: %s\n", - __FUNCTION__, pkgdir, uid, strerror(errno)); - rc = -1; - goto out; -oom: - selinux_log(SELINUX_ERROR, "%s: Out of memory\n", __FUNCTION__); - rc = -1; - goto out; -} - -int selinux_android_setcon(const char *con) -{ - int ret = setcon(con); - if (ret) - return ret; - /* - System properties must be reinitialized after setcon() otherwise the - previous property files will be leaked since mmap()'ed regions are not - closed as a result of setcon(). - */ - return __system_properties_init(); -} - -int selinux_android_setcontext(uid_t uid, - bool isSystemServer, - const char *seinfo, - const char *pkgname) -{ - char *orig_ctx_str = NULL, *ctx_str; - context_t ctx = NULL; - int rc = -1; - - if (is_selinux_enabled() <= 0) - return 0; - - rc = getcon(&ctx_str); - if (rc) - goto err; - - ctx = context_new(ctx_str); - orig_ctx_str = ctx_str; - if (!ctx) - goto oom; - - rc = seapp_context_lookup(SEAPP_DOMAIN, uid, isSystemServer, seinfo, pkgname, NULL, ctx); - if (rc == -1) - goto err; - else if (rc == -2) - goto oom; - - ctx_str = context_str(ctx); - if (!ctx_str) - goto oom; - - rc = security_check_context(ctx_str); - if (rc < 0) - goto err; - - if (strcmp(ctx_str, orig_ctx_str)) { - rc = selinux_android_setcon(ctx_str); - if (rc < 0) - goto err; - } - - rc = 0; -out: - freecon(orig_ctx_str); - context_free(ctx); - avc_netlink_close(); - return rc; -err: - if (isSystemServer) - selinux_log(SELINUX_ERROR, - "%s: Error setting context for system server: %s\n", - __FUNCTION__, strerror(errno)); - else - selinux_log(SELINUX_ERROR, - "%s: Error setting context for app with uid %d, seinfo %s: %s\n", - __FUNCTION__, uid, seinfo, strerror(errno)); - - rc = -1; - goto out; -oom: - selinux_log(SELINUX_ERROR, "%s: Out of memory\n", __FUNCTION__); - rc = -1; - goto out; -} - -static struct selabel_handle *fc_sehandle = NULL; -#define FC_DIGEST_SIZE SHA_DIGEST_LENGTH -static uint8_t fc_digest[FC_DIGEST_SIZE]; - -static bool compute_file_contexts_hash(uint8_t c_digest[]) -{ - int fd; - struct stat sb; - void *map; - - fd = open(seopts.value, O_CLOEXEC | O_RDONLY | O_NOFOLLOW); - if (fd < 0) { - selinux_log(SELINUX_ERROR, "SELinux: Could not open %s: %s\n", - seopts.value, strerror(errno)); - return false; - } - if (fstat(fd, &sb) < 0) { - selinux_log(SELINUX_ERROR, "SELinux: Could not stat %s: %s\n", - seopts.value, strerror(errno)); - close(fd); - return false; - } - map = mmap(NULL, sb.st_size, PROT_READ, MAP_PRIVATE, fd, 0); - if (map == MAP_FAILED) { - selinux_log(SELINUX_ERROR, "SELinux: Could not map %s: %s\n", - seopts.value, strerror(errno)); - close(fd); - return false; - } - SHA1(map, sb.st_size, c_digest); - munmap(map, sb.st_size); - close(fd); - - return true; -} - -static void file_context_init(void) -{ - if (!fc_sehandle) - fc_sehandle = selinux_android_file_context_handle(); -} - - - -static pthread_once_t fc_once = PTHREAD_ONCE_INIT; - -#define PKGTAB_SIZE 256 -static struct pkg_info *pkgTab[PKGTAB_SIZE]; - -static unsigned int pkghash(const char *pkgname) -{ - unsigned int h = 7; - for (; *pkgname; pkgname++) { - h = h * 31 + *pkgname; - } - return h & (PKGTAB_SIZE - 1); -} - -static bool pkg_parse_callback(pkg_info *info, void *userdata) { - - (void) userdata; - - unsigned int hash = pkghash(info->name); - if (pkgTab[hash]) - info->private_data = pkgTab[hash]; - pkgTab[hash] = info; - return true; -} - -static void package_info_init(void) -{ - - bool rc = packagelist_parse(pkg_parse_callback, NULL); - if (!rc) { - selinux_log(SELINUX_ERROR, "SELinux: Could NOT parse package list\n"); - return; - } - -#if DEBUG - { - unsigned int hash, buckets, entries, chainlen, longestchain; - struct pkg_info *info = NULL; - - buckets = entries = longestchain = 0; - for (hash = 0; hash < PKGTAB_SIZE; hash++) { - if (pkgTab[hash]) { - buckets++; - chainlen = 0; - for (info = pkgTab[hash]; info; info = (pkg_info *)info->private_data) { - chainlen++; - selinux_log(SELINUX_INFO, "%s: name=%s uid=%u debuggable=%s dataDir=%s seinfo=%s\n", - __FUNCTION__, - info->name, info->uid, info->debuggable ? "true" : "false", info->data_dir, info->seinfo); - } - entries += chainlen; - if (longestchain < chainlen) - longestchain = chainlen; - } - } - selinux_log(SELINUX_INFO, "SELinux: %d pkg entries and %d/%d buckets used, longest chain %d\n", entries, buckets, PKGTAB_SIZE, longestchain); - } -#endif - -} - -static pthread_once_t pkg_once = PTHREAD_ONCE_INIT; - -struct pkg_info *package_info_lookup(const char *name) -{ - struct pkg_info *info; - unsigned int hash; - - __selinux_once(pkg_once, package_info_init); - - hash = pkghash(name); - for (info = pkgTab[hash]; info; info = (pkg_info *)info->private_data) { - if (!strcmp(name, info->name)) - return info; - } - return NULL; -} - -/* The path prefixes of package data directories. */ -#define DATA_DATA_PATH "/data/data" -#define DATA_USER_PATH "/data/user" -#define DATA_USER_DE_PATH "/data/user_de" -#define EXPAND_USER_PATH "/mnt/expand/\?\?\?\?\?\?\?\?-\?\?\?\?-\?\?\?\?-\?\?\?\?-\?\?\?\?\?\?\?\?\?\?\?\?/user" -#define EXPAND_USER_DE_PATH "/mnt/expand/\?\?\?\?\?\?\?\?-\?\?\?\?-\?\?\?\?-\?\?\?\?-\?\?\?\?\?\?\?\?\?\?\?\?/user_de" -#define DATA_DATA_PREFIX DATA_DATA_PATH "/" -#define DATA_USER_PREFIX DATA_USER_PATH "/" -#define DATA_USER_DE_PREFIX DATA_USER_DE_PATH "/" - -static int pkgdir_selabel_lookup(const char *pathname, - const char *seinfo, - uid_t uid, - char **secontextp) -{ - char *pkgname = NULL, *end = NULL; - struct pkg_info *info = NULL; - char *secontext = *secontextp; - context_t ctx = NULL; - int rc = 0; - - /* Skip directory prefix before package name. */ - if (!strncmp(pathname, DATA_DATA_PREFIX, sizeof(DATA_DATA_PREFIX)-1)) { - pathname += sizeof(DATA_DATA_PREFIX) - 1; - } else if (!strncmp(pathname, DATA_USER_PREFIX, sizeof(DATA_USER_PREFIX)-1)) { - pathname += sizeof(DATA_USER_PREFIX) - 1; - while (isdigit(*pathname)) - pathname++; - if (*pathname == '/') - pathname++; - else - return 0; - } else if (!strncmp(pathname, DATA_USER_DE_PREFIX, sizeof(DATA_USER_DE_PREFIX)-1)) { - pathname += sizeof(DATA_USER_DE_PREFIX) - 1; - while (isdigit(*pathname)) - pathname++; - if (*pathname == '/') - pathname++; - else - return 0; - } else if (!fnmatch(EXPAND_USER_PATH, pathname, FNM_LEADING_DIR|FNM_PATHNAME)) { - pathname += sizeof(EXPAND_USER_PATH); - while (isdigit(*pathname)) - pathname++; - if (*pathname == '/') - pathname++; - else - return 0; - } else if (!fnmatch(EXPAND_USER_DE_PATH, pathname, FNM_LEADING_DIR|FNM_PATHNAME)) { - pathname += sizeof(EXPAND_USER_DE_PATH); - while (isdigit(*pathname)) - pathname++; - if (*pathname == '/') - pathname++; - else - return 0; - } else - return 0; - - if (!(*pathname)) - return 0; - - pkgname = strdup(pathname); - if (!pkgname) - return -1; - - for (end = pkgname; *end && *end != '/'; end++) - ; - pathname = end; - if (*end) - pathname++; - *end = '\0'; - - if (!seinfo) { - info = package_info_lookup(pkgname); - if (!info) { - selinux_log(SELINUX_WARNING, "SELinux: Could not look up information for package %s, cannot restorecon %s.\n", - pkgname, pathname); - free(pkgname); - return -1; - } - } - - ctx = context_new(secontext); - if (!ctx) - goto err; - - rc = seapp_context_lookup(SEAPP_TYPE, info ? info->uid : uid, 0, - info ? info->seinfo : seinfo, info ? info->name : pkgname, pathname, ctx); - if (rc < 0) - goto err; - - secontext = context_str(ctx); - if (!secontext) - goto err; - - if (!strcmp(secontext, *secontextp)) - goto out; - - rc = security_check_context(secontext); - if (rc < 0) - goto err; - - freecon(*secontextp); - *secontextp = strdup(secontext); - if (!(*secontextp)) - goto err; - - rc = 0; - -out: - free(pkgname); - context_free(ctx); - return rc; -err: - selinux_log(SELINUX_ERROR, "%s: Error looking up context for path %s, pkgname %s, seinfo %s, uid %u: %s\n", - __FUNCTION__, pathname, pkgname, info->seinfo, info->uid, strerror(errno)); - rc = -1; - goto out; -} - -#define RESTORECON_LAST "security.restorecon_last" - -static int restorecon_sb(const char *pathname, const struct stat *sb, - bool nochange, bool verbose, - const char *seinfo, uid_t uid) -{ - char *secontext = NULL; - char *oldsecontext = NULL; - int rc = 0; - - if (selabel_lookup(fc_sehandle, &secontext, pathname, sb->st_mode) < 0) - return 0; /* no match, but not an error */ - - if (lgetfilecon(pathname, &oldsecontext) < 0) - goto err; - - /* - * For subdirectories of /data/data or /data/user, we ignore selabel_lookup() - * and use pkgdir_selabel_lookup() instead. Files within those directories - * have different labeling rules, based off of /seapp_contexts, and - * installd is responsible for managing these labels instead of init. - */ - if (!strncmp(pathname, DATA_DATA_PREFIX, sizeof(DATA_DATA_PREFIX)-1) || - !strncmp(pathname, DATA_USER_PREFIX, sizeof(DATA_USER_PREFIX)-1) || - !strncmp(pathname, DATA_USER_DE_PREFIX, sizeof(DATA_USER_DE_PREFIX)-1) || - !fnmatch(EXPAND_USER_PATH, pathname, FNM_LEADING_DIR|FNM_PATHNAME) || - !fnmatch(EXPAND_USER_DE_PATH, pathname, FNM_LEADING_DIR|FNM_PATHNAME)) { - if (pkgdir_selabel_lookup(pathname, seinfo, uid, &secontext) < 0) - goto err; - } - - if (strcmp(oldsecontext, secontext) != 0) { - if (verbose) - selinux_log(SELINUX_INFO, - "SELinux: Relabeling %s from %s to %s.\n", pathname, oldsecontext, secontext); - if (!nochange) { - if (lsetfilecon(pathname, secontext) < 0) - goto err; - } - } - - rc = 0; - -out: - freecon(oldsecontext); - freecon(secontext); - return rc; - -err: - selinux_log(SELINUX_ERROR, - "SELinux: Could not set context for %s: %s\n", - pathname, strerror(errno)); - rc = -1; - goto out; -} - -#define SYS_PATH "/sys" -#define SYS_PREFIX SYS_PATH "/" - -static int selinux_android_restorecon_common(const char* pathname_orig, - const char *seinfo, - uid_t uid, - unsigned int flags) -{ - bool nochange = (flags & SELINUX_ANDROID_RESTORECON_NOCHANGE) ? true : false; - bool verbose = (flags & SELINUX_ANDROID_RESTORECON_VERBOSE) ? true : false; - bool recurse = (flags & SELINUX_ANDROID_RESTORECON_RECURSE) ? true : false; - bool force = (flags & SELINUX_ANDROID_RESTORECON_FORCE) ? true : false; - bool datadata = (flags & SELINUX_ANDROID_RESTORECON_DATADATA) ? true : false; - bool issys; - bool setrestoreconlast = true; - struct stat sb; - struct statfs sfsb; - FTS *fts; - FTSENT *ftsent; - char *pathname = NULL, *pathdnamer = NULL, *pathdname, *pathbname; - char * paths[2] = { NULL , NULL }; - int ftsflags = FTS_NOCHDIR | FTS_XDEV | FTS_PHYSICAL; - int error, sverrno; - char xattr_value[FC_DIGEST_SIZE]; - ssize_t size; - - if (is_selinux_enabled() <= 0) - return 0; - - __selinux_once(fc_once, file_context_init); - - if (!fc_sehandle) - return 0; - - /* - * Convert passed-in pathname to canonical pathname by resolving realpath of - * containing dir, then appending last component name. - */ - pathbname = basename(pathname_orig); - if (!strcmp(pathbname, "/") || !strcmp(pathbname, ".") || !strcmp(pathbname, "..")) { - pathname = realpath(pathname_orig, NULL); - if (!pathname) - goto realpatherr; - } else { - pathdname = dirname(pathname_orig); - pathdnamer = realpath(pathdname, NULL); - if (!pathdnamer) - goto realpatherr; - if (!strcmp(pathdnamer, "/")) - error = asprintf(&pathname, "/%s", pathbname); - else - error = asprintf(&pathname, "%s/%s", pathdnamer, pathbname); - if (error < 0) - goto oom; - } - - paths[0] = pathname; - issys = (!strcmp(pathname, SYS_PATH) - || !strncmp(pathname, SYS_PREFIX, sizeof(SYS_PREFIX)-1)) ? true : false; - - if (!recurse) { - if (lstat(pathname, &sb) < 0) { - error = -1; - goto cleanup; - } - - error = restorecon_sb(pathname, &sb, nochange, verbose, seinfo, uid); - goto cleanup; - } - - /* - * Ignore restorecon_last on /data/data or /data/user - * since their labeling is based on seapp_contexts and seinfo - * assignments rather than file_contexts and is managed by - * installd rather than init. - */ - if (!strncmp(pathname, DATA_DATA_PREFIX, sizeof(DATA_DATA_PREFIX)-1) || - !strncmp(pathname, DATA_USER_PREFIX, sizeof(DATA_USER_PREFIX)-1) || - !strncmp(pathname, DATA_USER_DE_PREFIX, sizeof(DATA_USER_DE_PREFIX)-1) || - !fnmatch(EXPAND_USER_PATH, pathname, FNM_LEADING_DIR|FNM_PATHNAME) || - !fnmatch(EXPAND_USER_DE_PATH, pathname, FNM_LEADING_DIR|FNM_PATHNAME)) - setrestoreconlast = false; - - /* Also ignore on /sys since it is regenerated on each boot regardless. */ - if (issys) - setrestoreconlast = false; - - /* Ignore files on in-memory filesystems */ - if (statfs(pathname, &sfsb) == 0) { - if (sfsb.f_type == RAMFS_MAGIC || sfsb.f_type == TMPFS_MAGIC) - setrestoreconlast = false; - } - - if (setrestoreconlast) { - size = getxattr(pathname, RESTORECON_LAST, xattr_value, sizeof fc_digest); - if (!force && size == sizeof fc_digest && memcmp(fc_digest, xattr_value, sizeof fc_digest) == 0) { - selinux_log(SELINUX_INFO, - "SELinux: Skipping restorecon_recursive(%s)\n", - pathname); - error = 0; - goto cleanup; - } - } - - fts = fts_open(paths, ftsflags, NULL); - if (!fts) { - error = -1; - goto cleanup; - } - - error = 0; - while ((ftsent = fts_read(fts)) != NULL) { - switch (ftsent->fts_info) { - case FTS_DC: - selinux_log(SELINUX_ERROR, - "SELinux: Directory cycle on %s.\n", ftsent->fts_path); - errno = ELOOP; - error = -1; - goto out; - case FTS_DP: - continue; - case FTS_DNR: - selinux_log(SELINUX_ERROR, - "SELinux: Could not read %s: %s.\n", ftsent->fts_path, strerror(errno)); - fts_set(fts, ftsent, FTS_SKIP); - continue; - case FTS_NS: - selinux_log(SELINUX_ERROR, - "SELinux: Could not stat %s: %s.\n", ftsent->fts_path, strerror(errno)); - fts_set(fts, ftsent, FTS_SKIP); - continue; - case FTS_ERR: - selinux_log(SELINUX_ERROR, - "SELinux: Error on %s: %s.\n", ftsent->fts_path, strerror(errno)); - fts_set(fts, ftsent, FTS_SKIP); - continue; - case FTS_D: - if (issys && !selabel_partial_match(fc_sehandle, ftsent->fts_path)) { - fts_set(fts, ftsent, FTS_SKIP); - continue; - } - - if (!datadata && - (!strcmp(ftsent->fts_path, DATA_DATA_PATH) || - !strncmp(ftsent->fts_path, DATA_USER_PREFIX, sizeof(DATA_USER_PREFIX)-1) || - !strncmp(ftsent->fts_path, DATA_USER_DE_PREFIX, sizeof(DATA_USER_DE_PREFIX)-1) || - !fnmatch(EXPAND_USER_PATH, ftsent->fts_path, FNM_LEADING_DIR|FNM_PATHNAME) || - !fnmatch(EXPAND_USER_DE_PATH, ftsent->fts_path, FNM_LEADING_DIR|FNM_PATHNAME))) { - // Don't label anything below this directory. - fts_set(fts, ftsent, FTS_SKIP); - // but fall through and make sure we label the directory itself - } - /* fall through */ - default: - error |= restorecon_sb(ftsent->fts_path, ftsent->fts_statp, nochange, verbose, seinfo, uid); - break; - } - } - - // Labeling successful. Mark the top level directory as completed. - if (setrestoreconlast && !nochange && !error) - setxattr(pathname, RESTORECON_LAST, fc_digest, sizeof fc_digest, 0); - -out: - sverrno = errno; - (void) fts_close(fts); - errno = sverrno; -cleanup: - free(pathdnamer); - free(pathname); - return error; -oom: - sverrno = errno; - selinux_log(SELINUX_ERROR, "%s: Out of memory\n", __FUNCTION__); - errno = sverrno; - error = -1; - goto cleanup; -realpatherr: - sverrno = errno; - selinux_log(SELINUX_ERROR, "SELinux: Could not get canonical path for %s restorecon: %s.\n", - pathname_orig, strerror(errno)); - errno = sverrno; - error = -1; - goto cleanup; -} - -int selinux_android_restorecon(const char *file, unsigned int flags) -{ - return selinux_android_restorecon_common(file, NULL, -1, flags); -} - -int selinux_android_restorecon_pkgdir(const char *pkgdir, - const char *seinfo, - uid_t uid, - unsigned int flags) -{ - return selinux_android_restorecon_common(pkgdir, seinfo, uid, flags | SELINUX_ANDROID_RESTORECON_DATADATA); -} - -struct selabel_handle* selinux_android_file_context_handle(void) -{ - char *path = NULL; - struct selabel_handle *sehandle; - struct selinux_opt fc_opts[] = { - { SELABEL_OPT_PATH, path }, - { SELABEL_OPT_BASEONLY, (char *)1 } - }; - - fc_opts[0].value = seopts.value; - - sehandle = selabel_open(SELABEL_CTX_FILE, fc_opts, 2); - - if (!sehandle) { - selinux_log(SELINUX_ERROR, "%s: Error getting file context handle (%s)\n", - __FUNCTION__, strerror(errno)); - return NULL; - } - if (!compute_file_contexts_hash(fc_digest)) { - selabel_close(sehandle); - return NULL; - } - selinux_log(SELINUX_INFO, "SELinux: Loaded file_contexts contexts from %s.\n", - fc_opts[0].value); - - return sehandle; -} - -struct selabel_handle* selinux_android_prop_context_handle(void) -{ - struct selabel_handle* sehandle; - - sehandle = selabel_open(SELABEL_CTX_ANDROID_PROP, - &seopts_prop, 1); - if (!sehandle) { - selinux_log(SELINUX_ERROR, "%s: Error getting property context handle (%s)\n", - __FUNCTION__, strerror(errno)); - return NULL; - } - selinux_log(SELINUX_INFO, "SELinux: Loaded property_contexts from %s.\n", - seopts_prop.value); - - return sehandle; -} - -struct selabel_handle* selinux_android_service_context_handle(void) -{ - struct selabel_handle* sehandle; - - sehandle = selabel_open(SELABEL_CTX_ANDROID_SERVICE, - &seopts_service, 1); - - if (!sehandle) { - selinux_log(SELINUX_ERROR, "%s: Error getting service context handle (%s)\n", - __FUNCTION__, strerror(errno)); - return NULL; - } - selinux_log(SELINUX_INFO, "SELinux: Loaded service_contexts from %s.\n", - seopts_service.value); - - return sehandle; -} - -void selinux_android_set_sehandle(const struct selabel_handle *hndl) -{ - fc_sehandle = (struct selabel_handle *) hndl; -} - -int selinux_android_load_policy(void) -{ - int fd = -1, rc; - struct stat sb; - void *map = NULL; - static int load_successful = 0; - - /* - * Since updating policy at runtime has been abolished - * we just check whether a policy has been loaded before - * and return if this is the case. - * There is no point in reloading policy. - */ - if (load_successful){ - selinux_log(SELINUX_WARNING, "SELinux: Attempted reload of SELinux policy!/n"); - return 0; - } - - set_selinuxmnt(SELINUXMNT); - fd = open(sepolicy_file, O_RDONLY | O_NOFOLLOW | O_CLOEXEC); - if (fd < 0) { - selinux_log(SELINUX_ERROR, "SELinux: Could not open sepolicy: %s\n", - strerror(errno)); - return -1; - } - if (fstat(fd, &sb) < 0) { - selinux_log(SELINUX_ERROR, "SELinux: Could not stat %s: %s\n", - sepolicy_file, strerror(errno)); - close(fd); - return -1; - } - map = mmap(NULL, sb.st_size, PROT_READ, MAP_PRIVATE, fd, 0); - if (map == MAP_FAILED) { - selinux_log(SELINUX_ERROR, "SELinux: Could not map %s: %s\n", - sepolicy_file, strerror(errno)); - close(fd); - return -1; - } - - rc = security_load_policy(map, sb.st_size); - if (rc < 0) { - selinux_log(SELINUX_ERROR, "SELinux: Could not load policy: %s\n", - strerror(errno)); - munmap(map, sb.st_size); - close(fd); - return -1; - } - - munmap(map, sb.st_size); - close(fd); - selinux_log(SELINUX_INFO, "SELinux: Loaded policy from %s\n", sepolicy_file); - load_successful = 1; - return 0; -} - -int selinux_log_callback(int type, const char *fmt, ...) -{ - va_list ap; - int priority; - char *strp; - - switch(type) { - case SELINUX_WARNING: - priority = ANDROID_LOG_WARN; - break; - case SELINUX_INFO: - priority = ANDROID_LOG_INFO; - break; - default: - priority = ANDROID_LOG_ERROR; - break; - } - - va_start(ap, fmt); - if (vasprintf(&strp, fmt, ap) != -1) { - LOG_PRI(priority, "SELinux", "%s", strp); - LOG_EVENT_STRING(AUDITD_LOG_TAG, strp); - free(strp); - } - va_end(ap); - return 0; -} diff --git a/src/avc.c b/src/avc.c deleted file mode 100644 index 528d897..0000000 --- a/src/avc.c +++ /dev/null @@ -1,1121 +0,0 @@ -/* - * Implementation of the userspace access vector cache (AVC). - * - * Author : Eamon Walsh <ewalsh@epoch.ncsc.mil> - * - * Derived from the kernel AVC implementation by - * Stephen Smalley <sds@epoch.ncsc.mil> and - * James Morris <jmorris@redhat.com>. - */ -#include <selinux/avc.h> -#include "selinux_internal.h" -#include <assert.h> -#include "avc_sidtab.h" -#include "avc_internal.h" - -#define AVC_CACHE_SLOTS 512 -#define AVC_CACHE_MAXNODES 410 - -struct avc_entry { - security_id_t ssid; - security_id_t tsid; - security_class_t tclass; - struct av_decision avd; - security_id_t create_sid; - int used; /* used recently */ -}; - -struct avc_node { - struct avc_entry ae; - struct avc_node *next; -}; - -struct avc_cache { - struct avc_node *slots[AVC_CACHE_SLOTS]; - uint32_t lru_hint; /* LRU hint for reclaim scan */ - uint32_t active_nodes; - uint32_t latest_notif; /* latest revocation notification */ -}; - -struct avc_callback_node { - int (*callback) (uint32_t event, security_id_t ssid, - security_id_t tsid, - security_class_t tclass, access_vector_t perms, - access_vector_t * out_retained); - uint32_t events; - security_id_t ssid; - security_id_t tsid; - security_class_t tclass; - access_vector_t perms; - struct avc_callback_node *next; -}; - -static void *avc_netlink_thread = NULL; -static void *avc_lock = NULL; -static void *avc_log_lock = NULL; -static struct avc_node *avc_node_freelist = NULL; -static struct avc_cache avc_cache; -static char *avc_audit_buf = NULL; -static struct avc_cache_stats cache_stats; -static struct avc_callback_node *avc_callbacks = NULL; -static struct sidtab avc_sidtab; - -static inline int avc_hash(security_id_t ssid, - security_id_t tsid, security_class_t tclass) -{ - return ((uintptr_t) ssid ^ ((uintptr_t) tsid << 2) ^ tclass) - & (AVC_CACHE_SLOTS - 1); -} - -int avc_context_to_sid(const char * ctx, security_id_t * sid) -{ - int rc; - /* avc_init needs to be called before this function */ - assert(avc_running); - - avc_get_lock(avc_lock); - rc = sidtab_context_to_sid(&avc_sidtab, ctx, sid); - avc_release_lock(avc_lock); - return rc; -} - -int avc_sid_to_context(security_id_t sid, char ** ctx) -{ - int rc; - *ctx = NULL; - avc_get_lock(avc_lock); - *ctx = strdup(sid->ctx); /* caller must free via freecon */ - rc = *ctx ? 0 : -1; - avc_release_lock(avc_lock); - return rc; -} - -int avc_get_initial_sid(const char * name, security_id_t * sid) -{ - int rc; - char * con; - - rc = security_get_initial_context(name, &con); - if (rc < 0) - return rc; - rc = avc_context_to_sid(con, sid); - - freecon(con); - - return rc; -} - -int avc_open(struct selinux_opt *opts, unsigned nopts) -{ - avc_setenforce = 0; - - while (nopts--) - switch(opts[nopts].type) { - case AVC_OPT_SETENFORCE: - avc_setenforce = 1; - avc_enforcing = !!opts[nopts].value; - break; - } - - return avc_init("avc", NULL, NULL, NULL, NULL); -} - -int avc_init(const char *prefix, - const struct avc_memory_callback *mem_cb, - const struct avc_log_callback *log_cb, - const struct avc_thread_callback *thread_cb, - const struct avc_lock_callback *lock_cb) -{ - struct avc_node *new; - int i, rc = 0; - - if (avc_running) - return 0; - - if (prefix) - strncpy(avc_prefix, prefix, AVC_PREFIX_SIZE - 1); - - set_callbacks(mem_cb, log_cb, thread_cb, lock_cb); - - avc_lock = avc_alloc_lock(); - avc_log_lock = avc_alloc_lock(); - - memset(&cache_stats, 0, sizeof(cache_stats)); - - for (i = 0; i < AVC_CACHE_SLOTS; i++) - avc_cache.slots[i] = 0; - avc_cache.lru_hint = 0; - avc_cache.active_nodes = 0; - avc_cache.latest_notif = 0; - - rc = sidtab_init(&avc_sidtab); - if (rc) { - avc_log(SELINUX_ERROR, - "%s: unable to initialize SID table\n", - avc_prefix); - goto out; - } - - avc_audit_buf = (char *)avc_malloc(AVC_AUDIT_BUFSIZE); - if (!avc_audit_buf) { - avc_log(SELINUX_ERROR, - "%s: unable to allocate audit buffer\n", - avc_prefix); - rc = -1; - goto out; - } - - for (i = 0; i < AVC_CACHE_MAXNODES; i++) { - new = avc_malloc(sizeof(*new)); - if (!new) { - avc_log(SELINUX_WARNING, - "%s: warning: only got %d av entries\n", - avc_prefix, i); - break; - } - memset(new, 0, sizeof(*new)); - new->next = avc_node_freelist; - avc_node_freelist = new; - } - - if (!avc_setenforce) { - rc = security_getenforce(); - if (rc < 0) { - avc_log(SELINUX_ERROR, - "%s: could not determine enforcing mode: %s\n", - avc_prefix, - strerror(errno)); - goto out; - } - avc_enforcing = rc; - } - - rc = avc_netlink_open(0); - if (rc < 0) { - avc_log(SELINUX_ERROR, - "%s: can't open netlink socket: %d (%s)\n", - avc_prefix, errno, strerror(errno)); - goto out; - } - if (avc_using_threads) { - avc_netlink_thread = avc_create_thread(&avc_netlink_loop); - avc_netlink_trouble = 0; - } - avc_running = 1; - out: - return rc; -} - -void avc_cache_stats(struct avc_cache_stats *p) -{ - memcpy(p, &cache_stats, sizeof(cache_stats)); -} - -void avc_sid_stats(void) -{ - /* avc_init needs to be called before this function */ - assert(avc_running); - avc_get_lock(avc_log_lock); - avc_get_lock(avc_lock); - sidtab_sid_stats(&avc_sidtab, avc_audit_buf, AVC_AUDIT_BUFSIZE); - avc_release_lock(avc_lock); - avc_log(SELINUX_INFO, "%s", avc_audit_buf); - avc_release_lock(avc_log_lock); -} - -void avc_av_stats(void) -{ - int i, chain_len, max_chain_len, slots_used; - struct avc_node *node; - - avc_get_lock(avc_lock); - - slots_used = 0; - max_chain_len = 0; - for (i = 0; i < AVC_CACHE_SLOTS; i++) { - node = avc_cache.slots[i]; - if (node) { - slots_used++; - chain_len = 0; - while (node) { - chain_len++; - node = node->next; - } - if (chain_len > max_chain_len) - max_chain_len = chain_len; - } - } - - avc_release_lock(avc_lock); - - avc_log(SELINUX_INFO, "%s: %d AV entries and %d/%d buckets used, " - "longest chain length %d\n", avc_prefix, - avc_cache.active_nodes, - slots_used, AVC_CACHE_SLOTS, max_chain_len); -} - -hidden_def(avc_av_stats) - -static inline struct avc_node *avc_reclaim_node(void) -{ - struct avc_node *prev, *cur; - int try; - uint32_t hvalue; - - hvalue = avc_cache.lru_hint; - for (try = 0; try < 2; try++) { - do { - prev = NULL; - cur = avc_cache.slots[hvalue]; - while (cur) { - if (!cur->ae.used) - goto found; - - cur->ae.used = 0; - - prev = cur; - cur = cur->next; - } - hvalue = (hvalue + 1) & (AVC_CACHE_SLOTS - 1); - } while (hvalue != avc_cache.lru_hint); - } - - errno = ENOMEM; /* this was a panic in the kernel... */ - return NULL; - - found: - avc_cache.lru_hint = hvalue; - - if (prev == NULL) - avc_cache.slots[hvalue] = cur->next; - else - prev->next = cur->next; - - return cur; -} - -static inline void avc_clear_avc_entry(struct avc_entry *ae) -{ - memset(ae, 0, sizeof(*ae)); -} - -static inline struct avc_node *avc_claim_node(security_id_t ssid, - security_id_t tsid, - security_class_t tclass) -{ - struct avc_node *new; - int hvalue; - - if (!avc_node_freelist) - avc_cleanup(); - - if (avc_node_freelist) { - new = avc_node_freelist; - avc_node_freelist = avc_node_freelist->next; - avc_cache.active_nodes++; - } else { - new = avc_reclaim_node(); - if (!new) - goto out; - } - - hvalue = avc_hash(ssid, tsid, tclass); - avc_clear_avc_entry(&new->ae); - new->ae.used = 1; - new->ae.ssid = ssid; - new->ae.tsid = tsid; - new->ae.tclass = tclass; - new->next = avc_cache.slots[hvalue]; - avc_cache.slots[hvalue] = new; - - out: - return new; -} - -static inline struct avc_node *avc_search_node(security_id_t ssid, - security_id_t tsid, - security_class_t tclass, - int *probes) -{ - struct avc_node *cur; - int hvalue; - int tprobes = 1; - - hvalue = avc_hash(ssid, tsid, tclass); - cur = avc_cache.slots[hvalue]; - while (cur != NULL && - (ssid != cur->ae.ssid || - tclass != cur->ae.tclass || tsid != cur->ae.tsid)) { - tprobes++; - cur = cur->next; - } - - if (cur == NULL) { - /* cache miss */ - goto out; - } - - /* cache hit */ - if (probes) - *probes = tprobes; - - cur->ae.used = 1; - - out: - return cur; -} - -/** - * avc_lookup - Look up an AVC entry. - * @ssid: source security identifier - * @tsid: target security identifier - * @tclass: target security class - * @requested: requested permissions, interpreted based on @tclass - * @aeref: AVC entry reference - * - * Look up an AVC entry that is valid for the - * @requested permissions between the SID pair - * (@ssid, @tsid), interpreting the permissions - * based on @tclass. If a valid AVC entry exists, - * then this function updates @aeref to refer to the - * entry and returns %0. Otherwise, -1 is returned. - */ -static int avc_lookup(security_id_t ssid, security_id_t tsid, - security_class_t tclass, - access_vector_t requested, struct avc_entry_ref *aeref) -{ - struct avc_node *node; - int probes, rc = 0; - - avc_cache_stats_incr(cav_lookups); - node = avc_search_node(ssid, tsid, tclass, &probes); - - if (node && ((node->ae.avd.decided & requested) == requested)) { - avc_cache_stats_incr(cav_hits); - avc_cache_stats_add(cav_probes, probes); - aeref->ae = &node->ae; - goto out; - } - - avc_cache_stats_incr(cav_misses); - rc = -1; - out: - return rc; -} - -/** - * avc_insert - Insert an AVC entry. - * @ssid: source security identifier - * @tsid: target security identifier - * @tclass: target security class - * @ae: AVC entry - * @aeref: AVC entry reference - * - * Insert an AVC entry for the SID pair - * (@ssid, @tsid) and class @tclass. - * The access vectors and the sequence number are - * normally provided by the security server in - * response to a security_compute_av() call. If the - * sequence number @ae->avd.seqno is not less than the latest - * revocation notification, then the function copies - * the access vectors into a cache entry, updates - * @aeref to refer to the entry, and returns %0. - * Otherwise, this function returns -%1 with @errno set to %EAGAIN. - */ -static int avc_insert(security_id_t ssid, security_id_t tsid, - security_class_t tclass, - struct avc_entry *ae, struct avc_entry_ref *aeref) -{ - struct avc_node *node; - int rc = 0; - - if (ae->avd.seqno < avc_cache.latest_notif) { - avc_log(SELINUX_WARNING, - "%s: seqno %d < latest_notif %d\n", avc_prefix, - ae->avd.seqno, avc_cache.latest_notif); - errno = EAGAIN; - rc = -1; - goto out; - } - - node = avc_claim_node(ssid, tsid, tclass); - if (!node) { - rc = -1; - goto out; - } - - memcpy(&node->ae.avd, &ae->avd, sizeof(ae->avd)); - aeref->ae = &node->ae; - out: - return rc; -} - -void avc_cleanup(void) -{ -} - -hidden_def(avc_cleanup) - -int avc_reset(void) -{ - struct avc_callback_node *c; - int i, ret, rc = 0, errsave = 0; - struct avc_node *node, *tmp; - errno = 0; - - if (!avc_running) - return 0; - - avc_get_lock(avc_lock); - - for (i = 0; i < AVC_CACHE_SLOTS; i++) { - node = avc_cache.slots[i]; - while (node) { - tmp = node; - node = node->next; - avc_clear_avc_entry(&tmp->ae); - tmp->next = avc_node_freelist; - avc_node_freelist = tmp; - avc_cache.active_nodes--; - } - avc_cache.slots[i] = 0; - } - avc_cache.lru_hint = 0; - - avc_release_lock(avc_lock); - - memset(&cache_stats, 0, sizeof(cache_stats)); - - for (c = avc_callbacks; c; c = c->next) { - if (c->events & AVC_CALLBACK_RESET) { - ret = c->callback(AVC_CALLBACK_RESET, 0, 0, 0, 0, 0); - if (ret && !rc) { - rc = ret; - errsave = errno; - } - } - } - errno = errsave; - return rc; -} - -hidden_def(avc_reset) - -void avc_destroy(void) -{ - struct avc_callback_node *c; - struct avc_node *node, *tmp; - int i; - /* avc_init needs to be called before this function */ - assert(avc_running); - - avc_get_lock(avc_lock); - - if (avc_using_threads) - avc_stop_thread(avc_netlink_thread); - avc_netlink_close(); - - for (i = 0; i < AVC_CACHE_SLOTS; i++) { - node = avc_cache.slots[i]; - while (node) { - tmp = node; - node = node->next; - avc_free(tmp); - } - } - while (avc_node_freelist) { - tmp = avc_node_freelist; - avc_node_freelist = tmp->next; - avc_free(tmp); - } - avc_release_lock(avc_lock); - - while (avc_callbacks) { - c = avc_callbacks; - avc_callbacks = c->next; - avc_free(c); - } - sidtab_destroy(&avc_sidtab); - avc_free_lock(avc_lock); - avc_free_lock(avc_log_lock); - avc_free(avc_audit_buf); - avc_running = 0; -} - -/* ratelimit stuff put aside for now --EFW */ -#if 0 -/* - * Copied from net/core/utils.c:net_ratelimit and modified for - * use by the AVC audit facility. - */ -#define AVC_MSG_COST 5*HZ -#define AVC_MSG_BURST 10*5*HZ - -/* - * This enforces a rate limit: not more than one kernel message - * every 5secs to make a denial-of-service attack impossible. - */ -static int avc_ratelimit(void) -{ - static unsigned long toks = 10 * 5 * HZ; - static unsigned long last_msg; - static int missed, rc = 0; - unsigned long now = jiffies; - void *ratelimit_lock = avc_alloc_lock(); - - avc_get_lock(ratelimit_lock); - toks += now - last_msg; - last_msg = now; - if (toks > AVC_MSG_BURST) - toks = AVC_MSG_BURST; - if (toks >= AVC_MSG_COST) { - int lost = missed; - missed = 0; - toks -= AVC_MSG_COST; - avc_release_lock(ratelimit_lock); - if (lost) { - avc_log(SELINUX_WARNING, - "%s: %d messages suppressed.\n", avc_prefix, - lost); - } - rc = 1; - goto out; - } - missed++; - avc_release_lock(ratelimit_lock); - out: - avc_free_lock(ratelimit_lock); - return rc; -} - -static inline int check_avc_ratelimit(void) -{ - if (avc_enforcing) - return avc_ratelimit(); - else { - /* If permissive, then never suppress messages. */ - return 1; - } -} -#endif /* ratelimit stuff */ - -/** - * avc_dump_av - Display an access vector in human-readable form. - * @tclass: target security class - * @av: access vector - */ -static void avc_dump_av(security_class_t tclass, access_vector_t av) -{ - const char *permstr; - access_vector_t bit = 1; - - if (av == 0) { - log_append(avc_audit_buf, " null"); - return; - } - - log_append(avc_audit_buf, " {"); - - while (av) { - if (av & bit) { - permstr = security_av_perm_to_string(tclass, bit); - if (!permstr) - break; - log_append(avc_audit_buf, " %s", permstr); - av &= ~bit; - } - bit <<= 1; - } - - if (av) - log_append(avc_audit_buf, " 0x%x", av); - log_append(avc_audit_buf, " }"); -} - -/** - * avc_dump_query - Display a SID pair and a class in human-readable form. - * @ssid: source security identifier - * @tsid: target security identifier - * @tclass: target security class - */ -static void avc_dump_query(security_id_t ssid, security_id_t tsid, - security_class_t tclass) -{ - avc_get_lock(avc_lock); - - log_append(avc_audit_buf, "scontext=%s tcontext=%s", - ssid->ctx, tsid->ctx); - - avc_release_lock(avc_lock); - log_append(avc_audit_buf, " tclass=%s", - security_class_to_string(tclass)); -} - -void avc_audit(security_id_t ssid, security_id_t tsid, - security_class_t tclass, access_vector_t requested, - struct av_decision *avd, int result, void *a) -{ - access_vector_t denied, audited; - - denied = requested & ~avd->allowed; - if (denied) - audited = denied & avd->auditdeny; - else if (!requested || result) - audited = denied = requested; - else - audited = requested & avd->auditallow; - if (!audited) - return; -#if 0 - if (!check_avc_ratelimit()) - return; -#endif - /* prevent overlapping buffer writes */ - avc_get_lock(avc_log_lock); - snprintf(avc_audit_buf, AVC_AUDIT_BUFSIZE, - "%s: %s ", avc_prefix, (denied || !requested) ? "denied" : "granted"); - avc_dump_av(tclass, audited); - log_append(avc_audit_buf, " for "); - - /* get any extra information printed by the callback */ - avc_suppl_audit(a, tclass, avc_audit_buf + strlen(avc_audit_buf), - AVC_AUDIT_BUFSIZE - strlen(avc_audit_buf)); - - log_append(avc_audit_buf, " "); - avc_dump_query(ssid, tsid, tclass); - - /* append permissive=0|1 like the kernel at the end */ - if (denied || !requested) - log_append(avc_audit_buf, " permissive=%d", !result); - - log_append(avc_audit_buf, "\n"); - avc_log(SELINUX_AVC, "%s", avc_audit_buf); - - avc_release_lock(avc_log_lock); -} - -hidden_def(avc_audit) - - -static void avd_init(struct av_decision *avd) -{ - avd->allowed = 0; - avd->auditallow = 0; - avd->auditdeny = 0xffffffff; - avd->seqno = avc_cache.latest_notif; - avd->flags = 0; -} - -int avc_has_perm_noaudit(security_id_t ssid, - security_id_t tsid, - security_class_t tclass, - access_vector_t requested, - struct avc_entry_ref *aeref, struct av_decision *avd) -{ - struct avc_entry *ae; - int rc = 0; - struct avc_entry entry; - access_vector_t denied; - struct avc_entry_ref ref; - - if (avd) - avd_init(avd); - - if (!avc_using_threads && !avc_app_main_loop) { - (void)avc_netlink_check_nb(); - } - - if (!aeref) { - avc_entry_ref_init(&ref); - aeref = &ref; - } - - avc_get_lock(avc_lock); - avc_cache_stats_incr(entry_lookups); - ae = aeref->ae; - if (ae) { - if (ae->ssid == ssid && - ae->tsid == tsid && - ae->tclass == tclass && - ((ae->avd.decided & requested) == requested)) { - avc_cache_stats_incr(entry_hits); - ae->used = 1; - } else { - avc_cache_stats_incr(entry_discards); - ae = 0; - } - } - - if (!ae) { - avc_cache_stats_incr(entry_misses); - rc = avc_lookup(ssid, tsid, tclass, requested, aeref); - if (rc) { - rc = security_compute_av(ssid->ctx, tsid->ctx, - tclass, requested, - &entry.avd); - if (rc && errno == EINVAL && !avc_enforcing) { - rc = errno = 0; - goto out; - } - if (rc) - goto out; - rc = avc_insert(ssid, tsid, tclass, &entry, aeref); - if (rc) - goto out; - } - ae = aeref->ae; - } - - if (avd) - memcpy(avd, &ae->avd, sizeof(*avd)); - - denied = requested & ~(ae->avd.allowed); - - if (!requested || denied) { - if (!avc_enforcing || - (ae->avd.flags & SELINUX_AVD_FLAGS_PERMISSIVE)) - ae->avd.allowed |= requested; - else { - errno = EACCES; - rc = -1; - } - } - - out: - avc_release_lock(avc_lock); - return rc; -} - -hidden_def(avc_has_perm_noaudit) - -int avc_has_perm(security_id_t ssid, security_id_t tsid, - security_class_t tclass, access_vector_t requested, - struct avc_entry_ref *aeref, void *auditdata) -{ - struct av_decision avd; - int errsave, rc; - - rc = avc_has_perm_noaudit(ssid, tsid, tclass, requested, aeref, &avd); - errsave = errno; - avc_audit(ssid, tsid, tclass, requested, &avd, rc, auditdata); - errno = errsave; - return rc; -} - -int avc_compute_create(security_id_t ssid, security_id_t tsid, - security_class_t tclass, security_id_t *newsid) -{ - int rc; - struct avc_entry_ref aeref; - struct avc_entry entry; - char * ctx; - - *newsid = NULL; - avc_entry_ref_init(&aeref); - - avc_get_lock(avc_lock); - - /* check for a cached entry */ - rc = avc_lookup(ssid, tsid, tclass, 0, &aeref); - if (rc) { - /* need to make a cache entry for this tuple */ - rc = security_compute_av(ssid->ctx, tsid->ctx, - tclass, 0, &entry.avd); - if (rc) - goto out; - rc = avc_insert(ssid, tsid, tclass, &entry, &aeref); - if (rc) - goto out; - } - - /* check for a saved compute_create value */ - if (!aeref.ae->create_sid) { - /* need to query the kernel policy */ - rc = security_compute_create(ssid->ctx, tsid->ctx, tclass, - &ctx); - if (rc) - goto out; - rc = sidtab_context_to_sid(&avc_sidtab, ctx, newsid); - freecon(ctx); - if (rc) - goto out; - - aeref.ae->create_sid = *newsid; - } else { - /* found saved value */ - *newsid = aeref.ae->create_sid; - } - - rc = 0; -out: - avc_release_lock(avc_lock); - return rc; -} - -int avc_add_callback(int (*callback) (uint32_t event, security_id_t ssid, - security_id_t tsid, - security_class_t tclass, - access_vector_t perms, - access_vector_t * out_retained), - uint32_t events, security_id_t ssid, - security_id_t tsid, - security_class_t tclass, access_vector_t perms) -{ - struct avc_callback_node *c; - int rc = 0; - - c = avc_malloc(sizeof(*c)); - if (!c) { - rc = -1; - goto out; - } - - c->callback = callback; - c->events = events; - c->ssid = ssid; - c->tsid = tsid; - c->tclass = tclass; - c->perms = perms; - c->next = avc_callbacks; - avc_callbacks = c; - out: - return rc; -} - -static inline int avc_sidcmp(security_id_t x, security_id_t y) -{ - return (x == y || x == SECSID_WILD || y == SECSID_WILD); -} - -static inline void avc_update_node(uint32_t event, struct avc_node *node, - access_vector_t perms) -{ - switch (event) { - case AVC_CALLBACK_GRANT: - node->ae.avd.allowed |= perms; - break; - case AVC_CALLBACK_TRY_REVOKE: - case AVC_CALLBACK_REVOKE: - node->ae.avd.allowed &= ~perms; - break; - case AVC_CALLBACK_AUDITALLOW_ENABLE: - node->ae.avd.auditallow |= perms; - break; - case AVC_CALLBACK_AUDITALLOW_DISABLE: - node->ae.avd.auditallow &= ~perms; - break; - case AVC_CALLBACK_AUDITDENY_ENABLE: - node->ae.avd.auditdeny |= perms; - break; - case AVC_CALLBACK_AUDITDENY_DISABLE: - node->ae.avd.auditdeny &= ~perms; - break; - } -} - -static int avc_update_cache(uint32_t event, security_id_t ssid, - security_id_t tsid, security_class_t tclass, - access_vector_t perms) -{ - struct avc_node *node; - int i; - - avc_get_lock(avc_lock); - - if (ssid == SECSID_WILD || tsid == SECSID_WILD) { - /* apply to all matching nodes */ - for (i = 0; i < AVC_CACHE_SLOTS; i++) { - for (node = avc_cache.slots[i]; node; node = node->next) { - if (avc_sidcmp(ssid, node->ae.ssid) && - avc_sidcmp(tsid, node->ae.tsid) && - tclass == node->ae.tclass) { - avc_update_node(event, node, perms); - } - } - } - } else { - /* apply to one node */ - node = avc_search_node(ssid, tsid, tclass, 0); - if (node) { - avc_update_node(event, node, perms); - } - } - - avc_release_lock(avc_lock); - - return 0; -} - -/* avc_control - update cache and call callbacks - * - * This should not be called directly; use the individual event - * functions instead. - */ -static int avc_control(uint32_t event, security_id_t ssid, - security_id_t tsid, security_class_t tclass, - access_vector_t perms, - uint32_t seqno, access_vector_t * out_retained) -{ - struct avc_callback_node *c; - access_vector_t tretained = 0, cretained = 0; - int ret, rc = 0, errsave = 0; - errno = 0; - - /* - * try_revoke only removes permissions from the cache - * state if they are not retained by the object manager. - * Hence, try_revoke must wait until after the callbacks have - * been invoked to update the cache state. - */ - if (event != AVC_CALLBACK_TRY_REVOKE) - avc_update_cache(event, ssid, tsid, tclass, perms); - - for (c = avc_callbacks; c; c = c->next) { - if ((c->events & event) && - avc_sidcmp(c->ssid, ssid) && - avc_sidcmp(c->tsid, tsid) && - c->tclass == tclass && (c->perms & perms)) { - cretained = 0; - ret = c->callback(event, ssid, tsid, tclass, - (c->perms & perms), &cretained); - if (ret && !rc) { - rc = ret; - errsave = errno; - } - if (!ret) - tretained |= cretained; - } - } - - if (event == AVC_CALLBACK_TRY_REVOKE) { - /* revoke any unretained permissions */ - perms &= ~tretained; - avc_update_cache(event, ssid, tsid, tclass, perms); - *out_retained = tretained; - } - - avc_get_lock(avc_lock); - if (seqno > avc_cache.latest_notif) - avc_cache.latest_notif = seqno; - avc_release_lock(avc_lock); - - errno = errsave; - return rc; -} - -/** - * avc_ss_grant - Grant previously denied permissions. - * @ssid: source security identifier or %SECSID_WILD - * @tsid: target security identifier or %SECSID_WILD - * @tclass: target security class - * @perms: permissions to grant - * @seqno: policy sequence number - */ -int avc_ss_grant(security_id_t ssid, security_id_t tsid, - security_class_t tclass, access_vector_t perms, - uint32_t seqno) -{ - return avc_control(AVC_CALLBACK_GRANT, - ssid, tsid, tclass, perms, seqno, 0); -} - -/** - * avc_ss_try_revoke - Try to revoke previously granted permissions. - * @ssid: source security identifier or %SECSID_WILD - * @tsid: target security identifier or %SECSID_WILD - * @tclass: target security class - * @perms: permissions to grant - * @seqno: policy sequence number - * @out_retained: subset of @perms that are retained - * - * Try to revoke previously granted permissions, but - * only if they are not retained as migrated permissions. - * Return the subset of permissions that are retained via @out_retained. - */ -int avc_ss_try_revoke(security_id_t ssid, security_id_t tsid, - security_class_t tclass, - access_vector_t perms, uint32_t seqno, - access_vector_t * out_retained) -{ - return avc_control(AVC_CALLBACK_TRY_REVOKE, - ssid, tsid, tclass, perms, seqno, out_retained); -} - -/** - * avc_ss_revoke - Revoke previously granted permissions. - * @ssid: source security identifier or %SECSID_WILD - * @tsid: target security identifier or %SECSID_WILD - * @tclass: target security class - * @perms: permissions to grant - * @seqno: policy sequence number - * - * Revoke previously granted permissions, even if - * they are retained as migrated permissions. - */ -int avc_ss_revoke(security_id_t ssid, security_id_t tsid, - security_class_t tclass, access_vector_t perms, - uint32_t seqno) -{ - return avc_control(AVC_CALLBACK_REVOKE, - ssid, tsid, tclass, perms, seqno, 0); -} - -/** - * avc_ss_reset - Flush the cache and revalidate migrated permissions. - * @seqno: policy sequence number - */ -int avc_ss_reset(uint32_t seqno) -{ - int rc; - - rc = avc_reset(); - - avc_get_lock(avc_lock); - if (seqno > avc_cache.latest_notif) - avc_cache.latest_notif = seqno; - avc_release_lock(avc_lock); - - return rc; -} - -/** - * avc_ss_set_auditallow - Enable or disable auditing of granted permissions. - * @ssid: source security identifier or %SECSID_WILD - * @tsid: target security identifier or %SECSID_WILD - * @tclass: target security class - * @perms: permissions to grant - * @seqno: policy sequence number - * @enable: enable flag. - */ -int avc_ss_set_auditallow(security_id_t ssid, security_id_t tsid, - security_class_t tclass, access_vector_t perms, - uint32_t seqno, uint32_t enable) -{ - if (enable) - return avc_control(AVC_CALLBACK_AUDITALLOW_ENABLE, - ssid, tsid, tclass, perms, seqno, 0); - else - return avc_control(AVC_CALLBACK_AUDITALLOW_DISABLE, - ssid, tsid, tclass, perms, seqno, 0); -} - -/** - * avc_ss_set_auditdeny - Enable or disable auditing of denied permissions. - * @ssid: source security identifier or %SECSID_WILD - * @tsid: target security identifier or %SECSID_WILD - * @tclass: target security class - * @perms: permissions to grant - * @seqno: policy sequence number - * @enable: enable flag. - */ -int avc_ss_set_auditdeny(security_id_t ssid, security_id_t tsid, - security_class_t tclass, access_vector_t perms, - uint32_t seqno, uint32_t enable) -{ - if (enable) - return avc_control(AVC_CALLBACK_AUDITDENY_ENABLE, - ssid, tsid, tclass, perms, seqno, 0); - else - return avc_control(AVC_CALLBACK_AUDITDENY_DISABLE, - ssid, tsid, tclass, perms, seqno, 0); -} diff --git a/src/avc_internal.c b/src/avc_internal.c deleted file mode 100644 index c89a886..0000000 --- a/src/avc_internal.c +++ /dev/null @@ -1,292 +0,0 @@ -/* - * Callbacks for user-supplied memory allocation, supplemental - * auditing, and locking routines. - * - * Author : Eamon Walsh <ewalsh@epoch.ncsc.mil> - * - * Netlink code derived in part from sample code by - * James Morris <jmorris@redhat.com>. - */ - -#include <errno.h> -#include <stdio.h> -#include <stdlib.h> -#include <stdint.h> -#include <unistd.h> -#include <fcntl.h> -#include <string.h> -#include <poll.h> -#include <sys/types.h> -#include <sys/socket.h> -#include <linux/types.h> -#include <linux/netlink.h> -#include "callbacks.h" -#include "selinux_netlink.h" -#include "avc_internal.h" - -#ifndef NETLINK_SELINUX -#define NETLINK_SELINUX 7 -#endif - -/* callback pointers */ -void *(*avc_func_malloc) (size_t) = NULL; -void (*avc_func_free) (void *) = NULL; - -void (*avc_func_log) (const char *, ...) = NULL; -void (*avc_func_audit) (void *, security_class_t, char *, size_t) = NULL; - -int avc_using_threads = 0; -int avc_app_main_loop = 0; -void *(*avc_func_create_thread) (void (*)(void)) = NULL; -void (*avc_func_stop_thread) (void *) = NULL; - -void *(*avc_func_alloc_lock) (void) = NULL; -void (*avc_func_get_lock) (void *) = NULL; -void (*avc_func_release_lock) (void *) = NULL; -void (*avc_func_free_lock) (void *) = NULL; - -/* message prefix string and avc enforcing mode */ -char avc_prefix[AVC_PREFIX_SIZE] = "uavc"; -int avc_running = 0; -int avc_enforcing = 1; -int avc_setenforce = 0; -int avc_netlink_trouble = 0; - -/* netlink socket code */ -static int fd = -1; - -int avc_netlink_open(int blocking) -{ - int len, rc = 0; - struct sockaddr_nl addr; - - fd = socket(PF_NETLINK, SOCK_RAW | SOCK_CLOEXEC, NETLINK_SELINUX); - if (fd < 0) { - rc = fd; - goto out; - } - - if (!blocking && fcntl(fd, F_SETFL, O_NONBLOCK)) { - close(fd); - fd = -1; - rc = -1; - goto out; - } - - len = sizeof(addr); - - memset(&addr, 0, len); - addr.nl_family = AF_NETLINK; - addr.nl_groups = SELNL_GRP_AVC; - - if (bind(fd, (struct sockaddr *)&addr, len) < 0) { - close(fd); - fd = -1; - rc = -1; - goto out; - } - out: - return rc; -} - -void avc_netlink_close(void) -{ - if (fd >= 0) - close(fd); - fd = -1; -} - -static int avc_netlink_receive(char *buf, unsigned buflen, int blocking) -{ - int rc; - struct pollfd pfd = { fd, POLLIN | POLLPRI, 0 }; - struct sockaddr_nl nladdr; - socklen_t nladdrlen = sizeof nladdr; - struct nlmsghdr *nlh = (struct nlmsghdr *)buf; - - do { - rc = poll(&pfd, 1, (blocking ? -1 : 0)); - } while (rc < 0 && errno == EINTR); - - if (rc == 0 && !blocking) { - errno = EWOULDBLOCK; - return -1; - } - else if (rc < 1) { - avc_log(SELINUX_ERROR, "%s: netlink poll: error %d\n", - avc_prefix, errno); - return rc; - } - - rc = recvfrom(fd, buf, buflen, 0, (struct sockaddr *)&nladdr, - &nladdrlen); - if (rc < 0) - return rc; - - if (nladdrlen != sizeof nladdr) { - avc_log(SELINUX_WARNING, - "%s: warning: netlink address truncated, len %d?\n", - avc_prefix, nladdrlen); - return -1; - } - - if (nladdr.nl_pid) { - avc_log(SELINUX_WARNING, - "%s: warning: received spoofed netlink packet from: %d\n", - avc_prefix, nladdr.nl_pid); - return -1; - } - - if (rc == 0) { - avc_log(SELINUX_WARNING, - "%s: warning: received EOF on netlink socket\n", - avc_prefix); - errno = EBADFD; - return -1; - } - - if (nlh->nlmsg_flags & MSG_TRUNC || nlh->nlmsg_len > (unsigned)rc) { - avc_log(SELINUX_WARNING, - "%s: warning: incomplete netlink message\n", - avc_prefix); - return -1; - } - - return 0; -} - -static int avc_netlink_process(char *buf) -{ - int rc; - struct nlmsghdr *nlh = (struct nlmsghdr *)buf; - - switch (nlh->nlmsg_type) { - case NLMSG_ERROR:{ - struct nlmsgerr *err = NLMSG_DATA(nlh); - - /* Netlink ack */ - if (err->error == 0) - break; - - errno = -err->error; - avc_log(SELINUX_ERROR, - "%s: netlink error: %d\n", avc_prefix, errno); - return -1; - } - - case SELNL_MSG_SETENFORCE:{ - struct selnl_msg_setenforce *msg = NLMSG_DATA(nlh); - avc_log(SELINUX_INFO, - "%s: received setenforce notice (enforcing=%d)\n", - avc_prefix, msg->val); - if (avc_setenforce) - break; - avc_enforcing = msg->val; - if (avc_enforcing && (rc = avc_ss_reset(0)) < 0) { - avc_log(SELINUX_ERROR, - "%s: cache reset returned %d (errno %d)\n", - avc_prefix, rc, errno); - return rc; - } - rc = selinux_netlink_setenforce(msg->val); - if (rc < 0) - return rc; - break; - } - - case SELNL_MSG_POLICYLOAD:{ - struct selnl_msg_policyload *msg = NLMSG_DATA(nlh); - avc_log(SELINUX_INFO, - "%s: received policyload notice (seqno=%d)\n", - avc_prefix, msg->seqno); - rc = avc_ss_reset(msg->seqno); - if (rc < 0) { - avc_log(SELINUX_ERROR, - "%s: cache reset returned %d (errno %d)\n", - avc_prefix, rc, errno); - return rc; - } - rc = selinux_netlink_policyload(msg->seqno); - if (rc < 0) - return rc; - break; - } - - default: - avc_log(SELINUX_WARNING, - "%s: warning: unknown netlink message %d\n", - avc_prefix, nlh->nlmsg_type); - } - return 0; -} - -int avc_netlink_check_nb(void) -{ - int rc; - char buf[1024] __attribute__ ((aligned)); - - while (1) { - errno = 0; - rc = avc_netlink_receive(buf, sizeof(buf), 0); - if (rc < 0) { - if (errno == EWOULDBLOCK) - return 0; - if (errno == 0 || errno == EINTR) - continue; - else { - avc_log(SELINUX_ERROR, - "%s: netlink recvfrom: error %d\n", - avc_prefix, errno); - return rc; - } - } - - (void)avc_netlink_process(buf); - } - return 0; -} - -/* run routine for the netlink listening thread */ -void avc_netlink_loop(void) -{ - int rc; - char buf[1024] __attribute__ ((aligned)); - - while (1) { - errno = 0; - rc = avc_netlink_receive(buf, sizeof(buf), 1); - if (rc < 0) { - if (errno == 0 || errno == EINTR) - continue; - else { - avc_log(SELINUX_ERROR, - "%s: netlink recvfrom: error %d\n", - avc_prefix, errno); - break; - } - } - - rc = avc_netlink_process(buf); - if (rc < 0) - break; - } - - close(fd); - fd = -1; - avc_netlink_trouble = 1; - avc_log(SELINUX_ERROR, - "%s: netlink thread: errors encountered, terminating\n", - avc_prefix); -} - -int avc_netlink_acquire_fd(void) -{ - avc_app_main_loop = 1; - - return fd; -} - -void avc_netlink_release_fd(void) -{ - avc_app_main_loop = 0; -} diff --git a/src/avc_internal.h b/src/avc_internal.h deleted file mode 100644 index 53610e8..0000000 --- a/src/avc_internal.h +++ /dev/null @@ -1,182 +0,0 @@ -/* - * This file describes the internal interface used by the AVC - * for calling the user-supplied memory allocation, supplemental - * auditing, and locking routine, as well as incrementing the - * statistics fields. - * - * Author : Eamon Walsh <ewalsh@epoch.ncsc.mil> - */ -#ifndef _SELINUX_AVC_INTERNAL_H_ -#define _SELINUX_AVC_INTERNAL_H_ - -#include <stdio.h> -#include <stdlib.h> -#include <string.h> -#include <selinux/avc.h> -#include "callbacks.h" -#include "dso.h" - -/* callback pointers */ -extern void *(*avc_func_malloc) (size_t) hidden; -extern void (*avc_func_free) (void *)hidden; - -extern void (*avc_func_log) (const char *, ...)hidden; -extern void (*avc_func_audit) (void *, security_class_t, char *, size_t)hidden; - -extern int avc_using_threads hidden; -extern int avc_app_main_loop hidden; -extern void *(*avc_func_create_thread) (void (*)(void))hidden; -extern void (*avc_func_stop_thread) (void *)hidden; - -extern void *(*avc_func_alloc_lock) (void)hidden; -extern void (*avc_func_get_lock) (void *)hidden; -extern void (*avc_func_release_lock) (void *)hidden; -extern void (*avc_func_free_lock) (void *)hidden; - -static inline void set_callbacks(const struct avc_memory_callback *mem_cb, - const struct avc_log_callback *log_cb, - const struct avc_thread_callback *thread_cb, - const struct avc_lock_callback *lock_cb) -{ - if (mem_cb) { - avc_func_malloc = mem_cb->func_malloc; - avc_func_free = mem_cb->func_free; - } - if (log_cb) { - avc_func_log = log_cb->func_log; - avc_func_audit = log_cb->func_audit; - } - if (thread_cb) { - avc_using_threads = 1; - avc_func_create_thread = thread_cb->func_create_thread; - avc_func_stop_thread = thread_cb->func_stop_thread; - } - if (lock_cb) { - avc_func_alloc_lock = lock_cb->func_alloc_lock; - avc_func_get_lock = lock_cb->func_get_lock; - avc_func_release_lock = lock_cb->func_release_lock; - avc_func_free_lock = lock_cb->func_free_lock; - } -} - -/* message prefix and enforcing mode*/ -#define AVC_PREFIX_SIZE 16 -extern char avc_prefix[AVC_PREFIX_SIZE] hidden; -extern int avc_running hidden; -extern int avc_enforcing hidden; -extern int avc_setenforce hidden; - -/* user-supplied callback interface for avc */ -static inline void *avc_malloc(size_t size) -{ - return avc_func_malloc ? avc_func_malloc(size) : malloc(size); -} - -static inline void avc_free(void *ptr) -{ - if (avc_func_free) - avc_func_free(ptr); - else - free(ptr); -} - -/* this is a macro in order to use the variadic capability. */ -#define avc_log(type, format...) \ - if (avc_func_log) \ - avc_func_log(format); \ - else \ - selinux_log(type, format); - -static inline void avc_suppl_audit(void *ptr, security_class_t class, - char *buf, size_t len) -{ - if (avc_func_audit) - avc_func_audit(ptr, class, buf, len); - else - selinux_audit(ptr, class, buf, len); -} - -static inline void *avc_create_thread(void (*run) (void)) -{ - return avc_func_create_thread ? avc_func_create_thread(run) : NULL; -} - -static inline void avc_stop_thread(void *thread) -{ - if (avc_func_stop_thread) - avc_func_stop_thread(thread); -} - -static inline void *avc_alloc_lock(void) -{ - return avc_func_alloc_lock ? avc_func_alloc_lock() : NULL; -} - -static inline void avc_get_lock(void *lock) -{ - if (avc_func_get_lock) - avc_func_get_lock(lock); -} - -static inline void avc_release_lock(void *lock) -{ - if (avc_func_release_lock) - avc_func_release_lock(lock); -} - -static inline void avc_free_lock(void *lock) -{ - if (avc_func_free_lock) - avc_func_free_lock(lock); -} - -/* statistics helper routines */ -#ifdef AVC_CACHE_STATS - -#define avc_cache_stats_incr(field) \ - cache_stats.field ++; -#define avc_cache_stats_add(field, num) \ - cache_stats.field += num; - -#else - -#define avc_cache_stats_incr(field) -#define avc_cache_stats_add(field, num) - -#endif - -/* logging helper routines */ -#define AVC_AUDIT_BUFSIZE 1024 - -/* again, we need the variadic capability here */ -#define log_append(buf,format...) \ - snprintf(buf+strlen(buf), AVC_AUDIT_BUFSIZE-strlen(buf), format) - -/* internal callbacks */ -int avc_ss_grant(security_id_t ssid, security_id_t tsid, - security_class_t tclass, access_vector_t perms, - uint32_t seqno) hidden; -int avc_ss_try_revoke(security_id_t ssid, security_id_t tsid, - security_class_t tclass, - access_vector_t perms, uint32_t seqno, - access_vector_t * out_retained) hidden; -int avc_ss_revoke(security_id_t ssid, security_id_t tsid, - security_class_t tclass, access_vector_t perms, - uint32_t seqno) hidden; -int avc_ss_reset(uint32_t seqno) hidden; -int avc_ss_set_auditallow(security_id_t ssid, security_id_t tsid, - security_class_t tclass, access_vector_t perms, - uint32_t seqno, uint32_t enable) hidden; -int avc_ss_set_auditdeny(security_id_t ssid, security_id_t tsid, - security_class_t tclass, access_vector_t perms, - uint32_t seqno, uint32_t enable) hidden; - -/* netlink kernel message code */ -extern int avc_netlink_trouble hidden; - -hidden_proto(avc_av_stats) - hidden_proto(avc_cleanup) - hidden_proto(avc_reset) - hidden_proto(avc_audit) - hidden_proto(avc_has_perm_noaudit) -#endif /* _SELINUX_AVC_INTERNAL_H_ */ diff --git a/src/avc_sidtab.c b/src/avc_sidtab.c deleted file mode 100644 index 52f21df..0000000 --- a/src/avc_sidtab.c +++ /dev/null @@ -1,152 +0,0 @@ -/* - * Implementation of the userspace SID hashtable. - * - * Author : Eamon Walsh, <ewalsh@epoch.ncsc.mil> - */ -#include <errno.h> -#include <stdio.h> -#include <stdlib.h> -#include <stdint.h> -#include <string.h> -#include "selinux_internal.h" -#include <selinux/avc.h> -#include "avc_sidtab.h" -#include "avc_internal.h" - -static inline unsigned sidtab_hash(const char * key) -{ - char *p, *keyp; - unsigned int size; - unsigned int val; - - val = 0; - keyp = (char *)key; - size = strlen(keyp); - for (p = keyp; (unsigned int)(p - keyp) < size; p++) - val = - (val << 4 | (val >> (8 * sizeof(unsigned int) - 4))) ^ (*p); - return val & (SIDTAB_SIZE - 1); -} - -int sidtab_init(struct sidtab *s) -{ - int i, rc = 0; - - s->htable = (struct sidtab_node **)avc_malloc - (sizeof(struct sidtab_node *) * SIDTAB_SIZE); - - if (!s->htable) { - rc = -1; - goto out; - } - for (i = 0; i < SIDTAB_SIZE; i++) - s->htable[i] = NULL; - s->nel = 0; - out: - return rc; -} - -int sidtab_insert(struct sidtab *s, const char * ctx) -{ - int hvalue, rc = 0; - struct sidtab_node *newnode; - char * newctx; - - newnode = (struct sidtab_node *)avc_malloc(sizeof(*newnode)); - if (!newnode) { - rc = -1; - goto out; - } - newctx = (char *) strdup(ctx); - if (!newctx) { - rc = -1; - avc_free(newnode); - goto out; - } - - hvalue = sidtab_hash(newctx); - newnode->next = s->htable[hvalue]; - newnode->sid_s.ctx = newctx; - newnode->sid_s.refcnt = 1; /* unused */ - s->htable[hvalue] = newnode; - s->nel++; - out: - return rc; -} - -int -sidtab_context_to_sid(struct sidtab *s, - const char * ctx, security_id_t * sid) -{ - int hvalue, rc = 0; - struct sidtab_node *cur; - - *sid = NULL; - hvalue = sidtab_hash(ctx); - - loop: - cur = s->htable[hvalue]; - while (cur != NULL && strcmp(cur->sid_s.ctx, ctx)) - cur = cur->next; - - if (cur == NULL) { /* need to make a new entry */ - rc = sidtab_insert(s, ctx); - if (rc) - goto out; - goto loop; /* find the newly inserted node */ - } - - *sid = &cur->sid_s; - out: - return rc; -} - -void sidtab_sid_stats(struct sidtab *h, char *buf, int buflen) -{ - int i, chain_len, slots_used, max_chain_len; - struct sidtab_node *cur; - - slots_used = 0; - max_chain_len = 0; - for (i = 0; i < SIDTAB_SIZE; i++) { - cur = h->htable[i]; - if (cur) { - slots_used++; - chain_len = 0; - while (cur) { - chain_len++; - cur = cur->next; - } - - if (chain_len > max_chain_len) - max_chain_len = chain_len; - } - } - - snprintf(buf, buflen, - "%s: %d SID entries and %d/%d buckets used, longest " - "chain length %d\n", avc_prefix, h->nel, slots_used, - SIDTAB_SIZE, max_chain_len); -} - -void sidtab_destroy(struct sidtab *s) -{ - int i; - struct sidtab_node *cur, *temp; - - if (!s) - return; - - for (i = 0; i < SIDTAB_SIZE; i++) { - cur = s->htable[i]; - while (cur != NULL) { - temp = cur; - cur = cur->next; - freecon(temp->sid_s.ctx); - avc_free(temp); - } - s->htable[i] = NULL; - } - avc_free(s->htable); - s->htable = NULL; -} diff --git a/src/avc_sidtab.h b/src/avc_sidtab.h deleted file mode 100644 index bce9b87..0000000 --- a/src/avc_sidtab.h +++ /dev/null @@ -1,36 +0,0 @@ -/* - * A security identifier table (sidtab) is a hash table - * of security context structures indexed by SID value. - */ -#ifndef _SELINUX_AVC_SIDTAB_H_ -#define _SELINUX_AVC_SIDTAB_H_ - -#include <selinux/selinux.h> -#include <selinux/avc.h> -#include "dso.h" - -struct sidtab_node { - struct security_id sid_s; - struct sidtab_node *next; -}; - -#define SIDTAB_HASH_BITS 7 -#define SIDTAB_HASH_BUCKETS (1 << SIDTAB_HASH_BITS) -#define SIDTAB_HASH_MASK (SIDTAB_HASH_BUCKETS-1) -#define SIDTAB_SIZE SIDTAB_HASH_BUCKETS - -struct sidtab { - struct sidtab_node **htable; - unsigned nel; -}; - -int sidtab_init(struct sidtab *s) hidden; -int sidtab_insert(struct sidtab *s, const char * ctx) hidden; - -int sidtab_context_to_sid(struct sidtab *s, - const char * ctx, security_id_t * sid) hidden; - -void sidtab_sid_stats(struct sidtab *s, char *buf, int buflen) hidden; -void sidtab_destroy(struct sidtab *s) hidden; - -#endif /* _SELINUX_AVC_SIDTAB_H_ */ diff --git a/src/booleans.c b/src/booleans.c deleted file mode 100644 index 17e0ad8..0000000 --- a/src/booleans.c +++ /dev/null @@ -1,263 +0,0 @@ -/* - * Author: Karl MacMillan <kmacmillan@tresys.com> - * - * Modified: - * Dan Walsh <dwalsh@redhat.com> - Added security_load_booleans(). - */ - -#include <sys/types.h> -#include <sys/stat.h> -#include <fcntl.h> -#include <assert.h> -#include <stdlib.h> -#include <dirent.h> -#include <string.h> -#include <stdio.h> -#include <unistd.h> -#include <fnmatch.h> -#include <limits.h> -#include <ctype.h> -#include <errno.h> - -#include "selinux_internal.h" -#include "policy.h" - -#define SELINUX_BOOL_DIR "/booleans/" - -static int filename_select(const struct dirent *d) -{ - if (d->d_name[0] == '.' - && (d->d_name[1] == '\0' - || (d->d_name[1] == '.' && d->d_name[2] == '\0'))) - return 0; - return 1; -} - -int security_get_boolean_names(char ***names, int *len) -{ - char path[PATH_MAX]; - int i, rc; - struct dirent **namelist; - char **n; - - assert(len); - if (!selinux_mnt) { - errno = ENOENT; - return -1; - } - - snprintf(path, sizeof path, "%s%s", selinux_mnt, SELINUX_BOOL_DIR); - *len = scandir(path, &namelist, &filename_select, alphasort); - if (*len <= 0) { - return -1; - } - - n = (char **)malloc(sizeof(char *) * *len); - if (!n) { - rc = -1; - goto bad; - } - - for (i = 0; i < *len; i++) { - n[i] = strdup(namelist[i]->d_name); - if (!n[i]) { - rc = -1; - goto bad_freen; - } - } - rc = 0; - *names = n; - out: - for (i = 0; i < *len; i++) { - free(namelist[i]); - } - free(namelist); - return rc; - bad_freen: - for (--i; i >= 0; --i) - free(n[i]); - free(n); - bad: - goto out; -} - -hidden_def(security_get_boolean_names) -#define STRBUF_SIZE 3 -static int get_bool_value(const char *name, char **buf) -{ - int fd, len; - char *fname = NULL; - - if (!selinux_mnt) { - errno = ENOENT; - return -1; - } - - *buf = (char *)malloc(sizeof(char) * (STRBUF_SIZE + 1)); - if (!*buf) - goto out; - (*buf)[STRBUF_SIZE] = 0; - - len = strlen(name) + strlen(selinux_mnt) + sizeof(SELINUX_BOOL_DIR); - fname = (char *)malloc(sizeof(char) * len); - if (!fname) - goto out; - snprintf(fname, len, "%s%s%s", selinux_mnt, SELINUX_BOOL_DIR, name); - - fd = open(fname, O_RDONLY); - if (fd < 0) - goto out; - - len = read(fd, *buf, STRBUF_SIZE); - close(fd); - if (len != STRBUF_SIZE) - goto out; - - free(fname); - return 0; - out: - if (*buf) - free(*buf); - if (fname) - free(fname); - return -1; -} - -int security_get_boolean_pending(const char *name) -{ - char *buf; - int val; - - if (get_bool_value(name, &buf)) - return -1; - - if (atoi(&buf[1])) - val = 1; - else - val = 0; - free(buf); - return val; -} - -int security_get_boolean_active(const char *name) -{ - char *buf; - int val; - - if (get_bool_value(name, &buf)) - return -1; - - buf[1] = '\0'; - if (atoi(buf)) - val = 1; - else - val = 0; - free(buf); - return val; -} - -hidden_def(security_get_boolean_active) - -int security_set_boolean(const char *name, int value) -{ - int fd, ret, len; - char buf[2], *fname; - - if (!selinux_mnt) { - errno = ENOENT; - return -1; - } - if (value < 0 || value > 1) { - errno = EINVAL; - return -1; - } - - len = strlen(name) + strlen(selinux_mnt) + sizeof(SELINUX_BOOL_DIR); - fname = (char *)malloc(sizeof(char) * len); - if (!fname) - return -1; - snprintf(fname, len, "%s%s%s", selinux_mnt, SELINUX_BOOL_DIR, name); - - fd = open(fname, O_WRONLY); - if (fd < 0) { - ret = -1; - goto out; - } - - if (value) - buf[0] = '1'; - else - buf[0] = '0'; - buf[1] = '\0'; - - ret = write(fd, buf, 2); - close(fd); - out: - free(fname); - if (ret > 0) - return 0; - else - return -1; -} - -hidden_def(security_set_boolean) - -int security_commit_booleans(void) -{ - int fd, ret; - char buf[2]; - char path[PATH_MAX]; - - if (!selinux_mnt) { - errno = ENOENT; - return -1; - } - - snprintf(path, sizeof path, "%s/commit_pending_bools", selinux_mnt); - fd = open(path, O_WRONLY); - if (fd < 0) - return -1; - - buf[0] = '1'; - buf[1] = '\0'; - - ret = write(fd, buf, 2); - close(fd); - - if (ret > 0) - return 0; - else - return -1; -} - -hidden_def(security_commit_booleans) - -static void rollback(SELboolean * boollist, int end) -{ - int i; - - for (i = 0; i < end; i++) - security_set_boolean(boollist[i].name, - security_get_boolean_active(boollist[i]. - name)); -} - -int security_set_boolean_list(size_t boolcnt, SELboolean * const boollist, - int permanent __attribute__((unused))) -{ - - size_t i; - for (i = 0; i < boolcnt; i++) { - if (security_set_boolean(boollist[i].name, boollist[i].value)) { - rollback(boollist, i); - return -1; - } - } - - /* OK, let's do the commit */ - if (security_commit_booleans()) { - return -1; - } - - return 0; -} diff --git a/src/callbacks.c b/src/callbacks.c deleted file mode 100644 index c3cf98b..0000000 --- a/src/callbacks.c +++ /dev/null @@ -1,124 +0,0 @@ -/* - * User-supplied callbacks and default implementations. - * Class and permission mappings. - */ - -#include <stdio.h> -#include <stdlib.h> -#include <stdarg.h> -#include <errno.h> -#include <selinux/selinux.h> -#include "callbacks.h" - -/* default implementations */ -static int __attribute__ ((format(printf, 2, 3))) -default_selinux_log(int type __attribute__((unused)), const char *fmt, ...) -{ - int rc; - va_list ap; - va_start(ap, fmt); - rc = vfprintf(stderr, fmt, ap); - va_end(ap); - return rc; -} - -static int -default_selinux_audit(void *ptr __attribute__((unused)), - security_class_t cls __attribute__((unused)), - char *buf __attribute__((unused)), - size_t len __attribute__((unused))) -{ - return 0; -} - -static int -default_selinux_validate(char **ctx) -{ - return security_check_context(*ctx); -} - -static int -default_selinux_setenforce(int enforcing __attribute__((unused))) -{ - return 0; -} - -static int -default_selinux_policyload(int seqno __attribute__((unused))) -{ - return 0; -} - -/* callback pointers */ -int __attribute__ ((format(printf, 2, 3))) -(*selinux_log)(int, const char *, ...) = - default_selinux_log; - -int -(*selinux_audit) (void *, security_class_t, char *, size_t) = - default_selinux_audit; - -int -(*selinux_validate)(char **ctx) = - default_selinux_validate; - -int -(*selinux_netlink_setenforce) (int enforcing) = - default_selinux_setenforce; - -int -(*selinux_netlink_policyload) (int seqno) = - default_selinux_policyload; - -/* callback setting function */ -void -selinux_set_callback(int type, union selinux_callback cb) -{ - switch (type) { - case SELINUX_CB_LOG: - selinux_log = cb.func_log; - break; - case SELINUX_CB_AUDIT: - selinux_audit = cb.func_audit; - break; - case SELINUX_CB_VALIDATE: - selinux_validate = cb.func_validate; - break; - case SELINUX_CB_SETENFORCE: - selinux_netlink_setenforce = cb.func_setenforce; - break; - case SELINUX_CB_POLICYLOAD: - selinux_netlink_policyload = cb.func_policyload; - break; - } -} - -/* callback getting function */ -union selinux_callback -selinux_get_callback(int type) -{ - union selinux_callback cb; - - switch (type) { - case SELINUX_CB_LOG: - cb.func_log = selinux_log; - break; - case SELINUX_CB_AUDIT: - cb.func_audit = selinux_audit; - break; - case SELINUX_CB_VALIDATE: - cb.func_validate = selinux_validate; - break; - case SELINUX_CB_SETENFORCE: - cb.func_setenforce = selinux_netlink_setenforce; - break; - case SELINUX_CB_POLICYLOAD: - cb.func_policyload = selinux_netlink_policyload; - break; - default: - memset(&cb, 0, sizeof(cb)); - errno = EINVAL; - break; - } - return cb; -} diff --git a/src/callbacks.h b/src/callbacks.h deleted file mode 100644 index 2a572e0..0000000 --- a/src/callbacks.h +++ /dev/null @@ -1,30 +0,0 @@ -/* - * This file describes the callbacks passed to selinux_init() and available - * for use from the library code. They all have default implementations. - */ -#ifndef _SELINUX_CALLBACKS_H_ -#define _SELINUX_CALLBACKS_H_ - -#include <stdio.h> -#include <stdlib.h> -#include <string.h> -#include <selinux/selinux.h> -#include "dso.h" - -/* callback pointers */ -extern int __attribute__ ((format(printf, 2, 3))) -(*selinux_log) (int type, const char *, ...) hidden; - -extern int -(*selinux_audit) (void *, security_class_t, char *, size_t) hidden; - -extern int -(*selinux_validate)(char **ctx) hidden; - -extern int -(*selinux_netlink_setenforce) (int enforcing) hidden; - -extern int -(*selinux_netlink_policyload) (int seqno) hidden; - -#endif /* _SELINUX_CALLBACKS_H_ */ diff --git a/src/canonicalize_context.c b/src/canonicalize_context.c deleted file mode 100644 index b8f874f..0000000 --- a/src/canonicalize_context.c +++ /dev/null @@ -1,62 +0,0 @@ -#include <unistd.h> -#include <sys/types.h> -#include <fcntl.h> -#include <stdlib.h> -#include <stdio.h> -#include <errno.h> -#include <string.h> -#include "selinux_internal.h" -#include "policy.h" -#include <limits.h> - -int security_canonicalize_context(const char * con, - char ** canoncon) -{ - char path[PATH_MAX]; - char *buf; - size_t size; - int fd, ret; - - if (!selinux_mnt) { - errno = ENOENT; - return -1; - } - - snprintf(path, sizeof path, "%s/context", selinux_mnt); - fd = open(path, O_RDWR); - if (fd < 0) - return -1; - - size = selinux_page_size; - buf = malloc(size); - if (!buf) { - ret = -1; - goto out; - } - strncpy(buf, con, size); - - ret = write(fd, buf, strlen(buf) + 1); - if (ret < 0) - goto out2; - - memset(buf, 0, size); - ret = read(fd, buf, size - 1); - if (ret < 0 && errno == EINVAL) { - /* Fall back to the original context for kernels - that do not support the extended interface. */ - strncpy(buf, con, size); - } - - *canoncon = strdup(buf); - if (!(*canoncon)) { - ret = -1; - goto out2; - } - ret = 0; - out2: - free(buf); - out: - close(fd); - return ret; -} - diff --git a/src/checkAccess.c b/src/checkAccess.c deleted file mode 100644 index dc11cf7..0000000 --- a/src/checkAccess.c +++ /dev/null @@ -1,62 +0,0 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ -#include <unistd.h> -#include <sys/types.h> -#include <stdlib.h> -#include <errno.h> -#include "selinux_internal.h" -#include <selinux/avc.h> -#include "avc_internal.h" - -static pthread_once_t once = PTHREAD_ONCE_INIT; -static int selinux_enabled; - -static void avc_init_once(void) -{ - selinux_enabled = is_selinux_enabled(); - if (selinux_enabled == 1) - avc_open(NULL, 0); -} - -int selinux_check_access(const char * scon, const char * tcon, const char *class, const char *perm, void *aux) { - int rc; - security_id_t scon_id; - security_id_t tcon_id; - security_class_t sclass; - access_vector_t av; - - __selinux_once(once, avc_init_once); - - if (selinux_enabled != 1) - return 0; - - rc = avc_context_to_sid(scon, &scon_id); - if (rc < 0) - return rc; - - rc = avc_context_to_sid(tcon, &tcon_id); - if (rc < 0) - return rc; - - sclass = string_to_security_class(class); - if (sclass == 0) { - rc = errno; - avc_log(SELINUX_ERROR, "Unknown class %s", class); - if (security_deny_unknown() == 0) - return 0; - errno = rc; - return -1; - } - - av = string_to_av_perm(sclass, perm); - if (av == 0) { - rc = errno; - avc_log(SELINUX_ERROR, "Unknown permission %s for class %s", perm, class); - if (security_deny_unknown() == 0) - return 0; - errno = rc; - return -1; - } - - return avc_has_perm (scon_id, tcon_id, sclass, av, NULL, aux); -} - diff --git a/src/check_context.c b/src/check_context.c deleted file mode 100644 index 7471194..0000000 --- a/src/check_context.c +++ /dev/null @@ -1,33 +0,0 @@ -#include <unistd.h> -#include <sys/types.h> -#include <fcntl.h> -#include <stdlib.h> -#include <errno.h> -#include <string.h> -#include <stdio.h> -#include "selinux_internal.h" -#include "policy.h" -#include <limits.h> - -int security_check_context(const char * con) -{ - char path[PATH_MAX]; - int fd, ret; - - if (!selinux_mnt) { - errno = ENOENT; - return -1; - } - - snprintf(path, sizeof path, "%s/context", selinux_mnt); - fd = open(path, O_RDWR); - if (fd < 0) - return -1; - - ret = write(fd, con, strlen(con) + 1); - close(fd); - if (ret < 0) - return -1; - return 0; -} - diff --git a/src/compute_av.c b/src/compute_av.c deleted file mode 100644 index d6f76f8..0000000 --- a/src/compute_av.c +++ /dev/null @@ -1,72 +0,0 @@ -#include <unistd.h> -#include <sys/types.h> -#include <fcntl.h> -#include <stdlib.h> -#include <stdio.h> -#include <errno.h> -#include <string.h> -#include <limits.h> -#include "selinux_internal.h" -#include "policy.h" -#include "mapping.h" - -int security_compute_av(const char * scon, - const char * tcon, - security_class_t tclass, - access_vector_t requested, - struct av_decision *avd) -{ - char path[PATH_MAX]; - char *buf; - size_t len; - int fd, ret; - - if (!selinux_mnt) { - errno = ENOENT; - return -1; - } - - snprintf(path, sizeof path, "%s/access", selinux_mnt); - fd = open(path, O_RDWR); - if (fd < 0) - return -1; - - len = selinux_page_size; - buf = malloc(len); - if (!buf) { - ret = -1; - goto out; - } - - snprintf(buf, len, "%s %s %hu %x", scon, tcon, - unmap_class(tclass), unmap_perm(tclass, requested)); - - ret = write(fd, buf, strlen(buf)); - if (ret < 0) - goto out2; - - memset(buf, 0, len); - ret = read(fd, buf, len - 1); - if (ret < 0) - goto out2; - - ret = sscanf(buf, "%x %x %x %x %u %x", - &avd->allowed, &avd->decided, - &avd->auditallow, &avd->auditdeny, - &avd->seqno, &avd->flags); - if (ret < 5) { - ret = -1; - goto out2; - } else if (ret < 6) - avd->flags = 0; - - map_decision(tclass, avd); - - ret = 0; - out2: - free(buf); - out: - close(fd); - return ret; -} - diff --git a/src/compute_create.c b/src/compute_create.c deleted file mode 100644 index d3b16c9..0000000 --- a/src/compute_create.c +++ /dev/null @@ -1,61 +0,0 @@ -#include <unistd.h> -#include <sys/types.h> -#include <fcntl.h> -#include <stdlib.h> -#include <stdio.h> -#include <errno.h> -#include <string.h> -#include <limits.h> -#include "selinux_internal.h" -#include "policy.h" -#include "mapping.h" - -int security_compute_create(const char * scon, - const char * tcon, - security_class_t tclass, - char ** newcon) -{ - char path[PATH_MAX]; - char *buf; - size_t size; - int fd, ret; - - if (!selinux_mnt) { - errno = ENOENT; - return -1; - } - - snprintf(path, sizeof path, "%s/create", selinux_mnt); - fd = open(path, O_RDWR); - if (fd < 0) - return -1; - - size = selinux_page_size; - buf = malloc(size); - if (!buf) { - ret = -1; - goto out; - } - snprintf(buf, size, "%s %s %hu", scon, tcon, unmap_class(tclass)); - - ret = write(fd, buf, strlen(buf)); - if (ret < 0) - goto out2; - - memset(buf, 0, size); - ret = read(fd, buf, size - 1); - if (ret < 0) - goto out2; - - *newcon = strdup(buf); - if (!(*newcon)) { - ret = -1; - goto out2; - } - ret = 0; - out2: - free(buf); - out: - close(fd); - return ret; -} diff --git a/src/context.c b/src/context.c deleted file mode 100644 index 66abea1..0000000 --- a/src/context.c +++ /dev/null @@ -1,197 +0,0 @@ -#include "context_internal.h" -#include <string.h> -#include <stdio.h> -#include <stdlib.h> -#include <errno.h> - -#define COMP_USER 0 -#define COMP_ROLE 1 -#define COMP_TYPE 2 -#define COMP_RANGE 3 - -typedef struct { - char *current_str; /* This is made up-to-date only when needed */ - char *(component[4]); -} context_private_t; - -/* - * Allocate a new context, initialized from str. There must be 3 or - * 4 colon-separated components and no whitespace in any component other - * than the MLS component. - */ -context_t context_new(const char *str) -{ - int i, count; - errno = 0; - context_private_t *n = - (context_private_t *) malloc(sizeof(context_private_t)); - context_t result = (context_t) malloc(sizeof(context_s_t)); - const char *p, *tok; - - if (result) - result->ptr = n; - else - free(n); - if (n == 0 || result == 0) { - goto err; - } - n->current_str = n->component[0] = n->component[1] = n->component[2] = - n->component[3] = 0; - for (i = count = 0, p = str; *p; p++) { - switch (*p) { - case ':': - count++; - break; - case '\n': - case '\t': - case '\r': - goto err; /* sanity check */ - case ' ': - if (count < 3) - goto err; /* sanity check */ - } - } - /* - * Could be anywhere from 2 - 5 - * e.g user:role:type to user:role:type:sens1:cata-sens2:catb - */ - if (count < 2 || count > 5) { /* might not have a range */ - goto err; - } - - n->component[3] = 0; - for (i = 0, tok = str; *tok; i++) { - if (i < 3) - for (p = tok; *p && *p != ':'; p++) { /* empty */ - } else { - /* MLS range is one component */ - for (p = tok; *p; p++) { /* empty */ - } - } - n->component[i] = (char *)malloc(p - tok + 1); - if (n->component[i] == 0) - goto err; - strncpy(n->component[i], tok, p - tok); - n->component[i][p - tok] = '\0'; - tok = *p ? p + 1 : p; - } - return result; - err: - if (errno == 0) errno = EINVAL; - context_free(result); - return 0; -} - -hidden_def(context_new) - -static void conditional_free(char **v) -{ - if (*v) { - free(*v); - } - *v = 0; -} - -/* - * free all storage used by a context. Safe to call with - * null pointer. - */ -void context_free(context_t context) -{ - context_private_t *n; - int i; - if (context) { - n = context->ptr; - if (n) { - conditional_free(&n->current_str); - for (i = 0; i < 4; i++) { - conditional_free(&n->component[i]); - } - free(n); - } - free(context); - } -} - -hidden_def(context_free) - -/* - * Return a pointer to the string value of the context. - */ -char *context_str(context_t context) -{ - context_private_t *n = context->ptr; - int i; - size_t total = 0; - conditional_free(&n->current_str); - for (i = 0; i < 4; i++) { - if (n->component[i]) { - total += strlen(n->component[i]) + 1; - } - } - n->current_str = malloc(total); - if (n->current_str != 0) { - char *cp = n->current_str; - - strcpy(cp, n->component[0]); - cp += strlen(cp); - for (i = 1; i < 4; i++) { - if (n->component[i]) { - *cp++ = ':'; - strcpy(cp, n->component[i]); - cp += strlen(cp); - } - } - } - return n->current_str; -} - -hidden_def(context_str) - -/* Returns nonzero iff failed */ -static int set_comp(context_private_t * n, int idx, const char *str) -{ - char *t = NULL; - const char *p; - if (str) { - t = (char *)malloc(strlen(str) + 1); - if (!t) { - return 1; - } - for (p = str; *p; p++) { - if (*p == '\t' || *p == '\n' || *p == '\r' || - ((*p == ':' || *p == ' ') && idx != COMP_RANGE)) { - free(t); - errno = EINVAL; - return 1; - } - } - strcpy(t, str); - } - conditional_free(&n->component[idx]); - n->component[idx] = t; - return 0; -} - -#define def_get(name,tag) \ -const char * context_ ## name ## _get(context_t context) \ -{ \ - context_private_t *n = context->ptr; \ - return n->component[tag]; \ -} \ -hidden_def(context_ ## name ## _get) - -def_get(type, COMP_TYPE) - def_get(user, COMP_USER) - def_get(range, COMP_RANGE) - def_get(role, COMP_ROLE) -#define def_set(name,tag) \ -int context_ ## name ## _set(context_t context, const char* str) \ -{ \ - return set_comp(context->ptr,tag,str);\ -} \ -hidden_def(context_ ## name ## _set) - def_set(type, COMP_TYPE) - def_set(role, COMP_ROLE) - def_set(user, COMP_USER) - def_set(range, COMP_RANGE) diff --git a/src/context_internal.h b/src/context_internal.h deleted file mode 100644 index 3c71e80..0000000 --- a/src/context_internal.h +++ /dev/null @@ -1,14 +0,0 @@ -#include <selinux/context.h> -#include "dso.h" - -hidden_proto(context_new) - hidden_proto(context_free) - hidden_proto(context_str) - hidden_proto(context_type_set) - hidden_proto(context_type_get) - hidden_proto(context_role_set) - hidden_proto(context_role_get) - hidden_proto(context_user_set) - hidden_proto(context_user_get) - hidden_proto(context_range_set) - hidden_proto(context_range_get) diff --git a/src/deny_unknown.c b/src/deny_unknown.c deleted file mode 100644 index c93998a..0000000 --- a/src/deny_unknown.c +++ /dev/null @@ -1,40 +0,0 @@ -#include <unistd.h> -#include <sys/types.h> -#include <fcntl.h> -#include <stdlib.h> -#include <errno.h> -#include <string.h> -#include "selinux_internal.h" -#include "policy.h" -#include <stdio.h> -#include <limits.h> - -int security_deny_unknown(void) -{ - int fd, ret, deny_unknown = 0; - char path[PATH_MAX]; - char buf[20]; - - if (!selinux_mnt) { - errno = ENOENT; - return -1; - } - - snprintf(path, sizeof(path), "%s/deny_unknown", selinux_mnt); - fd = open(path, O_RDONLY); - if (fd < 0) - return -1; - - memset(buf, 0, sizeof(buf)); - ret = read(fd, buf, sizeof(buf) - 1); - close(fd); - if (ret < 0) - return -1; - - if (sscanf(buf, "%d", &deny_unknown) != 1) - return -1; - - return deny_unknown; -} - -hidden_def(security_deny_unknown); diff --git a/src/disable.c b/src/disable.c deleted file mode 100644 index dac0f5b..0000000 --- a/src/disable.c +++ /dev/null @@ -1,38 +0,0 @@ -#include <unistd.h> -#include <sys/types.h> -#include <fcntl.h> -#include <stdlib.h> -#include <errno.h> -#include <string.h> -#include "selinux_internal.h" -#include "policy.h" -#include <stdio.h> -#include <limits.h> - -int security_disable(void) -{ - int fd, ret; - char path[PATH_MAX]; - char buf[20]; - - if (!selinux_mnt) { - errno = ENOENT; - return -1; - } - - snprintf(path, sizeof path, "%s/disable", selinux_mnt); - fd = open(path, O_WRONLY); - if (fd < 0) - return -1; - - buf[0] = '1'; - buf[1] = '\0'; - ret = write(fd, buf, strlen(buf)); - close(fd); - if (ret < 0) - return -1; - - return 0; -} - -hidden_def(security_disable) diff --git a/src/dso.h b/src/dso.h deleted file mode 100644 index 12c3d11..0000000 --- a/src/dso.h +++ /dev/null @@ -1,23 +0,0 @@ -#ifndef _SELINUX_DSO_H -#define _SELINUX_DSO_H 1 - -#ifdef SHARED -# define hidden __attribute__ ((visibility ("hidden"))) -# define hidden_proto(fct) __hidden_proto (fct, fct##_internal) -# define __hidden_proto(fct, internal) \ - extern __typeof (fct) internal; \ - extern __typeof (fct) fct __asm (#internal) hidden; -# if defined(__alpha__) || defined(__mips__) -# define hidden_def(fct) \ - asm (".globl " #fct "\n" #fct " = " #fct "_internal"); -# else -# define hidden_def(fct) \ - asm (".globl " #fct "\n.set " #fct ", " #fct "_internal"); -#endif -#else -# define hidden -# define hidden_proto(fct) -# define hidden_def(fct) -#endif - -#endif diff --git a/src/enabled.c b/src/enabled.c deleted file mode 100644 index c60eb19..0000000 --- a/src/enabled.c +++ /dev/null @@ -1,54 +0,0 @@ -#include <unistd.h> -#include <fcntl.h> -#include <string.h> -#include "selinux_internal.h" -#include <stdlib.h> -#include <errno.h> -#include <limits.h> -#include <stdio.h> -#include "policy.h" - -int is_selinux_enabled(void) -{ - /* init_selinuxmnt() gets called before this function. We - * will assume that if a selinux file system is mounted, then - * selinux is enabled. */ - return (selinux_mnt ? 1 : 0); -} - -hidden_def(is_selinux_enabled) - -/* - * Function: is_selinux_mls_enabled() - * Return: 1 on success - * 0 on failure - */ -int is_selinux_mls_enabled(void) -{ - char buf[20], path[PATH_MAX]; - int fd, ret, enabled = 0; - - if (!selinux_mnt) - return enabled; - - snprintf(path, sizeof path, "%s/mls", selinux_mnt); - fd = open(path, O_RDONLY); - if (fd < 0) - return enabled; - - memset(buf, 0, sizeof buf); - - do { - ret = read(fd, buf, sizeof buf - 1); - } while (ret < 0 && errno == EINTR); - close(fd); - if (ret < 0) - return enabled; - - if (!strcmp(buf, "1")) - enabled = 1; - - return enabled; -} - -hidden_def(is_selinux_mls_enabled) diff --git a/src/fgetfilecon.c b/src/fgetfilecon.c deleted file mode 100644 index 33cdc27..0000000 --- a/src/fgetfilecon.c +++ /dev/null @@ -1,51 +0,0 @@ -#include <unistd.h> -#include <fcntl.h> -#include <string.h> -#include <stdlib.h> -#include <errno.h> -#include <sys/xattr.h> -#include "selinux_internal.h" -#include "policy.h" - -int fgetfilecon(int fd, char ** context) -{ - char *buf; - ssize_t size; - ssize_t ret; - - size = INITCONTEXTLEN + 1; - buf = malloc(size); - if (!buf) - return -1; - memset(buf, 0, size); - - ret = fgetxattr(fd, XATTR_NAME_SELINUX, buf, size - 1); - if (ret < 0 && errno == ERANGE) { - char *newbuf; - - size = fgetxattr(fd, XATTR_NAME_SELINUX, NULL, 0); - if (size < 0) - goto out; - - size++; - newbuf = realloc(buf, size); - if (!newbuf) - goto out; - - buf = newbuf; - memset(buf, 0, size); - ret = fgetxattr(fd, XATTR_NAME_SELINUX, buf, size - 1); - } - out: - if (ret == 0) { - /* Re-map empty attribute values to errors. */ - errno = EOPNOTSUPP; - ret = -1; - } - if (ret < 0) - free(buf); - else - *context = buf; - return ret; -} - diff --git a/src/freecon.c b/src/freecon.c deleted file mode 100644 index 5290dfa..0000000 --- a/src/freecon.c +++ /dev/null @@ -1,11 +0,0 @@ -#include <unistd.h> -#include "selinux_internal.h" -#include <stdlib.h> -#include <errno.h> - -void freecon(char * con) -{ - free(con); -} - -hidden_def(freecon) diff --git a/src/fsetfilecon.c b/src/fsetfilecon.c deleted file mode 100644 index 17f8875..0000000 --- a/src/fsetfilecon.c +++ /dev/null @@ -1,15 +0,0 @@ -#include <unistd.h> -#include <fcntl.h> -#include <string.h> -#include <stdlib.h> -#include <errno.h> -#include <sys/xattr.h> -#include "selinux_internal.h" -#include "policy.h" - -int fsetfilecon(int fd, const char *context) -{ - return fsetxattr(fd, XATTR_NAME_SELINUX, context, strlen(context) + 1, - 0); -} - diff --git a/src/get_initial_context.c b/src/get_initial_context.c deleted file mode 100644 index 64863dd..0000000 --- a/src/get_initial_context.c +++ /dev/null @@ -1,55 +0,0 @@ -#include <unistd.h> -#include <sys/types.h> -#include <fcntl.h> -#include <stdlib.h> -#include <stdio.h> -#include <errno.h> -#include <string.h> -#include "selinux_internal.h" -#include "policy.h" -#include <limits.h> - -#define SELINUX_INITCON_DIR "/initial_contexts/" - -int security_get_initial_context(const char * name, char ** con) -{ - char path[PATH_MAX]; - char *buf; - size_t size; - int fd, ret; - - if (!selinux_mnt) { - errno = ENOENT; - return -1; - } - - snprintf(path, sizeof path, "%s%s%s", - selinux_mnt, SELINUX_INITCON_DIR, name); - fd = open(path, O_RDONLY); - if (fd < 0) - return -1; - - size = selinux_page_size; - buf = malloc(size); - if (!buf) { - ret = -1; - goto out; - } - memset(buf, 0, size); - ret = read(fd, buf, size - 1); - if (ret < 0) - goto out2; - - *con = strdup(buf); - if (!(*con)) { - ret = -1; - goto out2; - } - ret = 0; - out2: - free(buf); - out: - close(fd); - return ret; -} - diff --git a/src/getenforce.c b/src/getenforce.c deleted file mode 100644 index 4fb516a..0000000 --- a/src/getenforce.c +++ /dev/null @@ -1,40 +0,0 @@ -#include <unistd.h> -#include <sys/types.h> -#include <fcntl.h> -#include <stdlib.h> -#include <errno.h> -#include <string.h> -#include "selinux_internal.h" -#include "policy.h" -#include <stdio.h> -#include <limits.h> - -int security_getenforce(void) -{ - int fd, ret, enforce = 0; - char path[PATH_MAX]; - char buf[20]; - - if (!selinux_mnt) { - errno = ENOENT; - return -1; - } - - snprintf(path, sizeof path, "%s/enforce", selinux_mnt); - fd = open(path, O_RDONLY); - if (fd < 0) - return -1; - - memset(buf, 0, sizeof buf); - ret = read(fd, buf, sizeof buf - 1); - close(fd); - if (ret < 0) - return -1; - - if (sscanf(buf, "%d", &enforce) != 1) - return -1; - - return enforce; -} - -hidden_def(security_getenforce) diff --git a/src/getfilecon.c b/src/getfilecon.c deleted file mode 100644 index 02037de..0000000 --- a/src/getfilecon.c +++ /dev/null @@ -1,50 +0,0 @@ -#include <unistd.h> -#include <fcntl.h> -#include <string.h> -#include "selinux_internal.h" -#include <stdlib.h> -#include <errno.h> -#include <sys/xattr.h> -#include "policy.h" - -int getfilecon(const char *path, char ** context) -{ - char *buf; - ssize_t size; - ssize_t ret; - - size = INITCONTEXTLEN + 1; - buf = malloc(size); - if (!buf) - return -1; - memset(buf, 0, size); - - ret = getxattr(path, XATTR_NAME_SELINUX, buf, size - 1); - if (ret < 0 && errno == ERANGE) { - char *newbuf; - - size = getxattr(path, XATTR_NAME_SELINUX, NULL, 0); - if (size < 0) - goto out; - - size++; - newbuf = realloc(buf, size); - if (!newbuf) - goto out; - - buf = newbuf; - memset(buf, 0, size); - ret = getxattr(path, XATTR_NAME_SELINUX, buf, size - 1); - } - out: - if (ret == 0) { - /* Re-map empty attribute values to errors. */ - errno = EOPNOTSUPP; - ret = -1; - } - if (ret < 0) - free(buf); - else - *context = buf; - return ret; -} diff --git a/src/getpeercon.c b/src/getpeercon.c deleted file mode 100644 index 3bd29dc..0000000 --- a/src/getpeercon.c +++ /dev/null @@ -1,45 +0,0 @@ -#include <unistd.h> -#include <fcntl.h> -#include <string.h> -#include <stdlib.h> -#include <errno.h> -#include <sys/socket.h> -#include "selinux_internal.h" -#include "policy.h" - -#ifndef SO_PEERSEC -#define SO_PEERSEC 31 -#endif - -int getpeercon(int fd, char ** context) -{ - char *buf; - socklen_t size; - ssize_t ret; - - size = INITCONTEXTLEN + 1; - buf = malloc(size); - if (!buf) - return -1; - memset(buf, 0, size); - - ret = getsockopt(fd, SOL_SOCKET, SO_PEERSEC, buf, &size); - if (ret < 0 && errno == ERANGE) { - char *newbuf; - - newbuf = realloc(buf, size); - if (!newbuf) - goto out; - - buf = newbuf; - memset(buf, 0, size); - ret = getsockopt(fd, SOL_SOCKET, SO_PEERSEC, buf, &size); - } - out: - if (ret < 0) - free(buf); - else - *context = buf; - return ret; -} - diff --git a/src/init.c b/src/init.c deleted file mode 100644 index 65bc01b..0000000 --- a/src/init.c +++ /dev/null @@ -1,123 +0,0 @@ -#include <unistd.h> -#include <fcntl.h> -#include <string.h> -#include <stdlib.h> -#include <errno.h> -#include <ctype.h> -#include <stdio.h> -#include <dlfcn.h> - -#ifdef DARWIN -#include <sys/param.h> -#include <sys/mount.h> -#else -#include <sys/vfs.h> -#endif - -#include <stdint.h> -#include <limits.h> - -#include "dso.h" -#include "policy.h" -#include "selinux_internal.h" - -char *selinux_mnt = NULL; -int selinux_page_size = 0; - -static void init_selinuxmnt(void) -{ - char buf[BUFSIZ], *p; - FILE *fp=NULL; - struct statfs sfbuf; - int rc; - char *bufp; - int exists = 0; - - if (selinux_mnt) - return; - - /* We check to see if the preferred mount point for selinux file - * system has a selinuxfs. */ - do { - rc = statfs(SELINUXMNT, &sfbuf); - } while (rc < 0 && errno == EINTR); - if (rc == 0) { - if ((uint32_t)sfbuf.f_type == (uint32_t)SELINUX_MAGIC) { - selinux_mnt = strdup(SELINUXMNT); - return; - } - } - - /* Drop back to detecting it the long way. */ - fp = fopen("/proc/filesystems", "r"); - if (!fp) - return; - - while ((bufp = fgets(buf, sizeof buf - 1, fp)) != NULL) { - if (strstr(buf, "selinuxfs")) { - exists = 1; - break; - } - } - - if (!exists) - goto out; - - fclose(fp); - - /* At this point, the usual spot doesn't have an selinuxfs so - * we look around for it */ - fp = fopen("/proc/mounts", "r"); - if (!fp) - goto out; - - while ((bufp = fgets(buf, sizeof buf - 1, fp)) != NULL) { - char *tmp; - p = strchr(buf, ' '); - if (!p) - goto out; - p++; - tmp = strchr(p, ' '); - if (!tmp) - goto out; - if (!strncmp(tmp + 1, "selinuxfs ", 10)) { - *tmp = '\0'; - break; - } - } - - /* If we found something, dup it */ - if (bufp) - selinux_mnt = strdup(p); - - out: - if (fp) - fclose(fp); - return; -} - -void fini_selinuxmnt(void) -{ - free(selinux_mnt); - selinux_mnt = NULL; -} - -void set_selinuxmnt(const char *mnt) -{ - selinux_mnt = strdup(mnt); -} - -hidden_def(set_selinuxmnt) - -static void init_lib(void) __attribute__ ((constructor)); -static void init_lib(void) -{ - selinux_page_size = sysconf(_SC_PAGE_SIZE); - init_selinuxmnt(); -} - -static void fini_lib(void) __attribute__ ((destructor)); -static void fini_lib(void) -{ - fini_selinuxmnt(); -} diff --git a/src/label.c b/src/label.c deleted file mode 100644 index 6a67b65..0000000 --- a/src/label.c +++ /dev/null @@ -1,173 +0,0 @@ -/* - * Generalized labeling frontend for userspace object managers. - * - * Author : Eamon Walsh <ewalsh@epoch.ncsc.mil> - */ - -#include <sys/types.h> -#include <ctype.h> -#include <errno.h> -#include <stdio.h> -#include <stdlib.h> -#include <string.h> -#include <selinux/selinux.h> -#include "callbacks.h" -#include "label_internal.h" - -#define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0])) - -typedef int (*selabel_initfunc)(struct selabel_handle *rec, - const struct selinux_opt *opts, - unsigned nopts); - -static selabel_initfunc initfuncs[] = { - &selabel_file_init, - NULL, - NULL, - NULL, - &selabel_property_init, - &selabel_service_init, -}; - -/* - * Validation functions - */ - -static inline int selabel_is_validate_set(const struct selinux_opt *opts, - unsigned n) -{ - while (n--) - if (opts[n].type == SELABEL_OPT_VALIDATE) - return !!opts[n].value; - - return 0; -} - -int selabel_validate(struct selabel_handle *rec, - struct selabel_lookup_rec *contexts) -{ - int rc = 0; - - if (!rec->validating || contexts->validated) - goto out; - - rc = selinux_validate(&contexts->ctx_raw); - if (rc < 0) - goto out; - - contexts->validated = 1; -out: - return rc; -} - -/* - * Public API - */ - -struct selabel_handle *selabel_open(unsigned int backend, - const struct selinux_opt *opts, - unsigned nopts) -{ - struct selabel_handle *rec = NULL; - - if (backend >= ARRAY_SIZE(initfuncs)) { - errno = EINVAL; - goto out; - } - - if (initfuncs[backend] == NULL) - goto out; - - rec = (struct selabel_handle *)malloc(sizeof(*rec)); - if (!rec) - goto out; - - memset(rec, 0, sizeof(*rec)); - rec->backend = backend; - rec->validating = selabel_is_validate_set(opts, nopts); - - if ((*initfuncs[backend])(rec, opts, nopts)) { - free(rec->spec_file); - free(rec); - rec = NULL; - } - -out: - return rec; -} - -static struct selabel_lookup_rec * -selabel_lookup_common(struct selabel_handle *rec, - const char *key, int type) -{ - struct selabel_lookup_rec *lr; - lr = rec->func_lookup(rec, key, type); - if (!lr) - return NULL; - - return lr; -} - -int selabel_lookup(struct selabel_handle *rec, char **con, - const char *key, int type) -{ - struct selabel_lookup_rec *lr; - - lr = selabel_lookup_common(rec, key, type); - if (!lr) - return -1; - - *con = strdup(lr->ctx_raw); - return *con ? 0 : -1; -} - -bool selabel_partial_match(struct selabel_handle *rec, const char *key) -{ - if (!rec->func_partial_match) { - /* - * If the label backend does not support partial matching, - * then assume a match is possible. - */ - return true; - } - return rec->func_partial_match(rec, key); -} - -int selabel_lookup_best_match(struct selabel_handle *rec, char **con, - const char *key, const char **aliases, int type) -{ - struct selabel_lookup_rec *lr; - - if (!rec->func_lookup_best_match) { - errno = ENOTSUP; - return -1; - } - - lr = rec->func_lookup_best_match(rec, key, aliases, type); - if (!lr) - return -1; - - *con = strdup(lr->ctx_raw); - return *con ? 0 : -1; -} - -enum selabel_cmp_result selabel_cmp(struct selabel_handle *h1, - struct selabel_handle *h2) -{ - if (!h1->func_cmp || h1->func_cmp != h2->func_cmp) - return SELABEL_INCOMPARABLE; - - return h1->func_cmp(h1, h2); -} - -void selabel_close(struct selabel_handle *rec) -{ - rec->func_close(rec); - free(rec->spec_file); - free(rec); -} - -void selabel_stats(struct selabel_handle *rec) -{ - rec->func_stats(rec); -} diff --git a/src/label_android_property.c b/src/label_android_property.c deleted file mode 100644 index b0a807c..0000000 --- a/src/label_android_property.c +++ /dev/null @@ -1,350 +0,0 @@ -/* - * Property Service contexts backend for labeling Android - * property keys - */ - -#include <stdarg.h> -#include <string.h> -#include <ctype.h> -#include <errno.h> -#include <limits.h> -#include <sys/types.h> -#include <sys/stat.h> -#include "callbacks.h" -#include "label_internal.h" - -/* A property security context specification. */ -typedef struct spec { - struct selabel_lookup_rec lr; /* holds contexts for lookup result */ - char *property_key; /* property key string */ -} spec_t; - -/* Our stored configuration */ -struct saved_data { - /* - * The array of specifications is sorted for longest - * prefix match - */ - spec_t *spec_arr; - unsigned int nspec; /* total number of specifications */ -}; - -static int cmp(const void *A, const void *B) -{ - const struct spec *sp1 = A, *sp2 = B; - - if (strncmp(sp1->property_key, "*", 1) == 0) - return 1; - if (strncmp(sp2->property_key, "*", 1) == 0) - return -1; - - size_t L1 = strlen(sp1->property_key); - size_t L2 = strlen(sp2->property_key); - - return (L1 < L2) - (L1 > L2); -} - -/* - * Warn about duplicate specifications. - */ -static int nodups_specs(struct saved_data *data, const char *path) -{ - int rc = 0; - unsigned int ii, jj; - struct spec *curr_spec, *spec_arr = data->spec_arr; - - for (ii = 0; ii < data->nspec; ii++) { - curr_spec = &spec_arr[ii]; - for (jj = ii + 1; jj < data->nspec; jj++) { - if (!strcmp(spec_arr[jj].property_key, - curr_spec->property_key)) { - rc = -1; - errno = EINVAL; - if (strcmp(spec_arr[jj].lr.ctx_raw, - curr_spec->lr.ctx_raw)) { - selinux_log - (SELINUX_ERROR, - "%s: Multiple different specifications for %s (%s and %s).\n", - path, curr_spec->property_key, - spec_arr[jj].lr.ctx_raw, - curr_spec->lr.ctx_raw); - } else { - selinux_log - (SELINUX_ERROR, - "%s: Multiple same specifications for %s.\n", - path, curr_spec->property_key); - } - } - } - } - return rc; -} - -static int process_line(struct selabel_handle *rec, - const char *path, char *line_buf, - int pass, unsigned lineno) -{ - int items; - char *prop = NULL, *context = NULL; - struct saved_data *data = (struct saved_data *)rec->data; - spec_t *spec_arr = data->spec_arr; - unsigned int nspec = data->nspec; - const char *errbuf = NULL; - - items = read_spec_entries(line_buf, &errbuf, 2, &prop, &context); - if (items < 0) { - items = errno; - selinux_log(SELINUX_ERROR, - "%s: line %u error due to: %s\n", path, - lineno, errbuf ?: strerror(errno)); - errno = items; - return -1; - } - - if (items == 0) - return items; - - if (items != 2) { - selinux_log(SELINUX_ERROR, - "%s: line %u is missing fields\n", path, - lineno); - free(prop); - errno = EINVAL; - return -1; - } - - if (pass == 0) { - free(prop); - free(context); - } else if (pass == 1) { - /* On the second pass, process and store the specification in spec. */ - spec_arr[nspec].property_key = prop; - spec_arr[nspec].lr.ctx_raw = context; - - if (rec->validating) { - if (selabel_validate(rec, &spec_arr[nspec].lr) < 0) { - selinux_log(SELINUX_ERROR, - "%s: line %u has invalid context %s\n", - path, lineno, spec_arr[nspec].lr.ctx_raw); - errno = EINVAL; - return -1; - } - } - } - - data->nspec = ++nspec; - return 0; -} - -static int init(struct selabel_handle *rec, const struct selinux_opt *opts, - unsigned n) -{ - struct saved_data *data = (struct saved_data *)rec->data; - const char *path = NULL; - FILE *fp; - char line_buf[BUFSIZ]; - unsigned int lineno, maxnspec, pass; - int status = -1; - struct stat sb; - - /* Process arguments */ - while (n--) - switch (opts[n].type) { - case SELABEL_OPT_PATH: - path = opts[n].value; - break; - } - - if (!path) - return -1; - - /* Open the specification file. */ - if ((fp = fopen(path, "r")) == NULL) - return -1; - - if (fstat(fileno(fp), &sb) < 0) - goto finish; - errno = EINVAL; - if (!S_ISREG(sb.st_mode)) - goto finish; - - /* - * Two passes of the specification file. First is to get the size. - * After the first pass, the spec array is malloced to the appropriate - * size. Second pass is to populate the spec array and check for - * dups. - */ - maxnspec = UINT_MAX / sizeof(spec_t); - for (pass = 0; pass < 2; pass++) { - data->nspec = 0; - lineno = 0; - - while (fgets(line_buf, sizeof(line_buf) - 1, fp) - && data->nspec < maxnspec) { - if (process_line(rec, path, line_buf, pass, ++lineno) - != 0) - goto finish; - } - - if (pass == 1) { - status = nodups_specs(data, path); - - if (status) - goto finish; - } - - if (pass == 0) { - if (data->nspec == 0) { - status = 0; - goto finish; - } - - if (NULL == (data->spec_arr = - malloc(sizeof(spec_t) * data->nspec))) - goto finish; - - memset(data->spec_arr, 0, sizeof(spec_t) * data->nspec); - maxnspec = data->nspec; - rewind(fp); - } - } - - qsort(data->spec_arr, data->nspec, sizeof(struct spec), cmp); - - status = 0; -finish: - fclose(fp); - return status; -} - -/* - * Backend interface routines - */ -static void closef(struct selabel_handle *rec) -{ - struct saved_data *data = (struct saved_data *)rec->data; - struct spec *spec; - unsigned int i; - - for (i = 0; i < data->nspec; i++) { - spec = &data->spec_arr[i]; - free(spec->property_key); - free(spec->lr.ctx_raw); - free(spec->lr.ctx_trans); - } - - if (data->spec_arr) - free(data->spec_arr); - - free(data); -} - -static struct selabel_lookup_rec *lookup(struct selabel_handle *rec, - const char *key, - int __attribute__((unused)) type) -{ - struct saved_data *data = (struct saved_data *)rec->data; - spec_t *spec_arr = data->spec_arr; - unsigned int i; - struct selabel_lookup_rec *ret = NULL; - - if (!data->nspec) { - errno = ENOENT; - goto finish; - } - - for (i = 0; i < data->nspec; i++) { - if (strncmp(spec_arr[i].property_key, key, - strlen(spec_arr[i].property_key)) == 0) { - break; - } - if (strncmp(spec_arr[i].property_key, "*", 1) == 0) - break; - } - - if (i >= data->nspec) { - /* No matching specification. */ - errno = ENOENT; - goto finish; - } - - ret = &spec_arr[i].lr; - -finish: - return ret; -} - -static struct selabel_lookup_rec *service_lookup(struct selabel_handle *rec, - const char *key, - int __attribute__((unused)) type) -{ - struct saved_data *data = (struct saved_data *) rec->data; - spec_t *spec_arr = data->spec_arr; - unsigned int i; - struct selabel_lookup_rec *ret = NULL; - - if (!data->nspec) { - errno = ENOENT; - goto finish; - } - - for (i = 0; i < data->nspec; i++) { - if (strcmp(spec_arr[i].property_key, key) == 0) { - break; - } - if (strcmp(spec_arr[i].property_key, "*") == 0) break; - } - - if (i >= data->nspec) { - /* No matching specification. */ - errno = ENOENT; - goto finish; - } - - ret = &spec_arr[i].lr; - -finish: - return ret; -} - -static void stats(struct selabel_handle __attribute__((unused)) *rec) -{ - selinux_log(SELINUX_WARNING, "'stats' functionality not implemented.\n"); -} - -int selabel_property_init(struct selabel_handle *rec, - const struct selinux_opt *opts, - unsigned nopts) -{ - struct saved_data *data; - - data = (struct saved_data *)malloc(sizeof(*data)); - if (!data) - return -1; - memset(data, 0, sizeof(*data)); - - rec->data = data; - rec->func_close = &closef; - rec->func_stats = &stats; - rec->func_lookup = &lookup; - - return init(rec, opts, nopts); -} - -int selabel_service_init(struct selabel_handle *rec, - const struct selinux_opt *opts, - unsigned nopts) -{ - struct saved_data *data; - - data = (struct saved_data *)calloc(1, sizeof(*data)); - if (!data) - return -1; - - rec->data = data; - rec->func_close = &closef; - rec->func_stats = &stats; - rec->func_lookup = &service_lookup; - - return init(rec, opts, nopts); -} diff --git a/src/label_file.c b/src/label_file.c deleted file mode 100644 index d3e67c0..0000000 --- a/src/label_file.c +++ /dev/null @@ -1,859 +0,0 @@ -/* - * File contexts backend for labeling system - * - * Author : Eamon Walsh <ewalsh@tycho.nsa.gov> - * Author : Stephen Smalley <sds@tycho.nsa.gov> - */ - -#include <assert.h> -#include <fcntl.h> -#include <stdarg.h> -#include <string.h> -#include <stdio.h> -#include <ctype.h> -#include <errno.h> -#include <limits.h> -#include <stdint.h> -#include <unistd.h> -#include <sys/mman.h> -#include <sys/types.h> -#include <sys/stat.h> - -#include "callbacks.h" -#include "label_internal.h" -#include "label_file.h" - -/* - * Internals, mostly moved over from matchpathcon.c - */ - -/* return the length of the text that is the stem of a file name */ -static int get_stem_from_file_name(const char *const buf) -{ - const char *tmp = strchr(buf + 1, '/'); - - if (!tmp) - return 0; - return tmp - buf; -} - -/* find the stem of a file name, returns the index into stem_arr (or -1 if - * there is no match - IE for a file in the root directory or a regex that is - * too complex for us). Makes buf point to the text AFTER the stem. */ -static int find_stem_from_file(struct saved_data *data, const char **buf) -{ - int i; - int stem_len = get_stem_from_file_name(*buf); - - if (!stem_len) - return -1; - for (i = 0; i < data->num_stems; i++) { - if (stem_len == data->stem_arr[i].len - && !strncmp(*buf, data->stem_arr[i].buf, stem_len)) { - *buf += stem_len; - return i; - } - } - return -1; -} - -/* - * Warn about duplicate specifications. - */ -static int nodups_specs(struct saved_data *data, const char *path) -{ - int rc = 0; - unsigned int ii, jj; - struct spec *curr_spec, *spec_arr = data->spec_arr; - - for (ii = 0; ii < data->nspec; ii++) { - curr_spec = &spec_arr[ii]; - for (jj = ii + 1; jj < data->nspec; jj++) { - if ((!strcmp(spec_arr[jj].regex_str, - curr_spec->regex_str)) - && (!spec_arr[jj].mode || !curr_spec->mode - || spec_arr[jj].mode == curr_spec->mode)) { - rc = -1; - errno = EINVAL; - if (strcmp(spec_arr[jj].lr.ctx_raw, - curr_spec->lr.ctx_raw)) { - selinux_log - (SELINUX_ERROR, - "%s: Multiple different specifications for %s (%s and %s).\n", - path, curr_spec->regex_str, - spec_arr[jj].lr.ctx_raw, - curr_spec->lr.ctx_raw); - } else { - selinux_log - (SELINUX_ERROR, - "%s: Multiple same specifications for %s.\n", - path, curr_spec->regex_str); - } - } - } - } - return rc; -} - -static int load_mmap(struct selabel_handle *rec, const char *path, - struct stat *sb, bool isbinary) -{ - struct saved_data *data = (struct saved_data *)rec->data; - char mmap_path[PATH_MAX + 1]; - int mmapfd; - int rc; - struct stat mmap_stat; - char *addr, *str_buf; - size_t len; - int *stem_map; - struct mmap_area *mmap_area; - uint32_t i, magic, version; - uint32_t entry_len, stem_map_len, regex_array_len; - - if (isbinary) { - len = strlen(path); - if (len >= sizeof(mmap_path)) - return -1; - strcpy(mmap_path, path); - } else { - rc = snprintf(mmap_path, sizeof(mmap_path), "%s.bin", path); - if (rc >= (int)sizeof(mmap_path)) - return -1; - } - - mmapfd = open(mmap_path, O_RDONLY | O_CLOEXEC); - if (mmapfd < 0) - return -1; - - rc = fstat(mmapfd, &mmap_stat); - if (rc < 0) { - close(mmapfd); - return -1; - } - - /* if mmap is old, ignore it */ - if (mmap_stat.st_mtime < sb->st_mtime) { - close(mmapfd); - return -1; - } - - /* ok, read it in... */ - len = mmap_stat.st_size; - len += (sysconf(_SC_PAGE_SIZE) - 1); - len &= ~(sysconf(_SC_PAGE_SIZE) - 1); - - mmap_area = malloc(sizeof(*mmap_area)); - if (!mmap_area) { - close(mmapfd); - return -1; - } - - addr = mmap(NULL, len, PROT_READ, MAP_PRIVATE, mmapfd, 0); - close(mmapfd); - if (addr == MAP_FAILED) { - free(mmap_area); - perror("mmap"); - return -1; - } - - /* save where we mmap'd the file to cleanup on close() */ - mmap_area->addr = mmap_area->next_addr = addr; - mmap_area->len = mmap_area->next_len = len; - mmap_area->next = data->mmap_areas; - data->mmap_areas = mmap_area; - - /* check if this looks like an fcontext file */ - rc = next_entry(&magic, mmap_area, sizeof(uint32_t)); - if (rc < 0 || magic != SELINUX_MAGIC_COMPILED_FCONTEXT) - return -1; - - /* check if this version is higher than we understand */ - rc = next_entry(&version, mmap_area, sizeof(uint32_t)); - if (rc < 0 || version > SELINUX_COMPILED_FCONTEXT_MAX_VERS) - return -1; - - if (version >= SELINUX_COMPILED_FCONTEXT_PCRE_VERS) { - if (!regex_version()) { - return -1; - } - len = strlen(regex_version()); - - rc = next_entry(&entry_len, mmap_area, sizeof(uint32_t)); - if (rc < 0) - return -1; - - /* Check version lengths */ - if (len != entry_len) - return -1; - - /* Check if pcre version mismatch */ - str_buf = malloc(entry_len + 1); - if (!str_buf) - return -1; - - rc = next_entry(str_buf, mmap_area, entry_len); - if (rc < 0) { - free(str_buf); - return -1; - } - - str_buf[entry_len] = '\0'; - if ((strcmp(str_buf, regex_version()) != 0)) { - free(str_buf); - return -1; - } - free(str_buf); - } - - /* allocate the stems_data array */ - rc = next_entry(&stem_map_len, mmap_area, sizeof(uint32_t)); - if (rc < 0 || !stem_map_len) - return -1; - - /* - * map indexed by the stem # in the mmap file and contains the stem - * number in the data stem_arr - */ - stem_map = calloc(stem_map_len, sizeof(*stem_map)); - if (!stem_map) - return -1; - - for (i = 0; i < stem_map_len; i++) { - char *buf; - uint32_t stem_len; - int newid; - - /* the length does not inlude the nul */ - rc = next_entry(&stem_len, mmap_area, sizeof(uint32_t)); - if (rc < 0 || !stem_len) { - rc = -1; - goto err; - } - - /* Check for stem_len wrap around. */ - if (stem_len < UINT32_MAX) { - buf = (char *)mmap_area->next_addr; - /* Check if over-run before null check. */ - rc = next_entry(NULL, mmap_area, (stem_len + 1)); - if (rc < 0) - goto err; - - if (buf[stem_len] != '\0') { - rc = -1; - goto err; - } - } else { - rc = -1; - goto err; - } - - /* store the mapping between old and new */ - newid = find_stem(data, buf, stem_len); - if (newid < 0) { - newid = store_stem(data, buf, stem_len); - if (newid < 0) { - rc = newid; - goto err; - } - data->stem_arr[newid].from_mmap = 1; - } - stem_map[i] = newid; - } - - /* allocate the regex array */ - rc = next_entry(®ex_array_len, mmap_area, sizeof(uint32_t)); - if (rc < 0 || !regex_array_len) { - rc = -1; - goto err; - } - - for (i = 0; i < regex_array_len; i++) { - struct spec *spec; - int32_t stem_id, meta_chars; - uint32_t mode = 0, prefix_len = 0; - - rc = grow_specs(data); - if (rc < 0) - goto err; - - spec = &data->spec_arr[data->nspec]; - spec->from_mmap = 1; - spec->regcomp = 1; - - /* Process context */ - rc = next_entry(&entry_len, mmap_area, sizeof(uint32_t)); - if (rc < 0 || !entry_len) { - rc = -1; - goto err; - } - - str_buf = malloc(entry_len); - if (!str_buf) { - rc = -1; - goto err; - } - rc = next_entry(str_buf, mmap_area, entry_len); - if (rc < 0) - goto err; - - if (str_buf[entry_len - 1] != '\0') { - free(str_buf); - rc = -1; - goto err; - } - spec->lr.ctx_raw = str_buf; - - if (strcmp(spec->lr.ctx_raw, "<<none>>") && rec->validating) { - if (selabel_validate(rec, &spec->lr) < 0) { - selinux_log(SELINUX_ERROR, - "%s: context %s is invalid\n", mmap_path, spec->lr.ctx_raw); - goto err; - } - } - - /* Process regex string */ - rc = next_entry(&entry_len, mmap_area, sizeof(uint32_t)); - if (rc < 0 || !entry_len) { - rc = -1; - goto err; - } - - spec->regex_str = (char *)mmap_area->next_addr; - rc = next_entry(NULL, mmap_area, entry_len); - if (rc < 0) - goto err; - - if (spec->regex_str[entry_len - 1] != '\0') { - rc = -1; - goto err; - } - - /* Process mode */ - if (version >= SELINUX_COMPILED_FCONTEXT_MODE) - rc = next_entry(&mode, mmap_area, sizeof(uint32_t)); - else - rc = next_entry(&mode, mmap_area, sizeof(mode_t)); - if (rc < 0) - goto err; - - spec->mode = mode; - - /* map the stem id from the mmap file to the data->stem_arr */ - rc = next_entry(&stem_id, mmap_area, sizeof(int32_t)); - if (rc < 0) - goto err; - - if (stem_id < 0 || stem_id >= (int32_t)stem_map_len) - spec->stem_id = -1; - else - spec->stem_id = stem_map[stem_id]; - - /* retrieve the hasMetaChars bit */ - rc = next_entry(&meta_chars, mmap_area, sizeof(uint32_t)); - if (rc < 0) - goto err; - - spec->hasMetaChars = meta_chars; - /* and prefix length for use by selabel_lookup_best_match */ - if (version >= SELINUX_COMPILED_FCONTEXT_PREFIX_LEN) { - rc = next_entry(&prefix_len, mmap_area, - sizeof(uint32_t)); - if (rc < 0) - goto err; - - spec->prefix_len = prefix_len; - } - - rc = regex_load_mmap(mmap_area, &spec->regex); - if (rc < 0) - goto err; -#ifndef NO_PERSISTENTLY_STORED_PATTERNS - spec->regcomp = 1; -#else - spec->regcomp = 0; -#endif - - data->nspec++; - } - - /* win */ - rc = 0; -err: - free(stem_map); - - return rc; -} - -static int process_file(const char *path, const char *suffix, - struct selabel_handle *rec, const char *prefix) -{ - FILE *fp; - struct stat sb; - unsigned int lineno; - size_t line_len = 0; - char *line_buf = NULL; - int rc; - char stack_path[PATH_MAX + 1]; - bool isbinary = false; - uint32_t magic; - - /* append the path suffix if we have one */ - if (suffix) { - rc = snprintf(stack_path, sizeof(stack_path), - "%s.%s", path, suffix); - if (rc >= (int)sizeof(stack_path)) { - errno = ENAMETOOLONG; - return -1; - } - path = stack_path; - } - - /* Open the specification file. */ - fp = fopen(path, "r"); - if (fp) { - if (fstat(fileno(fp), &sb) < 0) - return -1; - if (!S_ISREG(sb.st_mode)) { - errno = EINVAL; - return -1; - } - - if (fread(&magic, sizeof magic, 1, fp) != 1) { - errno = EINVAL; - fclose(fp); - return -1; - } - - if (magic == SELINUX_MAGIC_COMPILED_FCONTEXT) { - /* file_contexts.bin format */ - fclose(fp); - fp = NULL; - isbinary = true; - } else { - rewind(fp); - } - } else { - /* - * Text file does not exist, so clear the timestamp - * so that we will always pass the timestamp comparison - * with the bin file in load_mmap(). - */ - sb.st_mtime = 0; - } - - rc = load_mmap(rec, path, &sb, isbinary); - if (rc == 0) - goto out; - - if (!fp) - return -1; /* no text or bin file */ - - /* - * Then do detailed validation of the input and fill the spec array - */ - lineno = 0; - rc = 0; - while (getline(&line_buf, &line_len, fp) > 0) { - rc = process_line(rec, path, prefix, line_buf, ++lineno); - if (rc) - goto out; - } - -out: - free(line_buf); - if (fp) - fclose(fp); - return rc; -} - -static void closef(struct selabel_handle *rec); - -static int init(struct selabel_handle *rec, const struct selinux_opt *opts, - unsigned n) -{ - struct saved_data *data = (struct saved_data *)rec->data; - const char *path = NULL; - const char *prefix = NULL; - int status = -1, baseonly = 0; - - /* Process arguments */ - while (n--) - switch(opts[n].type) { - case SELABEL_OPT_PATH: - path = opts[n].value; - break; - case SELABEL_OPT_SUBSET: - prefix = opts[n].value; - break; - case SELABEL_OPT_BASEONLY: - baseonly = !!opts[n].value; - break; - } - - rec->spec_file = strdup(path); - - /* - * The do detailed validation of the input and fill the spec array - */ - status = process_file(path, NULL, rec, prefix); - if (status) - goto finish; - - if (rec->validating) { - status = nodups_specs(data, path); - if (status) - goto finish; - } - - if (!baseonly) { - status = process_file(path, "homedirs", rec, prefix); - if (status && errno != ENOENT) - goto finish; - - status = process_file(path, "local", rec, prefix); - if (status && errno != ENOENT) - goto finish; - } - - status = sort_specs(data); - -finish: - if (status) - closef(rec); - - return status; -} - -/* - * Backend interface routines - */ -static void closef(struct selabel_handle *rec) -{ - struct saved_data *data = (struct saved_data *)rec->data; - struct mmap_area *area, *last_area; - struct spec *spec; - struct stem *stem; - unsigned int i; - - for (i = 0; i < data->nspec; i++) { - spec = &data->spec_arr[i]; - free(spec->lr.ctx_trans); - free(spec->lr.ctx_raw); - if (spec->from_mmap) - continue; - free(spec->regex_str); - free(spec->type_str); - regex_data_free(spec->regex); - } - - for (i = 0; i < (unsigned int)data->num_stems; i++) { - stem = &data->stem_arr[i]; - if (stem->from_mmap) - continue; - free(stem->buf); - } - - if (data->spec_arr) - free(data->spec_arr); - if (data->stem_arr) - free(data->stem_arr); - - area = data->mmap_areas; - while (area) { - munmap(area->addr, area->len); - last_area = area; - area = area->next; - free(last_area); - } - free(data); -} - -static struct spec *lookup_common(struct selabel_handle *rec, - const char *key, - int type, - bool partial) -{ - struct saved_data *data = (struct saved_data *)rec->data; - struct spec *spec_arr = data->spec_arr; - int i, rc, file_stem; - mode_t mode = (mode_t)type; - const char *buf; - struct spec *ret = NULL; - char *clean_key = NULL; - const char *prev_slash, *next_slash; - unsigned int sofar = 0; - struct regex_error_data regex_error_data; - - if (!data->nspec) { - errno = ENOENT; - goto finish; - } - - /* Remove duplicate slashes */ - if ((next_slash = strstr(key, "//"))) { - clean_key = (char *) malloc(strlen(key) + 1); - if (!clean_key) - goto finish; - prev_slash = key; - while (next_slash) { - memcpy(clean_key + sofar, prev_slash, next_slash - prev_slash); - sofar += next_slash - prev_slash; - prev_slash = next_slash + 1; - next_slash = strstr(prev_slash, "//"); - } - strcpy(clean_key + sofar, prev_slash); - key = clean_key; - } - - buf = key; - file_stem = find_stem_from_file(data, &buf); - mode &= S_IFMT; - - /* - * Check for matching specifications in reverse order, so that - * the last matching specification is used. - */ - for (i = data->nspec - 1; i >= 0; i--) { - struct spec *spec = &spec_arr[i]; - /* if the spec in question matches no stem or has the same - * stem as the file AND if the spec in question has no mode - * specified or if the mode matches the file mode then we do - * a regex check */ - if ((spec->stem_id == -1 || spec->stem_id == file_stem) && - (!mode || !spec->mode || mode == spec->mode)) { - if (compile_regex(data, spec, ®ex_error_data) < 0) - goto finish; - if (spec->stem_id == -1) - rc = regex_match(spec->regex, key, partial); - else - rc = regex_match(spec->regex, buf, partial); - if (rc == REGEX_MATCH) { - spec->matches++; - break; - } else if (partial && rc == REGEX_MATCH_PARTIAL) - break; - - if (rc == REGEX_NO_MATCH) - continue; - - errno = ENOENT; - /* else it's an error */ - goto finish; - } - } - - if (i < 0 || strcmp(spec_arr[i].lr.ctx_raw, "<<none>>") == 0) { - /* No matching specification. */ - errno = ENOENT; - goto finish; - } - - errno = 0; - ret = &spec_arr[i]; - -finish: - free(clean_key); - return ret; -} - -static struct selabel_lookup_rec *lookup(struct selabel_handle *rec, - const char *key, int type) -{ - struct spec *spec; - - spec = lookup_common(rec, key, type, false); - if (spec) - return &spec->lr; - return NULL; -} - -static bool partial_match(struct selabel_handle *rec, const char *key) -{ - return lookup_common(rec, key, 0, true) ? true : false; -} - -static struct selabel_lookup_rec *lookup_best_match(struct selabel_handle *rec, - const char *key, - const char **aliases, - int type) -{ - size_t n, i; - int best = -1; - struct spec **specs; - size_t prefix_len = 0; - struct selabel_lookup_rec *lr = NULL; - - if (!aliases || !aliases[0]) - return lookup(rec, key, type); - - for (n = 0; aliases[n]; n++) - ; - - specs = calloc(n+1, sizeof(struct spec *)); - if (!specs) - return NULL; - specs[0] = lookup_common(rec, key, type, false); - if (specs[0]) { - if (!specs[0]->hasMetaChars) { - /* exact match on key */ - lr = &specs[0]->lr; - goto out; - } - best = 0; - prefix_len = specs[0]->prefix_len; - } - for (i = 1; i <= n; i++) { - specs[i] = lookup_common(rec, aliases[i-1], type, false); - if (specs[i]) { - if (!specs[i]->hasMetaChars) { - /* exact match on alias */ - lr = &specs[i]->lr; - goto out; - } - if (specs[i]->prefix_len > prefix_len) { - best = i; - prefix_len = specs[i]->prefix_len; - } - } - } - - if (best >= 0) { - /* longest fixed prefix match on key or alias */ - lr = &specs[best]->lr; - } else { - errno = ENOENT; - } - -out: - free(specs); - return lr; -} - -static enum selabel_cmp_result incomp(struct spec *spec1, struct spec *spec2, const char *reason, int i, int j) -{ - selinux_log(SELINUX_INFO, - "selabel_cmp: mismatched %s on entry %d: (%s, %x, %s) vs entry %d: (%s, %x, %s)\n", - reason, - i, spec1->regex_str, spec1->mode, spec1->lr.ctx_raw, - j, spec2->regex_str, spec2->mode, spec2->lr.ctx_raw); - return SELABEL_INCOMPARABLE; -} - -static enum selabel_cmp_result cmp(struct selabel_handle *h1, - struct selabel_handle *h2) -{ - struct saved_data *data1 = (struct saved_data *)h1->data; - struct saved_data *data2 = (struct saved_data *)h2->data; - unsigned int i, nspec1 = data1->nspec, j, nspec2 = data2->nspec; - struct spec *spec_arr1 = data1->spec_arr, *spec_arr2 = data2->spec_arr; - struct stem *stem_arr1 = data1->stem_arr, *stem_arr2 = data2->stem_arr; - bool skipped1 = false, skipped2 = false; - - i = 0; - j = 0; - while (i < nspec1 && j < nspec2) { - struct spec *spec1 = &spec_arr1[i]; - struct spec *spec2 = &spec_arr2[j]; - - /* - * Because sort_specs() moves exact pathnames to the - * end, we might need to skip over additional regex - * entries that only exist in one of the configurations. - */ - if (!spec1->hasMetaChars && spec2->hasMetaChars) { - j++; - skipped2 = true; - continue; - } - - if (spec1->hasMetaChars && !spec2->hasMetaChars) { - i++; - skipped1 = true; - continue; - } - - if (spec1->regcomp && spec2->regcomp) { - if (regex_cmp(spec1->regex, spec2->regex) == SELABEL_INCOMPARABLE){ - return incomp(spec1, spec2, "regex", i, j); - } - } else { - if (strcmp(spec1->regex_str, spec2->regex_str)) - return incomp(spec1, spec2, "regex_str", i, j); - } - - if (spec1->mode != spec2->mode) - return incomp(spec1, spec2, "mode", i, j); - - if (spec1->stem_id == -1 && spec2->stem_id != -1) - return incomp(spec1, spec2, "stem_id", i, j); - if (spec2->stem_id == -1 && spec1->stem_id != -1) - return incomp(spec1, spec2, "stem_id", i, j); - if (spec1->stem_id != -1 && spec2->stem_id != -1) { - struct stem *stem1 = &stem_arr1[spec1->stem_id]; - struct stem *stem2 = &stem_arr2[spec2->stem_id]; - if (stem1->len != stem2->len || - strncmp(stem1->buf, stem2->buf, stem1->len)) - return incomp(spec1, spec2, "stem", i, j); - } - - if (strcmp(spec1->lr.ctx_raw, spec2->lr.ctx_raw)) - return incomp(spec1, spec2, "ctx_raw", i, j); - - i++; - j++; - } - - if ((skipped1 || i < nspec1) && !skipped2) - return SELABEL_SUPERSET; - if ((skipped2 || j < nspec2) && !skipped1) - return SELABEL_SUBSET; - if (skipped1 && skipped2) - return SELABEL_INCOMPARABLE; - return SELABEL_EQUAL; -} - - -static void stats(struct selabel_handle *rec) -{ - struct saved_data *data = (struct saved_data *)rec->data; - unsigned int i, nspec = data->nspec; - struct spec *spec_arr = data->spec_arr; - - for (i = 0; i < nspec; i++) { - if (spec_arr[i].matches == 0) { - if (spec_arr[i].type_str) { - selinux_log(SELINUX_WARNING, - "Warning! No matches for (%s, %s, %s)\n", - spec_arr[i].regex_str, - spec_arr[i].type_str, - spec_arr[i].lr.ctx_raw); - } else { - selinux_log(SELINUX_WARNING, - "Warning! No matches for (%s, %s)\n", - spec_arr[i].regex_str, - spec_arr[i].lr.ctx_raw); - } - } - } -} - -int selabel_file_init(struct selabel_handle *rec, const struct selinux_opt *opts, - unsigned nopts) -{ - struct saved_data *data; - - data = (struct saved_data *)malloc(sizeof(*data)); - if (!data) - return -1; - memset(data, 0, sizeof(*data)); - - rec->data = data; - rec->func_close = &closef; - rec->func_stats = &stats; - rec->func_lookup = &lookup; - rec->func_partial_match = &partial_match; - rec->func_lookup_best_match = &lookup_best_match; - rec->func_cmp = &cmp; - - return init(rec, opts, nopts); -} diff --git a/src/label_file.h b/src/label_file.h deleted file mode 100644 index d0ff254..0000000 --- a/src/label_file.h +++ /dev/null @@ -1,474 +0,0 @@ -#ifndef _SELABEL_FILE_H_ -#define _SELABEL_FILE_H_ - -#include <errno.h> -#include <string.h> - -#include <sys/stat.h> - -/* - * Android: regex.h/c was introduced to hold all dependencies on the regular - * expression back-end when we started supporting PCRE2. regex.h defines a - * minimal interface required by libselinux, so that the remaining code - * can be agnostic about the underlying implementation. - */ -#include "regex.h" - -#include "callbacks.h" -#include "label_internal.h" - -#define SELINUX_MAGIC_COMPILED_FCONTEXT 0xf97cff8a - -/* Version specific changes */ -#define SELINUX_COMPILED_FCONTEXT_NOPCRE_VERS 1 -#define SELINUX_COMPILED_FCONTEXT_PCRE_VERS 2 -#define SELINUX_COMPILED_FCONTEXT_MODE 3 -#define SELINUX_COMPILED_FCONTEXT_PREFIX_LEN 4 - -#define SELINUX_COMPILED_FCONTEXT_MAX_VERS SELINUX_COMPILED_FCONTEXT_PREFIX_LEN - -/* A file security context specification. */ -struct spec { - struct selabel_lookup_rec lr; /* holds contexts for lookup result */ - char *regex_str; /* regular expession string for diagnostics */ - char *type_str; /* type string for diagnostic messages */ - struct regex_data * regex; /* backend dependent regular expression data */ - mode_t mode; /* mode format value */ - int matches; /* number of matching pathnames */ - int stem_id; /* indicates which stem-compression item */ - char hasMetaChars; /* regular expression has meta-chars */ - char regcomp; /* regex_str has been compiled to regex */ - char from_mmap; /* this spec is from an mmap of the data */ - size_t prefix_len; /* length of fixed path prefix */ -}; - -/* A regular expression stem */ -struct stem { - char *buf; - int len; - char from_mmap; -}; - -/* Where we map the file in during selabel_open() */ -struct mmap_area { - void *addr; /* Start addr + len used to release memory at close */ - size_t len; - void *next_addr; /* Incremented by next_entry() */ - size_t next_len; /* Decremented by next_entry() */ - struct mmap_area *next; -}; - -/* Our stored configuration */ -struct saved_data { - /* - * The array of specifications, initially in the same order as in - * the specification file. Sorting occurs based on hasMetaChars. - */ - struct spec *spec_arr; - unsigned int nspec; - unsigned int alloc_specs; - - /* - * The array of regular expression stems. - */ - struct stem *stem_arr; - int num_stems; - int alloc_stems; - struct mmap_area *mmap_areas; -}; - -static inline mode_t string_to_mode(char *mode) -{ - size_t len; - - if (!mode) - return 0; - len = strlen(mode); - if (mode[0] != '-' || len != 2) - return -1; - switch (mode[1]) { - case 'b': - return S_IFBLK; - case 'c': - return S_IFCHR; - case 'd': - return S_IFDIR; - case 'p': - return S_IFIFO; - case 'l': - return S_IFLNK; - case 's': - return S_IFSOCK; - case '-': - return S_IFREG; - default: - return -1; - } - /* impossible to get here */ - return 0; -} - -static inline int grow_specs(struct saved_data *data) -{ - struct spec *specs; - size_t new_specs, total_specs; - - if (data->nspec < data->alloc_specs) - return 0; - - new_specs = data->nspec + 16; - total_specs = data->nspec + new_specs; - - specs = realloc(data->spec_arr, total_specs * sizeof(*specs)); - if (!specs) { - perror("realloc"); - return -1; - } - - /* blank the new entries */ - memset(&specs[data->nspec], 0, new_specs * sizeof(*specs)); - - data->spec_arr = specs; - data->alloc_specs = total_specs; - return 0; -} - -/* Determine if the regular expression specification has any meta characters. */ -static inline void spec_hasMetaChars(struct spec *spec) -{ - char *c; - int len; - char *end; - - c = spec->regex_str; - len = strlen(spec->regex_str); - end = c + len; - - spec->hasMetaChars = 0; - spec->prefix_len = len; - - /* Look at each character in the RE specification string for a - * meta character. Return when any meta character reached. */ - while (c < end) { - switch (*c) { - case '.': - case '^': - case '$': - case '?': - case '*': - case '+': - case '|': - case '[': - case '(': - case '{': - spec->hasMetaChars = 1; - spec->prefix_len = c - spec->regex_str; - return; - case '\\': /* skip the next character */ - c++; - break; - default: - break; - - } - c++; - } -} - -/* Move exact pathname specifications to the end. */ -static inline int sort_specs(struct saved_data *data) -{ - struct spec *spec_copy; - struct spec spec; - unsigned int i; - int front, back; - size_t len = sizeof(*spec_copy); - - spec_copy = malloc(len * data->nspec); - if (!spec_copy) - return -1; - - /* first move the exact pathnames to the back */ - front = 0; - back = data->nspec - 1; - for (i = 0; i < data->nspec; i++) { - if (data->spec_arr[i].hasMetaChars) - memcpy(&spec_copy[front++], &data->spec_arr[i], len); - else - memcpy(&spec_copy[back--], &data->spec_arr[i], len); - } - - /* - * now the exact pathnames are at the end, but they are in the reverse - * order. Since 'front' is now the first of the 'exact' we can run - * that part of the array switching the front and back element. - */ - back = data->nspec - 1; - while (front < back) { - /* save the front */ - memcpy(&spec, &spec_copy[front], len); - /* move the back to the front */ - memcpy(&spec_copy[front], &spec_copy[back], len); - /* put the old front in the back */ - memcpy(&spec_copy[back], &spec, len); - front++; - back--; - } - - free(data->spec_arr); - data->spec_arr = spec_copy; - - return 0; -} - -/* Return the length of the text that can be considered the stem, returns 0 - * if there is no identifiable stem */ -static inline int get_stem_from_spec(const char *const buf) -{ - const char *tmp = strchr(buf + 1, '/'); - const char *ind; - - if (!tmp) - return 0; - - for (ind = buf; ind < tmp; ind++) { - if (strchr(".^$?*+|[({", (int)*ind)) - return 0; - } - return tmp - buf; -} - -/* - * return the stemid given a string and a length - */ -static inline int find_stem(struct saved_data *data, const char *buf, - int stem_len) -{ - int i; - - for (i = 0; i < data->num_stems; i++) { - if (stem_len == data->stem_arr[i].len && - !strncmp(buf, data->stem_arr[i].buf, stem_len)) - return i; - } - - return -1; -} - -/* returns the index of the new stored object */ -static inline int store_stem(struct saved_data *data, char *buf, int stem_len) -{ - int num = data->num_stems; - - if (data->alloc_stems == num) { - struct stem *tmp_arr; - - data->alloc_stems = data->alloc_stems * 2 + 16; - tmp_arr = realloc(data->stem_arr, - sizeof(*tmp_arr) * data->alloc_stems); - if (!tmp_arr) - return -1; - data->stem_arr = tmp_arr; - } - data->stem_arr[num].len = stem_len; - data->stem_arr[num].buf = buf; - data->stem_arr[num].from_mmap = 0; - data->num_stems++; - - return num; -} - -/* find the stem of a file spec, returns the index into stem_arr for a new - * or existing stem, (or -1 if there is no possible stem - IE for a file in - * the root directory or a regex that is too complex for us). */ -static inline int find_stem_from_spec(struct saved_data *data, const char *buf) -{ - int stem_len = get_stem_from_spec(buf); - int stemid; - char *stem; - - if (!stem_len) - return -1; - - stemid = find_stem(data, buf, stem_len); - if (stemid >= 0) - return stemid; - - /* not found, allocate a new one */ - stem = strndup(buf, stem_len); - if (!stem) - return -1; - - return store_stem(data, stem, stem_len); -} - -/* This will always check for buffer over-runs and either read the next entry - * if buf != NULL or skip over the entry (as these areas are mapped in the - * current buffer). */ -static inline int next_entry(void *buf, struct mmap_area *fp, size_t bytes) -{ - if (bytes > fp->next_len) - return -1; - - if (buf) - memcpy(buf, fp->next_addr, bytes); - - fp->next_addr = (char *)fp->next_addr + bytes; - fp->next_len -= bytes; - return 0; -} - -static inline int compile_regex(struct saved_data *data, struct spec *spec, - struct regex_error_data * error_data) -{ - char *reg_buf, *anchored_regex, *cp; - struct stem *stem_arr = data->stem_arr; - size_t len; - int rc; - - if (spec->regcomp) - return 0; /* already done */ - - /* Skip the fixed stem. */ - reg_buf = spec->regex_str; - if (spec->stem_id >= 0) - reg_buf += stem_arr[spec->stem_id].len; - - /* Anchor the regular expression. */ - len = strlen(reg_buf); - cp = anchored_regex = malloc(len + 3); - if (!anchored_regex) - return -1; - - /* Create ^...$ regexp. */ - *cp++ = '^'; - memcpy(cp, reg_buf, len); - cp += len; - *cp++ = '$'; - *cp = '\0'; - - /* Compile the regular expression. */ - rc = regex_prepare_data(&spec->regex, anchored_regex, error_data); - free(anchored_regex); - if (rc < 0) { - return -1; - } - - /* Done. */ - spec->regcomp = 1; - - return 0; -} - -/* This service is used by label_file.c process_file() and - * utils/sefcontext_compile.c */ -static inline int process_line(struct selabel_handle *rec, - const char *path, const char *prefix, - char *line_buf, unsigned lineno) -{ - int items, len, rc; - char *regex = NULL, *type = NULL, *context = NULL; - struct saved_data *data = (struct saved_data *)rec->data; - struct spec *spec_arr; - unsigned int nspec = data->nspec; - char const *errbuf; - struct regex_error_data error_data; - - items = read_spec_entries(line_buf, &errbuf, 3, ®ex, &type, &context); - if (items < 0) { - rc = errno; - selinux_log(SELINUX_ERROR, - "%s: line %u error due to: %s\n", path, - lineno, errbuf ?: strerror(errno)); - errno = rc; - return -1; - } - - if (items == 0) - return items; - - if (items < 2) { - selinux_log(SELINUX_ERROR, - "%s: line %u is missing fields\n", path, - lineno); - if (items == 1) - free(regex); - errno = EINVAL; - return -1; - } else if (items == 2) { - /* The type field is optional. */ - context = type; - type = 0; - } - - len = get_stem_from_spec(regex); - if (len && prefix && strncmp(prefix, regex, len)) { - /* Stem of regex does not match requested prefix, discard. */ - free(regex); - free(type); - free(context); - return 0; - } - - rc = grow_specs(data); - if (rc) - return rc; - - spec_arr = data->spec_arr; - - /* process and store the specification in spec. */ - spec_arr[nspec].stem_id = find_stem_from_spec(data, regex); - spec_arr[nspec].regex_str = regex; - - spec_arr[nspec].type_str = type; - spec_arr[nspec].mode = 0; - - spec_arr[nspec].lr.ctx_raw = context; - - /* - * bump data->nspecs to cause closef() to cover it in its free - * but do not bump nspec since it's used below. - */ - data->nspec++; - - if (rec->validating && - compile_regex(data, &spec_arr[nspec], &error_data)) { - selinux_log(SELINUX_ERROR, - "%s: line %u has invalid regex %s: %s\n", - path, lineno, regex, - (errbuf ? errbuf : "out of memory")); - errno = EINVAL; - return -1; - } - - if (type) { - mode_t mode = string_to_mode(type); - - if (mode == (mode_t)-1) { - selinux_log(SELINUX_ERROR, - "%s: line %u has invalid file type %s\n", - path, lineno, type); - errno = EINVAL; - return -1; - } - spec_arr[nspec].mode = mode; - } - - /* Determine if specification has - * any meta characters in the RE */ - spec_hasMetaChars(&spec_arr[nspec]); - - if (strcmp(context, "<<none>>") && rec->validating) { - if (selabel_validate(rec, &spec_arr[nspec].lr) < 0) { - selinux_log(SELINUX_ERROR, - "%s: line %u has invalid context %s\n", - path, lineno, spec_arr[nspec].lr.ctx_raw); - errno = EINVAL; - return -1; - } - } - - return 0; -} - -#endif /* _SELABEL_FILE_H_ */ diff --git a/src/label_internal.h b/src/label_internal.h deleted file mode 100644 index cca44d5..0000000 --- a/src/label_internal.h +++ /dev/null @@ -1,95 +0,0 @@ -/* - * This file describes the internal interface used by the labeler - * for calling the user-supplied memory allocation, validation, - * and locking routine. - * - * Author : Eamon Walsh <ewalsh@epoch.ncsc.mil> - */ -#ifndef _SELABEL_INTERNAL_H_ -#define _SELABEL_INTERNAL_H_ - -#include <stdlib.h> -#include <stdarg.h> -#include <selinux/selinux.h> -#include <selinux/label.h> -#include "dso.h" - -/* - * Installed backends - */ -int selabel_file_init(struct selabel_handle *rec, const struct selinux_opt *opts, - unsigned nopts) hidden; -int selabel_media_init(struct selabel_handle *rec, const struct selinux_opt *opts, - unsigned nopts) hidden; -int selabel_x_init(struct selabel_handle *rec, const struct selinux_opt *opts, - unsigned nopts) hidden; -int selabel_db_init(struct selabel_handle *rec, - const struct selinux_opt *opts, unsigned nopts) hidden; -int selabel_property_init(struct selabel_handle *rec, - const struct selinux_opt *opts, unsigned nopts) hidden; -int selabel_service_init(struct selabel_handle *rec, - const struct selinux_opt *opts, unsigned nopts) hidden; - -/* - * Labeling internal structures - */ -struct selabel_sub { - char *src; - int slen; - char *dst; - struct selabel_sub *next; -}; - -struct selabel_lookup_rec { - char * ctx_raw; - char * ctx_trans; - int validated; -}; - -struct selabel_handle { - /* arguments that were passed to selabel_open */ - unsigned int backend; - int validating; - - /* labeling operations */ - struct selabel_lookup_rec *(*func_lookup) (struct selabel_handle *h, - const char *key, int type); - void (*func_close) (struct selabel_handle *h); - void (*func_stats) (struct selabel_handle *h); - bool (*func_partial_match) (struct selabel_handle *h, const char *key); - struct selabel_lookup_rec *(*func_lookup_best_match) - (struct selabel_handle *h, - const char *key, - const char **aliases, - int type); - enum selabel_cmp_result (*func_cmp)(struct selabel_handle *h1, - struct selabel_handle *h2); - - /* supports backend-specific state information */ - void *data; - - /* - * The main spec file used. Note for file contexts the local and/or - * homedirs could also have been used to resolve a context. - */ - char *spec_file; - - /* substitution support */ - struct selabel_sub *dist_subs; - struct selabel_sub *subs; -}; - -/* - * Validation function - */ -extern int -selabel_validate(struct selabel_handle *rec, - struct selabel_lookup_rec *contexts) hidden; - -/* - * The read_spec_entries function may be used to - * replace sscanf to read entries from spec files. - */ -extern int read_spec_entries(char *line_buf, const char **errbuf, int num_args, ...); - -#endif /* _SELABEL_INTERNAL_H_ */ diff --git a/src/label_support.c b/src/label_support.c deleted file mode 100644 index e226d51..0000000 --- a/src/label_support.c +++ /dev/null @@ -1,117 +0,0 @@ -/* - * This file contains helper functions for labeling support. - * - * Author : Richard Haines <richard_c_haines@btinternet.com> - */ - -#include <stdlib.h> -#include <stdarg.h> -#include <ctype.h> -#include <string.h> -#include <errno.h> -#include "label_internal.h" - -/* - * The read_spec_entries and read_spec_entry functions may be used to - * replace sscanf to read entries from spec files. The file and - * property services now use these. - */ - -/* - * Read an entry from a spec file (e.g. file_contexts) - * entry - Buffer to allocate for the entry. - * ptr - current location of the line to be processed. - * returns - 0 on success and *entry is set to be a null - * terminated value. On Error it returns -1 and - errno will be set. - * - */ -static inline int read_spec_entry(char **entry, char **ptr, int *len, const char **errbuf) -{ - *entry = NULL; - char *tmp_buf = NULL; - - while (isspace(**ptr) && **ptr != '\0') - (*ptr)++; - - tmp_buf = *ptr; - *len = 0; - - while (!isspace(**ptr) && **ptr != '\0') { - if (!isascii(**ptr)) { - errno = EINVAL; - *errbuf = "Non-ASCII characters found"; - return -1; - } - (*ptr)++; - (*len)++; - } - - if (*len) { - *entry = strndup(tmp_buf, *len); - if (!*entry) - return -1; - } - - return 0; -} - -/* - * line_buf - Buffer containing the spec entries . - * errbuf - Double pointer used for passing back specific error messages. - * num_args - The number of spec parameter entries to process. - * ... - A 'char **spec_entry' for each parameter. - * returns - The number of items processed. On error, it returns -1 with errno - * set and may set errbuf to a specific error message. - * - * This function calls read_spec_entry() to do the actual string processing. - * As such, can return anything from that function as well. - */ -int hidden read_spec_entries(char *line_buf, const char **errbuf, int num_args, ...) -{ - char **spec_entry, *buf_p; - int len, rc, items, entry_len = 0; - va_list ap; - - *errbuf = NULL; - - len = strlen(line_buf); - if (line_buf[len - 1] == '\n') - line_buf[len - 1] = '\0'; - else - /* Handle case if line not \n terminated by bumping - * the len for the check below (as the line is NUL - * terminated by getline(3)) */ - len++; - - buf_p = line_buf; - while (isspace(*buf_p)) - buf_p++; - - /* Skip comment lines and empty lines. */ - if (*buf_p == '#' || *buf_p == '\0') - return 0; - - /* Process the spec file entries */ - va_start(ap, num_args); - - items = 0; - while (items < num_args) { - spec_entry = va_arg(ap, char **); - - if (len - 1 == buf_p - line_buf) { - va_end(ap); - return items; - } - - rc = read_spec_entry(spec_entry, &buf_p, &entry_len, errbuf); - if (rc < 0) { - va_end(ap); - return rc; - } - if (entry_len) - items++; - } - va_end(ap); - return items; -} diff --git a/src/lgetfilecon.c b/src/lgetfilecon.c deleted file mode 100644 index 22851a4..0000000 --- a/src/lgetfilecon.c +++ /dev/null @@ -1,50 +0,0 @@ -#include <unistd.h> -#include <fcntl.h> -#include <string.h> -#include <stdlib.h> -#include <errno.h> -#include <sys/xattr.h> -#include "selinux_internal.h" -#include "policy.h" - -int lgetfilecon(const char *path, char ** context) -{ - char *buf; - ssize_t size; - ssize_t ret; - - size = INITCONTEXTLEN + 1; - buf = malloc(size); - if (!buf) - return -1; - memset(buf, 0, size); - - ret = lgetxattr(path, XATTR_NAME_SELINUX, buf, size - 1); - if (ret < 0 && errno == ERANGE) { - char *newbuf; - - size = lgetxattr(path, XATTR_NAME_SELINUX, NULL, 0); - if (size < 0) - goto out; - - size++; - newbuf = realloc(buf, size); - if (!newbuf) - goto out; - - buf = newbuf; - memset(buf, 0, size); - ret = lgetxattr(path, XATTR_NAME_SELINUX, buf, size - 1); - } - out: - if (ret == 0) { - /* Re-map empty attribute values to errors. */ - errno = EOPNOTSUPP; - ret = -1; - } - if (ret < 0) - free(buf); - else - *context = buf; - return ret; -} diff --git a/src/load_policy.c b/src/load_policy.c deleted file mode 100644 index 51a178a..0000000 --- a/src/load_policy.c +++ /dev/null @@ -1,41 +0,0 @@ -#include <unistd.h> -#include <sys/types.h> -#include <sys/stat.h> -#include <sys/mman.h> -#include <sys/mount.h> -#include <sys/utsname.h> -#include <fcntl.h> -#include <stdlib.h> -#include <stdio.h> -#include <ctype.h> -#include <string.h> -#include <errno.h> -#include "selinux_internal.h" -#include <dlfcn.h> -#include "policy.h" -#include <limits.h> -#include "callbacks.h" - -int security_load_policy(void *data, size_t len) -{ - char path[PATH_MAX]; - int fd, ret; - - if (!selinux_mnt) { - errno = ENOENT; - return -1; - } - - snprintf(path, sizeof path, "%s/load", selinux_mnt); - fd = open(path, O_RDWR | O_CLOEXEC); - if (fd < 0) - return -1; - - ret = write(fd, data, len); - close(fd); - if (ret < 0) - return -1; - return 0; -} - -hidden_def(security_load_policy) diff --git a/src/lsetfilecon.c b/src/lsetfilecon.c deleted file mode 100644 index 7147f9e..0000000 --- a/src/lsetfilecon.c +++ /dev/null @@ -1,15 +0,0 @@ -#include <unistd.h> -#include <fcntl.h> -#include <string.h> -#include <stdlib.h> -#include <errno.h> -#include <sys/xattr.h> -#include "selinux_internal.h" -#include "policy.h" - -int lsetfilecon(const char *path, const char *context) -{ - return lsetxattr(path, XATTR_NAME_SELINUX, context, strlen(context) + 1, - 0); -} - diff --git a/src/mapping.c b/src/mapping.c deleted file mode 100644 index f205804..0000000 --- a/src/mapping.c +++ /dev/null @@ -1,210 +0,0 @@ -/* - * Class and permission mappings. - */ - -#include <errno.h> -#include <stdio.h> -#include <stdlib.h> -#include <stdarg.h> -#include <selinux/selinux.h> -#include <selinux/avc.h> -#include "mapping.h" - -/* - * Class and permission mappings - */ - -struct selinux_mapping { - security_class_t value; /* real, kernel value */ - unsigned num_perms; - access_vector_t perms[sizeof(access_vector_t) * 8]; -}; - -static struct selinux_mapping *current_mapping = NULL; -static security_class_t current_mapping_size = 0; - -/* - * Mapping setting function - */ - -int -selinux_set_mapping(struct security_class_mapping *map) -{ - size_t size = sizeof(struct selinux_mapping); - security_class_t i, j; - unsigned k; - - free(current_mapping); - current_mapping = NULL; - current_mapping_size = 0; - - if (avc_reset() < 0) - goto err; - - /* Find number of classes in the input mapping */ - if (!map) { - errno = EINVAL; - goto err; - } - i = 0; - while (map[i].name) - i++; - - /* Allocate space for the class records, plus one for class zero */ - current_mapping = (struct selinux_mapping *)calloc(++i, size); - if (!current_mapping) - goto err; - - /* Store the raw class and permission values */ - j = 0; - while (map[j].name) { - struct security_class_mapping *p_in = map + (j++); - struct selinux_mapping *p_out = current_mapping + j; - - p_out->value = string_to_security_class(p_in->name); - if (!p_out->value) - goto err2; - - k = 0; - while (p_in->perms[k]) { - /* An empty permission string skips ahead */ - if (!*p_in->perms[k]) { - k++; - continue; - } - p_out->perms[k] = string_to_av_perm(p_out->value, - p_in->perms[k]); - if (!p_out->perms[k]) - goto err2; - k++; - } - p_out->num_perms = k; - } - - /* Set the mapping size here so the above lookups are "raw" */ - current_mapping_size = i; - return 0; -err2: - free(current_mapping); - current_mapping = NULL; - current_mapping_size = 0; -err: - return -1; -} - -/* - * Get real, kernel values from mapped values - */ - -security_class_t -unmap_class(security_class_t tclass) -{ - if (tclass < current_mapping_size) - return current_mapping[tclass].value; - - /* If here no mapping set or the class requested is not valid. */ - if (current_mapping_size != 0) { - errno = EINVAL; - return 0; - } - else - return tclass; -} - -access_vector_t -unmap_perm(security_class_t tclass, access_vector_t tperm) -{ - if (tclass < current_mapping_size) { - unsigned i; - access_vector_t kperm = 0; - - for (i=0; i<current_mapping[tclass].num_perms; i++) - if (tperm & (1<<i)) { - kperm |= current_mapping[tclass].perms[i]; - tperm &= ~(1<<i); - } - return kperm; - } - - /* If here no mapping set or the perm requested is not valid. */ - if (current_mapping_size != 0) { - errno = EINVAL; - return 0; - } - else - return tperm; -} - -/* - * Get mapped values from real, kernel values - */ - -security_class_t -map_class(security_class_t kclass) -{ - security_class_t i; - - for (i=0; i<current_mapping_size; i++) - if (current_mapping[i].value == kclass) - return i; - -/* If here no mapping set or the class requested is not valid. */ - if (current_mapping_size != 0) { - errno = EINVAL; - return 0; - } - else - return kclass; -} - -access_vector_t -map_perm(security_class_t tclass, access_vector_t kperm) -{ - if (tclass < current_mapping_size) { - unsigned i; - access_vector_t tperm = 0; - - for (i=0; i<current_mapping[tclass].num_perms; i++) - if (kperm & current_mapping[tclass].perms[i]) { - tperm |= 1<<i; - kperm &= ~current_mapping[tclass].perms[i]; - } - - if (tperm == 0) { - errno = EINVAL; - return 0; - } - else - return tperm; - } - return kperm; -} - -void -map_decision(security_class_t tclass, struct av_decision *avd) -{ - if (tclass < current_mapping_size) { - unsigned i; - access_vector_t result; - - for (i=0, result=0; i<current_mapping[tclass].num_perms; i++) - if (avd->allowed & current_mapping[tclass].perms[i]) - result |= 1<<i; - avd->allowed = result; - - for (i=0, result=0; i<current_mapping[tclass].num_perms; i++) - if (avd->decided & current_mapping[tclass].perms[i]) - result |= 1<<i; - avd->decided = result; - - for (i=0, result=0; i<current_mapping[tclass].num_perms; i++) - if (avd->auditallow & current_mapping[tclass].perms[i]) - result |= 1<<i; - avd->auditallow = result; - - for (i=0, result=0; i<current_mapping[tclass].num_perms; i++) - if (avd->auditdeny & current_mapping[tclass].perms[i]) - result |= 1<<i; - avd->auditdeny = result; - } -} diff --git a/src/mapping.h b/src/mapping.h deleted file mode 100644 index b96756b..0000000 --- a/src/mapping.h +++ /dev/null @@ -1,41 +0,0 @@ -/* - * This file describes the class and permission mappings used to - * hide the kernel numbers from userspace by allowing userspace object - * managers to specify a list of classes and permissions. - */ -#ifndef _SELINUX_MAPPING_H_ -#define _SELINUX_MAPPING_H_ - -#include <selinux/selinux.h> - -/* - * Get real, kernel values from mapped values - */ - -extern security_class_t -unmap_class(security_class_t tclass); - -extern access_vector_t -unmap_perm(security_class_t tclass, access_vector_t tperm); - -/* - * Get mapped values from real, kernel values - */ - -extern security_class_t -map_class(security_class_t kclass); - -extern access_vector_t -map_perm(security_class_t tclass, access_vector_t kperm); - -extern void -map_decision(security_class_t tclass, struct av_decision *avd); - -/*mapping is not used for embedded build*/ -#ifdef DISABLE_AVC -#define unmap_perm(x,y) y -#define unmap_class(x) x -#define map_decision(x,y) -#endif - -#endif /* _SELINUX_MAPPING_H_ */ diff --git a/src/policy.h b/src/policy.h deleted file mode 100644 index 92a416e..0000000 --- a/src/policy.h +++ /dev/null @@ -1,28 +0,0 @@ -#ifndef _POLICY_H_ -#define _POLICY_H_ - -/* Private definitions used internally by libselinux. */ - -/* xattr name for SELinux attributes. */ -#define XATTR_NAME_SELINUX "security.selinux" - -/* Initial length guess for getting contexts. */ -#define INITCONTEXTLEN 255 - -/* selinuxfs magic number */ -#define SELINUX_MAGIC 0xf97cff8c - -/* Preferred selinuxfs mount point directory paths. */ -#define SELINUXMNT "/sys/fs/selinux" -#define OLDSELINUXMNT "/selinux" - -/* selinuxfs filesystem type string. */ -#define SELINUXFS "selinuxfs" - -/* selinuxfs mount point determined at runtime */ -extern char *selinux_mnt; - -/* First version of policy supported in mainline Linux. */ -#define DEFAULT_POLICY_VERSION 15 - -#endif diff --git a/src/policyvers.c b/src/policyvers.c deleted file mode 100644 index 284a7f7..0000000 --- a/src/policyvers.c +++ /dev/null @@ -1,45 +0,0 @@ -#include <unistd.h> -#include <sys/types.h> -#include <fcntl.h> -#include <stdlib.h> -#include <errno.h> -#include <string.h> -#include "selinux_internal.h" -#include <stdio.h> -#include "policy.h" -#include "dso.h" -#include <limits.h> - -int security_policyvers(void) -{ - int fd, ret; - char path[PATH_MAX]; - char buf[20]; - unsigned vers = DEFAULT_POLICY_VERSION; - - if (!selinux_mnt) { - errno = ENOENT; - return -1; - } - - snprintf(path, sizeof path, "%s/policyvers", selinux_mnt); - fd = open(path, O_RDONLY); - if (fd < 0) { - if (errno == ENOENT) - return vers; - else - return -1; - } - memset(buf, 0, sizeof buf); - ret = read(fd, buf, sizeof buf - 1); - close(fd); - if (ret < 0) - return -1; - - if (sscanf(buf, "%u", &vers) != 1) - return -1; - - return vers; -} - -hidden_def(security_policyvers) diff --git a/src/procattr.c b/src/procattr.c deleted file mode 100644 index 74c0012..0000000 --- a/src/procattr.c +++ /dev/null @@ -1,176 +0,0 @@ -#include <sys/syscall.h> -#include <unistd.h> -#include <fcntl.h> -#include <string.h> -#include <stdlib.h> -#include <stdio.h> -#include <errno.h> -#include "selinux_internal.h" -#include "policy.h" - -#ifdef HOST -static pid_t gettid(void) -{ - return syscall(__NR_gettid); -} -#endif - -static int openattr(pid_t pid, const char *attr, int flags) -{ - int fd, rc; - char *path; - pid_t tid; - - if (pid > 0) { - rc = asprintf(&path, "/proc/%d/attr/%s", pid, attr); - } else if (pid == 0) { - rc = asprintf(&path, "/proc/thread-self/attr/%s", attr); - if (rc < 0) - return -1; - fd = open(path, flags | O_CLOEXEC); - if (fd >= 0 || errno != ENOENT) - goto out; - free(path); - tid = gettid(); - rc = asprintf(&path, "/proc/self/task/%d/attr/%s", tid, attr); - } else { - errno = EINVAL; - return -1; - } - if (rc < 0) - return -1; - - fd = open(path, flags | O_CLOEXEC); -out: - free(path); - return fd; -} - -static int getprocattrcon(char ** context, - pid_t pid, const char *attr) -{ - char *buf; - size_t size; - int fd; - ssize_t ret; - int errno_hold; - - fd = openattr(pid, attr, O_RDONLY); - if (fd < 0) - return -1; - - size = selinux_page_size; - buf = malloc(size); - if (!buf) { - ret = -1; - goto out; - } - memset(buf, 0, size); - - do { - ret = read(fd, buf, size - 1); - } while (ret < 0 && errno == EINTR); - if (ret < 0) - goto out2; - - if (ret == 0) { - *context = NULL; - goto out2; - } - - *context = strdup(buf); - if (!(*context)) { - ret = -1; - goto out2; - } - ret = 0; - out2: - free(buf); - out: - errno_hold = errno; - close(fd); - errno = errno_hold; - return ret; -} - -static int setprocattrcon(const char * context, - pid_t pid, const char *attr) -{ - int fd; - ssize_t ret; - int errno_hold; - - fd = openattr(pid, attr, O_RDWR); - if (fd < 0) - return -1; - if (context) - do { - ret = write(fd, context, strlen(context) + 1); - } while (ret < 0 && errno == EINTR); - else - do { - ret = write(fd, NULL, 0); /* clear */ - } while (ret < 0 && errno == EINTR); - errno_hold = errno; - close(fd); - errno = errno_hold; - if (ret < 0) - return -1; - else - return 0; -} - -#define getselfattr_def(fn, attr) \ - int get##fn(char **c) \ - { \ - return getprocattrcon(c, 0, #attr); \ - } - -#define setselfattr_def(fn, attr) \ - int set##fn(const char * c) \ - { \ - return setprocattrcon(c, 0, #attr); \ - } - -#define all_selfattr_def(fn, attr) \ - getselfattr_def(fn, attr) \ - setselfattr_def(fn, attr) - -#define getpidattr_def(fn, attr) \ - int get##fn(pid_t pid, char **c) \ - { \ - if (pid <= 0) { \ - errno = EINVAL; \ - return -1; \ - } else { \ - return getprocattrcon(c, pid, #attr); \ - } \ - } - -all_selfattr_def(con, current) - getpidattr_def(pidcon, current) - getselfattr_def(prevcon, prev) - all_selfattr_def(execcon, exec) - all_selfattr_def(fscreatecon, fscreate) - all_selfattr_def(sockcreatecon, sockcreate) - all_selfattr_def(keycreatecon, keycreate) - - hidden_def(getcon_raw) - hidden_def(getcon) - hidden_def(getexeccon_raw) - hidden_def(getfilecon_raw) - hidden_def(getfilecon) - hidden_def(getfscreatecon_raw) - hidden_def(getkeycreatecon_raw) - hidden_def(getpeercon_raw) - hidden_def(getpidcon_raw) - hidden_def(getprevcon_raw) - hidden_def(getprevcon) - hidden_def(getsockcreatecon_raw) - hidden_def(setcon_raw) - hidden_def(setexeccon_raw) - hidden_def(setexeccon) - hidden_def(setfilecon_raw) - hidden_def(setfscreatecon_raw) - hidden_def(setkeycreatecon_raw) - hidden_def(setsockcreatecon_raw) diff --git a/src/regex.c b/src/regex.c deleted file mode 100644 index 32fe6ab..0000000 --- a/src/regex.c +++ /dev/null @@ -1,391 +0,0 @@ -#include <assert.h> -#include <stdint.h> -#include <stdio.h> -#include <string.h> - -#include "regex.h" -#include "label_file.h" - -int regex_prepare_data(struct regex_data ** regex, char const * pattern_string, - struct regex_error_data * errordata) { - memset(errordata, 0, sizeof(struct regex_error_data)); - *regex = regex_data_create(); - if (!(*regex)) - return -1; -#ifdef USE_PCRE2 - (*regex)->regex = pcre2_compile((PCRE2_SPTR)pattern_string, - PCRE2_ZERO_TERMINATED, - PCRE2_DOTALL, - &errordata->error_code, - &errordata->error_offset, NULL); -#else - (*regex)->regex = pcre_compile(pattern_string, PCRE_DOTALL, - &errordata->error_buffer, - &errordata->error_offset, NULL); -#endif - if (!(*regex)->regex) { - goto err; - } - -#ifdef USE_PCRE2 - (*regex)->match_data = - pcre2_match_data_create_from_pattern((*regex)->regex, NULL); - if (!(*regex)->match_data) { - goto err; - } -#else - (*regex)->sd = pcre_study((*regex)->regex, 0, &errordata->error_buffer); - if (!(*regex)->sd && errordata->error_buffer) { - goto err; - } - (*regex)->extra_owned = !!(*regex)->sd; -#endif - return 0; - -err: regex_data_free(*regex); - *regex = NULL; - return -1; -} - -char const * regex_version() { -#ifdef USE_PCRE2 - static int initialized = 0; - static char * version_string = NULL; - size_t version_string_len; - if (!initialized) { - version_string_len = pcre2_config(PCRE2_CONFIG_VERSION, NULL); - version_string = (char*) malloc(version_string_len); - if (!version_string) { - return NULL; - } - pcre2_config(PCRE2_CONFIG_VERSION, version_string); - initialized = 1; - } - return version_string; -#else - return pcre_version(); -#endif -} - -int regex_load_mmap(struct mmap_area * mmap_area, struct regex_data ** regex) { - int rc; - size_t entry_len, info_len; - - rc = next_entry(&entry_len, mmap_area, sizeof(uint32_t)); -#ifdef USE_PCRE2 - if (rc < 0) - return -1; - -#ifndef NO_PERSISTENTLY_STORED_PATTERNS - /* this should yield exactly one because we store one pattern at a time - */ - rc = pcre2_serialize_get_number_of_codes(mmap_area->next_addr); - if (rc != 1) - return -1; - - *regex = regex_data_create(); - if (!*regex) - return -1; - - rc = pcre2_serialize_decode(&(*regex)->regex, 1, - (PCRE2_SPTR)mmap_area->next_addr, NULL); - if (rc != 1) - goto err; - - (*regex)->match_data = - pcre2_match_data_create_from_pattern((*regex)->regex, NULL); - if (!(*regex)->match_data) - goto err; - -#endif /* NO_PERSISTENTLY_STORED_PATTERNS */ - /* and skip the decoded bit */ - rc = next_entry(NULL, mmap_area, entry_len); - if (rc < 0) - goto err; - - return 0; -#else - if (rc < 0 || !entry_len) { - rc = -1; - return -1; - } - *regex = regex_data_create(); - if (!(*regex)) - return -1; - - (*regex)->regex = (pcre *) mmap_area->next_addr; - rc = next_entry(NULL, mmap_area, entry_len); - if (rc < 0) - goto err; - - /* Check that regex lengths match. pcre_fullinfo() - * also validates its magic number. */ - rc = pcre_fullinfo((*regex)->regex, NULL, PCRE_INFO_SIZE, &info_len); - if (rc < 0 || info_len != entry_len) { - goto err; - } - - rc = next_entry(&entry_len, mmap_area, sizeof(uint32_t)); - if (rc < 0 || !entry_len) { - goto err; - } - (*regex)->lsd.study_data = (void *) mmap_area->next_addr; - (*regex)->lsd.flags |= PCRE_EXTRA_STUDY_DATA; - rc = next_entry(NULL, mmap_area, entry_len); - if (rc < 0) - goto err; - - /* Check that study data lengths match. */ - rc = pcre_fullinfo((*regex)->regex, &(*regex)->lsd, - PCRE_INFO_STUDYSIZE, - &info_len); - if (rc < 0 || info_len != entry_len) { - goto err; - } - (*regex)->extra_owned = 0; - return 0; -#endif - err: regex_data_free(*regex); - *regex = NULL; - return -1; -} - -int regex_writef(struct regex_data * regex, FILE * fp) { - int rc; - size_t len; -#ifdef USE_PCRE2 - PCRE2_UCHAR * bytes; - PCRE2_SIZE to_write; - -#ifndef NO_PERSISTENTLY_STORED_PATTERNS - /* encode the patter for serialization */ - rc = pcre2_serialize_encode(®ex->regex, 1, &bytes, &to_write, NULL); - if (rc != 1) - return -1; - -#else - (void)regex; // silence unused parameter warning - to_write = 0; -#endif - /* write serialized pattern's size */ - len = fwrite(&to_write, sizeof(uint32_t), 1, fp); - if (len != 1) { -#ifndef NO_PERSISTENTLY_STORED_PATTERNS - pcre2_serialize_free(bytes); -#endif - return -1; - } - -#ifndef NO_PERSISTENTLY_STORED_PATTERNS - /* write serialized pattern */ - len = fwrite(bytes, 1, to_write, fp); - if (len != to_write) { - pcre2_serialize_free(bytes); - return -1; - } - pcre2_serialize_free(bytes); -#endif -#else - uint32_t to_write; - size_t size; - pcre_extra * sd = regex->extra_owned ? regex->sd : ®ex->lsd; - - /* determine the size of the pcre data in bytes */ - rc = pcre_fullinfo(regex->regex, NULL, PCRE_INFO_SIZE, &size); - if (rc < 0) - return -1; - - /* write the number of bytes in the pcre data */ - to_write = size; - len = fwrite(&to_write, sizeof(uint32_t), 1, fp); - if (len != 1) - return -1; - - /* write the actual pcre data as a char array */ - len = fwrite(regex->regex, 1, to_write, fp); - if (len != to_write) - return -1; - - /* determine the size of the pcre study info */ - rc = pcre_fullinfo(regex->regex, sd, PCRE_INFO_STUDYSIZE, &size); - if (rc < 0) - return -1; - - /* write the number of bytes in the pcre study data */ - to_write = size; - len = fwrite(&to_write, sizeof(uint32_t), 1, fp); - if (len != 1) - return -1; - - /* write the actual pcre study data as a char array */ - len = fwrite(sd->study_data, 1, to_write, fp); - if (len != to_write) - return -1; -#endif - return 0; -} - -struct regex_data * regex_data_create() { - struct regex_data * dummy = (struct regex_data*) malloc( - sizeof(struct regex_data)); - if (dummy) { - memset(dummy, 0, sizeof(struct regex_data)); - } - return dummy; -} - -void regex_data_free(struct regex_data * regex) { - if (regex) { -#ifdef USE_PCRE2 - if (regex->regex) { - pcre2_code_free(regex->regex); - } - if (regex->match_data) { - pcre2_match_data_free(regex->match_data); - } -#else - if (regex->regex) - pcre_free(regex->regex); - if (regex->extra_owned && regex->sd) { - pcre_free_study(regex->sd); - } -#endif - free(regex); - } -} - -int regex_match(struct regex_data * regex, char const * subject, int partial) { - int rc; -#ifdef USE_PCRE2 - rc = pcre2_match(regex->regex, - (PCRE2_SPTR)subject, PCRE2_ZERO_TERMINATED, 0, - partial ? PCRE2_PARTIAL_SOFT : 0, regex->match_data, - NULL); - if (rc > 0) - return REGEX_MATCH; - switch (rc) { - case PCRE2_ERROR_PARTIAL: - return REGEX_MATCH_PARTIAL; - case PCRE2_ERROR_NOMATCH: - return REGEX_NO_MATCH; - default: - return REGEX_ERROR; - } -#else - rc = pcre_exec(regex->regex, - regex->extra_owned ? regex->sd : ®ex->lsd, subject, - strlen(subject), 0, partial ? PCRE_PARTIAL_SOFT : 0, - NULL, - 0); - switch (rc) { - case 0: - return REGEX_MATCH; - case PCRE_ERROR_PARTIAL: - return REGEX_MATCH_PARTIAL; - case PCRE_ERROR_NOMATCH: - return REGEX_NO_MATCH; - default: - return REGEX_ERROR; - } -#endif -} - -/* TODO Replace this compare function with something that actually compares the - * regular expressions. - * This compare function basically just compares the binary representations of - * the automatons, and because this representation contains pointers and - * metadata, it can only return a match if regex1 == regex2. - * Preferably, this function would be replaced with an algorithm that computes - * the equivalence of the automatons systematically. - */ -int regex_cmp(struct regex_data * regex1, struct regex_data * regex2) { - int rc; - size_t len1, len2; -#ifdef USE_PCRE2 - rc = pcre2_pattern_info(regex1->regex, PCRE2_INFO_SIZE, &len1); - assert(rc == 0); - rc = pcre2_pattern_info(regex2->regex, PCRE2_INFO_SIZE, &len2); - assert(rc == 0); - if (len1 != len2 || memcmp(regex1->regex, regex2->regex, len1)) - return SELABEL_INCOMPARABLE; -#else - rc = pcre_fullinfo(regex1->regex, NULL, PCRE_INFO_SIZE, &len1); - assert(rc == 0); - rc = pcre_fullinfo(regex2->regex, NULL, PCRE_INFO_SIZE, &len2); - assert(rc == 0); - if (len1 != len2 || memcmp(regex1->regex, regex2->regex, len1)) - return SELABEL_INCOMPARABLE; -#endif - return SELABEL_EQUAL; -} - -void regex_format_error(struct regex_error_data const * error_data, - char * buffer, size_t buf_size) { - unsigned the_end_length = buf_size > 4 ? 4 : buf_size; - char * ptr = &buffer[buf_size - the_end_length]; - int rc = 0; - size_t pos = 0; - if (!buffer || !buf_size) - return; - rc = snprintf(buffer, buf_size, "REGEX back-end error: "); - if (rc < 0) - /* If snprintf fails it constitutes a logical error that needs - * fixing. - */ - abort(); - - pos += rc; - if (pos >= buf_size) - goto truncated; - - if (error_data->error_offset > 0) { -#ifdef USE_PCRE2 - rc = snprintf(buffer + pos, buf_size - pos, "At offset %zu: ", - error_data->error_offset); -#else - rc = snprintf(buffer + pos, buf_size - pos, "At offset %d: ", - error_data->error_offset); -#endif - if (rc < 0) - abort(); - - } - pos += rc; - if (pos >= buf_size) - goto truncated; - -#ifdef USE_PCRE2 - rc = pcre2_get_error_message(error_data->error_code, - (PCRE2_UCHAR*)(buffer + pos), - buf_size - pos); - if (rc == PCRE2_ERROR_NOMEMORY) - goto truncated; -#else - rc = snprintf(buffer + pos, buf_size - pos, "%s", - error_data->error_buffer); - if (rc < 0) - abort(); - - if ((size_t)rc < strlen(error_data->error_buffer)) - goto truncated; -#endif - - return; - -truncated: - /* replace end of string with "..." to indicate that it was truncated */ - switch (the_end_length) { - /* no break statements, fall-through is intended */ - case 4: - *ptr++ = '.'; - case 3: - *ptr++ = '.'; - case 2: - *ptr++ = '.'; - case 1: - *ptr++ = '\0'; - default: - break; - } - return; -} diff --git a/src/regex.h b/src/regex.h deleted file mode 100644 index 7b74f32..0000000 --- a/src/regex.h +++ /dev/null @@ -1,166 +0,0 @@ -#ifndef SRC_REGEX_H_ -#define SRC_REGEX_H_ - -#include <stdio.h> - -#ifdef USE_PCRE2 -#include <pcre2.h> -#else -#include <pcre.h> -#endif - -enum { - REGEX_MATCH, - REGEX_MATCH_PARTIAL, - REGEX_NO_MATCH, - REGEX_ERROR = -1, -}; - -#ifdef USE_PCRE2 -struct regex_data { - pcre2_code * regex; /* compiled regular expression */ - pcre2_match_data * match_data; /* match data block required for the compiled - pattern in regex2 */ -}; - -struct regex_error_data { - int error_code; - PCRE2_SIZE error_offset; -}; - -/* ^^^^^^ USE_PCRE2 ^^^^^^ */ -#else -/* vvvvvv USE_PCRE vvvvvv */ - -/* Prior to version 8.20, libpcre did not have pcre_free_study() */ -#if (PCRE_MAJOR < 8 || (PCRE_MAJOR == 8 && PCRE_MINOR < 20)) -#define pcre_free_study pcre_free -#endif - -struct regex_data { - pcre *regex; /* compiled regular expression */ - int extra_owned; - union { - pcre_extra *sd; /* pointer to extra compiled stuff */ - pcre_extra lsd; /* used to hold the mmap'd version */ - }; -}; - -struct regex_error_data { - char const * error_buffer; - int error_offset; -}; - -#endif /* USE_PCRE2 */ - -struct mmap_area; - -/** - * regex_verison returns the version string of the underlying regular - * regular expressions library. In the case of PCRE it just returns the - * result of pcre_version(). In the case of PCRE2, the very first time this - * function is called it allocates a buffer large enough to hold the version - * string and reads the PCRE2_CONFIG_VERSION option to fill the buffer. - * The allocated buffer will linger in memory until the calling process is being - * reaped. - * - * It may return NULL on error. - */ -char const * regex_version(); -/** - * This constructor function allocates a buffer for a regex_data structure. - * The buffer is being initialized with zeroes. - */ -struct regex_data * regex_data_create(); -/** - * This complementary destructor function frees the a given regex_data buffer. - * It also frees any non NULL member pointers with the appropriate pcreX_X_free - * function. For PCRE this function respects the extra_owned field and frees - * the pcre_extra data conditionally. Calling this function on a NULL pointer is - * save. - */ -void regex_data_free(struct regex_data * regex); -/** - * This function compiles the regular expression. Additionally, it prepares - * data structures required by the different underlying engines. For PCRE - * it calls pcre_study to generate optional data required for optimized - * execution of the compiled pattern. In the case of PCRE2, it allocates - * a pcre2_match_data structure of appropriate size to hold all possible - * matches created by the pattern. - * - * @arg regex If successful, the structure returned through *regex was allocated - * with regex_data_create and must be freed with regex_data_free. - * @arg pattern_string The pattern string that is to be compiled. - * @arg errordata A pointer to a regex_error_data structure must be passed - * to this function. This structure depends on the underlying - * implementation. It can be passed to regex_format_error - * to generate a human readable error message. - * @retval 0 on success - * @retval -1 on error - */ -int regex_prepare_data(struct regex_data ** regex, char const * pattern_string, - struct regex_error_data * errordata); -/** - * This function loads a serialized precompiled pattern from a contiguous - * data region given by map_area. - * - * @arg map_area Description of the memory region holding a serialized - * representation of the precompiled pattern. - * @arg regex If successful, the structure returned through *regex was allocated - * with regex_data_create and must be freed with regex_data_free. - * - * @retval 0 on success - * @retval -1 on error - */ -int regex_load_mmap(struct mmap_area * map_area, struct regex_data ** regex); -/** - * This function stores a precompiled regular expression to a file. - * In the case of PCRE, it just dumps the binary representation of the - * precomplied pattern into a file. In the case of PCRE2, it uses the - * serialization function provided by the library. - * - * @arg regex The precomplied regular expression data. - * @arg fp A file stream specifying the output file. - */ -int regex_writef(struct regex_data * regex, FILE * fp); -/** - * This function applies a precompiled pattern to a subject string and - * returns whether or not a match was found. - * - * @arg regex The precompiled pattern. - * @arg subject The subject string. - * @arg partial Boolean indicating if partial matches are wanted. A nonzero - * value is equivalent to specifying PCRE[2]_PARTIAL_SOFT as - * option to pcre_exec of pcre2_match. - * @retval REGEX_MATCH if a match was found - * @retval REGEX_MATCH_PARTIAL if a partial match was found - * @retval REGEX_NO_MATCH if no match was found - * @retval REGEX_ERROR if an error was encountered during the execution of the - * regular expression - */ -int regex_match(struct regex_data * regex, char const * subject, int partial); -/** - * This function compares two compiled regular expressions (regex1 and regex2). - * It compares the binary representations of the compiled patterns. It is a very - * crude approximation because the binary representation holds data like - * reference counters, that has nothing to do with the actual state machine. - * - * @retval SELABEL_EQUAL if the pattern's binary representations are exactly - * the same - * @retval SELABEL_INCOMPARABLE otherwise - */ -int regex_cmp(struct regex_data * regex1, struct regex_data * regex2); -/** - * This function takes the error data returned by regex_prepare_data and turns - * it in to a human readable error message. - * If the buffer given to hold the error message is to small it truncates the - * message and indicates the truncation with an ellipsis ("...") at the end of - * the buffer. - * - * @arg error_data Error data as returned by regex_prepare_data. - * @arg buffer String buffer to hold the formated error string. - * @arg buf_size Total size of the given bufer in bytes. - */ -void regex_format_error(struct regex_error_data const * error_data, - char * buffer, size_t buf_size); -#endif /* SRC_REGEX_H_ */ diff --git a/src/selinux_internal.h b/src/selinux_internal.h deleted file mode 100644 index 5087bb6..0000000 --- a/src/selinux_internal.h +++ /dev/null @@ -1,132 +0,0 @@ -#include <selinux/selinux.h> -#include <pthread.h> -#include "dso.h" - -hidden_proto(selinux_mkload_policy) - hidden_proto(set_selinuxmnt) - hidden_proto(security_disable) - hidden_proto(security_policyvers) - hidden_proto(security_load_policy) - hidden_proto(security_get_boolean_active) - hidden_proto(security_get_boolean_names) - hidden_proto(security_set_boolean) - hidden_proto(security_commit_booleans) - hidden_proto(security_check_context) - hidden_proto(security_check_context_raw) - hidden_proto(security_canonicalize_context) - hidden_proto(security_canonicalize_context_raw) - hidden_proto(security_compute_av) - hidden_proto(security_compute_av_raw) - hidden_proto(security_compute_av_flags) - hidden_proto(security_compute_av_flags_raw) - hidden_proto(security_compute_user) - hidden_proto(security_compute_user_raw) - hidden_proto(security_compute_create) - hidden_proto(security_compute_create_raw) - hidden_proto(security_compute_member_raw) - hidden_proto(security_compute_relabel_raw) - hidden_proto(is_selinux_enabled) - hidden_proto(is_selinux_mls_enabled) - hidden_proto(freecon) - hidden_proto(freeconary) - hidden_proto(getprevcon) - hidden_proto(getprevcon_raw) - hidden_proto(getcon) - hidden_proto(getcon_raw) - hidden_proto(setcon_raw) - hidden_proto(getpeercon_raw) - hidden_proto(getpidcon_raw) - hidden_proto(getexeccon_raw) - hidden_proto(getfilecon) - hidden_proto(getfilecon_raw) - hidden_proto(lgetfilecon_raw) - hidden_proto(fgetfilecon_raw) - hidden_proto(setfilecon_raw) - hidden_proto(lsetfilecon_raw) - hidden_proto(fsetfilecon_raw) - hidden_proto(setexeccon) - hidden_proto(setexeccon_raw) - hidden_proto(getfscreatecon_raw) - hidden_proto(getkeycreatecon_raw) - hidden_proto(getsockcreatecon_raw) - hidden_proto(setfscreatecon_raw) - hidden_proto(setkeycreatecon_raw) - hidden_proto(setsockcreatecon_raw) - hidden_proto(security_getenforce) - hidden_proto(security_setenforce) - hidden_proto(security_deny_unknown) - hidden_proto(selinux_binary_policy_path) - hidden_proto(selinux_default_context_path) - hidden_proto(selinux_securetty_types_path) - hidden_proto(selinux_failsafe_context_path) - hidden_proto(selinux_removable_context_path) - hidden_proto(selinux_virtual_domain_context_path) - hidden_proto(selinux_virtual_image_context_path) - hidden_proto(selinux_file_context_path) - hidden_proto(selinux_file_context_homedir_path) - hidden_proto(selinux_file_context_local_path) - hidden_proto(selinux_file_context_subs_path) - hidden_proto(selinux_netfilter_context_path) - hidden_proto(selinux_homedir_context_path) - hidden_proto(selinux_user_contexts_path) - hidden_proto(selinux_booleans_path) - hidden_proto(selinux_customizable_types_path) - hidden_proto(selinux_media_context_path) - hidden_proto(selinux_x_context_path) - hidden_proto(selinux_sepgsql_context_path) - hidden_proto(selinux_path) - hidden_proto(selinux_check_passwd_access) - hidden_proto(selinux_check_securetty_context) - hidden_proto(matchpathcon_init_prefix) - hidden_proto(selinux_users_path) - hidden_proto(selinux_usersconf_path); -hidden_proto(selinux_translations_path); -hidden_proto(selinux_colors_path); -hidden_proto(selinux_getenforcemode); -hidden_proto(selinux_getpolicytype); -hidden_proto(selinux_raw_to_trans_context); -hidden_proto(selinux_trans_to_raw_context); - hidden_proto(selinux_raw_context_to_color); -hidden_proto(security_get_initial_context); -hidden_proto(security_get_initial_context_raw); -hidden_proto(selinux_reset_config); - -extern int selinux_page_size hidden; - -/* Make pthread_once optional */ -#pragma weak pthread_once -#pragma weak pthread_key_create -#pragma weak pthread_key_delete -#pragma weak pthread_setspecific - -/* Call handler iff the first call. */ -#define __selinux_once(ONCE_CONTROL, INIT_FUNCTION) \ - do { \ - if (pthread_once != NULL) \ - pthread_once (&(ONCE_CONTROL), (INIT_FUNCTION)); \ - else if ((ONCE_CONTROL) == PTHREAD_ONCE_INIT) { \ - INIT_FUNCTION (); \ - (ONCE_CONTROL) = 2; \ - } \ - } while (0) - -/* Pthread key macros */ -#define __selinux_key_create(KEY, DESTRUCTOR) \ - do { \ - if (pthread_key_create != NULL) \ - pthread_key_create(KEY, DESTRUCTOR); \ - } while (0) - -#define __selinux_key_delete(KEY) \ - do { \ - if (pthread_key_delete != NULL) \ - pthread_key_delete(KEY); \ - } while (0) - -#define __selinux_setspecific(KEY, VALUE) \ - do { \ - if (pthread_setspecific != NULL) \ - pthread_setspecific(KEY, VALUE); \ - } while (0) - - diff --git a/src/selinux_netlink.h b/src/selinux_netlink.h deleted file mode 100644 index 88ef551..0000000 --- a/src/selinux_netlink.h +++ /dev/null @@ -1,31 +0,0 @@ -/* - * Netlink event notifications for SELinux. - * - * Author: James Morris <jmorris@redhat.com> - */ -#ifndef _LINUX_SELINUX_NETLINK_H -#define _LINUX_SELINUX_NETLINK_H - -/* Message types. */ -#define SELNL_MSG_BASE 0x10 -enum { - SELNL_MSG_SETENFORCE = SELNL_MSG_BASE, - SELNL_MSG_POLICYLOAD, - SELNL_MSG_MAX -}; - -/* Multicast groups */ -#define SELNL_GRP_NONE 0x00000000 -#define SELNL_GRP_AVC 0x00000001 /* AVC notifications */ -#define SELNL_GRP_ALL 0xffffffff - -/* Message structures */ -struct selnl_msg_setenforce { - int32_t val; -}; - -struct selnl_msg_policyload { - uint32_t seqno; -}; - -#endif /* _LINUX_SELINUX_NETLINK_H */ diff --git a/src/sestatus.c b/src/sestatus.c deleted file mode 100644 index ed29dc5..0000000 --- a/src/sestatus.c +++ /dev/null @@ -1,349 +0,0 @@ -/* - * sestatus.c - * - * APIs to reference SELinux kernel status page (/selinux/status) - * - * Author: KaiGai Kohei <kaigai@ak.jp.nec.com> - * - */ -#include <fcntl.h> -#include <limits.h> -#include <sched.h> -#include <sys/mman.h> -#include <sys/stat.h> -#include <sys/types.h> -#include <unistd.h> -#include "avc_internal.h" -#include "policy.h" - -/* - * copied from the selinux/include/security.h - */ -struct selinux_status_t -{ - uint32_t version; /* version number of thie structure */ - uint32_t sequence; /* sequence number of seqlock logic */ - uint32_t enforcing; /* current setting of enforcing mode */ - uint32_t policyload; /* times of policy reloaded */ - uint32_t deny_unknown; /* current setting of deny_unknown */ - /* version > 0 support above status */ -} __attribute((packed)); - -/* - * `selinux_status' - * - * NULL : not initialized yet - * MAP_FAILED : opened, but fallback-mode - * Valid Pointer : opened and mapped correctly - */ -static struct selinux_status_t *selinux_status = NULL; -static int selinux_status_fd; -static uint32_t last_seqno; - -static uint32_t fallback_sequence; -static int fallback_enforcing; -static int fallback_policyload; - -/* - * read_sequence - * - * A utility routine to reference kernel status page according to - * seqlock logic. Since selinux_status->sequence is an odd value during - * the kernel status page being updated, we try to synchronize completion - * of this updating, but we assume it is rare. - * The sequence is almost even number. - * - * __sync_synchronize is a portable memory barrier for various kind - * of architecture that is supported by GCC. - */ -static inline uint32_t read_sequence(struct selinux_status_t *status) -{ - uint32_t seqno = 0; - - do { - /* - * No need for sched_yield() in the first trial of - * this loop. - */ - if (seqno & 0x0001) - sched_yield(); - - seqno = status->sequence; - - __sync_synchronize(); - - } while (seqno & 0x0001); - - return seqno; -} - -/* - * selinux_status_updated - * - * It returns whether something has been happened since the last call. - * Because `selinux_status->sequence' shall be always incremented on - * both of setenforce/policyreload events, so differences from the last - * value informs us something has been happened. - */ -int selinux_status_updated(void) -{ - uint32_t curr_seqno; - int result = 0; - - if (selinux_status == NULL) { - errno = EINVAL; - return -1; - } - - if (selinux_status == MAP_FAILED) { - if (avc_netlink_check_nb() < 0) - return -1; - - curr_seqno = fallback_sequence; - } else { - curr_seqno = read_sequence(selinux_status); - } - - /* - * `curr_seqno' is always even-number, so it does not match with - * `last_seqno' being initialized to odd-number in the first call. - * We never return 'something was updated' in the first call, - * because this function focuses on status-updating since the last - * invocation. - */ - if (last_seqno & 0x0001) - last_seqno = curr_seqno; - - if (last_seqno != curr_seqno) - { - last_seqno = curr_seqno; - result = 1; - } - return result; -} - -/* - * selinux_status_getenforce - * - * It returns the current performing mode of SELinux. - * 1 means currently we run in enforcing mode, or 0 means permissive mode. - */ -int selinux_status_getenforce(void) -{ - uint32_t seqno; - uint32_t enforcing; - - if (selinux_status == NULL) { - errno = EINVAL; - return -1; - } - - if (selinux_status == MAP_FAILED) { - if (avc_netlink_check_nb() < 0) - return -1; - - return fallback_enforcing; - } - - /* sequence must not be changed during references */ - do { - seqno = read_sequence(selinux_status); - - enforcing = selinux_status->enforcing; - - } while (seqno != read_sequence(selinux_status)); - - return enforcing ? 1 : 0; -} - -/* - * selinux_status_policyload - * - * It returns times of policy reloaded on the running system. - * Note that it is not a reliable value on fallback-mode until it receives - * the first event message via netlink socket, so, a correct usage of this - * value is to compare it with the previous value to detect policy reloaded - * event. - */ -int selinux_status_policyload(void) -{ - uint32_t seqno; - uint32_t policyload; - - if (selinux_status == NULL) { - errno = EINVAL; - return -1; - } - - if (selinux_status == MAP_FAILED) { - if (avc_netlink_check_nb() < 0) - return -1; - - return fallback_policyload; - } - - /* sequence must not be changed during references */ - do { - seqno = read_sequence(selinux_status); - - policyload = selinux_status->policyload; - - } while (seqno != read_sequence(selinux_status)); - - return policyload; -} - -/* - * selinux_status_deny_unknown - * - * It returns a guideline to handle undefined object classes or permissions. - * 0 means SELinux treats policy queries on undefined stuff being allowed, - * however, 1 means such queries are denied. - */ -int selinux_status_deny_unknown(void) -{ - uint32_t seqno; - uint32_t deny_unknown; - - if (selinux_status == NULL) { - errno = EINVAL; - return -1; - } - - if (selinux_status == MAP_FAILED) - return security_deny_unknown(); - - /* sequence must not be changed during references */ - do { - seqno = read_sequence(selinux_status); - - deny_unknown = selinux_status->deny_unknown; - - } while (seqno != read_sequence(selinux_status)); - - return deny_unknown ? 1 : 0; -} - -/* - * callback routines for fallback case using netlink socket - */ -static int fallback_cb_setenforce(int enforcing) -{ - fallback_sequence += 2; - fallback_enforcing = enforcing; - - return 0; -} - -static int fallback_cb_policyload(int policyload) -{ - fallback_sequence += 2; - fallback_policyload = policyload; - - return 0; -} - -/* - * selinux_status_open - * - * It tries to open and mmap kernel status page (/selinux/status). - * Since Linux 2.6.37 or later supports this feature, we may run - * fallback routine using a netlink socket on older kernels, if - * the supplied `fallback' is not zero. - * It returns 0 on success, or -1 on error. - */ -int selinux_status_open(int fallback) -{ - int fd; - char path[PATH_MAX]; - long pagesize; - - if (!selinux_mnt) { - errno = ENOENT; - return -1; - } - - pagesize = sysconf(_SC_PAGESIZE); - if (pagesize < 0) - return -1; - - snprintf(path, sizeof(path), "%s/status", selinux_mnt); - fd = open(path, O_RDONLY | O_CLOEXEC); - if (fd < 0) - goto error; - - selinux_status = mmap(NULL, pagesize, PROT_READ, MAP_SHARED, fd, 0); - if (selinux_status == MAP_FAILED) { - close(fd); - goto error; - } - selinux_status_fd = fd; - last_seqno = (uint32_t)(-1); - - return 0; - -error: - /* - * If caller wants fallback routine, we try to provide - * an equivalent functionality using existing netlink - * socket, although it needs system call invocation to - * receive event notification. - */ - if (fallback && avc_netlink_open(0) == 0) { - union selinux_callback cb; - - /* register my callbacks */ - cb.func_setenforce = fallback_cb_setenforce; - selinux_set_callback(SELINUX_CB_SETENFORCE, cb); - cb.func_policyload = fallback_cb_policyload; - selinux_set_callback(SELINUX_CB_POLICYLOAD, cb); - - /* mark as fallback mode */ - selinux_status = MAP_FAILED; - selinux_status_fd = avc_netlink_acquire_fd(); - last_seqno = (uint32_t)(-1); - - fallback_sequence = 0; - fallback_enforcing = security_getenforce(); - fallback_policyload = 0; - - return 1; - } - selinux_status = NULL; - - return -1; -} - -/* - * selinux_status_close - * - * It unmap and close the kernel status page, or close netlink socket - * if fallback mode. - */ -void selinux_status_close(void) -{ - long pagesize; - - /* not opened */ - if (selinux_status == NULL) - return; - - /* fallback-mode */ - if (selinux_status == MAP_FAILED) - { - avc_netlink_release_fd(); - avc_netlink_close(); - selinux_status = NULL; - return; - } - - pagesize = sysconf(_SC_PAGESIZE); - /* not much we can do other than leak memory */ - if (pagesize > 0) - munmap(selinux_status, pagesize); - selinux_status = NULL; - - close(selinux_status_fd); - selinux_status_fd = -1; - last_seqno = (uint32_t)(-1); -} diff --git a/src/setenforce.c b/src/setenforce.c deleted file mode 100644 index e5e7612..0000000 --- a/src/setenforce.c +++ /dev/null @@ -1,37 +0,0 @@ -#include <unistd.h> -#include <sys/types.h> -#include <fcntl.h> -#include <stdlib.h> -#include <errno.h> -#include <string.h> -#include "selinux_internal.h" -#include "policy.h" -#include <stdio.h> -#include <limits.h> - -int security_setenforce(int value) -{ - int fd, ret; - char path[PATH_MAX]; - char buf[20]; - - if (!selinux_mnt) { - errno = ENOENT; - return -1; - } - - snprintf(path, sizeof path, "%s/enforce", selinux_mnt); - fd = open(path, O_RDWR); - if (fd < 0) - return -1; - - snprintf(buf, sizeof buf, "%d", value); - ret = write(fd, buf, strlen(buf)); - close(fd); - if (ret < 0) - return -1; - - return 0; -} - -hidden_def(security_setenforce) diff --git a/src/setfilecon.c b/src/setfilecon.c deleted file mode 100644 index 81322f8..0000000 --- a/src/setfilecon.c +++ /dev/null @@ -1,15 +0,0 @@ -#include <unistd.h> -#include <fcntl.h> -#include <string.h> -#include <stdlib.h> -#include <errno.h> -#include <sys/xattr.h> -#include "selinux_internal.h" -#include "policy.h" - -int setfilecon(const char *path, const char *context) -{ - return setxattr(path, XATTR_NAME_SELINUX, context, strlen(context) + 1, - 0); -} - diff --git a/src/stringrep.c b/src/stringrep.c deleted file mode 100644 index c867222..0000000 --- a/src/stringrep.c +++ /dev/null @@ -1,277 +0,0 @@ -/* - * String representation support for classes and permissions. - */ -#include <sys/stat.h> -#include <dirent.h> -#include <fcntl.h> -#include <limits.h> -#include <unistd.h> -#include <errno.h> -#include <stddef.h> -#include <stdio.h> -#include <stdlib.h> -#include <string.h> -#include <stdint.h> -#include <ctype.h> -#include "selinux_internal.h" -#include "policy.h" -#include "mapping.h" - -#define MAXVECTORS 8*sizeof(access_vector_t) - -struct discover_class_node { - char *name; - security_class_t value; - char **perms; - - struct discover_class_node *next; -}; - -static struct discover_class_node *discover_class_cache = NULL; - -static struct discover_class_node * get_class_cache_entry_name(const char *s) -{ - struct discover_class_node *node = discover_class_cache; - - for (; node != NULL && strcmp(s,node->name) != 0; node = node->next); - - return node; -} - -static struct discover_class_node * get_class_cache_entry_value(security_class_t c) -{ - struct discover_class_node *node = discover_class_cache; - - for (; node != NULL && c != node->value; node = node->next); - - return node; -} - -static struct discover_class_node * discover_class(const char *s) -{ - int fd, ret; - char path[PATH_MAX]; - char buf[20]; - DIR *dir; - struct dirent *dentry; - size_t i; - - struct discover_class_node *node; - - if (!selinux_mnt) { - errno = ENOENT; - return NULL; - } - - /* allocate a node */ - node = malloc(sizeof(struct discover_class_node)); - if (node == NULL) - return NULL; - - /* allocate array for perms */ - node->perms = calloc(MAXVECTORS,sizeof(char*)); - if (node->perms == NULL) - goto err1; - - /* load up the name */ - node->name = strdup(s); - if (node->name == NULL) - goto err2; - - /* load up class index */ - snprintf(path, sizeof path, "%s/class/%s/index", selinux_mnt,s); - fd = open(path, O_RDONLY); - if (fd < 0) - goto err3; - - memset(buf, 0, sizeof(buf)); - ret = read(fd, buf, sizeof(buf) - 1); - close(fd); - if (ret < 0) - goto err3; - - if (sscanf(buf, "%hu", &node->value) != 1) - goto err3; - - /* load up permission indicies */ - snprintf(path, sizeof path, "%s/class/%s/perms",selinux_mnt,s); - dir = opendir(path); - if (dir == NULL) - goto err3; - - dentry = readdir(dir); - while (dentry != NULL) { - unsigned int value; - struct stat m; - - snprintf(path, sizeof path, "%s/class/%s/perms/%s", selinux_mnt,s,dentry->d_name); - fd = open(path, O_RDONLY | O_CLOEXEC); - if (fd < 0) - goto err4; - - if (fstat(fd, &m) < 0) { - close(fd); - goto err4; - } - - if (m.st_mode & S_IFDIR) { - close(fd); - dentry = readdir(dir); - continue; - } - - memset(buf, 0, sizeof(buf)); - ret = read(fd, buf, sizeof(buf) - 1); - close(fd); - if (ret < 0) - goto err4; - - if (sscanf(buf, "%u", &value) != 1) - goto err4; - - if (value == 0 || value > MAXVECTORS) - goto err4; - - node->perms[value-1] = strdup(dentry->d_name); - if (node->perms[value-1] == NULL) - goto err4; - - dentry = readdir(dir); - } - closedir(dir); - - node->next = discover_class_cache; - discover_class_cache = node; - - return node; - -err4: - closedir(dir); - for (i=0; i<MAXVECTORS; i++) - free(node->perms[i]); -err3: - free(node->name); -err2: - free(node->perms); -err1: - free(node); - return NULL; -} - -security_class_t string_to_security_class(const char *s) -{ - struct discover_class_node *node; - - node = get_class_cache_entry_name(s); - if (node == NULL) { - node = discover_class(s); - - if (node == NULL) { - errno = EINVAL; - return 0; - } - } - - return map_class(node->value); -} - -access_vector_t string_to_av_perm(security_class_t tclass, const char *s) -{ - struct discover_class_node *node; - security_class_t kclass = unmap_class(tclass); - - node = get_class_cache_entry_value(kclass); - if (node != NULL) { - size_t i; - for (i=0; i<MAXVECTORS && node->perms[i] != NULL; i++) - if (strcmp(node->perms[i],s) == 0) - return map_perm(tclass, 1<<i); - } - - errno = EINVAL; - return 0; -} - -const char *security_class_to_string(security_class_t tclass) -{ - struct discover_class_node *node; - - tclass = unmap_class(tclass); - - node = get_class_cache_entry_value(tclass); - if (node) - return node->name; - return NULL; -} - -const char *security_av_perm_to_string(security_class_t tclass, - access_vector_t av) -{ - struct discover_class_node *node; - size_t i; - - av = unmap_perm(tclass, av); - tclass = unmap_class(tclass); - - node = get_class_cache_entry_value(tclass); - if (av && node) - for (i = 0; i<MAXVECTORS; i++) - if ((1<<i) & av) - return node->perms[i]; - - return NULL; -} - -int security_av_string(security_class_t tclass, access_vector_t av, char **res) -{ - unsigned int i = 0; - size_t len = 5; - access_vector_t tmp = av; - int rc = 0; - const char *str; - char *ptr; - - /* first pass computes the required length */ - while (tmp) { - if (tmp & 1) { - str = security_av_perm_to_string(tclass, av & (1<<i)); - if (str) - len += strlen(str) + 1; - else { - rc = -1; - errno = EINVAL; - goto out; - } - } - tmp >>= 1; - i++; - } - - *res = malloc(len); - if (!*res) { - rc = -1; - goto out; - } - - /* second pass constructs the string */ - i = 0; - tmp = av; - ptr = *res; - - if (!av) { - sprintf(ptr, "null"); - goto out; - } - - ptr += sprintf(ptr, "{ "); - while (tmp) { - if (tmp & 1) - ptr += sprintf(ptr, "%s ", security_av_perm_to_string( - tclass, av & (1<<i))); - tmp >>= 1; - i++; - } - sprintf(ptr, "}"); -out: - return rc; -} diff --git a/utils/sefcontext_compile.c b/utils/sefcontext_compile.c deleted file mode 100644 index f88c756..0000000 --- a/utils/sefcontext_compile.c +++ /dev/null @@ -1,363 +0,0 @@ -#include <ctype.h> -#include <errno.h> -#include <stdint.h> -#include <stdio.h> -#include <string.h> -#include <unistd.h> -#include <sys/types.h> -#include <sys/stat.h> -#include <getopt.h> -#include <limits.h> -#include <selinux/selinux.h> - -#include "../src/label_file.h" -#include "../src/regex.h" - -static int validate_context(char __attribute__ ((unused)) **ctx) -{ - return 0; -} - -static int process_file(struct selabel_handle *rec, const char *filename) -{ - unsigned int line_num; - int rc; - char *line_buf = NULL; - size_t line_len = 0; - FILE *context_file; - const char *prefix = NULL; - - context_file = fopen(filename, "r"); - if (!context_file) { - fprintf(stderr, "Error opening %s: %s\n", - filename, strerror(errno)); - return -1; - } - - line_num = 0; - rc = 0; - while (getline(&line_buf, &line_len, context_file) > 0) { - rc = process_line(rec, filename, prefix, line_buf, ++line_num); - if (rc) - goto out; - } -out: - free(line_buf); - fclose(context_file); - return rc; -} - -/* - * File Format - * - * u32 - magic number - * u32 - version - * u32 - length of pcre version EXCLUDING nul - * char - pcre version string EXCLUDING nul - * u32 - number of stems - * ** Stems - * u32 - length of stem EXCLUDING nul - * char - stem char array INCLUDING nul - * u32 - number of regexs - * ** Regexes - * u32 - length of upcoming context INCLUDING nul - * char - char array of the raw context - * u32 - length of the upcoming regex_str - * char - char array of the original regex string including the stem. - * u32 - mode bits for >= SELINUX_COMPILED_FCONTEXT_MODE - * mode_t for <= SELINUX_COMPILED_FCONTEXT_PCRE_VERS - * s32 - stemid associated with the regex - * u32 - spec has meta characters - * u32 - The specs prefix_len if >= SELINUX_COMPILED_FCONTEXT_PREFIX_LEN - * u32 - data length of the pcre regex - * char - a bufer holding the raw pcre regex info - * u32 - data length of the pcre regex study daya - * char - a buffer holding the raw pcre regex study data - */ -static int write_binary_file(struct saved_data *data, int fd) -{ - struct spec *specs = data->spec_arr; - FILE *bin_file; - size_t len; - uint32_t magic = SELINUX_MAGIC_COMPILED_FCONTEXT; - uint32_t section_len; - uint32_t i; - int rc; - - bin_file = fdopen(fd, "w"); - if (!bin_file) { - perror("fopen output_file"); - exit(EXIT_FAILURE); - } - - /* write some magic number */ - len = fwrite(&magic, sizeof(uint32_t), 1, bin_file); - if (len != 1) - goto err; - - /* write the version */ - section_len = SELINUX_COMPILED_FCONTEXT_MAX_VERS; - len = fwrite(§ion_len, sizeof(uint32_t), 1, bin_file); - if (len != 1) - goto err; - - /* write version of the regex back-end */ - if (!regex_version()) - goto err; - section_len = strlen(regex_version()); - len = fwrite(§ion_len, sizeof(uint32_t), 1, bin_file); - if (len != 1) - goto err; - len = fwrite(regex_version(), sizeof(char), section_len, bin_file); - if (len != section_len) - goto err; - - /* write the number of stems coming */ - section_len = data->num_stems; - len = fwrite(§ion_len, sizeof(uint32_t), 1, bin_file); - if (len != 1) - goto err; - - for (i = 0; i < section_len; i++) { - char *stem = data->stem_arr[i].buf; - uint32_t stem_len = data->stem_arr[i].len; - - /* write the strlen (aka no nul) */ - len = fwrite(&stem_len, sizeof(uint32_t), 1, bin_file); - if (len != 1) - goto err; - - /* include the nul in the file */ - stem_len += 1; - len = fwrite(stem, sizeof(char), stem_len, bin_file); - if (len != stem_len) - goto err; - } - - /* write the number of regexes coming */ - section_len = data->nspec; - len = fwrite(§ion_len, sizeof(uint32_t), 1, bin_file); - if (len != 1) - goto err; - - for (i = 0; i < section_len; i++) { - char *context = specs[i].lr.ctx_raw; - char *regex_str = specs[i].regex_str; - mode_t mode = specs[i].mode; - size_t prefix_len = specs[i].prefix_len; - int32_t stem_id = specs[i].stem_id; - struct regex_data *re = specs[i].regex; - uint32_t to_write; - size_t size; - - /* length of the context string (including nul) */ - to_write = strlen(context) + 1; - len = fwrite(&to_write, sizeof(uint32_t), 1, bin_file); - if (len != 1) - goto err; - - /* original context strin (including nul) */ - len = fwrite(context, sizeof(char), to_write, bin_file); - if (len != to_write) - goto err; - - /* length of the original regex string (including nul) */ - to_write = strlen(regex_str) + 1; - len = fwrite(&to_write, sizeof(uint32_t), 1, bin_file); - if (len != 1) - goto err; - - /* original regex string */ - len = fwrite(regex_str, sizeof(char), to_write, bin_file); - if (len != to_write) - goto err; - - /* binary F_MODE bits */ - to_write = mode; - len = fwrite(&to_write, sizeof(uint32_t), 1, bin_file); - if (len != 1) - goto err; - - /* stem for this regex (could be -1) */ - len = fwrite(&stem_id, sizeof(stem_id), 1, bin_file); - if (len != 1) - goto err; - - /* does this spec have a metaChar? */ - to_write = specs[i].hasMetaChars; - len = fwrite(&to_write, sizeof(to_write), 1, bin_file); - if (len != 1) - goto err; - - /* For SELINUX_COMPILED_FCONTEXT_PREFIX_LEN */ - to_write = prefix_len; - len = fwrite(&to_write, sizeof(to_write), 1, bin_file); - if (len != 1) - goto err; - - /* Write regex related data */ - rc = regex_writef(re, bin_file); - if (rc < 0) - goto err; - } - - rc = 0; -out: - fclose(bin_file); - return rc; -err: - rc = -1; - goto out; -} - -static void free_specs(struct saved_data *data) -{ - struct spec *specs = data->spec_arr; - unsigned int num_entries = data->nspec; - unsigned int i; - - for (i = 0; i < num_entries; i++) { - free(specs[i].lr.ctx_raw); - free(specs[i].lr.ctx_trans); - free(specs[i].regex_str); - free(specs[i].type_str); - regex_data_free(specs[i].regex); - } - free(specs); - - num_entries = data->num_stems; - for (i = 0; i < num_entries; i++) - free(data->stem_arr[i].buf); - free(data->stem_arr); - - memset(data, 0, sizeof(*data)); -} - -static void usage(const char *progname) -{ - fprintf(stderr, - "usage: %s [-o out_file] fc_file\n" - "Where:\n\t" - "-o Optional file name of the PCRE formatted binary\n\t" - " file to be output. If not specified the default\n\t" - " will be fc_file with the .bin suffix appended.\n\t" - "fc_file The text based file contexts file to be processed.\n", - progname); - exit(EXIT_FAILURE); -} - -int main(int argc, char *argv[]) -{ - const char *path = NULL; - const char *out_file = NULL; - char stack_path[PATH_MAX + 1]; - char *tmp = NULL; - int fd, rc, opt; - struct stat buf; - struct selabel_handle *rec = NULL; - struct saved_data *data = NULL; - - if (argc < 2) - usage(argv[0]); - - while ((opt = getopt(argc, argv, "o:")) > 0) { - switch (opt) { - case 'o': - out_file = optarg; - break; - default: - usage(argv[0]); - } - } - - if (optind >= argc) - usage(argv[0]); - - path = argv[optind]; - if (stat(path, &buf) < 0) { - fprintf(stderr, "Can not stat: %s: %m\n", path); - exit(EXIT_FAILURE); - } - - /* Generate dummy handle for process_line() function */ - rec = (struct selabel_handle *)calloc(1, sizeof(*rec)); - if (!rec) { - fprintf(stderr, "Failed to calloc handle\n"); - exit(EXIT_FAILURE); - } - rec->backend = SELABEL_CTX_FILE; - - /* Need to set validation on to get the bin file generated by the - * process_line function, however as the bin file being generated - * may not be related to the currently loaded policy (that it - * would be validated against), then set callback to ignore any - * validation. */ - rec->validating = 1; - selinux_set_callback(SELINUX_CB_VALIDATE, - (union selinux_callback)&validate_context); - - data = (struct saved_data *)calloc(1, sizeof(*data)); - if (!data) { - fprintf(stderr, "Failed to calloc saved_data\n"); - free(rec); - exit(EXIT_FAILURE); - } - - rec->data = data; - - rc = process_file(rec, path); - if (rc < 0) - goto err; - - rc = sort_specs(data); - if (rc) - goto err; - - if (out_file) - rc = snprintf(stack_path, sizeof(stack_path), "%s", out_file); - else - rc = snprintf(stack_path, sizeof(stack_path), "%s.bin", path); - - if (rc < 0 || rc >= (int)sizeof(stack_path)) - goto err; - - tmp = malloc(strlen(stack_path) + 7); - if (!tmp) - goto err; - - rc = sprintf(tmp, "%sXXXXXX", stack_path); - if (rc < 0) - goto err; - - fd = mkstemp(tmp); - if (fd < 0) - goto err; - - rc = fchmod(fd, buf.st_mode); - if (rc < 0) { - perror("fchmod failed to set permission on compiled regexs"); - goto err_unlink; - } - - rc = write_binary_file(data, fd); - if (rc < 0) - goto err_unlink; - - rc = rename(tmp, stack_path); - if (rc < 0) - goto err_unlink; - - rc = 0; -out: - free_specs(data); - free(rec); - free(data); - free(tmp); - return rc; - -err_unlink: - unlink(tmp); -err: - rc = -1; - goto out; -} |