OstreeSePolicy: add ostree_sepolicy_get_csum()

This can be used as a fingerprint to determine whether two
OstreeSePolicy objects are equivalent.

Also add documentation for ostree_sepolicy_get_name().

Closes: #219
Approved by: cgwalters
This commit is contained in:
Jonathan Lebon 2016-03-23 15:54:49 -04:00 committed by Colin Walters (automation)
parent 456f515522
commit b7a04d51f8
5 changed files with 132 additions and 10 deletions

View File

@ -331,4 +331,5 @@ global:
LIBOSTREE_2016.5 {
global:
ostree_repo_import_object_from_with_trust;
ostree_sepolicy_get_csum;
} LIBOSTREE_2016.4;

View File

@ -50,6 +50,7 @@ struct OstreeSePolicy {
GFile *selinux_policy_root;
struct selabel_handle *selinux_hnd;
char *selinux_policy_name;
char *selinux_policy_csum;
#endif
};
@ -77,6 +78,7 @@ ostree_sepolicy_finalize (GObject *object)
#ifdef HAVE_SELINUX
g_clear_object (&self->selinux_policy_root);
g_clear_pointer (&self->selinux_policy_name, g_free);
g_clear_pointer (&self->selinux_policy_csum, g_free);
if (self->selinux_hnd)
{
selabel_close (self->selinux_hnd);
@ -155,6 +157,93 @@ ostree_sepolicy_class_init (OstreeSePolicyClass *klass)
G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
}
#ifdef HAVE_SELINUX
/* Find the latest policy file in our root and return its checksum. */
static gboolean
get_policy_checksum (char **out_csum,
GCancellable *cancellable,
GError **error)
{
gboolean ret = FALSE;
const char *binary_policy_path = selinux_binary_policy_path ();
const char *binfile_prefix = glnx_basename (binary_policy_path);
g_autofree char *bindir_path = g_path_get_dirname (binary_policy_path);
glnx_fd_close int bindir_dfd = -1;
g_autofree char *best_policy = NULL;
int best_version = 0;
g_auto(GLnxDirFdIterator) dfd_iter = { 0,};
if (!glnx_opendirat (AT_FDCWD, bindir_path, TRUE, &bindir_dfd, error))
goto out;
if (!glnx_dirfd_iterator_init_at (bindir_dfd, ".", FALSE, &dfd_iter, error))
goto out;
while (TRUE)
{
struct dirent *dent = NULL;
if (!glnx_dirfd_iterator_next_dent_ensure_dtype (&dfd_iter, &dent,
cancellable, error))
goto out;
if (dent == NULL)
break;
if (dent->d_type == DT_REG)
{
/* We could probably save a few hundred nanoseconds if we accept that
* the prefix will always be "policy" and hardcode that in a static
* compile-once GRegex... But picture how exciting it'd be if it *did*
* somehow change; there would be cheers & slow-mo high-fives at the
* sight of our code not breaking. Is that hope not worth a fraction
* of a millisecond? I believe it is... or maybe I'm just lazy. */
g_autofree char *regex = g_strdup_printf ("^\\Q%s\\E\\.[0-9]+$",
binfile_prefix);
/* we could use match groups to extract the version, but mehhh, we
* already have the prefix on hand */
if (g_regex_match_simple (regex, dent->d_name, 0, 0))
{
int version = /* do +1 for the period */
(int)g_ascii_strtoll (dent->d_name + strlen (binfile_prefix)+1,
NULL, 10);
g_assert (version > 0);
if (version > best_version)
{
best_version = version;
g_free (best_policy);
best_policy = g_strdup (dent->d_name);
}
}
}
}
if (!best_policy)
{
g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
"Could not find binary policy file");
goto out;
}
*out_csum = ot_checksum_file_at (bindir_dfd, best_policy, G_CHECKSUM_SHA256,
cancellable, error);
if (*out_csum == NULL)
goto out;
ret = TRUE;
out:
return ret;
}
#endif
static gboolean
initable_init (GInitable *initable,
GCancellable *cancellable,
@ -257,6 +346,12 @@ initable_init (GInitable *initable,
freecon (con);
}
if (!get_policy_checksum (&self->selinux_policy_csum, cancellable, error))
{
g_prefix_error (error, "While calculating SELinux checksum: ");
goto out;
}
self->selinux_policy_name = g_strdup (policytype);
self->selinux_policy_root = g_object_ref (etc_selinux_dir);
}
@ -306,6 +401,12 @@ ostree_sepolicy_get_path (OstreeSePolicy *self)
return self->path;
}
/**
* ostree_sepolicy_get_name:
* @self:
*
* Returns: (transfer none): Type of current policy
*/
const char *
ostree_sepolicy_get_name (OstreeSePolicy *self)
{
@ -316,6 +417,22 @@ ostree_sepolicy_get_name (OstreeSePolicy *self)
#endif
}
/**
* ostree_sepolicy_get_csum:
* @self:
*
* Returns: (transfer none): Checksum of current policy
*/
const char *
ostree_sepolicy_get_csum (OstreeSePolicy *self)
{
#ifdef HAVE_SELINUX
return self->selinux_policy_csum;
#else
return NULL;
#endif
}
/**
* ostree_sepolicy_get_label:
* @self: Self

View File

@ -44,6 +44,9 @@ GFile * ostree_sepolicy_get_path (OstreeSePolicy *self);
_OSTREE_PUBLIC
const char *ostree_sepolicy_get_name (OstreeSePolicy *self);
_OSTREE_PUBLIC
const char *ostree_sepolicy_get_csum (OstreeSePolicy *self);
_OSTREE_PUBLIC
gboolean ostree_sepolicy_get_label (OstreeSePolicy *self,
const char *relpath,

View File

@ -140,17 +140,17 @@ ot_gio_checksum_stream (GInputStream *in,
}
char *
ot_checksum_file (GFile *file,
GChecksumType checksum_type,
GCancellable *cancellable,
GError **error)
ot_checksum_file_at (int dfd,
const char *path,
GChecksumType checksum_type,
GCancellable *cancellable,
GError **error)
{
GChecksum *checksum = NULL;
char *ret = NULL;
g_autoptr(GInputStream) in = NULL;
in = (GInputStream*)g_file_read (file, cancellable, error);
if (!in)
if (!ot_openat_read_stream (dfd, path, TRUE, &in, cancellable, error))
goto out;
checksum = g_checksum_new (checksum_type);

View File

@ -53,10 +53,11 @@ gboolean ot_gio_checksum_stream (GInputStream *in,
GCancellable *cancellable,
GError **error);
char * ot_checksum_file (GFile *file,
GChecksumType checksum_type,
GCancellable *cancellable,
GError **error);
char * ot_checksum_file_at (int dfd,
const char *path,
GChecksumType checksum_type,
GCancellable *cancellable,
GError **error);
void ot_gio_checksum_stream_async (GInputStream *in,
int io_priority,