Skip to content

Commit

Permalink
Use *at functions for directory creation
Browse files Browse the repository at this point in the history
Perform path traversal manually and do not follow symlinks.
  • Loading branch information
Vogtinator committed Jul 9, 2024
1 parent 5f0ea08 commit a3a81fb
Showing 1 changed file with 58 additions and 6 deletions.
64 changes: 58 additions & 6 deletions sbin/create_dirs_from_rpmdb.c
Original file line number Diff line number Diff line change
Expand Up @@ -21,10 +21,12 @@
#include <config.h>
#endif

#include <assert.h>
#include <errno.h>
#include <fcntl.h>
#include <getopt.h>
#include <grp.h>
#include <libgen.h>
#include <malloc.h>
#include <pwd.h>
#include <rpm/rpmcli.h>
Expand Down Expand Up @@ -270,19 +272,69 @@ int create_dirs(struct node *node, size_t size) {
if (verbose_flag)
printf("Create %s\n", node->dirname);

if (mkdir(node->dirname, node->fmode) < 0) {
const char *component = "/";
int dirfd = -1;
int saved_errno = 0;

{
// strdup for use with strtok
char *local_path = strdup(node->dirname);
if (!local_path) {
perror("strdup");
rc = 1;
continue;
}

char *saveptr = NULL;
while (1) {
const char *next_component = strtok_r(local_path, "/", &saveptr);
if (next_component == NULL) {
// component is the last part
break;
}

int nextdirfd = openat(dirfd, component, O_RDONLY | O_DIRECTORY | O_NOFOLLOW);
saved_errno = errno;
close(dirfd);

dirfd = nextdirfd;
component = next_component;

if (dirfd < 0) {
break;
}

dirfd = nextdirfd;
}

free(local_path);

if (dirfd < 0) {
errno = saved_errno;
fprintf(stderr, "Failed to traverse path for '%s': %m\n", node->dirname);
rc = 1;
continue;
}
}

const char *node_basename = component;

// Ok to assign mode before chown?
if (mkdirat(dirfd, node_basename, node->fmode) < 0) {
fprintf(stderr, "Failed to create directory '%s': %m\n", node->dirname);
rc = 1;
continue;
}

if (chown(node->dirname, node->user_id, node->group_id) < 0) {
// Ok to assign ownership before se labels?
if (fchownat(dirfd, node_basename, node->user_id, node->group_id, AT_SYMLINK_NOFOLLOW) < 0) {
fprintf(stderr, "Failed to set owner/group for '%s': %m\n", node->dirname);
/* wrong permissions are bad, remove dir and continue */
rmdir(node->dirname);
unlinkat(dirfd, node_basename, AT_REMOVEDIR);
rc = 1;
continue;
}

/* ignore errors here, time stamps are not critical */
utimes(node->dirname, stamps);

Expand All @@ -295,7 +347,7 @@ int create_dirs(struct node *node, size_t size) {
}

fprintf(stderr, "Failed to get default context for directory '%s': %m\n", node->dirname);
rmdir(node->dirname);
unlinkat(dirfd, node_basename, AT_REMOVEDIR);
rc = 1;
continue;
}
Expand All @@ -307,7 +359,7 @@ int create_dirs(struct node *node, size_t size) {
if (errno != ENODATA) {
fprintf(stderr, "Failed to get old context for '%s': %m\n", node->dirname);
freecon(newcon);
rmdir(node->dirname);
unlinkat(dirfd, node_basename, AT_REMOVEDIR);
rc = 1;
continue;
}
Expand All @@ -319,7 +371,7 @@ int create_dirs(struct node *node, size_t size) {
printf("Set SELinux file context to %s\n", newcon);
if (setfilecon_raw(node->dirname, newcon) < 0) {
fprintf(stderr, "Failed to set new context for '%s': %m\n", node->dirname);
rmdir(node->dirname);
unlinkat(dirfd, node_basename, AT_REMOVEDIR);
rc = 1;
}
}
Expand Down

0 comments on commit a3a81fb

Please sign in to comment.