Skip to content

Commit

Permalink
debugfs: expose a 'preserve' command line switch in rdump command
Browse files Browse the repository at this point in the history
rdump assumed the user wanted to preserve permissions and ownership when
dumping a filesystem directory recursively with 'rdump'. This is in
opposition with the way the 'dump' or 'dump_inode' command has been
designed, since it expose a '-p' command line switch to allow the end
users to explicitly opt-in for permission and ownership preservation.

The inability to explicitly ask for permission and ownership
preservation would get rdump to default to preservation, which is a
problem when faced with filesystems having directories with the read
flag but not the execute flag, since it would only allow to enumerate
the directory content, but not see the inode details. Therefore getting
debugfs in all kinds of issues trying to set ownership and permissions
of files it can't see.

This fix introduce a 'preserve' ('-p') flag in rdump command so that
users can explicitly opt-in for it, and debugfs will default to a safer
way of operation (no preserve).
  • Loading branch information
qkaiser committed Feb 9, 2024
1 parent b3955de commit a21fa98
Showing 1 changed file with 83 additions and 54 deletions.
137 changes: 83 additions & 54 deletions debugfs/dump.c
Original file line number Diff line number Diff line change
Expand Up @@ -256,12 +256,16 @@ static void rdump_symlink(ext2_ino_t ino, struct ext2_inode *inode,
free(buf);
}

typedef struct rdump_dirent_private {
char* fullname;
int preserve;
} rdump_dirent_private_t;

static int rdump_dirent(struct ext2_dir_entry *, int, int, char *, void *);

static void rdump_inode(ext2_ino_t ino, struct ext2_inode *inode,
const char *name, const char *dumproot)
{
char *fullname;
const char *name, const char *dumproot, int preserve) {
char *fullname;

/* There are more efficient ways to do this, but this method
* requires only minimal debugging. */
Expand All @@ -272,16 +276,16 @@ static void rdump_inode(ext2_ino_t ino, struct ext2_inode *inode,
}
sprintf(fullname, "%s/%s", dumproot, name);

if (LINUX_S_ISLNK(inode->i_mode))
rdump_symlink(ino, inode, fullname);
else if (LINUX_S_ISREG(inode->i_mode)) {
int fd;
fd = open(fullname, O_WRONLY | O_CREAT | O_TRUNC | O_LARGEFILE, S_IRWXU);
if (fd == -1) {
com_err("rdump", errno, "while opening %s", fullname);
goto errout;
}
if (dump_file("rdump", ino, fd, 1, fullname) != 0) {
if (LINUX_S_ISLNK(inode->i_mode))
rdump_symlink(ino, inode, fullname);
else if (LINUX_S_ISREG(inode->i_mode)) {
int fd;
fd = open(fullname, O_WRONLY | O_CREAT | O_TRUNC | O_LARGEFILE, S_IRWXU);
if (fd == -1) {
com_err("rdump", errno, "while opening %s", fullname);
goto errout;
}
if (dump_file("rdump", ino, fd, preserve, fullname) != 0) {
com_err("rdump", errno, "while dumping %s", fullname);
free(fullname);
exit(1);
Expand All @@ -302,28 +306,36 @@ static void rdump_inode(ext2_ino_t ino, struct ext2_inode *inode,
goto errout;
}

retval = ext2fs_dir_iterate(current_fs, ino, 0, 0,
rdump_dirent, (void *) fullname);
if (retval)
com_err("rdump", retval, "while dumping %s", fullname);

fix_perms("rdump", inode, -1, fullname);
}
/* else do nothing (don't dump device files, sockets, fifos, etc.) */
rdump_dirent_private_t* entry = malloc(sizeof(rdump_dirent_private_t));
if (entry == NULL) {
com_err("rdump", errno, "while allocating entry for %s", fullname);
}
entry->fullname = fullname;
entry->preserve = preserve;

retval = ext2fs_dir_iterate(current_fs, ino, 0, 0, rdump_dirent,
(void *)entry);
free(entry);
if (retval)
com_err("rdump", retval, "while dumping %s", fullname);
if (preserve)
fix_perms("rdump", inode, -1, fullname);
}
/* else do nothing (don't dump device files, sockets, fifos, etc.) */

errout:
free(fullname);
}



static int rdump_dirent(struct ext2_dir_entry *dirent,
int offset EXT2FS_ATTR((unused)),
int blocksize EXT2FS_ATTR((unused)),
char *buf EXT2FS_ATTR((unused)), void *private)
{
char name[EXT2_NAME_LEN + 1];
int thislen;
const char *dumproot = private;
struct ext2_inode inode;
int offset EXT2FS_ATTR((unused)),
int blocksize EXT2FS_ATTR((unused)),
char *buf EXT2FS_ATTR((unused)), void *private) {
char name[EXT2_NAME_LEN + 1];
int thislen;
struct ext2_inode inode;

thislen = ext2fs_dirent_name_len(dirent);
strncpy(name, dirent->name, thislen);
Expand All @@ -332,42 +344,59 @@ static int rdump_dirent(struct ext2_dir_entry *dirent,
if (debugfs_read_inode(dirent->inode, &inode, name))
return 0;

rdump_inode(dirent->inode, &inode, name, dumproot);
rdump_inode(dirent->inode, &inode, name, ((rdump_dirent_private_t*)private)->fullname, ((rdump_dirent_private_t*)private)->preserve);

return 0;
}

void do_rdump(int argc, char **argv, int sci_idx EXT2FS_ATTR((unused)),
void *infop EXT2FS_ATTR((unused)))
{
struct stat st;
char *dest_dir;
int i;
void *infop EXT2FS_ATTR((unused))) {

int i, c;
int preserve = 0;
char *dest_dir;
struct stat st;
ext2_ino_t ino;
struct ext2_inode inode;

reset_getopt();
while ((c = getopt(argc, argv, "p")) != EOF) {
switch (c) {
case 'p':
preserve++;
break;
default:
print_usage:
com_err(argv[0], 0,
"Usage: rdump [-p] "
"[<fs_directory_1> <fs_directory_2> ...] <output_file>");
exit(1);
}
}

if (common_args_process(argc, argv, 3, INT_MAX, "rdump",
"<directory>... <native directory>", 0))
return;
if (optind > argc - 2)
goto print_usage;

/* Pull out last argument */
dest_dir = argv[argc - 1];
argc--;

/* Ensure last arg is a directory. */
if (stat(dest_dir, &st) == -1) {
com_err("rdump", errno, "while statting %s", dest_dir);
return;
}
if (!S_ISDIR(st.st_mode)) {
com_err("rdump", 0, "%s is not a directory", dest_dir);
return;
}
/* Ensure last arg is a directory. */
if (stat(dest_dir, &st) == -1) {
com_err("rdump", errno, "while statting %s", dest_dir);
return;
}

for (i = 1; i < argc; i++) {
char *arg = argv[i], *basename;
struct ext2_inode inode;
ext2_ino_t ino = string_to_inode(arg);
if (!ino)
continue;
if (!S_ISDIR(st.st_mode)) {
com_err("rdump", 0, "%s is not a directory", dest_dir);
return;
}

for (i = optind; i < argc; i++) {
char *arg = argv[i], *basename;
ino = string_to_inode(arg);
if (!ino)
continue;

if (debugfs_read_inode(ino, &inode, arg))
continue;
Expand All @@ -378,7 +407,7 @@ void do_rdump(int argc, char **argv, int sci_idx EXT2FS_ATTR((unused)),
else
basename = arg;

rdump_inode(ino, &inode, basename, dest_dir);
rdump_inode(ino, &inode, basename, dest_dir, preserve);
}
}

Expand Down

0 comments on commit a21fa98

Please sign in to comment.