]> git.ipfire.org Git - thirdparty/util-linux.git/blobdiff - disk-utils/fsck.cramfs.c
Merge branch 'PR/libmount-exec-errors' of github.com:karelzak/util-linux-work
[thirdparty/util-linux.git] / disk-utils / fsck.cramfs.c
index 7503fae2fbb137c90bd06e61886eef8f56719eb8..b5d64c36aa6c401ad04f7e7e6b422121c2d7fac7 100644 (file)
@@ -1,4 +1,6 @@
 /*
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ *
  * cramfsck - check a cramfs file system
  *
  * Copyright (C) 2000-2002 Transmeta Corporation
@@ -126,9 +128,9 @@ static void __attribute__((__noreturn__)) usage(void)
        fputs(_(" -b, --blocksize <size>   use this blocksize, defaults to page size\n"), out);
        fputs(_("     --extract[=<dir>]    test uncompression, optionally extract into <dir>\n"), out);
        fputs(USAGE_SEPARATOR, out);
-       printf(USAGE_HELP_OPTIONS(26));
+       fprintf(out, USAGE_HELP_OPTIONS(26));
 
-       printf(USAGE_MAN_TAIL("fsck.cramfs(8)"));
+       fprintf(out, USAGE_MAN_TAIL("fsck.cramfs(8)"));
        exit(FSCK_EX_OK);
 }
 
@@ -434,7 +436,7 @@ static void change_file_status(char *path, struct cramfs_inode *i)
                if (S_ISLNK(i->mode))
                        return;
                if (((S_ISUID | S_ISGID) & i->mode) && chmod(path, i->mode) < 0)
-                       err(FSCK_EX_ERROR, _("chown failed: %s"), path);
+                       err(FSCK_EX_ERROR, _("chmod failed: %s"), path);
        }
        if (S_ISLNK(i->mode))
                return;
@@ -442,6 +444,23 @@ static void change_file_status(char *path, struct cramfs_inode *i)
                err(FSCK_EX_ERROR, _("utimes failed: %s"), path);
 }
 
+static int is_dangerous_filename(char *name, int len)
+{
+       return (len == 1 && name[0] == '.') ||
+              (len == 2 && name[0] == '.' && name[1] == '.');
+}
+
+static void __attribute__((__noreturn__))
+       errx_path(const char *mesg, const char *name, size_t namelen)
+{
+       char buf[PATH_MAX] = { 0 };
+
+       namelen = min(namelen, sizeof(buf) - 1);
+       memcpy(buf, name, namelen);
+
+       errx(FSCK_EX_UNCORRECTED, "%s: %s", mesg, buf);
+}
+
 static void do_directory(char *path, struct cramfs_inode *i)
 {
        int pathlen = strlen(path);
@@ -471,6 +490,7 @@ static void do_directory(char *path, struct cramfs_inode *i)
        }
        while (count > 0) {
                struct cramfs_inode *child = iget(offset);
+               char *name;
                int size;
                int newlen = child->namelen << 2;
 
@@ -478,8 +498,13 @@ static void do_directory(char *path, struct cramfs_inode *i)
                count -= size;
 
                offset += sizeof(struct cramfs_inode);
+               name = romfs_read(offset);
 
-               memcpy(newpath + pathlen, romfs_read(offset), newlen);
+               if (memchr(name, '/', newlen) != NULL)
+                       errx_path(_("illegal filename"), name, newlen);
+               if (*extract_dir != '\0' && is_dangerous_filename(name, newlen))
+                       errx_path(_("dangerous filename"), name, newlen);
+               memcpy(newpath + pathlen, name, newlen);
                newpath[pathlen + newlen] = 0;
                if (newlen == 0)
                        errx(FSCK_EX_UNCORRECTED, _("filename length is zero"));