@@ -128,6 +128,12 @@ extern int selinux_restorecon_parallel(const char *pathname,
*/
#define SELINUX_RESTORECON_COUNT_ERRORS 0x20000
+/*
+ * In addition to the type component also change the user and
+ * role component of security contexts.
+ */
+#define SELINUX_RESTORECON_SET_USER_ROLE 0x40000
+
/**
* selinux_restorecon_set_sehandle - Set the global fc handle.
* @hndl: specifies handle to set as the global fc handle.
@@ -76,6 +76,7 @@ struct rest_flags {
bool progress;
bool mass_relabel;
bool set_specctx;
+ bool set_user_role;
bool add_assoc;
bool recurse;
bool userealpath;
@@ -585,43 +586,65 @@ static void filespec_destroy(void)
/*
* Called if SELINUX_RESTORECON_SET_SPECFILE_CTX is not set to check if
* the type components differ, updating newtypecon if so.
+ * Also update user and role components if
+ * SELINUX_RESTORECON_SET_USER_ROLE is set.
*/
-static int compare_types(const char *curcon, const char *newcon, char **newtypecon)
+static int compare_portions(const char *curcon, const char *newcon,
+ bool set_user_role, char **newtypecon)
{
- int types_differ = 0;
- context_t cona;
- context_t conb;
+ context_t curctx;
+ context_t newctx;
+ bool update = false;
int rc = 0;
- cona = context_new(curcon);
- if (!cona) {
+ curctx = context_new(curcon);
+ if (!curctx) {
rc = -1;
goto out;
}
- conb = context_new(newcon);
- if (!conb) {
- context_free(cona);
+ newctx = context_new(newcon);
+ if (!newctx) {
+ context_free(curctx);
rc = -1;
goto out;
}
- types_differ = strcmp(context_type_get(cona), context_type_get(conb));
- if (types_differ) {
- rc |= context_user_set(conb, context_user_get(cona));
- rc |= context_role_set(conb, context_role_get(cona));
- rc |= context_range_set(conb, context_range_get(cona));
- if (!rc) {
- *newtypecon = strdup(context_str(conb));
- if (!*newtypecon) {
- rc = -1;
+ if (strcmp(context_type_get(curctx), context_type_get(newctx)) != 0) {
+ update = true;
+ rc = context_type_set(curctx, context_type_get(newctx));
+ if (rc)
+ goto err;
+ }
+
+ if (set_user_role) {
+ if (strcmp(context_user_get(curctx), context_user_get(newctx)) != 0) {
+ update = true;
+ rc = context_user_set(curctx, context_user_get(newctx));
+ if (rc)
+ goto err;
+ }
+
+ if (strcmp(context_role_get(curctx), context_role_get(newctx)) != 0) {
+ update = true;
+ rc = context_role_set(curctx, context_role_get(newctx));
+ if (rc)
goto err;
- }
}
}
+ if (update) {
+ *newtypecon = strdup(context_str(curctx));
+ if (!*newtypecon) {
+ rc = -1;
+ goto err;
+ }
+ } else {
+ *newtypecon = NULL;
+ }
+
err:
- context_free(cona);
- context_free(conb);
+ context_free(curctx);
+ context_free(newctx);
out:
return rc;
}
@@ -631,7 +654,6 @@ static int restorecon_sb(const char *pathname, const struct stat *sb,
{
char *newcon = NULL;
char *curcon = NULL;
- char *newtypecon = NULL;
int rc;
const char *lookup_path = pathname;
@@ -724,8 +746,13 @@ static int restorecon_sb(const char *pathname, const struct stat *sb,
}
if (!flags->set_specctx && curcon) {
- /* If types different then update newcon. */
- rc = compare_types(curcon, newcon, &newtypecon);
+ char *newtypecon;
+
+ /* If types are different then update newcon.
+ * Also update if SELINUX_RESTORECON_SET_USER_ROLE
+ * is set and user or role differs.
+ */
+ rc = compare_portions(curcon, newcon, flags->set_user_role, &newtypecon);
if (rc)
goto err;
@@ -1025,6 +1052,8 @@ static int selinux_restorecon_common(const char *pathname_orig,
SELINUX_RESTORECON_RECURSE) ? true : false;
state.flags.set_specctx = (restorecon_flags &
SELINUX_RESTORECON_SET_SPECFILE_CTX) ? true : false;
+ state.flags.set_user_role = (restorecon_flags &
+ SELINUX_RESTORECON_SET_USER_ROLE) ? true : false;
state.flags.userealpath = (restorecon_flags &
SELINUX_RESTORECON_REALPATH) ? true : false;
state.flags.set_xdev = (restorecon_flags &