Hi, When `selinux_restorecon()` is called first time, it creates a static `fc_sehandle`. This semanage store handle is used later in `selabel_` functions and left initialized to be used on the next call `selinux_restorecon()`. It probably help with multiple sequential runs of `selinux_restorecon()`. But since commit d96f27bf7cb9 ("libsemanage: Preserve file context and ownership in policy store"), `selinux_restorecon` is also run internally when policy store is changed by libsemanage. It means that if a user tries to change file contexts and then relabel affected files, `selinux_restorecon` uses semanage handle created before policy change and therefore with old data, see the code [1]: [root@localhost ~]# mkdir -p /data/test/subtest [root@localhost ~]# gcc libsemanage-add-fcontext.c -lsemanage -lselinux [root@localhost ~]# ./a.out Relabeled /data/test from unconfined_u:object_r:default_t:s0 to system_u:object_r:default_t:s0 Relabeled /data/test/subtest from unconfined_u:object_r:default_t:s0 to system_u:object_r:default_t:s0 Two ideas how to solve it I have: - destroy fc_sehandle at the end selinux_restorecon() if the handle was initialized there - could this affect the performance? - document in man page this issue and suggest users to use sehandle = selinux_restorecon_default_handle() selinux_restorecon_set_sehandle(sehandle) before any libsemanage store operation I'm looking for any reasonable solution or ideas. [1] #include <selinux/restorecon.h> #include <semanage/context_record.h> #include <semanage/fcontext_record.h> #include <semanage/fcontexts_local.h> #include <semanage/handle.h> #include <semanage/semanage.h> #include <stdio.h> int main(const int argc, const char **argv) { semanage_handle_t *sh = NULL; semanage_fcontext_t *fcontext; semanage_context_t *con; semanage_fcontext_key_t *k; int exist = 0; sh = semanage_handle_create(); if (sh == NULL) { perror("Can't create semanage handle\n"); return -1; } semanage_select_store(sh, "targeted", SEMANAGE_CON_DIRECT); if (semanage_is_managed(sh) < 0) { perror("Semanage store can't be accessed\n"); return -1; } if (semanage_access_check(sh) < 0) { perror("Semanage access check failed\n"); return -1; } if (semanage_connect(sh) < 0) { perror("Semanage connect failed\n"); return -1; } if (semanage_begin_transaction(sh) < 0) { return -1; } semanage_fcontext_key_t *key_ptr; semanage_fcontext_key_create(sh, "/data/test(/.*)?", 0, &key_ptr); semanage_fcontext_t *fcontext_ptr; semanage_fcontext_create(sh, &fcontext_ptr); semanage_context_t *con_ptr; semanage_context_from_string(sh, "system_u:object_r:tmp_t:s0", &con_ptr); semanage_fcontext_set_expr(sh, fcontext_ptr, "/data/test(/.*)?"); semanage_fcontext_set_type(fcontext_ptr, 0); semanage_fcontext_set_con(sh, fcontext_ptr, con_ptr); semanage_fcontext_modify_local(sh, key_ptr, fcontext_ptr); if (semanage_commit(sh) < 0) { perror("Semanage commit failed\n"); return -1; } if (semanage_disconnect(sh) < 0) { perror("Semanage disconnect failed\n"); return -1; } selinux_restorecon("/data/test", SELINUX_RESTORECON_RECURSE | SELINUX_RESTORECON_VERBOSE | SELINUX_RESTORECON_SET_SPECFILE_CTX); }