Skip to content

Commit

Permalink
libselinux: Save digest of all partial matches for directory
Browse files Browse the repository at this point in the history
We used to hash the file_context and skip the restorecon on the top
level directory if the hash doesn't change. But the file_context
might change after an OTA update; and some users experienced long
restorecon time as they have lots of files under directories like
/data/media.

This CL tries to hash all the partial match entries in the
file_context for each directory; and skips the restorecon if that
digest stays the same, regardless of the changes to the other parts
of file_context.

This is a version ported from Android that was originally written by:
xunchang <xunchang@google.com>

Signed-off-by: Richard Haines <richard_c_haines@btinternet.com>
  • Loading branch information
Richard Haines authored and fishilico committed Jul 27, 2019
1 parent c00ed59 commit e016502
Show file tree
Hide file tree
Showing 12 changed files with 560 additions and 138 deletions.
5 changes: 5 additions & 0 deletions libselinux/include/selinux/label.h
Original file line number Diff line number Diff line change
Expand Up @@ -106,6 +106,11 @@ int selabel_lookup_raw(struct selabel_handle *handle, char **con,

bool selabel_partial_match(struct selabel_handle *handle, const char *key);

bool selabel_get_digests_all_partial_matches(struct selabel_handle *rec,
const char *key,
uint8_t **calculated_digest,
uint8_t **xattr_digest,
size_t *digest_len);
bool selabel_hash_all_partial_matches(struct selabel_handle *rec,
const char *key, uint8_t* digest);

Expand Down
17 changes: 11 additions & 6 deletions libselinux/include/selinux/restorecon.h
Original file line number Diff line number Diff line change
Expand Up @@ -27,8 +27,8 @@ extern int selinux_restorecon(const char *pathname,
* restorecon_flags options
*/
/*
* Force the checking of labels even if the stored SHA1
* digest matches the specfiles SHA1 digest.
* Force the checking of labels even if the stored SHA1 digest
* matches the specfiles SHA1 digest (requires CAP_SYS_ADMIN).
*/
#define SELINUX_RESTORECON_IGNORE_DIGEST 0x0001
/*
Expand Down Expand Up @@ -96,12 +96,17 @@ extern int selinux_restorecon(const char *pathname,
* See SELINUX_RESTORECON_PROGRESS flag for details.
*/
#define SELINUX_RESTORECON_MASS_RELABEL 0x4000
/*
* Set if no digest is to be read or written (as only processes
* running with CAP_SYS_ADMIN can read/write digests).
*/
#define SELINUX_RESTORECON_SKIP_DIGEST 0x8000

/**
* selinux_restorecon_set_sehandle - Set the global fc handle.
* @hndl: specifies handle to set as the global fc handle.
*
* Called by a process that has already called selabel_open(3) with it's
* Called by a process that has already called selabel_open(3) with its
* required parameters, or if selinux_restorecon_default_handle(3) has been
* called to set the default selabel_open(3) parameters.
*/
Expand All @@ -110,7 +115,7 @@ extern void selinux_restorecon_set_sehandle(struct selabel_handle *hndl);
/**
* selinux_restorecon_default_handle - Sets default selabel_open(3) parameters
* to use the currently loaded policy and
* file_contexts, also requests the digest.
* file_contexts.
*
* Return value is the created handle on success or NULL with @errno set on
* failure.
Expand All @@ -134,12 +139,12 @@ extern void selinux_restorecon_set_exclude_list(const char **exclude_list);
extern int selinux_restorecon_set_alt_rootpath(const char *alt_rootpath);

/**
* selinux_restorecon_xattr - Read/remove RESTORECON_LAST xattr entries.
* selinux_restorecon_xattr - Read/remove security.sehash xattr entries.
* @pathname: specifies directory path to check.
* @xattr_flags: specifies the actions to be performed.
* @xattr_list: a linked list of struct dir_xattr structures containing
* the directory, digest and result of the action on the
* RESTORECON_LAST entry.
* security.sehash entry.
*
* selinux_restorecon_xattr(3) will automatically call
* selinux_restorecon_default_handle(3) and selinux_restorecon_set_sehandle(3)
Expand Down
70 changes: 70 additions & 0 deletions libselinux/man/man3/selabel_get_digests_all_partial_matches.3
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
.TH "selabel_get_digests_all_partial_matches" "3" "14 April 2019" "SELinux API documentation"

.SH "NAME"
selabel_get_digests_all_partial_matches \- retrieve the partial matches digest
and the xattr digest that applies to the supplied 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_get_digests_all_partial_matches("
.in +\w'selabel_get_digests_all_partial_matches('u
.BI "struct selabel_handle *" hnd ,
.br
.BI "const char *" key ,
.br
.BI "uint8_t **" calculated_digest ,
.br
.BI "uint8_t **" xattr_digest ,
.br
.BI "size_t *" digest_len ");"
.in
.
.SH "DESCRIPTION"
.BR selabel_get_digests_all_partial_matches ()
retrieves the file_contexts partial matches digest and the xattr digest that
applies to the supplied path on the handle
.IR hnd .
.br
The
.IR key
parameter is the path to retrieve the digests.
.br
The
.IR calculated_digest
is a pointer to the
.IR key
calculated file_contexts digest of all applicable partial matches, or NULL if
none exist. The caller must
.BR free (3)
the buffer.
.br
The
.IR xattr_digest
is a pointer to the
.IR key
.BR xattr (7)
stored digest, or NULL if it does not exist.
The caller must
.BR free (3)
the buffer.
.br
The
.IR digest_len
is the length of the digests that will always be returned (even if both are
NULL). Note that if both digests are returned, they will always be the same length.
.sp
.SH "RETURN VALUE"
TRUE if the digests match or FALSE if they do not or either or both are missing.
.sp
.SH "SEE ALSO"
.BR selinux_restorecon (3),
.BR selabel_partial_match (3),
.BR selabel_open (3),
.BR selinux (8),
.BR selabel_file (5)
81 changes: 42 additions & 39 deletions libselinux/man/man3/selinux_restorecon.3
Original file line number Diff line number Diff line change
Expand Up @@ -28,39 +28,53 @@ If this is a directory and the
.B SELINUX_RESTORECON_RECURSE
has been set (for descending through directories), then
.BR selinux_restorecon ()
will write an SHA1 digest of the combined specfiles (see the
will write an SHA1 digest of specfile entries caculated by
.BR selabel_get_digests_all_partial_matches (3)
to an extended attribute of
.IR security.sehash
once the relabeling has been completed successfully (see the
.B NOTES
section for details) to an extended attribute of
.IR security.restorecon_last
once the relabeling has been completed successfully. This digest will be
checked should
section for details).
.br
These digests will be checked should
.BR selinux_restorecon ()
be rerun
with the
be rerun with the
.IR restorecon_flags
.B SELINUX_RESTORECON_RECURSE
flag set. If any of the specfiles had been updated, the digest
flag set. If any of the specfile entries had been updated, the digest
will also be updated. However if the digest is the same, no relabeling checks
will take place (unless the
will take place.
.br
The
.IR restorecon_flags
that can be used to manage the usage of the SHA1 digest are:
.RS
.B SELINUX_RESTORECON_SKIP_DIGEST
.br
.B SELINUX_RESTORECON_IGNORE_DIGEST
flag is set).
.RE
.sp
.IR restorecon_flags
contains the labeling option/rules as follows:
.sp
.RS
.sp
.B SELINUX_RESTORECON_SKIP_DIGEST
Do not check or update any extended attribute
.IR security.sehash
entries.
.sp
.B SELINUX_RESTORECON_IGNORE_DIGEST
force the checking of labels even if the stored SHA1 digest matches the
specfiles SHA1 digest. The specfiles digest will be written to the
.IR security.restorecon_last
specfile entries SHA1 digest. The specfile entries digest will be written to the
.IR security.sehash
extended attribute once relabeling has been completed successfully provided the
.B SELINUX_RESTORECON_NOCHANGE
flag has not been set.
.sp
.B SELINUX_RESTORECON_NOCHANGE
don't change any file labels (passive check) or update the digest in the
.IR security.restorecon_last
.IR security.sehash
extended attribute.
.sp
.B SELINUX_RESTORECON_SET_SPECFILE_CTX
Expand All @@ -70,7 +84,7 @@ default specfile context.
.sp
.B SELINUX_RESTORECON_RECURSE
change file and directory labels recursively (descend directories)
and if successful write an SHA1 digest of the combined specfiles to an
and if successful write an SHA1 digest of the specfile entries to an
extended attribute as described in the
.B NOTES
section.
Expand Down Expand Up @@ -182,53 +196,40 @@ To improve performance when relabeling file systems recursively (e.g. the
.B SELINUX_RESTORECON_RECURSE
flag is set)
.BR selinux_restorecon ()
will write an SHA1 digest of the specfiles that are processed by
.BR selabel_open (3)
will write a caculated SHA1 digest of the specfile entries returned by
.BR selabel_get_digests_all_partial_matches (3)
to an extended attribute named
.IR security.restorecon_last
to the directory specified in the
.IR pathname .
.IR security.sehash
for each directory in the
.IR pathname
path.
.IP "2." 4
To check the extended attribute entry use
.BR getfattr (1) ,
for example:
.sp
.RS
.RS
getfattr -e hex -n security.restorecon_last /
getfattr -e hex -n security.sehash /
.RE
.RE
.IP "3." 4
The SHA1 digest is calculated by
.BR selabel_open (3)
concatenating the specfiles it reads during initialisation with the
resulting digest and list of specfiles being retrieved by
.BR selabel_digest (3).
.IP "4." 4
The specfiles consist of the mandatory
.I file_contexts
file plus any subs, subs_dist, local and homedir entries (text or binary versions)
as determined by any
.BR selabel_open (3)
options e.g.
.BR SELABEL_OPT_BASEONLY .
.sp
Should any of the specfiles have changed, then when
Should any of the specfile entries have changed, then when
.BR selinux_restorecon ()
is run again with the
.B SELINUX_RESTORECON_RECURSE
flag set, a new SHA1 digest will be calculated and all files will be automatically
flag set, new SHA1 digests will be calculated and all files automatically
relabeled depending on the settings of the
.B SELINUX_RESTORECON_SET_SPECFILE_CTX
flag (provided
.B SELINUX_RESTORECON_NOCHANGE
is not set).
.IP "5." 4
.IP "4." 4
.B /sys
and in-memory filesystems do not support the
.IR security.restorecon_last
.IR security.sehash
extended attribute and are automatically excluded from any relabeling checks.
.IP "6." 4
.IP "5." 4
By default
.B stderr
is used to log output messages and errors. This may be changed by calling
Expand All @@ -239,6 +240,8 @@ with the
option.
.
.SH "SEE ALSO"
.BR selabel_get_digests_all_partial_matches (3),
.br
.BR selinux_restorecon_set_sehandle (3),
.br
.BR selinux_restorecon_default_handle (3),
Expand Down
8 changes: 4 additions & 4 deletions libselinux/man/man3/selinux_restorecon_xattr.3
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

.SH "NAME"
selinux_restorecon_xattr \- manage default
.I security.restorecon_last
.I security.sehash
extended attribute entries added by
.BR selinux_restorecon (3),
.BR setfiles (8)
Expand All @@ -29,7 +29,7 @@ structures containing information described below based on:
.RS
.IR pathname
containing a directory tree to be searched for
.I security.restorecon_last
.I security.sehash
extended attribute entries.
.sp
.IR xattr_flags
Expand Down Expand Up @@ -119,7 +119,7 @@ By default
.BR selinux_restorecon_xattr (3)
will use the default set of specfiles described in
.BR files_contexts (5)
to calculate the initial SHA1 digest to be used for comparison.
to calculate the SHA1 digests to be used for comparison.
To change this default behavior
.BR selabel_open (3)
must be called specifying the required
Expand All @@ -143,7 +143,7 @@ flag has been set.
and
.B TMPFS
filesystems do not support the
.IR security.restorecon_last
.IR security.sehash
extended attribute and are automatically excluded from searches.
.IP "4." 4
By default
Expand Down
15 changes: 15 additions & 0 deletions libselinux/src/label.c
Original file line number Diff line number Diff line change
Expand Up @@ -274,6 +274,21 @@ bool selabel_partial_match(struct selabel_handle *rec, const char *key)
return rec->func_partial_match(rec, key);
}

bool selabel_get_digests_all_partial_matches(struct selabel_handle *rec,
const char *key,
uint8_t **calculated_digest,
uint8_t **xattr_digest,
size_t *digest_len)
{
if (!rec->func_get_digests_all_partial_matches)
return false;

return rec->func_get_digests_all_partial_matches(rec, key,
calculated_digest,
xattr_digest,
digest_len);
}

bool selabel_hash_all_partial_matches(struct selabel_handle *rec,
const char *key, uint8_t *digest) {
if (!rec->func_hash_all_partial_matches) {
Expand Down
Loading

0 comments on commit e016502

Please sign in to comment.