* [PATCH 2/3] libselinux: Add setfiles support to selinux_restorecon(3)
@ 2016-05-10 15:23 Richard Haines
2016-05-20 17:03 ` Stephen Smalley
0 siblings, 1 reply; 3+ messages in thread
From: Richard Haines @ 2016-05-10 15:23 UTC (permalink / raw)
To: selinux
Add additional error handling, flags, xdev and alt_rootpath
support for setfiles(8) functionality.
Signed-off-by: Richard Haines <richard_c_haines@btinternet.com>
---
libselinux/include/selinux/restorecon.h | 17 +++
libselinux/man/man3/selinux_restorecon.3 | 13 +++
.../man/man3/selinux_restorecon_set_alt_rootpath.3 | 34 ++++++
libselinux/src/selinux_restorecon.c | 126 +++++++++++++++++----
libselinux/utils/selinux_restorecon.c | 28 ++++-
5 files changed, 197 insertions(+), 21 deletions(-)
create mode 100644 libselinux/man/man3/selinux_restorecon_set_alt_rootpath.3
diff --git a/libselinux/include/selinux/restorecon.h b/libselinux/include/selinux/restorecon.h
index 0b93b0c..6b3e0f1 100644
--- a/libselinux/include/selinux/restorecon.h
+++ b/libselinux/include/selinux/restorecon.h
@@ -50,6 +50,14 @@ extern int selinux_restorecon(const char *pathname,
* If there is a different context that matched the inode,
* then use the first context that matched. */
#define SELINUX_RESTORECON_ADD_ASSOC 256
+/* Abort on errors during the file tree walk. */
+#define SELINUX_RESTORECON_ABORT_ON_ERROR 512
+/* Log any label changes to syslog. */
+#define SELINUX_RESTORECON_SYSLOG_CHANGES 1024
+/* Log what spec matched each file. */
+#define SELINUX_RESTORECON_LOG_MATCHES 2048
+/* Ignore files that do not exist. */
+#define SELINUX_RESTORECON_IGNORE_NOENTRY 4096
/**
* selinux_restorecon_set_sehandle - Set the global fc handle.
@@ -77,6 +85,15 @@ extern struct selabel_handle *selinux_restorecon_default_handle(void);
*/
extern void selinux_restorecon_set_exclude_list(const char **exclude_list);
+/**
+ * selinux_restorecon_set_alt_rootpath - Use alternate rootpath.
+ * directories that are to be excluded
+ * from relabeling.
+ * @alt_rootpath: containing the alternate rootpath to be used. The path MUST
+ * NOT be terminated with a '/'. The path MUST NOT be only '/'.
+ */
+extern void selinux_restorecon_set_alt_rootpath(const char *alt_rootpath);
+
#ifdef __cplusplus
}
#endif
diff --git a/libselinux/man/man3/selinux_restorecon.3 b/libselinux/man/man3/selinux_restorecon.3
index bbb6721..1d79f91 100644
--- a/libselinux/man/man3/selinux_restorecon.3
+++ b/libselinux/man/man3/selinux_restorecon.3
@@ -106,6 +106,19 @@ entry from which the descent began.
.B SELINUX_RESTORECON_ADD_ASSOC
attempt to add an association between an inode and a context. If there is a
different context that matched the inode, then use the first context that matched.
+.sp
+.B SELINUX_RESTORECON_ABORT_ON_ERROR
+abort on errors during the file tree walk.
+.sp
+.B SELINUX_RESTORECON_SYSLOG_CHANGES
+log any label changes to
+.BR syslog (3).
+.sp
+.B SELINUX_RESTORECON_LOG_MATCHES
+log what specfile context matched each file.
+.sp
+.B SELINUX_RESTORECON_IGNORE_NOENTRY
+ignore files that do not exist.
.RE
.sp
The behavior regarding the checking and updating of the SHA1 digest described
diff --git a/libselinux/man/man3/selinux_restorecon_set_alt_rootpath.3 b/libselinux/man/man3/selinux_restorecon_set_alt_rootpath.3
new file mode 100644
index 0000000..79223eb
--- /dev/null
+++ b/libselinux/man/man3/selinux_restorecon_set_alt_rootpath.3
@@ -0,0 +1,34 @@
+.TH "selinux_restorecon_set_alt_rootpath" "3" "28 April 2016" "Security Enhanced Linux" "SELinux API documentation"
+
+.SH "NAME"
+selinux_restorecon_set_alt_rootpath \- set an alternate rootpath.
+.
+.SH "SYNOPSIS"
+.B #include <selinux/restorecon.h>
+.sp
+.BI "void selinux_restorecon_set_alt_rootpath(const char *" alt_rootpath ");"
+.in +\w'void selinux_restorecon_set_alt_rootpath('u
+.
+.SH "DESCRIPTION"
+.BR selinux_restorecon_set_alt_rootpath ()
+passes to
+.BR selinux_restorecon (3)
+a pointer containing an alternate rootpath
+.IR alt_rootpath .
+.br
+The path MUST NOT be terminated with a trailing '/'.
+.br
+The path MUST NOT be '/' (i.e. the root path).
+.sp
+.BR selinux_restorecon_set_alt_rootpath ()
+must be called prior to
+.BR selinux_restorecon (3).
+.
+.SH "SEE ALSO"
+.BR selinux_restorecon (3),
+.br
+.BR selinux_restorecon_set_sehandle (3),
+.br
+.BR selinux_restorecon_default_handle (3),
+.br
+.BR selinux_restorecon_set_exclude_list (3)
diff --git a/libselinux/src/selinux_restorecon.c b/libselinux/src/selinux_restorecon.c
index 2794659..11ae8a0 100644
--- a/libselinux/src/selinux_restorecon.c
+++ b/libselinux/src/selinux_restorecon.c
@@ -22,6 +22,7 @@
#include <sys/vfs.h>
#include <linux/magic.h>
#include <libgen.h>
+#include <syslog.h>
#include <selinux/selinux.h>
#include <selinux/context.h>
#include <selinux/label.h>
@@ -39,6 +40,8 @@ static struct selabel_handle *fc_sehandle = NULL;
static unsigned char *fc_digest = NULL;
static size_t fc_digest_len = 0;
static const char **fc_exclude_list = NULL;
+static const char *rootpath = NULL;
+static int rootpathlen;
static size_t fc_count = 0;
#define STAR_COUNT 1000
@@ -47,12 +50,16 @@ struct rest_flags {
bool nochange;
bool verbose;
bool progress;
- bool specctx;
+ bool set_specctx;
bool add_assoc;
- bool ignore;
+ bool ignore_digest;
bool recurse;
bool userealpath;
bool xdev;
+ bool abort_on_error;
+ bool syslog_changes;
+ bool log_matches;
+ bool ignore_enoent;
};
static void restorecon_init(void)
@@ -67,13 +74,15 @@ static void restorecon_init(void)
static pthread_once_t fc_once = PTHREAD_ONCE_INIT;
-
static int check_excluded(const char *file)
{
int i;
+ size_t len;
for (i = 0; fc_exclude_list[i]; i++) {
- if (strcmp(file, fc_exclude_list[i]) == 0)
+ len = strlen(fc_exclude_list[i]);
+ /* Check if 'file' is in an excluded directory. */
+ if (strncmp(file, fc_exclude_list[i], len) == 0)
return 1;
}
return 0;
@@ -360,10 +369,29 @@ static int restorecon_sb(const char *pathname, const struct stat *sb,
char *newcon = NULL;
char *curcon = NULL;
char *newtypecon = NULL;
- int rc = 0;
+ int rc;
bool updated = false;
+ const char *tmp_pathname = pathname;
+
+ if (rootpath) {
+ if (strncmp(rootpath, tmp_pathname, rootpathlen) != 0) {
+ selinux_log(SELINUX_ERROR,
+ "%s is not located in alt_rootpath %s\n",
+ tmp_pathname, rootpath);
+ return -1;
+ }
+ tmp_pathname += rootpathlen;
+ }
- if (selabel_lookup_raw(fc_sehandle, &newcon, pathname, sb->st_mode) < 0)
+ if (rootpath != NULL && tmp_pathname[0] == '\0')
+ /* this is actually the root dir of the alt root. */
+ rc = selabel_lookup_raw(fc_sehandle, &newcon, "/",
+ sb->st_mode);
+ else
+ rc = selabel_lookup_raw(fc_sehandle, &newcon, tmp_pathname,
+ sb->st_mode);
+
+ if (rc < 0)
return 0; /* no match, but not an error */
if (flags->add_assoc) {
@@ -385,6 +413,10 @@ static int restorecon_sb(const char *pathname, const struct stat *sb,
}
}
+ if (flags->log_matches)
+ selinux_log(SELINUX_INFO, "%s matched by %s\n",
+ pathname, newcon);
+
if (lgetfilecon_raw(pathname, &curcon) < 0) {
if (errno != ENODATA)
goto err;
@@ -401,7 +433,7 @@ static int restorecon_sb(const char *pathname, const struct stat *sb,
}
if (strcmp(curcon, newcon) != 0) {
- if (!flags->specctx && curcon &&
+ if (!flags->set_specctx && curcon &&
(is_context_customizable(curcon) > 0)) {
if (flags->verbose) {
selinux_log(SELINUX_INFO,
@@ -411,7 +443,7 @@ static int restorecon_sb(const char *pathname, const struct stat *sb,
}
}
- if (!flags->specctx && curcon) {
+ if (!flags->set_specctx && curcon) {
/* If types different then update newcon. */
rc = compare_types(curcon, newcon, &newtypecon);
if (rc)
@@ -436,6 +468,16 @@ static int restorecon_sb(const char *pathname, const struct stat *sb,
"%s %s from %s to %s\n",
updated ? "Relabeled" : "Would relabel",
pathname, curcon, newcon);
+
+ if (flags->syslog_changes && !flags->nochange) {
+ if (curcon)
+ syslog(LOG_INFO,
+ "relabeling %s from %s to %s\n",
+ pathname, curcon, newcon);
+ else
+ syslog(LOG_INFO, "labeling %s to %s\n",
+ pathname, newcon);
+ }
}
out:
@@ -468,11 +510,11 @@ int selinux_restorecon(const char *pathname_orig,
SELINUX_RESTORECON_VERBOSE) ? true : false;
flags.progress = (restorecon_flags &
SELINUX_RESTORECON_PROGRESS) ? true : false;
- flags.specctx = (restorecon_flags &
+ flags.set_specctx = (restorecon_flags &
SELINUX_RESTORECON_SET_SPECFILE_CTX) ? true : false;
flags.add_assoc = (restorecon_flags &
SELINUX_RESTORECON_ADD_ASSOC) ? true : false;
- flags.ignore = (restorecon_flags &
+ flags.ignore_digest = (restorecon_flags &
SELINUX_RESTORECON_IGNORE_DIGEST) ? true : false;
flags.recurse = (restorecon_flags &
SELINUX_RESTORECON_RECURSE) ? true : false;
@@ -480,6 +522,14 @@ int selinux_restorecon(const char *pathname_orig,
SELINUX_RESTORECON_REALPATH) ? true : false;
flags.xdev = (restorecon_flags &
SELINUX_RESTORECON_XDEV) ? true : false;
+ flags.abort_on_error = (restorecon_flags &
+ SELINUX_RESTORECON_ABORT_ON_ERROR) ? true : false;
+ flags.syslog_changes = (restorecon_flags &
+ SELINUX_RESTORECON_SYSLOG_CHANGES) ? true : false;
+ flags.log_matches = (restorecon_flags &
+ SELINUX_RESTORECON_LOG_MATCHES) ? true : false;
+ flags.ignore_enoent = (restorecon_flags &
+ SELINUX_RESTORECON_IGNORE_NOENTRY) ? true : false;
bool issys;
bool setrestoreconlast = true; /* TRUE = set xattr RESTORECON_LAST
@@ -494,6 +544,7 @@ int selinux_restorecon(const char *pathname_orig,
int error, sverrno;
char *xattr_value = NULL;
ssize_t size;
+ dev_t dev_num = 0;
if (flags.verbose && flags.progress)
flags.verbose = false;
@@ -545,8 +596,17 @@ int selinux_restorecon(const char *pathname_orig,
sizeof(SYS_PREFIX) - 1)) ? true : false;
if (lstat(pathname, &sb) < 0) {
- error = -1;
- goto cleanup;
+ if (flags.ignore_enoent && errno == ENOENT) {
+ free(pathdnamer);
+ free(pathname);
+ return 0;
+ } else {
+ selinux_log(SELINUX_ERROR,
+ "lstat(%s) failed: %s\n",
+ pathname, strerror(errno));
+ error = -1;
+ goto cleanup;
+ }
}
/* Ignore restoreconlast if not a directory */
@@ -572,7 +632,7 @@ int selinux_restorecon(const char *pathname_orig,
size = getxattr(pathname, RESTORECON_LAST, xattr_value,
fc_digest_len);
- if (!flags.ignore && size == fc_digest_len &&
+ if (!flags.ignore_digest && size == fc_digest_len &&
memcmp(fc_digest, xattr_value, fc_digest_len)
== 0) {
selinux_log(SELINUX_INFO,
@@ -589,13 +649,22 @@ int selinux_restorecon(const char *pathname_orig,
fts_flags = FTS_PHYSICAL | FTS_NOCHDIR;
fts = fts_open(paths, fts_flags, NULL);
- if (!fts) {
- error = -1;
- goto cleanup;
- }
+ if (!fts)
+ goto fts_err;
+
+ ftsent = fts_read(fts);
+ if (!ftsent)
+ goto fts_err;
+
+ /* Keep the inode of the first device. */
+ dev_num = ftsent->fts_statp->st_dev;
error = 0;
- while ((ftsent = fts_read(fts)) != NULL) {
+ do {
+ /* If the XDEV flag is set and the device is different */
+ if (flags.xdev && ftsent->fts_statp->st_dev != dev_num)
+ continue;
+
switch (ftsent->fts_info) {
case FTS_DC:
selinux_log(SELINUX_ERROR,
@@ -644,9 +713,12 @@ int selinux_restorecon(const char *pathname_orig,
error |= restorecon_sb(ftsent->fts_path,
ftsent->fts_statp, &flags);
+
+ if (error && flags.abort_on_error)
+ goto out;
break;
}
- }
+ } while ((ftsent = fts_read(fts)) != NULL);
/* Labeling successful. Mark the top level directory as completed. */
if (setrestoreconlast && !flags.nochange && !error) {
@@ -672,12 +744,14 @@ cleanup:
free(pathname);
free(xattr_value);
return error;
+
oom:
sverrno = errno;
selinux_log(SELINUX_ERROR, "%s: Out of memory\n", __func__);
errno = sverrno;
error = -1;
goto cleanup;
+
realpatherr:
sverrno = errno;
selinux_log(SELINUX_ERROR,
@@ -686,6 +760,13 @@ realpatherr:
errno = sverrno;
error = -1;
goto cleanup;
+
+fts_err:
+ selinux_log(SELINUX_ERROR,
+ "fts error while labeling %s: %s\n",
+ paths[0], strerror(errno));
+ error = -1;
+ goto cleanup;
}
/* selinux_restorecon_set_sehandle(3) is called to set the global fc handle */
@@ -757,3 +838,10 @@ void selinux_restorecon_set_exclude_list(const char **exclude_list)
{
fc_exclude_list = exclude_list;
}
+
+/* selinux_restorecon_set_alt_rootpath(3) sets an alternate rootpath. */
+void selinux_restorecon_set_alt_rootpath(const char *alt_rootpath)
+{
+ rootpath = alt_rootpath;
+ rootpathlen = strlen(rootpath);
+}
diff --git a/libselinux/utils/selinux_restorecon.c b/libselinux/utils/selinux_restorecon.c
index 2552d63..da59fcd 100644
--- a/libselinux/utils/selinux_restorecon.c
+++ b/libselinux/utils/selinux_restorecon.c
@@ -37,7 +37,7 @@ static int validate_context(char **contextp)
static void usage(const char *progname)
{
fprintf(stderr,
- "\nusage: %s [-FCnRrdeia] [-v|-P] [-p policy] [-f specfile] "
+ "\nusage: %s [-FCnRrdeiIaAsl] [-v|-P] [-x alt_rootpath] [-p policy] [-f specfile] "
"pathname ...\n"
"Where:\n\t"
"-F Set the label to that in specfile.\n\t"
@@ -57,9 +57,14 @@ static void usage(const char *progname)
"-e Exclude this file/directory (add multiple -e entries).\n\t"
"-i Do not set SELABEL_OPT_DIGEST option when calling "
" selabel_open(3).\n\t"
+ "-I Ignore files that do not exist.\n\t"
"-a Add an association between an inode and a context.\n\t"
" If there is a different context that matched the inode,\n\t"
" then use the first context that matched.\n\t"
+ "-A Abort on errors during the file tree walk.\n\t"
+ "-s Log any label changes to syslog(3).\n\t"
+ "-l Log what specfile context matched each file.\n\t"
+ "-x Set alternate rootpath.\n\t"
"-p Optional binary policy file (also sets validate context "
"option).\n\t"
"-f Optional file contexts file.\n\t"
@@ -101,6 +106,7 @@ int main(int argc, char **argv)
int opt, i;
unsigned int restorecon_flags = 0;
char *path = NULL, *digest = NULL, *validate = NULL;
+ char *alt_rootpath = NULL;
FILE *policystream;
bool ignore_digest = false, require_selinux = true;
bool verbose = false, progress = false;
@@ -118,7 +124,7 @@ int main(int argc, char **argv)
exclude_list = NULL;
exclude_count = 0;
- while ((opt = getopt(argc, argv, "iFCnRvPrdae:f:p:")) > 0) {
+ while ((opt = getopt(argc, argv, "iIFCnRvPrdaAsle:f:p:x:")) > 0) {
switch (opt) {
case 'F':
restorecon_flags |=
@@ -190,9 +196,24 @@ int main(int argc, char **argv)
case 'i':
ignore_digest = true;
break;
+ case 'I':
+ restorecon_flags |= SELINUX_RESTORECON_IGNORE_NOENTRY;
+ break;
case 'a':
restorecon_flags |= SELINUX_RESTORECON_ADD_ASSOC;
break;
+ case 'A':
+ restorecon_flags |= SELINUX_RESTORECON_ABORT_ON_ERROR;
+ break;
+ case 's':
+ restorecon_flags |= SELINUX_RESTORECON_SYSLOG_CHANGES;
+ break;
+ case 'l':
+ restorecon_flags |= SELINUX_RESTORECON_LOG_MATCHES;
+ break;
+ case 'x':
+ alt_rootpath = optarg;
+ break;
default:
usage(argv[0]);
}
@@ -247,6 +268,9 @@ int main(int argc, char **argv)
selinux_restorecon_set_exclude_list
((const char **)exclude_list);
+ if (alt_rootpath)
+ selinux_restorecon_set_alt_rootpath(alt_rootpath);
+
/* Call restorecon for each path in list */
for (i = optind; i < argc; i++) {
if (selinux_restorecon(argv[i], restorecon_flags) < 0) {
--
2.5.5
^ permalink raw reply related [flat|nested] 3+ messages in thread
* Re: [PATCH 2/3] libselinux: Add setfiles support to selinux_restorecon(3)
2016-05-10 15:23 [PATCH 2/3] libselinux: Add setfiles support to selinux_restorecon(3) Richard Haines
@ 2016-05-20 17:03 ` Stephen Smalley
2016-05-31 15:21 ` Richard Haines
0 siblings, 1 reply; 3+ messages in thread
From: Stephen Smalley @ 2016-05-20 17:03 UTC (permalink / raw)
To: Richard Haines, selinux
On 05/10/2016 11:23 AM, Richard Haines wrote:
> Add additional error handling, flags, xdev and alt_rootpath
> support for setfiles(8) functionality.
>
> Signed-off-by: Richard Haines <richard_c_haines@btinternet.com>
> ---
> libselinux/include/selinux/restorecon.h | 17 +++
> libselinux/man/man3/selinux_restorecon.3 | 13 +++
> .../man/man3/selinux_restorecon_set_alt_rootpath.3 | 34 ++++++
> libselinux/src/selinux_restorecon.c | 126 +++++++++++++++++----
> libselinux/utils/selinux_restorecon.c | 28 ++++-
> 5 files changed, 197 insertions(+), 21 deletions(-)
> create mode 100644 libselinux/man/man3/selinux_restorecon_set_alt_rootpath.3
>
> diff --git a/libselinux/include/selinux/restorecon.h b/libselinux/include/selinux/restorecon.h
> index 0b93b0c..6b3e0f1 100644
> --- a/libselinux/include/selinux/restorecon.h
> +++ b/libselinux/include/selinux/restorecon.h
> @@ -50,6 +50,14 @@ extern int selinux_restorecon(const char *pathname,
> * If there is a different context that matched the inode,
> * then use the first context that matched. */
> #define SELINUX_RESTORECON_ADD_ASSOC 256
> +/* Abort on errors during the file tree walk. */
> +#define SELINUX_RESTORECON_ABORT_ON_ERROR 512
> +/* Log any label changes to syslog. */
> +#define SELINUX_RESTORECON_SYSLOG_CHANGES 1024
> +/* Log what spec matched each file. */
> +#define SELINUX_RESTORECON_LOG_MATCHES 2048
> +/* Ignore files that do not exist. */
> +#define SELINUX_RESTORECON_IGNORE_NOENTRY 4096
Maybe we should express these as hex values since they are flags.
> diff --git a/libselinux/man/man3/selinux_restorecon_set_alt_rootpath.3 b/libselinux/man/man3/selinux_restorecon_set_alt_rootpath.3
> new file mode 100644
> index 0000000..79223eb
> --- /dev/null
> +++ b/libselinux/man/man3/selinux_restorecon_set_alt_rootpath.3
> @@ -0,0 +1,34 @@
> +.TH "selinux_restorecon_set_alt_rootpath" "3" "28 April 2016" "Security Enhanced Linux" "SELinux API documentation"
> +
> +.SH "NAME"
> +selinux_restorecon_set_alt_rootpath \- set an alternate rootpath.
> +.
> +.SH "SYNOPSIS"
> +.B #include <selinux/restorecon.h>
> +.sp
> +.BI "void selinux_restorecon_set_alt_rootpath(const char *" alt_rootpath ");"
> +.in +\w'void selinux_restorecon_set_alt_rootpath('u
> +.
> +.SH "DESCRIPTION"
> +.BR selinux_restorecon_set_alt_rootpath ()
> +passes to
> +.BR selinux_restorecon (3)
> +a pointer containing an alternate rootpath
> +.IR alt_rootpath .
> +.br
> +The path MUST NOT be terminated with a trailing '/'.
> +.br
> +The path MUST NOT be '/' (i.e. the root path).
Any particular reason we can't just handle this in the implementation?
> diff --git a/libselinux/src/selinux_restorecon.c b/libselinux/src/selinux_restorecon.c
> index 2794659..11ae8a0 100644
> --- a/libselinux/src/selinux_restorecon.c
> +++ b/libselinux/src/selinux_restorecon.c
> @@ -22,6 +22,7 @@
> #include <sys/vfs.h>
> #include <linux/magic.h>
> #include <libgen.h>
> +#include <syslog.h>
> #include <selinux/selinux.h>
> #include <selinux/context.h>
> #include <selinux/label.h>
> @@ -39,6 +40,8 @@ static struct selabel_handle *fc_sehandle = NULL;
> static unsigned char *fc_digest = NULL;
> static size_t fc_digest_len = 0;
> static const char **fc_exclude_list = NULL;
> +static const char *rootpath = NULL;
> +static int rootpathlen;
> static size_t fc_count = 0;
> #define STAR_COUNT 1000
>
> @@ -47,12 +50,16 @@ struct rest_flags {
> bool nochange;
> bool verbose;
> bool progress;
> - bool specctx;
> + bool set_specctx;
> bool add_assoc;
> - bool ignore;
> + bool ignore_digest;
> bool recurse;
> bool userealpath;
> bool xdev;
> + bool abort_on_error;
> + bool syslog_changes;
> + bool log_matches;
> + bool ignore_enoent;
> };
>
> static void restorecon_init(void)
> @@ -67,13 +74,15 @@ static void restorecon_init(void)
>
> static pthread_once_t fc_once = PTHREAD_ONCE_INIT;
>
> -
> static int check_excluded(const char *file)
> {
> int i;
> + size_t len;
>
> for (i = 0; fc_exclude_list[i]; i++) {
> - if (strcmp(file, fc_exclude_list[i]) == 0)
> + len = strlen(fc_exclude_list[i]);
> + /* Check if 'file' is in an excluded directory. */
> + if (strncmp(file, fc_exclude_list[i], len) == 0)
> return 1;
Simple prefix match could give you a false positive, e.g. if /foo/bar is
on the exclude list and there is a file /foo/barfoo.
Any particular reason you aren't using setfiles restore.c exclude() logic?
However, is it even possible to reach /foo/bar/baz if we are checking
the exclude list on each component and pruning the tree walk on a match
of /foo/bar?
> }
> return 0;
> @@ -360,10 +369,29 @@ static int restorecon_sb(const char *pathname, const struct stat *sb,
> char *newcon = NULL;
> char *curcon = NULL;
> char *newtypecon = NULL;
> - int rc = 0;
> + int rc;
> bool updated = false;
> + const char *tmp_pathname = pathname;
Maybe call it lookup_path or something more descriptive.
> +
> + if (rootpath) {
> + if (strncmp(rootpath, tmp_pathname, rootpathlen) != 0) {
> + selinux_log(SELINUX_ERROR,
> + "%s is not located in alt_rootpath %s\n",
> + tmp_pathname, rootpath);
> + return -1;
> + }
> + tmp_pathname += rootpathlen;
> + }
>
> - if (selabel_lookup_raw(fc_sehandle, &newcon, pathname, sb->st_mode) < 0)
> + if (rootpath != NULL && tmp_pathname[0] == '\0')
> + /* this is actually the root dir of the alt root. */
> + rc = selabel_lookup_raw(fc_sehandle, &newcon, "/",
> + sb->st_mode);
> + else
> + rc = selabel_lookup_raw(fc_sehandle, &newcon, tmp_pathname,
> + sb->st_mode);
> +
> + if (rc < 0)
> return 0; /* no match, but not an error */
>
> if (flags->add_assoc) {
> @@ -436,6 +468,16 @@ static int restorecon_sb(const char *pathname, const struct stat *sb,
> "%s %s from %s to %s\n",
> updated ? "Relabeled" : "Would relabel",
> pathname, curcon, newcon);
> +
> + if (flags->syslog_changes && !flags->nochange) {
> + if (curcon)
> + syslog(LOG_INFO,
> + "relabeling %s from %s to %s\n",
> + pathname, curcon, newcon);
> + else
> + syslog(LOG_INFO, "labeling %s to %s\n",
> + pathname, newcon);
> + }
Wondering if this could be handled by the caller just specifying a log
callback that calls syslog rather than doing it here, but probably would
conflict with other logging.
> @@ -589,13 +649,22 @@ int selinux_restorecon(const char *pathname_orig,
> fts_flags = FTS_PHYSICAL | FTS_NOCHDIR;
>
> fts = fts_open(paths, fts_flags, NULL);
> - if (!fts) {
> - error = -1;
> - goto cleanup;
> - }
> + if (!fts)
> + goto fts_err;
> +
> + ftsent = fts_read(fts);
> + if (!ftsent)
> + goto fts_err;
> +
> + /* Keep the inode of the first device. */
> + dev_num = ftsent->fts_statp->st_dev;
>
> error = 0;
> - while ((ftsent = fts_read(fts)) != NULL) {
> + do {
> + /* If the XDEV flag is set and the device is different */
> + if (flags.xdev && ftsent->fts_statp->st_dev != dev_num)
> + continue;
Why is this necessary given that we already set FTS_XDEV above?
> +
> switch (ftsent->fts_info) {
> case FTS_DC:
> selinux_log(SELINUX_ERROR,
> @@ -644,9 +713,12 @@ int selinux_restorecon(const char *pathname_orig,
>
> error |= restorecon_sb(ftsent->fts_path,
> ftsent->fts_statp, &flags);
> +
> + if (error && flags.abort_on_error)
> + goto out;
> break;
> }
> - }
> + } while ((ftsent = fts_read(fts)) != NULL);
>
> /* Labeling successful. Mark the top level directory as completed. */
> if (setrestoreconlast && !flags.nochange && !error) {
> @@ -672,12 +744,14 @@ cleanup:
> free(pathname);
> free(xattr_value);
> return error;
> +
> oom:
> sverrno = errno;
> selinux_log(SELINUX_ERROR, "%s: Out of memory\n", __func__);
> errno = sverrno;
> error = -1;
> goto cleanup;
> +
> realpatherr:
> sverrno = errno;
> selinux_log(SELINUX_ERROR,
> @@ -686,6 +760,13 @@ realpatherr:
> errno = sverrno;
> error = -1;
> goto cleanup;
> +
> +fts_err:
> + selinux_log(SELINUX_ERROR,
> + "fts error while labeling %s: %s\n",
> + paths[0], strerror(errno));
> + error = -1;
> + goto cleanup;
> }
>
> /* selinux_restorecon_set_sehandle(3) is called to set the global fc handle */
> @@ -757,3 +838,10 @@ void selinux_restorecon_set_exclude_list(const char **exclude_list)
> {
> fc_exclude_list = exclude_list;
> }
> +
> +/* selinux_restorecon_set_alt_rootpath(3) sets an alternate rootpath. */
> +void selinux_restorecon_set_alt_rootpath(const char *alt_rootpath)
> +{
> + rootpath = alt_rootpath;
Should we be strdup()'ing this in case the caller is passing a local
variable or other transient memory that won't stay around necessarily
for later restorecon() calls?
> + rootpathlen = strlen(rootpath);
> +}
> diff --git a/libselinux/utils/selinux_restorecon.c b/libselinux/utils/selinux_restorecon.c
> index 2552d63..da59fcd 100644
> --- a/libselinux/utils/selinux_restorecon.c
> +++ b/libselinux/utils/selinux_restorecon.c
> @@ -37,7 +37,7 @@ static int validate_context(char **contextp)
> static void usage(const char *progname)
> {
> fprintf(stderr,
> - "\nusage: %s [-FCnRrdeia] [-v|-P] [-p policy] [-f specfile] "
> + "\nusage: %s [-FCnRrdeiIaAsl] [-v|-P] [-x alt_rootpath] [-p policy] [-f specfile] "
> "pathname ...\n"
> "Where:\n\t"
> "-F Set the label to that in specfile.\n\t"
> @@ -57,9 +57,14 @@ static void usage(const char *progname)
> "-e Exclude this file/directory (add multiple -e entries).\n\t"
> "-i Do not set SELABEL_OPT_DIGEST option when calling "
> " selabel_open(3).\n\t"
> + "-I Ignore files that do not exist.\n\t"
> "-a Add an association between an inode and a context.\n\t"
> " If there is a different context that matched the inode,\n\t"
> " then use the first context that matched.\n\t"
> + "-A Abort on errors during the file tree walk.\n\t"
> + "-s Log any label changes to syslog(3).\n\t"
> + "-l Log what specfile context matched each file.\n\t"
> + "-x Set alternate rootpath.\n\t"
> "-p Optional binary policy file (also sets validate context "
> "option).\n\t"
> "-f Optional file contexts file.\n\t"
> @@ -101,6 +106,7 @@ int main(int argc, char **argv)
> int opt, i;
> unsigned int restorecon_flags = 0;
> char *path = NULL, *digest = NULL, *validate = NULL;
> + char *alt_rootpath = NULL;
> FILE *policystream;
> bool ignore_digest = false, require_selinux = true;
> bool verbose = false, progress = false;
> @@ -118,7 +124,7 @@ int main(int argc, char **argv)
> exclude_list = NULL;
> exclude_count = 0;
>
> - while ((opt = getopt(argc, argv, "iFCnRvPrdae:f:p:")) > 0) {
> + while ((opt = getopt(argc, argv, "iIFCnRvPrdaAsle:f:p:x:")) > 0) {
> switch (opt) {
> case 'F':
> restorecon_flags |=
> @@ -190,9 +196,24 @@ int main(int argc, char **argv)
> case 'i':
> ignore_digest = true;
> break;
> + case 'I':
> + restorecon_flags |= SELINUX_RESTORECON_IGNORE_NOENTRY;
> + break;
> case 'a':
> restorecon_flags |= SELINUX_RESTORECON_ADD_ASSOC;
> break;
> + case 'A':
> + restorecon_flags |= SELINUX_RESTORECON_ABORT_ON_ERROR;
> + break;
> + case 's':
> + restorecon_flags |= SELINUX_RESTORECON_SYSLOG_CHANGES;
> + break;
> + case 'l':
> + restorecon_flags |= SELINUX_RESTORECON_LOG_MATCHES;
> + break;
> + case 'x':
> + alt_rootpath = optarg;
> + break;
> default:
> usage(argv[0]);
> }
> @@ -247,6 +268,9 @@ int main(int argc, char **argv)
> selinux_restorecon_set_exclude_list
> ((const char **)exclude_list);
>
> + if (alt_rootpath)
> + selinux_restorecon_set_alt_rootpath(alt_rootpath);
> +
> /* Call restorecon for each path in list */
> for (i = optind; i < argc; i++) {
> if (selinux_restorecon(argv[i], restorecon_flags) < 0) {
>
^ permalink raw reply [flat|nested] 3+ messages in thread
* Re: [PATCH 2/3] libselinux: Add setfiles support to selinux_restorecon(3)
2016-05-20 17:03 ` Stephen Smalley
@ 2016-05-31 15:21 ` Richard Haines
0 siblings, 0 replies; 3+ messages in thread
From: Richard Haines @ 2016-05-31 15:21 UTC (permalink / raw)
To: Stephen Smalley; +Cc: selinux@tycho.nsa.gov
> On Friday, 20 May 2016, 18:01, Stephen Smalley <sds@tycho.nsa.gov> wrote:
> > On 05/10/2016 11:23 AM, Richard Haines wrote:
>> Add additional error handling, flags, xdev and alt_rootpath
>> support for setfiles(8) functionality.
>>
>> Signed-off-by: Richard Haines <richard_c_haines@btinternet.com>
>> ---
>> libselinux/include/selinux/restorecon.h | 17 +++
>> libselinux/man/man3/selinux_restorecon.3 | 13 +++
>> .../man/man3/selinux_restorecon_set_alt_rootpath.3 | 34 ++++++
>> libselinux/src/selinux_restorecon.c | 126
> +++++++++++++++++----
>> libselinux/utils/selinux_restorecon.c | 28 ++++-
>> 5 files changed, 197 insertions(+), 21 deletions(-)
>> create mode 100644
> libselinux/man/man3/selinux_restorecon_set_alt_rootpath.3
>>
>> diff --git a/libselinux/include/selinux/restorecon.h
> b/libselinux/include/selinux/restorecon.h
>> index 0b93b0c..6b3e0f1 100644
>> --- a/libselinux/include/selinux/restorecon.h
>> +++ b/libselinux/include/selinux/restorecon.h
>> @@ -50,6 +50,14 @@ extern int selinux_restorecon(const char *pathname,
>> * If there is a different context that matched the inode,
>> * then use the first context that matched. */
>> #define SELINUX_RESTORECON_ADD_ASSOC 256
>> +/* Abort on errors during the file tree walk. */
>> +#define SELINUX_RESTORECON_ABORT_ON_ERROR 512
>> +/* Log any label changes to syslog. */
>> +#define SELINUX_RESTORECON_SYSLOG_CHANGES 1024
>> +/* Log what spec matched each file. */
>> +#define SELINUX_RESTORECON_LOG_MATCHES 2048
>> +/* Ignore files that do not exist. */
>> +#define SELINUX_RESTORECON_IGNORE_NOENTRY 4096
>
> Maybe we should express these as hex values since they are flags.
Fixed.
>
>> diff --git a/libselinux/man/man3/selinux_restorecon_set_alt_rootpath.3
> b/libselinux/man/man3/selinux_restorecon_set_alt_rootpath.3
>> new file mode 100644
>> index 0000000..79223eb
>> --- /dev/null
>> +++ b/libselinux/man/man3/selinux_restorecon_set_alt_rootpath.3
>> @@ -0,0 +1,34 @@
>> +.TH "selinux_restorecon_set_alt_rootpath" "3" "28
> April 2016" "Security Enhanced Linux" "SELinux API
> documentation"
>> +
>> +.SH "NAME"
>> +selinux_restorecon_set_alt_rootpath \- set an alternate rootpath.
>> +.
>> +.SH "SYNOPSIS"
>> +.B #include <selinux/restorecon.h>
>> +.sp
>> +.BI "void selinux_restorecon_set_alt_rootpath(const char *"
> alt_rootpath ");"
>> +.in +\w'void selinux_restorecon_set_alt_rootpath('u
>> +.
>> +.SH "DESCRIPTION"
>> +.BR selinux_restorecon_set_alt_rootpath ()
>> +passes to
>> +.BR selinux_restorecon (3)
>> +a pointer containing an alternate rootpath
>> +.IR alt_rootpath .
>> +.br
>> +The path MUST NOT be terminated with a trailing '/'.
>> +.br
>> +The path MUST NOT be '/' (i.e. the root path).
>
> Any particular reason we can't just handle this in the implementation?
Used code from setfiles.c to handle this now.
>
>> diff --git a/libselinux/src/selinux_restorecon.c
> b/libselinux/src/selinux_restorecon.c
>> index 2794659..11ae8a0 100644
>> --- a/libselinux/src/selinux_restorecon.c
>> +++ b/libselinux/src/selinux_restorecon.c
>> @@ -22,6 +22,7 @@
>> #include <sys/vfs.h>
>> #include <linux/magic.h>
>> #include <libgen.h>
>> +#include <syslog.h>
>> #include <selinux/selinux.h>
>> #include <selinux/context.h>
>> #include <selinux/label.h>
>> @@ -39,6 +40,8 @@ static struct selabel_handle *fc_sehandle = NULL;
>> static unsigned char *fc_digest = NULL;
>> static size_t fc_digest_len = 0;
>> static const char **fc_exclude_list = NULL;
>> +static const char *rootpath = NULL;
>> +static int rootpathlen;
>> static size_t fc_count = 0;
>> #define STAR_COUNT 1000
>>
>> @@ -47,12 +50,16 @@ struct rest_flags {
>> bool nochange;
>> bool verbose;
>> bool progress;
>> - bool specctx;
>> + bool set_specctx;
>> bool add_assoc;
>> - bool ignore;
>> + bool ignore_digest;
>> bool recurse;
>> bool userealpath;
>> bool xdev;
>> + bool abort_on_error;
>> + bool syslog_changes;
>> + bool log_matches;
>> + bool ignore_enoent;
>> };
>>
>> static void restorecon_init(void)
>> @@ -67,13 +74,15 @@ static void restorecon_init(void)
>>
>> static pthread_once_t fc_once = PTHREAD_ONCE_INIT;
>>
>> -
>> static int check_excluded(const char *file)
>> {
>> int i;
>> + size_t len;
>>
>> for (i = 0; fc_exclude_list[i]; i++) {
>> - if (strcmp(file, fc_exclude_list[i]) == 0)
>> + len = strlen(fc_exclude_list[i]);
>> + /* Check if 'file' is in an excluded directory. */
>> + if (strncmp(file, fc_exclude_list[i], len) == 0)
>> return 1;
>
> Simple prefix match could give you a false positive, e.g. if /foo/bar is
> on the exclude list and there is a file /foo/barfoo.
> Any particular reason you aren't using setfiles restore.c exclude() logic?
> However, is it even possible to reach /foo/bar/baz if we are checking
> the exclude list on each component and pruning the tree walk on a match
> of /foo/bar?
Adding exclude_non_seclabel_mounts(), add_exclude() and remove_exclude()
to selinux_restorecon to handle this.
>
>
>> }
>> return 0;
>> @@ -360,10 +369,29 @@ static int restorecon_sb(const char *pathname, const
> struct stat *sb,
>> char *newcon = NULL;
>> char *curcon = NULL;
>> char *newtypecon = NULL;
>> - int rc = 0;
>> + int rc;
>> bool updated = false;
>> + const char *tmp_pathname = pathname;
>
> Maybe call it lookup_path or something more descriptive.
Fixed.
>
>> +
>> + if (rootpath) {
>> + if (strncmp(rootpath, tmp_pathname, rootpathlen) != 0) {
>> + selinux_log(SELINUX_ERROR,
>> + "%s is not located in alt_rootpath
> %s\n",
>> + tmp_pathname, rootpath);
>> + return -1;
>> + }
>> + tmp_pathname += rootpathlen;
>> + }
>>
>> - if (selabel_lookup_raw(fc_sehandle, &newcon, pathname,
> sb->st_mode) < 0)
>> + if (rootpath != NULL && tmp_pathname[0] == '\0')
>> + /* this is actually the root dir of the alt root. */
>> + rc = selabel_lookup_raw(fc_sehandle, &newcon, "/",
>> + sb->st_mode);
>> + else
>> + rc = selabel_lookup_raw(fc_sehandle, &newcon, tmp_pathname,
>> + sb->st_mode);
>> +
>> + if (rc < 0)
>> return 0; /* no match, but not an error */
>>
>> if (flags->add_assoc) {
>
>
>> @@ -436,6 +468,16 @@ static int restorecon_sb(const char *pathname, const
> struct stat *sb,
>> "%s %s from %s to %s\n",
>> updated ? "Relabeled" : "Would
> relabel",
>> pathname, curcon, newcon);
>> +
>> + if (flags->syslog_changes && !flags->nochange)
> {
>> + if (curcon)
>> + syslog(LOG_INFO,
>> + "relabeling %s from %s to %s\n",
>> + pathname, curcon, newcon);
>> + else
>> + syslog(LOG_INFO, "labeling %s to %s\n",
>> + pathname, newcon);
>> + }
>
> Wondering if this could be handled by the caller just specifying a log
> callback that calls syslog rather than doing it here, but probably would
> conflict with other logging.
I've left this as is at present as I would need time to experiment with
callbacks. Could review later ???
>
>> @@ -589,13 +649,22 @@ int selinux_restorecon(const char *pathname_orig,
>> fts_flags = FTS_PHYSICAL | FTS_NOCHDIR;
>>
>> fts = fts_open(paths, fts_flags, NULL);
>> - if (!fts) {
>> - error = -1;
>> - goto cleanup;
>> - }
>> + if (!fts)
>> + goto fts_err;
>> +
>> + ftsent = fts_read(fts);
>> + if (!ftsent)
>> + goto fts_err;
>> +
>> + /* Keep the inode of the first device. */
>> + dev_num = ftsent->fts_statp->st_dev;
>>
>> error = 0;
>> - while ((ftsent = fts_read(fts)) != NULL) {
>> + do {
>> + /* If the XDEV flag is set and the device is different */
>> + if (flags.xdev && ftsent->fts_statp->st_dev !=
> dev_num)
>> + continue;
>
> Why is this necessary given that we already set FTS_XDEV above?
After much testing I found this did not work as I expected so implemented
the current setfiles logic that works. I've now found the original
patch from http://marc.info/?l=selinux&m=124688830500777&w=2 and added the
following text from this to the updated code:
/*
* Keep the inode of the first device. This is because the FTS_XDEV
* flag tells fts not to descend into directories with different
* device numbers, but fts will still give back the actual directory.
* By saving the device number of the directory that was passed to
* selinux_restorecon() and then skipping all actions on any
* directories with a different device number when the FTS_XDEV flag
* is set (from http://marc.info/?l=selinux&m=124688830500777&w=2).
*/
>
>> +
>> switch (ftsent->fts_info) {
>> case FTS_DC:
>> selinux_log(SELINUX_ERROR,
>> @@ -644,9 +713,12 @@ int selinux_restorecon(const char *pathname_orig,
>>
>> error |= restorecon_sb(ftsent->fts_path,
>> ftsent->fts_statp, &flags);
>> +
>> + if (error && flags.abort_on_error)
>> + goto out;
>> break;
>> }
>> - }
>> + } while ((ftsent = fts_read(fts)) != NULL);
>>
>> /* Labeling successful. Mark the top level directory as completed. */
>> if (setrestoreconlast && !flags.nochange && !error)
> {
>> @@ -672,12 +744,14 @@ cleanup:
>> free(pathname);
>> free(xattr_value);
>> return error;
>> +
>> oom:
>> sverrno = errno;
>> selinux_log(SELINUX_ERROR, "%s: Out of memory\n",
> __func__);
>> errno = sverrno;
>> error = -1;
>> goto cleanup;
>> +
>> realpatherr:
>> sverrno = errno;
>> selinux_log(SELINUX_ERROR,
>> @@ -686,6 +760,13 @@ realpatherr:
>> errno = sverrno;
>> error = -1;
>> goto cleanup;
>> +
>> +fts_err:
>> + selinux_log(SELINUX_ERROR,
>> + "fts error while labeling %s: %s\n",
>> + paths[0], strerror(errno));
>> + error = -1;
>> + goto cleanup;
>> }
>>
>> /* selinux_restorecon_set_sehandle(3) is called to set the global fc
> handle */
>> @@ -757,3 +838,10 @@ void selinux_restorecon_set_exclude_list(const char
> **exclude_list)
>> {
>> fc_exclude_list = exclude_list;
>> }
>> +
>> +/* selinux_restorecon_set_alt_rootpath(3) sets an alternate rootpath. */
>> +void selinux_restorecon_set_alt_rootpath(const char *alt_rootpath)
>> +{
>> + rootpath = alt_rootpath;
>
> Should we be strdup()'ing this in case the caller is passing a local
> variable or other transient memory that won't stay around necessarily
> for later restorecon() calls?
Used code from setfiles.c to handle this now that dups entry.
>
>
>> + rootpathlen = strlen(rootpath);
>> +}
>> diff --git a/libselinux/utils/selinux_restorecon.c
> b/libselinux/utils/selinux_restorecon.c
>> index 2552d63..da59fcd 100644
>> --- a/libselinux/utils/selinux_restorecon.c
>> +++ b/libselinux/utils/selinux_restorecon.c
>> @@ -37,7 +37,7 @@ static int validate_context(char **contextp)
>> static void usage(const char *progname)
>> {
>> fprintf(stderr,
>> - "\nusage: %s [-FCnRrdeia] [-v|-P] [-p policy] [-f
> specfile] "
>> + "\nusage: %s [-FCnRrdeiIaAsl] [-v|-P] [-x alt_rootpath]
> [-p policy] [-f specfile] "
>> "pathname ...\n"
>> "Where:\n\t"
>> "-F Set the label to that in specfile.\n\t"
>> @@ -57,9 +57,14 @@ static void usage(const char *progname)
>> "-e Exclude this file/directory (add multiple -e
> entries).\n\t"
>> "-i Do not set SELABEL_OPT_DIGEST option when calling "
>> " selabel_open(3).\n\t"
>> + "-I Ignore files that do not exist.\n\t"
>> "-a Add an association between an inode and a
> context.\n\t"
>> " If there is a different context that matched the
> inode,\n\t"
>> " then use the first context that
> matched.\n\t"
>> + "-A Abort on errors during the file tree
> walk.\n\t"
>> + "-s Log any label changes to syslog(3).\n\t"
>> + "-l Log what specfile context matched each
> file.\n\t"
>> + "-x Set alternate rootpath.\n\t"
>> "-p Optional binary policy file (also sets validate context
> "
>> "option).\n\t"
>> "-f Optional file contexts file.\n\t"
>> @@ -101,6 +106,7 @@ int main(int argc, char **argv)
>> int opt, i;
>> unsigned int restorecon_flags = 0;
>> char *path = NULL, *digest = NULL, *validate = NULL;
>> + char *alt_rootpath = NULL;
>> FILE *policystream;
>> bool ignore_digest = false, require_selinux = true;
>> bool verbose = false, progress = false;
>> @@ -118,7 +124,7 @@ int main(int argc, char **argv)
>> exclude_list = NULL;
>> exclude_count = 0;
>>
>> - while ((opt = getopt(argc, argv, "iFCnRvPrdae:f:p:")) >
> 0) {
>> + while ((opt = getopt(argc, argv, "iIFCnRvPrdaAsle:f:p:x:"))
>> 0) {
>> switch (opt) {
>> case 'F':
>> restorecon_flags |=
>> @@ -190,9 +196,24 @@ int main(int argc, char **argv)
>> case 'i':
>> ignore_digest = true;
>> break;
>> + case 'I':
>> + restorecon_flags |= SELINUX_RESTORECON_IGNORE_NOENTRY;
>> + break;
>> case 'a':
>> restorecon_flags |= SELINUX_RESTORECON_ADD_ASSOC;
>> break;
>> + case 'A':
>> + restorecon_flags |= SELINUX_RESTORECON_ABORT_ON_ERROR;
>> + break;
>> + case 's':
>> + restorecon_flags |= SELINUX_RESTORECON_SYSLOG_CHANGES;
>> + break;
>> + case 'l':
>> + restorecon_flags |= SELINUX_RESTORECON_LOG_MATCHES;
>> + break;
>> + case 'x':
>> + alt_rootpath = optarg;
>> + break;
>> default:
>> usage(argv[0]);
>> }
>> @@ -247,6 +268,9 @@ int main(int argc, char **argv)
>> selinux_restorecon_set_exclude_list
>> ((const char **)exclude_list);
>>
>> + if (alt_rootpath)
>> + selinux_restorecon_set_alt_rootpath(alt_rootpath);
>> +
>> /* Call restorecon for each path in list */
>> for (i = optind; i < argc; i++) {
>> if (selinux_restorecon(argv[i], restorecon_flags) < 0) {
>>
>
^ permalink raw reply [flat|nested] 3+ messages in thread
end of thread, other threads:[~2016-05-31 15:24 UTC | newest]
Thread overview: 3+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2016-05-10 15:23 [PATCH 2/3] libselinux: Add setfiles support to selinux_restorecon(3) Richard Haines
2016-05-20 17:03 ` Stephen Smalley
2016-05-31 15:21 ` Richard Haines
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.