summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorStephen Smalley <sds@tycho.nsa.gov>2014-01-30 10:13:12 -0500
committerStephen Smalley <sds@tycho.nsa.gov>2014-02-06 12:30:03 -0500
commit08587cfbf9de7d89a3d2d4e87aecd82a478e3289 (patch)
tree391121a174b8429ff41ce36bc047a2883dff3082
parentb77c0360fa9baaac5e9cad173520a103f878bcbf (diff)
downloadlibselinux-08587cfbf9de7d89a3d2d4e87aecd82a478e3289.tar.gz
Unify toolbox restorecon and libselinux restorecon implementations.
Extend the libselinux restorecon implementation to allow reuse by the toolbox restorecon command. This simply requires adding support for the nochange (-n) and verbose (-v) options to the libselinux functions and rewriting the toolbox restorecon command to use the libselinux functions. Also add a force (-F) option to support forcing a restorecon_recursive even if the restorecon_last attribute matches the current file_contexts hash so that we can continue to force a restorecon via the toolbox command for testing or when we know something else has changed (e.g. for when we support relabeling /data/data and package information has changed). Change-Id: I92bb3259790a7195ba56a5e9555c3b6c76ceb862 Signed-off-by: Stephen Smalley <sds@tycho.nsa.gov>
-rw-r--r--include/selinux/android.h6
-rw-r--r--src/android.c128
2 files changed, 92 insertions, 42 deletions
diff --git a/include/selinux/android.h b/include/selinux/android.h
index d3b5e17..bb3993b 100644
--- a/include/selinux/android.h
+++ b/include/selinux/android.h
@@ -32,6 +32,12 @@ extern int selinux_android_setfilecon2(const char *pkgdir,
const char *seinfo,
uid_t uid);
+#define SELINUX_ANDROID_RESTORECON_NOCHANGE 1
+#define SELINUX_ANDROID_RESTORECON_VERBOSE 2
+#define SELINUX_ANDROID_RESTORECON_RECURSE 4
+#define SELINUX_ANDROID_RESTORECON_FORCE 8
+extern int selinux_android_restorecon_flags(const char *file, unsigned int flags);
+
extern int selinux_android_restorecon(const char *file);
extern int selinux_android_restorecon_recursive(const char *file);
diff --git a/src/android.c b/src/android.c
index 5810e63..aca5adb 100644
--- a/src/android.c
+++ b/src/android.c
@@ -8,13 +8,13 @@
#include <errno.h>
#include <pwd.h>
#include <grp.h>
-#include <ftw.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>
@@ -704,9 +704,11 @@ static void file_context_init(void)
sehandle = file_context_open();
}
+static pthread_once_t fc_once = PTHREAD_ONCE_INIT;
+
#define RESTORECON_LAST "security.restorecon_last"
-static int restorecon_sb(const char *pathname, const struct stat *sb, bool setrestoreconlast)
+static int restorecon_sb(const char *pathname, const struct stat *sb, bool setrestoreconlast, bool nochange, bool verbose)
{
char *secontext = NULL;
char *oldsecontext = NULL;
@@ -721,56 +723,41 @@ static int restorecon_sb(const char *pathname, const struct stat *sb, bool setre
}
if (strcmp(oldsecontext, secontext) != 0) {
- if (lsetfilecon(pathname, secontext) < 0) {
- selinux_log(SELINUX_ERROR,
- "SELinux: Could not set context for %s to %s: %s\n",
- pathname, secontext, strerror(errno));
- freecon(oldsecontext);
- freecon(secontext);
- return -1;
+ if (verbose)
+ selinux_log(SELINUX_INFO,
+ "SELinux: Relabeling %s from %s to %s.\n", pathname, oldsecontext, secontext);
+ if (!nochange) {
+ if (lsetfilecon(pathname, secontext) < 0) {
+ selinux_log(SELINUX_ERROR,
+ "SELinux: Could not set context for %s to %s: %s\n",
+ pathname, secontext, strerror(errno));
+ freecon(oldsecontext);
+ freecon(secontext);
+ return -1;
+ }
}
}
freecon(oldsecontext);
freecon(secontext);
- if (setrestoreconlast && S_ISDIR(sb->st_mode))
+ if (setrestoreconlast && !nochange && S_ISDIR(sb->st_mode))
setxattr(pathname, RESTORECON_LAST, fc_digest, sizeof fc_digest, 0);
return 0;
}
-static pthread_once_t fc_once = PTHREAD_ONCE_INIT;
-
-int selinux_android_restorecon(const char *pathname)
+int selinux_android_restorecon_flags(const char* pathname, 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;
struct stat sb;
-
- if (is_selinux_enabled() <= 0)
- return 0;
-
- __selinux_once(fc_once, file_context_init);
-
- if (!sehandle)
- return 0;
-
- if (lstat(pathname, &sb) < 0)
- return -1;
-
- return restorecon_sb(pathname, &sb, false);
-}
-
-static int nftw_restorecon(const char* filename, const struct stat* statptr,
- int fileflags __attribute__((unused)),
- struct FTW* pftw __attribute__((unused)))
-{
- restorecon_sb(filename, statptr, true);
- return 0;
-}
-
-int selinux_android_restorecon_recursive(const char* pathname)
-{
- int fd_limit = 20;
- int flags = FTW_DEPTH | FTW_MOUNT | FTW_PHYS;
+ FTS *fts;
+ FTSENT *ftsent;
+ char *const paths[2] = { __UNCONST(pathname), NULL };
+ int ftsflags = FTS_COMFOLLOW | FTS_NOCHDIR | FTS_XDEV | FTS_PHYSICAL;
+ int error, sverrno;
char xattr_value[FC_DIGEST_SIZE];
ssize_t size;
@@ -782,15 +769,72 @@ int selinux_android_restorecon_recursive(const char* pathname)
if (!sehandle)
return 0;
+ if (!recurse) {
+ if (lstat(pathname, &sb) < 0)
+ return -1;
+
+ return restorecon_sb(pathname, &sb, false, nochange, verbose);
+ }
+
size = getxattr(pathname, RESTORECON_LAST, xattr_value, sizeof fc_digest);
- if (size == sizeof fc_digest && memcmp(fc_digest, xattr_value, sizeof fc_digest) == 0) {
+ 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);
return 0;
}
- return nftw(pathname, nftw_restorecon, fd_limit, flags);
+ fts = fts_open(paths, ftsflags, NULL);
+ if (!fts)
+ return -1;
+
+ 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;
+ default:
+ (void) restorecon_sb(ftsent->fts_path, ftsent->fts_statp, true, nochange, verbose);
+ break;
+ }
+ }
+
+out:
+ sverrno = errno;
+ (void) fts_close(fts);
+ error = sverrno;
+ return error;
+}
+
+int selinux_android_restorecon(const char* pathname)
+{
+ return selinux_android_restorecon_flags(pathname, 0);
+}
+
+int selinux_android_restorecon_recursive(const char* pathname)
+{
+ return selinux_android_restorecon_flags(pathname, SELINUX_ANDROID_RESTORECON_RECURSE);
}
struct selabel_handle* selinux_android_file_context_handle(void)