Merge remote-tracking branch 'aosp/upstream-master' into mymerge
Change-Id: Ib31d805f4abcc7bebc923a5d9fa35ce7aa6e29b4
This commit is contained in:
commit
e39c09f418
16 changed files with 808 additions and 71 deletions
|
@ -1,3 +1,4 @@
|
|||
* Add selabel partial and best match APIs, from Richard Haines.
|
||||
* Use os.walk() instead of the deprecated os.path.walk(), from Petr
|
||||
Lautrbach & Miro Hrončok
|
||||
* is_selinux_enabled(): drop no-policy-loaded test, from Stephen Smalley.
|
||||
|
|
|
@ -6,6 +6,7 @@
|
|||
#ifndef _SELABEL_H_
|
||||
#define _SELABEL_H_
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <sys/types.h>
|
||||
#include <selinux/selinux.h>
|
||||
|
||||
|
@ -97,6 +98,13 @@ int selabel_lookup(struct selabel_handle *handle, char **con,
|
|||
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);
|
||||
int selabel_lookup_best_match_raw(struct selabel_handle *rec, char **con,
|
||||
const char *key, const char **aliases, int type);
|
||||
|
||||
/**
|
||||
* selabel_stats - log labeling operation statistics.
|
||||
* @handle: specifies backend instance to query
|
||||
|
|
100
libselinux/man/man3/selabel_lookup_best_match.3
Normal file
100
libselinux/man/man3/selabel_lookup_best_match.3
Normal file
|
@ -0,0 +1,100 @@
|
|||
.TH "selabel_lookup_best_match" "3" "05 May 2015" "Security Enhanced Linux" "SELinux API documentation"
|
||||
|
||||
.SH "NAME"
|
||||
selabel_lookup_best_match \- obtain a best match SELinux security
|
||||
context \- Only supported on file backend.
|
||||
.
|
||||
.SH "SYNOPSIS"
|
||||
.B #include <selinux/selinux.h>
|
||||
.br
|
||||
.B #include <selinux/label.h>
|
||||
.sp
|
||||
.BI "int selabel_lookup_best_match(struct selabel_handle *" hnd ,
|
||||
.in +\w'int selabel_lookup_best_match('u
|
||||
.BI "char **" context ,
|
||||
.br
|
||||
.BI "const char *" key ,
|
||||
.br
|
||||
.BI "const char **" links ,
|
||||
.br
|
||||
.BI "int " type ");"
|
||||
.in
|
||||
.sp
|
||||
.BI "int selabel_lookup_best_match_raw(struct selabel_handle *" hnd ,
|
||||
.in +\w'int selabel_lookup_best_match_raw('u
|
||||
.BI "char **" context ,
|
||||
.br
|
||||
.BI "const char *" key ,
|
||||
.br
|
||||
.BI "const char **" links ,
|
||||
.br
|
||||
.BI "int " type ");"
|
||||
.in
|
||||
.
|
||||
.SH "DESCRIPTION"
|
||||
.BR selabel_lookup_best_match ()
|
||||
performs a best match lookup operation on the handle
|
||||
.IR hnd ,
|
||||
returning the result in the memory pointed to by
|
||||
.IR context ,
|
||||
which must be freed by the caller using
|
||||
.BR freecon (3).
|
||||
The \fIkey\fR parameter is a file path to check for best match using zero or
|
||||
more \fIlink\fR (aliases) parameters. The order of precedence for best match is:
|
||||
.RS
|
||||
.IP "1." 4
|
||||
An exact match for the real path (\fIkey\fR) or
|
||||
.IP "2." 4
|
||||
An exact match for any of the \fIlink\fRs (aliases), or
|
||||
.IP "3." 4
|
||||
The longest fixed prefix match.
|
||||
.RE
|
||||
.sp
|
||||
The \fItype\fR parameter is an optional file \fImode\fR argument that should
|
||||
be set to the mode bits of the file, as determined by \fBlstat\fR(2).
|
||||
\fImode\fR may be zero, however full matching may not occur.
|
||||
|
||||
.BR selabel_lookup_best_match_raw ()
|
||||
behaves identically to
|
||||
.BR selabel_lookup_best_match ()
|
||||
but does not perform context translation.
|
||||
.
|
||||
.SH "RETURN VALUE"
|
||||
On success, zero is returned. On error, \-1 is returned and
|
||||
.I errno
|
||||
is set appropriately.
|
||||
.
|
||||
.SH "ERRORS"
|
||||
.TP
|
||||
.B ENOENT
|
||||
No context corresponding to the input
|
||||
.I key
|
||||
and
|
||||
.I type
|
||||
was found.
|
||||
.TP
|
||||
.B EINVAL
|
||||
The
|
||||
.I key
|
||||
and/or
|
||||
.I type
|
||||
inputs are invalid, or the context being returned failed validation.
|
||||
.TP
|
||||
.B ENOMEM
|
||||
An attempt to allocate memory failed.
|
||||
.sp
|
||||
.SH "NOTES"
|
||||
Example usage - When a service creates a device node, it may also create one
|
||||
or more symlinks to the device node. These symlinks may be the only stable
|
||||
name for the device, e.g. if the partition is dynamically assigned.
|
||||
The file label backend supports this by looking up the "best match"
|
||||
for a device node based on its real path (\fIkey\fR) and any \fIlink\fRs to it
|
||||
(aliases). The order of precedence for best match is described above.
|
||||
.sp
|
||||
.SH "SEE ALSO"
|
||||
.BR selabel_open (3),
|
||||
.BR selabel_stats (3),
|
||||
.BR selinux_set_callback (3),
|
||||
.BR selinux (8),
|
||||
.BR lstat (2),
|
||||
.BR selabel_file (5)
|
1
libselinux/man/man3/selabel_lookup_best_match_raw.3
Normal file
1
libselinux/man/man3/selabel_lookup_best_match_raw.3
Normal file
|
@ -0,0 +1 @@
|
|||
.so man3/selabel_lookup_best_match.3
|
34
libselinux/man/man3/selabel_partial_match.3
Normal file
34
libselinux/man/man3/selabel_partial_match.3
Normal file
|
@ -0,0 +1,34 @@
|
|||
.TH "selabel_partial_match" "3" "05 May 2015" "Security Enhanced Linux" "SELinux API documentation"
|
||||
|
||||
.SH "NAME"
|
||||
selabel_partial_match \- determine whether a direct or partial match is
|
||||
possible on a file path \- Only supported on file backend.
|
||||
.
|
||||
.SH "SYNOPSIS"
|
||||
.B #include <stdbool.h>
|
||||
.br
|
||||
.B #include <selinux/selinux.h>
|
||||
.br
|
||||
.B #include <selinux/label.h>
|
||||
.sp
|
||||
.BI "bool selabel_partial_match(struct selabel_handle *" hnd ,
|
||||
.in +\w'int selabel_partial_match('u
|
||||
.BI "const char *" key ");"
|
||||
.in
|
||||
.
|
||||
.SH "DESCRIPTION"
|
||||
.BR selabel_partial_match ()
|
||||
performs a partial match operation on the handle
|
||||
.IR hnd ,
|
||||
returning TRUE or FALSE.
|
||||
The \fIkey\fR parameter is a file path to check for a direct or partial match.
|
||||
.sp
|
||||
.SH "RETURN VALUE"
|
||||
TRUE is returned if a direct or partial match is found, FALSE if not.
|
||||
.sp
|
||||
.SH "SEE ALSO"
|
||||
.BR selabel_open (3),
|
||||
.BR selabel_stats (3),
|
||||
.BR selinux_set_callback (3),
|
||||
.BR selinux (8),
|
||||
.BR selabel_file (5)
|
|
@ -154,6 +154,98 @@ out:
|
|||
return rc;
|
||||
}
|
||||
|
||||
/* Public API helpers */
|
||||
static char *selabel_sub_key(struct selabel_handle *rec, const char *key)
|
||||
{
|
||||
char *ptr = NULL;
|
||||
char *dptr = NULL;
|
||||
|
||||
ptr = selabel_sub(rec->subs, key);
|
||||
if (ptr) {
|
||||
dptr = selabel_sub(rec->dist_subs, ptr);
|
||||
if (dptr) {
|
||||
free(ptr);
|
||||
ptr = dptr;
|
||||
}
|
||||
} else {
|
||||
ptr = selabel_sub(rec->dist_subs, key);
|
||||
}
|
||||
if (ptr)
|
||||
return ptr;
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static int selabel_fini(struct selabel_handle *rec,
|
||||
struct selabel_lookup_rec *lr,
|
||||
int translating)
|
||||
{
|
||||
if (compat_validate(rec, lr, rec->spec_file, 0))
|
||||
return -1;
|
||||
|
||||
if (translating && !lr->ctx_trans &&
|
||||
selinux_raw_to_trans_context(lr->ctx_raw, &lr->ctx_trans))
|
||||
return -1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct selabel_lookup_rec *
|
||||
selabel_lookup_common(struct selabel_handle *rec, int translating,
|
||||
const char *key, int type)
|
||||
{
|
||||
struct selabel_lookup_rec *lr;
|
||||
char *ptr = NULL;
|
||||
|
||||
if (key == NULL) {
|
||||
errno = EINVAL;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
ptr = selabel_sub_key(rec, key);
|
||||
if (ptr) {
|
||||
lr = rec->func_lookup(rec, ptr, type);
|
||||
free(ptr);
|
||||
} else {
|
||||
lr = rec->func_lookup(rec, key, type);
|
||||
}
|
||||
if (!lr)
|
||||
return NULL;
|
||||
|
||||
if (selabel_fini(rec, lr, translating))
|
||||
return NULL;
|
||||
|
||||
return lr;
|
||||
}
|
||||
|
||||
static struct selabel_lookup_rec *
|
||||
selabel_lookup_bm_common(struct selabel_handle *rec, int translating,
|
||||
const char *key, int type, const char **aliases)
|
||||
{
|
||||
struct selabel_lookup_rec *lr;
|
||||
char *ptr = NULL;
|
||||
|
||||
if (key == NULL) {
|
||||
errno = EINVAL;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
ptr = selabel_sub_key(rec, key);
|
||||
if (ptr) {
|
||||
lr = rec->func_lookup_best_match(rec, ptr, aliases, type);
|
||||
free(ptr);
|
||||
} else {
|
||||
lr = rec->func_lookup_best_match(rec, key, aliases, type);
|
||||
}
|
||||
if (!lr)
|
||||
return NULL;
|
||||
|
||||
if (selabel_fini(rec, lr, translating))
|
||||
return NULL;
|
||||
|
||||
return lr;
|
||||
}
|
||||
|
||||
/*
|
||||
* Public API
|
||||
*/
|
||||
|
@ -188,48 +280,6 @@ out:
|
|||
return rec;
|
||||
}
|
||||
|
||||
static struct selabel_lookup_rec *
|
||||
selabel_lookup_common(struct selabel_handle *rec, int translating,
|
||||
const char *key, int type)
|
||||
{
|
||||
struct selabel_lookup_rec *lr;
|
||||
char *ptr = NULL;
|
||||
char *dptr = NULL;
|
||||
|
||||
if (key == NULL) {
|
||||
errno = EINVAL;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
ptr = selabel_sub(rec->subs, key);
|
||||
if (ptr) {
|
||||
dptr = selabel_sub(rec->dist_subs, ptr);
|
||||
if (dptr) {
|
||||
free(ptr);
|
||||
ptr = dptr;
|
||||
}
|
||||
} else {
|
||||
ptr = selabel_sub(rec->dist_subs, key);
|
||||
}
|
||||
if (ptr) {
|
||||
lr = rec->func_lookup(rec, ptr, type);
|
||||
free(ptr);
|
||||
} else {
|
||||
lr = rec->func_lookup(rec, key, type);
|
||||
}
|
||||
if (!lr)
|
||||
return NULL;
|
||||
|
||||
if (compat_validate(rec, lr, rec->spec_file, 0))
|
||||
return NULL;
|
||||
|
||||
if (translating && !lr->ctx_trans &&
|
||||
selinux_raw_to_trans_context(lr->ctx_raw, &lr->ctx_trans))
|
||||
return NULL;
|
||||
|
||||
return lr;
|
||||
}
|
||||
|
||||
int selabel_lookup(struct selabel_handle *rec, char **con,
|
||||
const char *key, int type)
|
||||
{
|
||||
|
@ -256,6 +306,66 @@ int selabel_lookup_raw(struct selabel_handle *rec, char **con,
|
|||
return *con ? 0 : -1;
|
||||
}
|
||||
|
||||
bool selabel_partial_match(struct selabel_handle *rec, const char *key)
|
||||
{
|
||||
char *ptr;
|
||||
bool ret;
|
||||
|
||||
if (!rec->func_partial_match) {
|
||||
/*
|
||||
* If the label backend does not support partial matching,
|
||||
* then assume a match is possible.
|
||||
*/
|
||||
return true;
|
||||
}
|
||||
|
||||
ptr = selabel_sub_key(rec, key);
|
||||
if (ptr) {
|
||||
ret = rec->func_partial_match(rec, ptr);
|
||||
free(ptr);
|
||||
} else {
|
||||
ret = rec->func_partial_match(rec, key);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
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 = selabel_lookup_bm_common(rec, 1, key, type, aliases);
|
||||
if (!lr)
|
||||
return -1;
|
||||
|
||||
*con = strdup(lr->ctx_trans);
|
||||
return *con ? 0 : -1;
|
||||
}
|
||||
|
||||
int selabel_lookup_best_match_raw(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 = selabel_lookup_bm_common(rec, 0, key, type, aliases);
|
||||
if (!lr)
|
||||
return -1;
|
||||
|
||||
*con = strdup(lr->ctx_raw);
|
||||
return *con ? 0 : -1;
|
||||
}
|
||||
|
||||
void selabel_close(struct selabel_handle *rec)
|
||||
{
|
||||
selabel_subs_fini(rec->subs);
|
||||
|
|
|
@ -601,15 +601,17 @@ static void closef(struct selabel_handle *rec)
|
|||
free(data);
|
||||
}
|
||||
|
||||
static struct selabel_lookup_rec *lookup(struct selabel_handle *rec,
|
||||
const char *key, int type)
|
||||
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;
|
||||
int i, rc, file_stem, pcre_options = 0;
|
||||
mode_t mode = (mode_t)type;
|
||||
const char *buf;
|
||||
struct selabel_lookup_rec *ret = NULL;
|
||||
struct spec *ret = NULL;
|
||||
char *clean_key = NULL;
|
||||
const char *prev_slash, *next_slash;
|
||||
unsigned int sofar = 0;
|
||||
|
@ -621,7 +623,7 @@ static struct selabel_lookup_rec *lookup(struct selabel_handle *rec,
|
|||
|
||||
/* Remove duplicate slashes */
|
||||
if ((next_slash = strstr(key, "//"))) {
|
||||
clean_key = malloc(strlen(key) + 1);
|
||||
clean_key = (char *) malloc(strlen(key) + 1);
|
||||
if (!clean_key)
|
||||
goto finish;
|
||||
prev_slash = key;
|
||||
|
@ -639,6 +641,9 @@ static struct selabel_lookup_rec *lookup(struct selabel_handle *rec,
|
|||
file_stem = find_stem_from_file(data, &buf);
|
||||
mode &= S_IFMT;
|
||||
|
||||
if (partial)
|
||||
pcre_options |= PCRE_PARTIAL_SOFT;
|
||||
|
||||
/*
|
||||
* Check for matching specifications in reverse order, so that
|
||||
* the last matching specification is used.
|
||||
|
@ -654,14 +659,22 @@ static struct selabel_lookup_rec *lookup(struct selabel_handle *rec,
|
|||
if (compile_regex(data, spec, NULL) < 0)
|
||||
goto finish;
|
||||
if (spec->stem_id == -1)
|
||||
rc = pcre_exec(spec->regex, get_pcre_extra(spec), key, strlen(key), 0, 0, NULL, 0);
|
||||
rc = pcre_exec(spec->regex,
|
||||
get_pcre_extra(spec),
|
||||
key, strlen(key), 0,
|
||||
pcre_options, NULL, 0);
|
||||
else
|
||||
rc = pcre_exec(spec->regex, get_pcre_extra(spec), buf, strlen(buf), 0, 0, NULL, 0);
|
||||
|
||||
rc = pcre_exec(spec->regex,
|
||||
get_pcre_extra(spec),
|
||||
buf, strlen(buf), 0,
|
||||
pcre_options, NULL, 0);
|
||||
if (rc == 0) {
|
||||
spec->matches++;
|
||||
break;
|
||||
} else if (rc == PCRE_ERROR_NOMATCH)
|
||||
} else if (partial && rc == PCRE_ERROR_PARTIAL)
|
||||
break;
|
||||
|
||||
if (rc == PCRE_ERROR_NOMATCH)
|
||||
continue;
|
||||
|
||||
errno = ENOENT;
|
||||
|
@ -677,13 +690,87 @@ static struct selabel_lookup_rec *lookup(struct selabel_handle *rec,
|
|||
}
|
||||
|
||||
errno = 0;
|
||||
ret = &spec_arr[i].lr;
|
||||
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 void stats(struct selabel_handle *rec)
|
||||
{
|
||||
struct saved_data *data = (struct saved_data *)rec->data;
|
||||
|
@ -722,6 +809,8 @@ int selabel_file_init(struct selabel_handle *rec, struct selinux_opt *opts,
|
|||
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;
|
||||
|
||||
return init(rec, opts, nopts);
|
||||
}
|
||||
|
|
|
@ -31,6 +31,7 @@ struct spec {
|
|||
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 */
|
||||
|
|
|
@ -57,6 +57,12 @@ struct selabel_handle {
|
|||
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);
|
||||
|
||||
/* supports backend-specific state information */
|
||||
void *data;
|
||||
|
|
126
libselinux/utils/selabel_lookup.c
Normal file
126
libselinux/utils/selabel_lookup.c
Normal file
|
@ -0,0 +1,126 @@
|
|||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <getopt.h>
|
||||
#include <errno.h>
|
||||
#include <selinux/selinux.h>
|
||||
#include <selinux/label.h>
|
||||
|
||||
static void usage(const char *progname)
|
||||
{
|
||||
fprintf(stderr,
|
||||
"usage: %s -b backend [-v] [-r] -k key [-t type] [-f file]\n\n"
|
||||
"Where:\n\t"
|
||||
"-b The backend - \"file\", \"media\", \"x\", \"db\" or "
|
||||
"\"prop\"\n\t"
|
||||
"-v Validate entries against loaded policy.\n\t"
|
||||
"-r Use \"raw\" function.\n\t"
|
||||
"-k Lookup key - Depends on backend.\n\t"
|
||||
"-t Lookup type - Optional as depends on backend.\n\t"
|
||||
"-f Optional file containing the specs (defaults to\n\t"
|
||||
" those used by loaded policy).\n\n"
|
||||
"Examples:\n\t"
|
||||
"%s -v -b file -k /run -t 0\n\t"
|
||||
" lookup with validation against the loaded policy, the\n\t"
|
||||
" \"file\" backend for path \"/run\" with mode = 0\n\t"
|
||||
"%s -r -b x -t 4 -k X11:ButtonPress\n\t"
|
||||
" lookup_raw the \"X\" backend for type SELABEL_X_EVENT\n\t"
|
||||
" using key \"X11:ButtonPress\"\n\n",
|
||||
progname, progname, progname);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
int raw = 0, type = 0, backend = 0, rc, opt;
|
||||
char *validate = NULL, *key = NULL, *context = NULL, *file = NULL;
|
||||
|
||||
struct selabel_handle *hnd;
|
||||
struct selinux_opt selabel_option[] = {
|
||||
{ SELABEL_OPT_PATH, file },
|
||||
{ SELABEL_OPT_VALIDATE, validate }
|
||||
};
|
||||
|
||||
if (argc < 3)
|
||||
usage(argv[0]);
|
||||
|
||||
while ((opt = getopt(argc, argv, "b:f:vrk:t:")) > 0) {
|
||||
switch (opt) {
|
||||
case 'b':
|
||||
if (!strcasecmp(optarg, "file")) {
|
||||
backend = SELABEL_CTX_FILE;
|
||||
} else if (!strcmp(optarg, "media")) {
|
||||
backend = SELABEL_CTX_MEDIA;
|
||||
} else if (!strcmp(optarg, "x")) {
|
||||
backend = SELABEL_CTX_X;
|
||||
} else if (!strcmp(optarg, "db")) {
|
||||
backend = SELABEL_CTX_DB;
|
||||
} else if (!strcmp(optarg, "prop")) {
|
||||
backend = SELABEL_CTX_ANDROID_PROP;
|
||||
} else {
|
||||
fprintf(stderr, "Unknown backend: %s\n",
|
||||
optarg);
|
||||
usage(argv[0]);
|
||||
}
|
||||
break;
|
||||
case 'f':
|
||||
file = optarg;
|
||||
break;
|
||||
case 'v':
|
||||
validate = (char *)1;
|
||||
break;
|
||||
case 'r':
|
||||
raw = 1;
|
||||
break;
|
||||
case 'k':
|
||||
key = optarg;
|
||||
break;
|
||||
case 't':
|
||||
type = atoi(optarg);
|
||||
break;
|
||||
default:
|
||||
usage(argv[0]);
|
||||
}
|
||||
}
|
||||
|
||||
selabel_option[0].value = file;
|
||||
selabel_option[1].value = validate;
|
||||
|
||||
hnd = selabel_open(backend, selabel_option, 2);
|
||||
if (!hnd) {
|
||||
fprintf(stderr, "ERROR: selabel_open - Could not obtain "
|
||||
"handle.\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
switch (raw) {
|
||||
case 1:
|
||||
rc = selabel_lookup_raw(hnd, &context, key, type);
|
||||
break;
|
||||
default:
|
||||
rc = selabel_lookup(hnd, &context, key, type);
|
||||
}
|
||||
selabel_close(hnd);
|
||||
|
||||
if (rc) {
|
||||
switch (errno) {
|
||||
case ENOENT:
|
||||
fprintf(stderr, "ERROR: selabel_lookup failed to "
|
||||
"find a valid context.\n");
|
||||
break;
|
||||
case EINVAL:
|
||||
fprintf(stderr, "ERROR: selabel_lookup failed to "
|
||||
"validate context, or key / type are "
|
||||
"invalid.\n");
|
||||
break;
|
||||
default:
|
||||
fprintf(stderr, "selabel_lookup ERROR: %s\n",
|
||||
strerror(errno));
|
||||
}
|
||||
} else {
|
||||
printf("Default context: %s\n", context);
|
||||
freecon(context);
|
||||
}
|
||||
|
||||
return rc;
|
||||
}
|
164
libselinux/utils/selabel_lookup_best_match.c
Normal file
164
libselinux/utils/selabel_lookup_best_match.c
Normal file
|
@ -0,0 +1,164 @@
|
|||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <getopt.h>
|
||||
#include <errno.h>
|
||||
#include <sys/stat.h>
|
||||
#include <selinux/selinux.h>
|
||||
#include <selinux/label.h>
|
||||
|
||||
static void usage(const char *progname)
|
||||
{
|
||||
fprintf(stderr,
|
||||
"usage: %s [-v] [-r] -p path [-m mode] [-f file] [link...]\n\n"
|
||||
"Where:\n\t"
|
||||
"-v Validate file_contxts entries against loaded policy.\n\t"
|
||||
"-r Use \"raw\" function.\n\t"
|
||||
"-p Path to check for best match using the link(s) provided.\n\t"
|
||||
"-m Optional mode (b, c, d, p, l, s or f) Defaults to 0.\n\t"
|
||||
"-f Optional file containing the specs (defaults to\n\t"
|
||||
" those used by loaded policy).\n\t"
|
||||
"link Zero or more links to check against, the order of\n\t"
|
||||
" precedence for best match is:\n\t\t"
|
||||
" 1) An exact match for the real path (if no links), or\n\t\t"
|
||||
" 2) An exact match for any of the links (aliases), or\n\t\t"
|
||||
" 3) The longest fixed prefix match.\n\n"
|
||||
"Example:\n\t"
|
||||
"%s -p /dev/initctl /run/systemd/initctl/fifo\n\t"
|
||||
" Find best matching context for the specified path using one link.\n\n",
|
||||
progname, progname);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
static mode_t string_to_mode(char *s)
|
||||
{
|
||||
switch (s[0]) {
|
||||
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 'f':
|
||||
return S_IFREG;
|
||||
};
|
||||
return 0;
|
||||
}
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
int raw = 0, mode = 0, rc, opt, i, num_links, string_size;
|
||||
char *validate = NULL, *path = NULL, *context = NULL, *file = NULL;
|
||||
|
||||
char **links = NULL;
|
||||
|
||||
struct selabel_handle *hnd;
|
||||
struct selinux_opt options[] = {
|
||||
{ SELABEL_OPT_PATH, file },
|
||||
{ SELABEL_OPT_VALIDATE, validate }
|
||||
};
|
||||
|
||||
if (argc < 3)
|
||||
usage(argv[0]);
|
||||
|
||||
while ((opt = getopt(argc, argv, "f:vrp:m:")) > 0) {
|
||||
switch (opt) {
|
||||
case 'f':
|
||||
file = optarg;
|
||||
break;
|
||||
case 'v':
|
||||
validate = (char *)1;
|
||||
break;
|
||||
case 'r':
|
||||
raw = 1;
|
||||
break;
|
||||
case 'p':
|
||||
path = optarg;
|
||||
break;
|
||||
case 'm':
|
||||
mode = string_to_mode(optarg);
|
||||
break;
|
||||
default:
|
||||
usage(argv[0]);
|
||||
}
|
||||
}
|
||||
|
||||
/* Count links */
|
||||
for (i = optind, num_links = 0; i < argc; i++, num_links++)
|
||||
;
|
||||
|
||||
if (num_links != 0) {
|
||||
links = malloc(sizeof(char *) * num_links);
|
||||
|
||||
if (links == NULL) {
|
||||
fprintf(stderr, "ERROR: malloc failed.");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
for (i = optind, num_links = 0; i < argc; i++, num_links++) {
|
||||
string_size = strlen(argv[i]) + 1;
|
||||
links[num_links] = malloc(string_size);
|
||||
if (links[num_links] == NULL) {
|
||||
fprintf(stderr, "ERROR: malloc failed.");
|
||||
exit(1);
|
||||
}
|
||||
strcpy(links[num_links], argv[i]);
|
||||
}
|
||||
}
|
||||
|
||||
options[0].value = file;
|
||||
options[1].value = validate;
|
||||
|
||||
hnd = selabel_open(SELABEL_CTX_FILE, options, 2);
|
||||
if (!hnd) {
|
||||
fprintf(stderr, "ERROR: selabel_open - Could not obtain "
|
||||
"handle.\n");
|
||||
rc = -1;
|
||||
goto out;
|
||||
}
|
||||
|
||||
switch (raw) {
|
||||
case 1:
|
||||
rc = selabel_lookup_best_match_raw(hnd, &context, path,
|
||||
(const char **)links, mode);
|
||||
break;
|
||||
default:
|
||||
rc = selabel_lookup_best_match(hnd, &context, path,
|
||||
(const char **)links, mode);
|
||||
}
|
||||
selabel_close(hnd);
|
||||
|
||||
if (rc) {
|
||||
switch (errno) {
|
||||
case ENOENT:
|
||||
fprintf(stderr, "ERROR: selabel_lookup_best_match "
|
||||
"failed to find a valid context.\n");
|
||||
break;
|
||||
case EINVAL:
|
||||
fprintf(stderr, "ERROR: selabel_lookup_best_match "
|
||||
"failed to validate context, or path / mode "
|
||||
"are invalid.\n");
|
||||
break;
|
||||
default:
|
||||
fprintf(stderr, "selabel_lookup_best_match ERROR: "
|
||||
"%s\n", strerror(errno));
|
||||
}
|
||||
} else {
|
||||
printf("Best match context: %s\n", context);
|
||||
freecon(context);
|
||||
}
|
||||
out:
|
||||
if (num_links != 0) {
|
||||
for (i = 0; i < num_links; i++)
|
||||
free(links[i]);
|
||||
free(links);
|
||||
}
|
||||
|
||||
return rc;
|
||||
}
|
75
libselinux/utils/selabel_partial_match.c
Normal file
75
libselinux/utils/selabel_partial_match.c
Normal file
|
@ -0,0 +1,75 @@
|
|||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <getopt.h>
|
||||
#include <errno.h>
|
||||
#include <stdbool.h>
|
||||
#include <selinux/selinux.h>
|
||||
#include <selinux/label.h>
|
||||
|
||||
static void usage(const char *progname)
|
||||
{
|
||||
fprintf(stderr,
|
||||
"usage: %s [-v] -p <path> [-f file]\n\n"
|
||||
"Where:\n\t"
|
||||
"-v Validate file_contxts entries against loaded policy.\n\t"
|
||||
"-p Path to check if a match or partial match is possible\n\t"
|
||||
" against a regex entry in the file_contexts file.\n\t"
|
||||
"-f Optional file_contexts file (defaults to current policy).\n\n"
|
||||
"Example:\n\t"
|
||||
"%s -p /sys/devices/system/cpu/online\n\t"
|
||||
" Check if a match or partial match is possible against\n\t"
|
||||
" the path \"/sys/devices/system/cpu/online\", returning\n\t"
|
||||
" TRUE or FALSE.\n\n", progname, progname);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
int opt;
|
||||
bool partial_match;
|
||||
char *validate = NULL, *path = NULL, *file = NULL;
|
||||
|
||||
struct selabel_handle *hnd;
|
||||
struct selinux_opt selabel_option[] = {
|
||||
{ SELABEL_OPT_PATH, file },
|
||||
{ SELABEL_OPT_VALIDATE, validate }
|
||||
};
|
||||
|
||||
if (argc < 2)
|
||||
usage(argv[0]);
|
||||
|
||||
while ((opt = getopt(argc, argv, "f:vp:")) > 0) {
|
||||
switch (opt) {
|
||||
case 'f':
|
||||
file = optarg;
|
||||
break;
|
||||
case 'v':
|
||||
validate = (char *)1;
|
||||
break;
|
||||
case 'p':
|
||||
path = optarg;
|
||||
break;
|
||||
default:
|
||||
usage(argv[0]);
|
||||
}
|
||||
}
|
||||
|
||||
selabel_option[0].value = file;
|
||||
selabel_option[1].value = validate;
|
||||
|
||||
hnd = selabel_open(SELABEL_CTX_FILE, selabel_option, 2);
|
||||
if (!hnd) {
|
||||
fprintf(stderr, "ERROR: selabel_open - Could not obtain "
|
||||
"handle.\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
partial_match = selabel_partial_match(hnd, path);
|
||||
|
||||
printf("Match or Partial match: %s\n",
|
||||
partial_match == 1 ? "TRUE" : "FALSE");
|
||||
|
||||
selabel_close(hnd);
|
||||
return partial_match;
|
||||
}
|
|
@ -1,3 +1,4 @@
|
|||
* Verify users prior to evaluating users in cil, from Yuli Khodorkovskiy.
|
||||
* Binary modules do not support ioctl rules, from Stephen Smalley.
|
||||
* Add support for ioctl command whitelisting, from Jeff Vander Stoep.
|
||||
* Don't use symbol versioning for static object files, from Yuli Khodorkovskiy.
|
||||
|
|
|
@ -1691,12 +1691,30 @@ exit:
|
|||
return rc;
|
||||
}
|
||||
|
||||
static int cil_pre_verify(struct cil_db *db)
|
||||
{
|
||||
int rc = SEPOL_ERR;
|
||||
struct cil_args_verify extra_args;
|
||||
|
||||
extra_args.db = db;
|
||||
|
||||
rc = cil_tree_walk(db->ast->root, __cil_pre_verify_helper, NULL, NULL, &extra_args);
|
||||
if (rc != SEPOL_OK) {
|
||||
cil_log(CIL_ERR, "Failed to verify cil database\n");
|
||||
goto exit;
|
||||
}
|
||||
|
||||
exit:
|
||||
return rc;
|
||||
}
|
||||
|
||||
int cil_post_process(struct cil_db *db)
|
||||
{
|
||||
int rc = SEPOL_ERR;
|
||||
|
||||
rc = cil_verify_no_classperms_loop(db);
|
||||
rc = cil_pre_verify(db);
|
||||
if (rc != SEPOL_OK) {
|
||||
cil_log(CIL_ERR, "Failed to verify cil database\n");
|
||||
goto exit;
|
||||
}
|
||||
|
||||
|
|
|
@ -601,7 +601,7 @@ exit:
|
|||
return rc;
|
||||
}
|
||||
|
||||
int __cil_verify_user(struct cil_db *db, struct cil_tree_node *node)
|
||||
static int __cil_verify_user_pre_eval(struct cil_tree_node *node)
|
||||
{
|
||||
int rc = SEPOL_ERR;
|
||||
struct cil_user *user = node->data;
|
||||
|
@ -635,6 +635,17 @@ int __cil_verify_user(struct cil_db *db, struct cil_tree_node *node)
|
|||
}
|
||||
}
|
||||
|
||||
return SEPOL_OK;
|
||||
exit:
|
||||
cil_log(CIL_ERR, "Invalid user at line %d of %s\n", node->line, node->path);
|
||||
return rc;
|
||||
}
|
||||
|
||||
static int __cil_verify_user_post_eval(struct cil_db *db, struct cil_tree_node *node)
|
||||
{
|
||||
int rc = SEPOL_ERR;
|
||||
struct cil_user *user = node->data;
|
||||
|
||||
/* Verify user range only if anonymous */
|
||||
if (user->range->datum.name == NULL) {
|
||||
rc = __cil_verify_levelrange(db, user->range);
|
||||
|
@ -1318,7 +1329,7 @@ int __cil_verify_helper(struct cil_tree_node *node, uint32_t *finished, void *ex
|
|||
case 0: {
|
||||
switch (node->flavor) {
|
||||
case CIL_USER:
|
||||
rc = __cil_verify_user(db, node);
|
||||
rc = __cil_verify_user_post_eval(db, node);
|
||||
break;
|
||||
case CIL_SELINUXUSERDEFAULT:
|
||||
(*nseuserdflt)++;
|
||||
|
@ -1531,7 +1542,7 @@ static int __cil_verify_map_class(struct cil_tree_node *node)
|
|||
return SEPOL_OK;
|
||||
}
|
||||
|
||||
static int __cil_verify_no_classperms_loop_helper(struct cil_tree_node *node, uint32_t *finished, __attribute__((unused)) void *extra_args)
|
||||
int __cil_pre_verify_helper(struct cil_tree_node *node, uint32_t *finished, __attribute__((unused)) void *extra_args)
|
||||
{
|
||||
int rc = SEPOL_ERR;
|
||||
|
||||
|
@ -1549,6 +1560,12 @@ static int __cil_verify_no_classperms_loop_helper(struct cil_tree_node *node, ui
|
|||
}
|
||||
|
||||
switch (node->flavor) {
|
||||
case CIL_USER:
|
||||
rc = __cil_verify_user_pre_eval(node);
|
||||
if (rc != SEPOL_OK) {
|
||||
goto exit;
|
||||
}
|
||||
break;
|
||||
case CIL_MAP_CLASS:
|
||||
rc = __cil_verify_map_class(node);
|
||||
break;
|
||||
|
@ -1563,17 +1580,3 @@ static int __cil_verify_no_classperms_loop_helper(struct cil_tree_node *node, ui
|
|||
exit:
|
||||
return rc;
|
||||
}
|
||||
|
||||
int cil_verify_no_classperms_loop(struct cil_db *db)
|
||||
{
|
||||
int rc = SEPOL_ERR;
|
||||
|
||||
rc = cil_tree_walk(db->ast->root, __cil_verify_no_classperms_loop_helper, NULL, NULL, NULL);
|
||||
if (rc != SEPOL_OK) {
|
||||
cil_log(CIL_ERR, "Failed to verify no loops in class permissions\n");
|
||||
goto exit;
|
||||
}
|
||||
|
||||
exit:
|
||||
return rc;
|
||||
}
|
||||
|
|
|
@ -68,6 +68,6 @@ int __cil_verify_ordered(struct cil_tree_node *current, enum cil_flavor flavor);
|
|||
int __cil_verify_initsids(struct cil_list *sids);
|
||||
int __cil_verify_senscat(struct cil_sens *sens, struct cil_cat *cat);
|
||||
int __cil_verify_helper(struct cil_tree_node *node, __attribute__((unused)) uint32_t *finished, void *extra_args);
|
||||
int cil_verify_no_classperms_loop(struct cil_db *db);
|
||||
int __cil_pre_verify_helper(struct cil_tree_node *node, __attribute__((unused)) uint32_t *finished, void *extra_args);
|
||||
|
||||
#endif
|
||||
|
|
Loading…
Reference in a new issue