diff mbox series

[v3] libsemanage: Preserve file context and ownership in policy store

Message ID 20240723125850.1228121-1-vmojzis@redhat.com (mailing list archive)
State Superseded
Delegated to: Petr Lautrbach
Headers show
Series [v3] libsemanage: Preserve file context and ownership in policy store | expand

Commit Message

Vit Mojzis July 23, 2024, 12:58 p.m. UTC
Make sure that file context (all parts) and ownership of
files/directories in policy store does not change no matter which user
and under which context executes policy rebuild.

Fixes:
  # semodule -B
  # ls -lZ  /etc/selinux/targeted/contexts/files

-rw-r--r--. 1 root root unconfined_u:object_r:file_context_t:s0 421397 Jul 11 09:57 file_contexts
-rw-r--r--. 1 root root unconfined_u:object_r:file_context_t:s0 593470 Jul 11 09:57 file_contexts.bin
-rw-r--r--. 1 root root unconfined_u:object_r:file_context_t:s0  14704 Jul 11 09:57 file_contexts.homedirs
-rw-r--r--. 1 root root unconfined_u:object_r:file_context_t:s0  20289 Jul 11 09:57 file_contexts.homedirs.bin

  SELinux user changed from system_u to the user used to execute semodule

  # capsh --user=testuser --caps="cap_dac_override,cap_chown+eip" --addamb=cap_dac_override,cap_chown -- -c "semodule -B"
  # ls -lZ  /etc/selinux/targeted/contexts/files

-rw-r--r--. 1 testuser testuser unconfined_u:object_r:file_context_t:s0 421397 Jul 19 09:10 file_contexts
-rw-r--r--. 1 testuser testuser unconfined_u:object_r:file_context_t:s0 593470 Jul 19 09:10 file_contexts.bin
-rw-r--r--. 1 testuser testuser unconfined_u:object_r:file_context_t:s0  14704 Jul 19 09:10 file_contexts.homedirs
-rw-r--r--. 1 testuser testuser unconfined_u:object_r:file_context_t:s0  20289 Jul 19 09:10 file_contexts.homedirs.bin

  Both file context and ownership changed -- causes remote login
  failures and other issues in some scenarios.

Signed-off-by: Vit Mojzis <vmojzis@redhat.com>
---
 libsemanage/src/semanage_store.c | 28 ++++++++++++++++++++++++++++
 libsemanage/src/semanage_store.h |  1 +
 2 files changed, 29 insertions(+)

Comments

Stephen Smalley July 23, 2024, 2:56 p.m. UTC | #1
On Tue, Jul 23, 2024 at 9:09 AM Vit Mojzis <vmojzis@redhat.com> wrote:
>
> Make sure that file context (all parts) and ownership of
> files/directories in policy store does not change no matter which user
> and under which context executes policy rebuild.
>
> Fixes:
>   # semodule -B
>   # ls -lZ  /etc/selinux/targeted/contexts/files
>
> -rw-r--r--. 1 root root unconfined_u:object_r:file_context_t:s0 421397 Jul 11 09:57 file_contexts
> -rw-r--r--. 1 root root unconfined_u:object_r:file_context_t:s0 593470 Jul 11 09:57 file_contexts.bin
> -rw-r--r--. 1 root root unconfined_u:object_r:file_context_t:s0  14704 Jul 11 09:57 file_contexts.homedirs
> -rw-r--r--. 1 root root unconfined_u:object_r:file_context_t:s0  20289 Jul 11 09:57 file_contexts.homedirs.bin
>
>   SELinux user changed from system_u to the user used to execute semodule
>
>   # capsh --user=testuser --caps="cap_dac_override,cap_chown+eip" --addamb=cap_dac_override,cap_chown -- -c "semodule -B"
>   # ls -lZ  /etc/selinux/targeted/contexts/files
>
> -rw-r--r--. 1 testuser testuser unconfined_u:object_r:file_context_t:s0 421397 Jul 19 09:10 file_contexts
> -rw-r--r--. 1 testuser testuser unconfined_u:object_r:file_context_t:s0 593470 Jul 19 09:10 file_contexts.bin
> -rw-r--r--. 1 testuser testuser unconfined_u:object_r:file_context_t:s0  14704 Jul 19 09:10 file_contexts.homedirs
> -rw-r--r--. 1 testuser testuser unconfined_u:object_r:file_context_t:s0  20289 Jul 19 09:10 file_contexts.homedirs.bin
>
>   Both file context and ownership changed -- causes remote login
>   failures and other issues in some scenarios.
>
> Signed-off-by: Vit Mojzis <vmojzis@redhat.com>
> ---

> @@ -3018,3 +3028,21 @@ int semanage_nc_sort(semanage_handle_t * sh, const char *buf, size_t buf_len,
>
>         return 0;
>  }
> +
> +/* Make sure the file context and ownership of files in the policy
> + * store does not change */
> +void semanage_setfiles(const char *path){
> +       struct stat sb;
> +
> +       /* Fix the user and role portions of the context, ignore errors
> +        * since this is not a critical operation */
> +       selinux_restorecon(path, SELINUX_RESTORECON_SET_SPECFILE_CTX | SELINUX_RESTORECON_IGNORE_NOENTRY);
> +
> +       /* Make sure "path" is owned by root */
> +       if (geteuid() != 0 || getegid() != 0)
> +               /* Skip files with the SUID or SGID bit set -- abuse protection */
> +               if ((stat(path, &sb) == -1) ||
> +                   (S_ISREG(sb.st_mode) && (sb.st_mode & (S_ISUID | S_ISGID))))
> +                               return;
> +               chown(path, 0, 0);
> +}

Did you consider the fd = open(path, O_PATH); fstat(fd, &sb); ...
fchown(fd, 0, 0); pattern to avoid a race between the check and chown
(e.g. link changed from one file to another in between)?
Vit Mojzis July 23, 2024, 4:54 p.m. UTC | #2
On 7/23/24 16:56, Stephen Smalley wrote:
> On Tue, Jul 23, 2024 at 9:09 AM Vit Mojzis <vmojzis@redhat.com> wrote:
>> Make sure that file context (all parts) and ownership of
>> files/directories in policy store does not change no matter which user
>> and under which context executes policy rebuild.
>>
>> Fixes:
>>    # semodule -B
>>    # ls -lZ  /etc/selinux/targeted/contexts/files
>>
>> -rw-r--r--. 1 root root unconfined_u:object_r:file_context_t:s0 421397 Jul 11 09:57 file_contexts
>> -rw-r--r--. 1 root root unconfined_u:object_r:file_context_t:s0 593470 Jul 11 09:57 file_contexts.bin
>> -rw-r--r--. 1 root root unconfined_u:object_r:file_context_t:s0  14704 Jul 11 09:57 file_contexts.homedirs
>> -rw-r--r--. 1 root root unconfined_u:object_r:file_context_t:s0  20289 Jul 11 09:57 file_contexts.homedirs.bin
>>
>>    SELinux user changed from system_u to the user used to execute semodule
>>
>>    # capsh --user=testuser --caps="cap_dac_override,cap_chown+eip" --addamb=cap_dac_override,cap_chown -- -c "semodule -B"
>>    # ls -lZ  /etc/selinux/targeted/contexts/files
>>
>> -rw-r--r--. 1 testuser testuser unconfined_u:object_r:file_context_t:s0 421397 Jul 19 09:10 file_contexts
>> -rw-r--r--. 1 testuser testuser unconfined_u:object_r:file_context_t:s0 593470 Jul 19 09:10 file_contexts.bin
>> -rw-r--r--. 1 testuser testuser unconfined_u:object_r:file_context_t:s0  14704 Jul 19 09:10 file_contexts.homedirs
>> -rw-r--r--. 1 testuser testuser unconfined_u:object_r:file_context_t:s0  20289 Jul 19 09:10 file_contexts.homedirs.bin
>>
>>    Both file context and ownership changed -- causes remote login
>>    failures and other issues in some scenarios.
>>
>> Signed-off-by: Vit Mojzis <vmojzis@redhat.com>
>> ---
>> @@ -3018,3 +3028,21 @@ int semanage_nc_sort(semanage_handle_t * sh, const char *buf, size_t buf_len,
>>
>>          return 0;
>>   }
>> +
>> +/* Make sure the file context and ownership of files in the policy
>> + * store does not change */
>> +void semanage_setfiles(const char *path){
>> +       struct stat sb;
>> +
>> +       /* Fix the user and role portions of the context, ignore errors
>> +        * since this is not a critical operation */
>> +       selinux_restorecon(path, SELINUX_RESTORECON_SET_SPECFILE_CTX | SELINUX_RESTORECON_IGNORE_NOENTRY);
>> +
>> +       /* Make sure "path" is owned by root */
>> +       if (geteuid() != 0 || getegid() != 0)
>> +               /* Skip files with the SUID or SGID bit set -- abuse protection */
>> +               if ((stat(path, &sb) == -1) ||
>> +                   (S_ISREG(sb.st_mode) && (sb.st_mode & (S_ISUID | S_ISGID))))
>> +                               return;
>> +               chown(path, 0, 0);
>> +}
> Did you consider the fd = open(path, O_PATH); fstat(fd, &sb); ...
> fchown(fd, 0, 0); pattern to avoid a race between the check and chown
> (e.g. link changed from one file to another in between)?
>

Briefly, the code would be a bit less readable (interweaving writing 
file content and ownership/labeling) and we'd still need the current 
approach for any file created by another binary (e.g. sefcontext_compile).
I'll rewrite it if you prefer that approach, but do you expect such 
races to be common? The whole ownership issue already seems like a 
corner-case.

Vit
Stephen Smalley July 23, 2024, 5:24 p.m. UTC | #3
On Tue, Jul 23, 2024 at 12:54 PM Vit Mojzis <vmojzis@redhat.com> wrote:
>
>
>
> On 7/23/24 16:56, Stephen Smalley wrote:
> > On Tue, Jul 23, 2024 at 9:09 AM Vit Mojzis <vmojzis@redhat.com> wrote:
> >> Make sure that file context (all parts) and ownership of
> >> files/directories in policy store does not change no matter which user
> >> and under which context executes policy rebuild.
> >>
> >> Fixes:
> >>    # semodule -B
> >>    # ls -lZ  /etc/selinux/targeted/contexts/files
> >>
> >> -rw-r--r--. 1 root root unconfined_u:object_r:file_context_t:s0 421397 Jul 11 09:57 file_contexts
> >> -rw-r--r--. 1 root root unconfined_u:object_r:file_context_t:s0 593470 Jul 11 09:57 file_contexts.bin
> >> -rw-r--r--. 1 root root unconfined_u:object_r:file_context_t:s0  14704 Jul 11 09:57 file_contexts.homedirs
> >> -rw-r--r--. 1 root root unconfined_u:object_r:file_context_t:s0  20289 Jul 11 09:57 file_contexts.homedirs.bin
> >>
> >>    SELinux user changed from system_u to the user used to execute semodule
> >>
> >>    # capsh --user=testuser --caps="cap_dac_override,cap_chown+eip" --addamb=cap_dac_override,cap_chown -- -c "semodule -B"
> >>    # ls -lZ  /etc/selinux/targeted/contexts/files
> >>
> >> -rw-r--r--. 1 testuser testuser unconfined_u:object_r:file_context_t:s0 421397 Jul 19 09:10 file_contexts
> >> -rw-r--r--. 1 testuser testuser unconfined_u:object_r:file_context_t:s0 593470 Jul 19 09:10 file_contexts.bin
> >> -rw-r--r--. 1 testuser testuser unconfined_u:object_r:file_context_t:s0  14704 Jul 19 09:10 file_contexts.homedirs
> >> -rw-r--r--. 1 testuser testuser unconfined_u:object_r:file_context_t:s0  20289 Jul 19 09:10 file_contexts.homedirs.bin
> >>
> >>    Both file context and ownership changed -- causes remote login
> >>    failures and other issues in some scenarios.
> >>
> >> Signed-off-by: Vit Mojzis <vmojzis@redhat.com>
> >> ---
> >> @@ -3018,3 +3028,21 @@ int semanage_nc_sort(semanage_handle_t * sh, const char *buf, size_t buf_len,
> >>
> >>          return 0;
> >>   }
> >> +
> >> +/* Make sure the file context and ownership of files in the policy
> >> + * store does not change */
> >> +void semanage_setfiles(const char *path){
> >> +       struct stat sb;
> >> +
> >> +       /* Fix the user and role portions of the context, ignore errors
> >> +        * since this is not a critical operation */
> >> +       selinux_restorecon(path, SELINUX_RESTORECON_SET_SPECFILE_CTX | SELINUX_RESTORECON_IGNORE_NOENTRY);
> >> +
> >> +       /* Make sure "path" is owned by root */
> >> +       if (geteuid() != 0 || getegid() != 0)
> >> +               /* Skip files with the SUID or SGID bit set -- abuse protection */
> >> +               if ((stat(path, &sb) == -1) ||
> >> +                   (S_ISREG(sb.st_mode) && (sb.st_mode & (S_ISUID | S_ISGID))))
> >> +                               return;
> >> +               chown(path, 0, 0);
> >> +}
> > Did you consider the fd = open(path, O_PATH); fstat(fd, &sb); ...
> > fchown(fd, 0, 0); pattern to avoid a race between the check and chown
> > (e.g. link changed from one file to another in between)?
> >
>
> Briefly, the code would be a bit less readable (interweaving writing
> file content and ownership/labeling) and we'd still need the current
> approach for any file created by another binary (e.g. sefcontext_compile).

Not sure I understand that last part - why can't you do the same
open(path, O_PATH); fstat(fd, &sb); ... fchown(fd, 0, 0); for files
created by a helper program - just do it in the parent after the child
exits?

> I'll rewrite it if you prefer that approach, but do you expect such
> races to be common? The whole ownership issue already seems like a
> corner-case.

Shrug. That sort of race has been exploited in the past to relabel or
chown a file of your choosing by switching out one symlink for another
at the last minute but admittedly we are doing the restorecon by path
so your code is consistent.
No big deal to me either way.
Stephen Smalley July 25, 2024, 12:08 p.m. UTC | #4
On Tue, Jul 23, 2024 at 9:09 AM Vit Mojzis <vmojzis@redhat.com> wrote:
>
> Make sure that file context (all parts) and ownership of
> files/directories in policy store does not change no matter which user
> and under which context executes policy rebuild.
>
> Fixes:
>   # semodule -B
>   # ls -lZ  /etc/selinux/targeted/contexts/files
>
> -rw-r--r--. 1 root root unconfined_u:object_r:file_context_t:s0 421397 Jul 11 09:57 file_contexts
> -rw-r--r--. 1 root root unconfined_u:object_r:file_context_t:s0 593470 Jul 11 09:57 file_contexts.bin
> -rw-r--r--. 1 root root unconfined_u:object_r:file_context_t:s0  14704 Jul 11 09:57 file_contexts.homedirs
> -rw-r--r--. 1 root root unconfined_u:object_r:file_context_t:s0  20289 Jul 11 09:57 file_contexts.homedirs.bin
>
>   SELinux user changed from system_u to the user used to execute semodule
>
>   # capsh --user=testuser --caps="cap_dac_override,cap_chown+eip" --addamb=cap_dac_override,cap_chown -- -c "semodule -B"
>   # ls -lZ  /etc/selinux/targeted/contexts/files
>
> -rw-r--r--. 1 testuser testuser unconfined_u:object_r:file_context_t:s0 421397 Jul 19 09:10 file_contexts
> -rw-r--r--. 1 testuser testuser unconfined_u:object_r:file_context_t:s0 593470 Jul 19 09:10 file_contexts.bin
> -rw-r--r--. 1 testuser testuser unconfined_u:object_r:file_context_t:s0  14704 Jul 19 09:10 file_contexts.homedirs
> -rw-r--r--. 1 testuser testuser unconfined_u:object_r:file_context_t:s0  20289 Jul 19 09:10 file_contexts.homedirs.bin
>
>   Both file context and ownership changed -- causes remote login
>   failures and other issues in some scenarios.
>
> Signed-off-by: Vit Mojzis <vmojzis@redhat.com>
> ---
> @@ -3018,3 +3028,21 @@ int semanage_nc_sort(semanage_handle_t * sh, const char *buf, size_t buf_len,
>
>         return 0;
>  }
> +
> +/* Make sure the file context and ownership of files in the policy
> + * store does not change */
> +void semanage_setfiles(const char *path){
> +       struct stat sb;
> +
> +       /* Fix the user and role portions of the context, ignore errors
> +        * since this is not a critical operation */
> +       selinux_restorecon(path, SELINUX_RESTORECON_SET_SPECFILE_CTX | SELINUX_RESTORECON_IGNORE_NOENTRY);
> +
> +       /* Make sure "path" is owned by root */
> +       if (geteuid() != 0 || getegid() != 0)
> +               /* Skip files with the SUID or SGID bit set -- abuse protection */
> +               if ((stat(path, &sb) == -1) ||
> +                   (S_ISREG(sb.st_mode) && (sb.st_mode & (S_ISUID | S_ISGID))))
> +                               return;
> +               chown(path, 0, 0);

I think you meant to wrap the body of the above if statement with { }
so that the chown() only executes if geteuid() != 0 or getegid() != 0
too.
Yes?
This isn't Python ;)

> +}
Vit Mojzis July 25, 2024, 4:09 p.m. UTC | #5
On 7/23/24 19:24, Stephen Smalley wrote:
> On Tue, Jul 23, 2024 at 12:54 PM Vit Mojzis <vmojzis@redhat.com> wrote:
>>
>>
>> On 7/23/24 16:56, Stephen Smalley wrote:
>>> On Tue, Jul 23, 2024 at 9:09 AM Vit Mojzis <vmojzis@redhat.com> wrote:
>>>> Make sure that file context (all parts) and ownership of
>>>> files/directories in policy store does not change no matter which user
>>>> and under which context executes policy rebuild.
>>>>
>>>> Fixes:
>>>>     # semodule -B
>>>>     # ls -lZ  /etc/selinux/targeted/contexts/files
>>>>
>>>> -rw-r--r--. 1 root root unconfined_u:object_r:file_context_t:s0 421397 Jul 11 09:57 file_contexts
>>>> -rw-r--r--. 1 root root unconfined_u:object_r:file_context_t:s0 593470 Jul 11 09:57 file_contexts.bin
>>>> -rw-r--r--. 1 root root unconfined_u:object_r:file_context_t:s0  14704 Jul 11 09:57 file_contexts.homedirs
>>>> -rw-r--r--. 1 root root unconfined_u:object_r:file_context_t:s0  20289 Jul 11 09:57 file_contexts.homedirs.bin
>>>>
>>>>     SELinux user changed from system_u to the user used to execute semodule
>>>>
>>>>     # capsh --user=testuser --caps="cap_dac_override,cap_chown+eip" --addamb=cap_dac_override,cap_chown -- -c "semodule -B"
>>>>     # ls -lZ  /etc/selinux/targeted/contexts/files
>>>>
>>>> -rw-r--r--. 1 testuser testuser unconfined_u:object_r:file_context_t:s0 421397 Jul 19 09:10 file_contexts
>>>> -rw-r--r--. 1 testuser testuser unconfined_u:object_r:file_context_t:s0 593470 Jul 19 09:10 file_contexts.bin
>>>> -rw-r--r--. 1 testuser testuser unconfined_u:object_r:file_context_t:s0  14704 Jul 19 09:10 file_contexts.homedirs
>>>> -rw-r--r--. 1 testuser testuser unconfined_u:object_r:file_context_t:s0  20289 Jul 19 09:10 file_contexts.homedirs.bin
>>>>
>>>>     Both file context and ownership changed -- causes remote login
>>>>     failures and other issues in some scenarios.
>>>>
>>>> Signed-off-by: Vit Mojzis <vmojzis@redhat.com>
>>>> ---
>>>> @@ -3018,3 +3028,21 @@ int semanage_nc_sort(semanage_handle_t * sh, const char *buf, size_t buf_len,
>>>>
>>>>           return 0;
>>>>    }
>>>> +
>>>> +/* Make sure the file context and ownership of files in the policy
>>>> + * store does not change */
>>>> +void semanage_setfiles(const char *path){
>>>> +       struct stat sb;
>>>> +
>>>> +       /* Fix the user and role portions of the context, ignore errors
>>>> +        * since this is not a critical operation */
>>>> +       selinux_restorecon(path, SELINUX_RESTORECON_SET_SPECFILE_CTX | SELINUX_RESTORECON_IGNORE_NOENTRY);
>>>> +
>>>> +       /* Make sure "path" is owned by root */
>>>> +       if (geteuid() != 0 || getegid() != 0)
>>>> +               /* Skip files with the SUID or SGID bit set -- abuse protection */
>>>> +               if ((stat(path, &sb) == -1) ||
>>>> +                   (S_ISREG(sb.st_mode) && (sb.st_mode & (S_ISUID | S_ISGID))))
>>>> +                               return;
>>>> +               chown(path, 0, 0);
>>>> +}
>>> Did you consider the fd = open(path, O_PATH); fstat(fd, &sb); ...
>>> fchown(fd, 0, 0); pattern to avoid a race between the check and chown
>>> (e.g. link changed from one file to another in between)?
>>>
>> Briefly, the code would be a bit less readable (interweaving writing
>> file content and ownership/labeling) and we'd still need the current
>> approach for any file created by another binary (e.g. sefcontext_compile).
> Not sure I understand that last part - why can't you do the same
> open(path, O_PATH); fstat(fd, &sb); ... fchown(fd, 0, 0); for files
> created by a helper program - just do it in the parent after the child
> exits?

Sorry, I misunderstood. I thought you wanted to add the fchown into 
existing code that opens the file.
I actually tried that in semanage_copy_file, but chown to root caused 
the rename to fail (and
selinux_restorecon had to be changed to setfscreatecon because of 
permissions as well) so I had to go
back to fixing everything after the rename.
Also, I had to switch O_PATH for O_RDONLY since O_PATH does not permit 
fchown.

Good catch with the curly braces after "if". What a rookie mistake.

>
>> I'll rewrite it if you prefer that approach, but do you expect such
>> races to be common? The whole ownership issue already seems like a
>> corner-case.
> Shrug. That sort of race has been exploited in the past to relabel or
> chown a file of your choosing by switching out one symlink for another
> at the last minute but admittedly we are doing the restorecon by path
> so your code is consistent.
> No big deal to me either way.
>
diff mbox series

Patch

diff --git a/libsemanage/src/semanage_store.c b/libsemanage/src/semanage_store.c
index 27c5d349..a7dd1f6f 100644
--- a/libsemanage/src/semanage_store.c
+++ b/libsemanage/src/semanage_store.c
@@ -36,6 +36,7 @@  typedef struct dbase_policydb dbase_t;
 #include "database_policydb.h"
 #include "handle.h"
 
+#include <selinux/restorecon.h>
 #include <selinux/selinux.h>
 #include <sepol/policydb.h>
 #include <sepol/module.h>
@@ -767,6 +768,8 @@  int semanage_copy_file(const char *src, const char *dst, mode_t mode,
 	if (!retval && rename(tmp, dst) == -1)
 		return -1;
 
+	semanage_setfiles(dst);
+
 out:
 	errno = errsv;
 	return retval;
@@ -819,6 +822,8 @@  static int semanage_copy_dir_flags(const char *src, const char *dst, int flag)
 			goto cleanup;
 		}
 		umask(mask);
+
+		semanage_setfiles(dst);
 	}
 
 	for (i = 0; i < len; i++) {
@@ -837,6 +842,7 @@  static int semanage_copy_dir_flags(const char *src, const char *dst, int flag)
 				goto cleanup;
 			}
 			umask(mask);
+			semanage_setfiles(path2);
 		} else if (S_ISREG(sb.st_mode) && flag == 1) {
 			mask = umask(0077);
 			if (semanage_copy_file(path, path2, sb.st_mode,
@@ -938,6 +944,7 @@  int semanage_mkdir(semanage_handle_t *sh, const char *path)
 
 		}
 		umask(mask);
+		semanage_setfiles(path);
 	}
 	else {
 		/* check that it really is a directory */
@@ -1614,16 +1621,19 @@  static int semanage_validate_and_compile_fcontexts(semanage_handle_t * sh)
 		    semanage_final_path(SEMANAGE_FINAL_TMP, SEMANAGE_FC)) != 0) {
 		goto cleanup;
 	}
+	semanage_setfiles(semanage_final_path(SEMANAGE_FINAL_TMP, SEMANAGE_FC_BIN));
 
 	if (sefcontext_compile(sh,
 		    semanage_final_path(SEMANAGE_FINAL_TMP, SEMANAGE_FC_LOCAL)) != 0) {
 		goto cleanup;
 	}
+	semanage_setfiles(semanage_final_path(SEMANAGE_FINAL_TMP, SEMANAGE_FC_LOCAL_BIN));
 
 	if (sefcontext_compile(sh,
 		    semanage_final_path(SEMANAGE_FINAL_TMP, SEMANAGE_FC_HOMEDIRS)) != 0) {
 		goto cleanup;
 	}
+	semanage_setfiles(semanage_final_path(SEMANAGE_FINAL_TMP, SEMANAGE_FC_HOMEDIRS_BIN));
 
 	status = 0;
 cleanup:
@@ -3018,3 +3028,21 @@  int semanage_nc_sort(semanage_handle_t * sh, const char *buf, size_t buf_len,
 
 	return 0;
 }
+
+/* Make sure the file context and ownership of files in the policy
+ * store does not change */
+void semanage_setfiles(const char *path){
+	struct stat sb;
+
+	/* Fix the user and role portions of the context, ignore errors
+	 * since this is not a critical operation */
+	selinux_restorecon(path, SELINUX_RESTORECON_SET_SPECFILE_CTX | SELINUX_RESTORECON_IGNORE_NOENTRY);
+
+	/* Make sure "path" is owned by root */
+	if (geteuid() != 0 || getegid() != 0)
+		/* Skip files with the SUID or SGID bit set -- abuse protection */
+		if ((stat(path, &sb) == -1) ||
+		    (S_ISREG(sb.st_mode) && (sb.st_mode & (S_ISUID | S_ISGID))))
+				return;
+		chown(path, 0, 0);
+}
diff --git a/libsemanage/src/semanage_store.h b/libsemanage/src/semanage_store.h
index 1fc77da8..e21dadeb 100644
--- a/libsemanage/src/semanage_store.h
+++ b/libsemanage/src/semanage_store.h
@@ -124,6 +124,7 @@  int semanage_get_cil_paths(semanage_handle_t * sh, semanage_module_info_t *modin
 int semanage_get_active_modules(semanage_handle_t *sh,
 			       semanage_module_info_t **modinfo, int *num_modules);
 
+void semanage_setfiles(const char *path);
 
 /* lock file routines */
 int semanage_get_trans_lock(semanage_handle_t * sh);