policycoreutils: setfiles - Utility to find security.restorecon_last entries

This patch adds restorecon_xattr(8) to find and/or remove
security.restorecon_last entries added by setfiles(8) or
restorecon(8). Uses the services of selinux_restorecon_xattr(3).

Signed-off-by: Richard Haines <richard_c_haines@btinternet.com>
This commit is contained in:
Richard Haines 2016-09-26 16:30:30 +01:00 committed by James Carter
parent 2d814ff4c7
commit f1352e7399
4 changed files with 348 additions and 3 deletions

View file

@ -17,13 +17,15 @@ ifeq ($(AUDITH), /usr/include/libaudit.h)
LDLIBS += -laudit LDLIBS += -laudit
endif endif
all: setfiles restorecon man all: setfiles restorecon restorecon_xattr man
setfiles: setfiles.o restore.o setfiles: setfiles.o restore.o
restorecon: setfiles restorecon: setfiles
ln -sf setfiles restorecon ln -sf setfiles restorecon
restorecon_xattr: restorecon_xattr.o restore.o
man: man:
@cp -af setfiles.8 setfiles.8.man @cp -af setfiles.8 setfiles.8.man
@cp -af restorecon.8 restorecon.8.man @cp -af restorecon.8 restorecon.8.man
@ -35,14 +37,16 @@ install: all
-mkdir -p $(SBINDIR) -mkdir -p $(SBINDIR)
install -m 755 setfiles $(SBINDIR) install -m 755 setfiles $(SBINDIR)
(cd $(SBINDIR) && ln -sf setfiles restorecon) (cd $(SBINDIR) && ln -sf setfiles restorecon)
install -m 755 restorecon_xattr $(SBINDIR)
install -m 644 setfiles.8.man $(MANDIR)/man8/setfiles.8 install -m 644 setfiles.8.man $(MANDIR)/man8/setfiles.8
install -m 644 restorecon.8.man $(MANDIR)/man8/restorecon.8 install -m 644 restorecon.8.man $(MANDIR)/man8/restorecon.8
install -m 644 restorecon_xattr.8 $(MANDIR)/man8/restorecon_xattr.8
clean: clean:
rm -f setfiles restorecon *.o setfiles.8.man restorecon.8.man rm -f setfiles restorecon restorecon_xattr *.o setfiles.8.man restorecon.8.man
indent: indent:
../../scripts/Lindent $(wildcard *.[ch]) ../../scripts/Lindent $(wildcard *.[ch])
relabel: install relabel: install
$(SBINDIR)/restorecon $(SBINDIR)/setfiles $(SBINDIR)/restorecon $(SBINDIR)/setfiles $(SBINDIR)/restorecon_xattr

View file

@ -56,5 +56,6 @@ void restore_init(struct restore_opts *opts);
void restore_finish(void); void restore_finish(void);
void add_exclude(const char *directory); void add_exclude(const char *directory);
int process_glob(char *name, struct restore_opts *opts); int process_glob(char *name, struct restore_opts *opts);
extern char **exclude_list;
#endif #endif

View file

@ -0,0 +1,119 @@
.TH "restorecon_xattr" "8" "24 Sept 2016" "" "SELinux User Command"
.SH "NAME"
restorecon_xattr \- manage
.I security.restorecon_last
extended attribute entries added by
.BR setfiles (8)
or
.BR restorecon (8).
.SH "SYNOPSIS"
.B restorecon_xattr
.RB [ \-d ]
.RB [ \-D ]
.RB [ \-m ]
.RB [ \-n ]
.RB [ \-r ]
.RB [ \-v ]
.RB [ \-e
.IR directory ]
.RB [ \-f
.IR specfile ]
.I pathname
.SH "DESCRIPTION"
.B restorecon_xattr
will display the SHA1 digests added to extended attributes
.I security.restorecon_last
or delete the attribute completely. These attributes are set by
.BR restorecon (8)
or
.BR setfiles (8)
to specified directories when relabeling recursively.
.sp
.B restorecon_xattr
is useful for managing the extended attribute entries particularly when
users forget what directories they ran
.BR restorecon (8)
or
.BR setfiles (8)
from.
.sp
.B RAMFS
and
.B TMPFS
filesystems do not support the
.I security.restorecon_last
extended attribute and are automatically excluded from searches.
.sp
By default
.B restorecon_xattr
will display the SHA1 digests with "Match" appended if they match the default
specfile set or the
.I specfile
set used with the
.B \-f
option. Non-matching SHA1 digests will be displayed with "No Match" appended.
This feature can be disabled by the
.B \-n
option.
.SH "OPTIONS"
.TP
.B \-d
delete all non-matching
.I security.restorecon_last
directory digest entries.
.TP
.B \-D
delete all
.I security.restorecon_last
directory digest entries.
.TP
.B \-m
do not read
.B /proc/mounts
to obtain a list of non-seclabel mounts to be excluded from relabeling checks.
.br
Setting
.B \-m
is useful where there is a non-seclabel fs mounted with a seclabel fs mounted
on a directory below this.
.TP
.B \-n
Do not append "Match" or "No Match" to displayed digests.
.TP
.B \-r
recursively descend directories.
.TP
.B \-v
display SHA1 digest generated by specfile set.
.TP
.B \-e
.I directory
.br
directory to exclude (repeat option for more than one directory).
.TP
.B \-f
.I specfile
.br
an optional
.I specfile
containing file context entries as described in
.BR file_contexts (5).
This will be used by
.BR selabel_open (3)
to retrieve the set of labeling entries, with the SHA1 digest being
retrieved by
.BR selabel_digest (3).
If the option is not specified, then the default file_contexts will be used.
.SH "ARGUMENTS"
.TP
.I pathname
.br
the pathname of the directory tree to be searched.
.SH "SEE ALSO"
.BR restorecon (8),
.BR setfiles (8)

View file

@ -0,0 +1,221 @@
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <getopt.h>
#include <errno.h>
#include <stdbool.h>
#include <sys/xattr.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <selinux/selinux.h>
#include <selinux/label.h>
#include <selinux/restorecon.h>
#include "restore.h"
static void usage(const char *progname)
{
fprintf(stderr,
"\nusage: %s [-vnrmdD] [-e directory] [-f specfile] pathname\n"
"\nWhere:\n\t"
"-v Display digest generated by specfile set.\n\t"
"-n Do not append \"Match\" or \"No Match\" to displayed digests.\n\t"
"-r Recursively descend directories.\n\t"
"-m Do not read /proc/mounts for entries to be excluded.\n\t"
"-d Delete non-matching digest entries.\n\t"
"-D Delete all digest entries.\n\t"
"-e Directory to exclude (repeat option for more than one directory).\n\t"
"-f Optional specfile for calculating the digest.\n\t"
"pathname Path to search for xattr \"security.restorecon_last\" entries.\n\n",
progname);
exit(-1);
}
int main(int argc, char **argv)
{
int opt, rc;
unsigned int xattr_flags = 0, delete_digest = 0, recurse = 0;
unsigned int delete_all_digests = 0, ignore_mounts = 0;
bool display_digest = false;
char *sha1_buf, **specfiles, *fc_file = NULL;
unsigned char *fc_digest = NULL;
size_t i, fc_digest_len = 0, num_specfiles;
struct stat sb;
struct selabel_handle *hnd = NULL;
struct dir_xattr *current, *next, **xattr_list = NULL;
bool no_comment = true;
if (argc < 2)
usage(argv[0]);
if (is_selinux_enabled() <= 0) {
fprintf(stderr,
"SELinux must be enabled to perform this operation.\n");
exit(-1);
}
exclude_list = NULL;
while ((opt = getopt(argc, argv, "vnrmdDe:f:")) > 0) {
switch (opt) {
case 'v':
display_digest = true;
break;
case 'n':
no_comment = false;
break;
case 'r':
recurse = SELINUX_RESTORECON_XATTR_RECURSE;
break;
case 'm':
ignore_mounts = SELINUX_RESTORECON_XATTR_IGNORE_MOUNTS;
break;
case 'd':
delete_digest =
SELINUX_RESTORECON_XATTR_DELETE_NONMATCH_DIGESTS;
break;
case 'D':
delete_all_digests =
SELINUX_RESTORECON_XATTR_DELETE_ALL_DIGESTS;
break;
case 'e':
if (lstat(optarg, &sb) < 0 && errno != EACCES) {
fprintf(stderr, "Can't stat exclude path \"%s\", %s - ignoring.\n",
optarg, strerror(errno));
break;
}
add_exclude(optarg);
break;
case 'f':
fc_file = optarg;
break;
default:
usage(argv[0]);
}
}
if (optind >= argc) {
fprintf(stderr, "No pathname specified\n");
exit(-1);
}
struct selinux_opt selinux_opts[] = {
{ SELABEL_OPT_PATH, fc_file },
{ SELABEL_OPT_DIGEST, (char *)1 }
};
hnd = selabel_open(SELABEL_CTX_FILE, selinux_opts, 2);
if (!hnd) {
switch (errno) {
case EOVERFLOW:
fprintf(stderr, "Error: Number of specfiles or"
" specfile buffer caused an overflow.\n");
break;
default:
fprintf(stderr, "Error: selabel_open: %s\n",
strerror(errno));
}
exit(-1);
}
/* Use own handle as need to allow different file_contexts. */
selinux_restorecon_set_sehandle(hnd);
if (display_digest) {
if (selabel_digest(hnd, &fc_digest, &fc_digest_len,
&specfiles, &num_specfiles) < 0) {
fprintf(stderr,
"Error: selabel_digest: Digest not available.\n");
selabel_close(hnd);
exit(-1);
}
sha1_buf = malloc(fc_digest_len * 2 + 1);
if (!sha1_buf) {
fprintf(stderr,
"Error allocating digest buffer: %s\n",
strerror(errno));
selabel_close(hnd);
exit(-1);
}
for (i = 0; i < fc_digest_len; i++)
sprintf((&sha1_buf[i * 2]), "%02x", fc_digest[i]);
printf("specfiles SHA1 digest: %s\n", sha1_buf);
printf("calculated using the following specfile(s):\n");
if (specfiles) {
for (i = 0; i < num_specfiles; i++)
printf("%s\n", specfiles[i]);
}
free(sha1_buf);
printf("\n");
}
if (exclude_list)
selinux_restorecon_set_exclude_list
((const char **)exclude_list);
xattr_flags = delete_digest | delete_all_digests |
ignore_mounts | recurse;
if (selinux_restorecon_xattr(argv[optind], xattr_flags, &xattr_list)) {
fprintf(stderr,
"Error selinux_restorecon_xattr: %s\n",
strerror(errno));
rc = -1;
goto out;
}
if (xattr_list) {
current = *xattr_list;
while (current) {
next = current->next;
printf("%s ", current->directory);
switch (current->result) {
case MATCH:
printf("Digest: %s%s", current->digest,
no_comment ? " Match\n" : "\n");
break;
case NOMATCH:
printf("Digest: %s%s", current->digest,
no_comment ? " No Match\n" : "\n");
break;
case DELETED_MATCH:
printf("Deleted Digest: %s%s", current->digest,
no_comment ? " Match\n" : "\n");
break;
case DELETED_NOMATCH:
printf("Deleted Digest: %s%s",
current->digest,
no_comment ? " No Match\n" : "\n");
break;
case ERROR:
printf("Digest: %s Error removing xattr\n",
current->digest);
break;
}
current = next;
}
/* Free memory */
current = *xattr_list;
while (current) {
next = current->next;
free(current->directory);
free(current->digest);
free(current);
current = next;
}
}
rc = 0;
out:
selabel_close(hnd);
restore_finish();
return rc;
}