From: Michael Tremer Date: Fri, 17 Mar 2023 10:00:59 +0000 (+0000) Subject: FHS: Implement some simple filesystem checks X-Git-Url: http://git.ipfire.org/gitweb/gitweb.cgi?a=commitdiff_plain;h=0c931ee9b7b86ceb054b9d6a3ee5deb142dbe813;p=people%2Fstevee%2Fpakfire.git FHS: Implement some simple filesystem checks Signed-off-by: Michael Tremer --- diff --git a/Makefile.am b/Makefile.am index 6d2a0b7b..e9b2b238 100644 --- a/Makefile.am +++ b/Makefile.am @@ -227,6 +227,7 @@ libpakfire_la_SOURCES = \ src/libpakfire/digest.c \ src/libpakfire/dist.c \ src/libpakfire/downloader.c \ + src/libpakfire/fhs.c \ src/libpakfire/file.c \ src/libpakfire/filelist.c \ src/libpakfire/jail.c \ @@ -267,6 +268,7 @@ pkginclude_HEADERS += \ src/libpakfire/include/pakfire/digest.h \ src/libpakfire/include/pakfire/dist.h \ src/libpakfire/include/pakfire/downloader.h \ + src/libpakfire/include/pakfire/fhs.h \ src/libpakfire/include/pakfire/file.h \ src/libpakfire/include/pakfire/filelist.h \ src/libpakfire/include/pakfire/i18n.h \ diff --git a/src/libpakfire/build.c b/src/libpakfire/build.c index e12ce63f..66bdbd19 100644 --- a/src/libpakfire/build.c +++ b/src/libpakfire/build.c @@ -32,6 +32,7 @@ #include #include #include +#include #include #include #include @@ -1189,6 +1190,35 @@ static int pakfire_build_post_check_broken_symlinks( PAKFIRE_BUILD_ERROR_IF_NOT_EMPTY); } +/* + Filesystem Layout Check +*/ +static int __pakfire_build_post_check_filesystem( + struct pakfire* pakfire, struct pakfire_file* file, void* data) { + struct pakfire_filelist* illegal = (struct pakfire_filelist*)data; + int r; + + // Perform FHS check + r = pakfire_fhs_check_file(pakfire, file); + if (r) { + r = pakfire_filelist_add(illegal, file); + if (r) + return r; + } + + return 0; +} + +static int pakfire_build_post_check_filesystem( + struct pakfire_build* build, struct pakfire_filelist* filelist) { + return pakfire_build_post_process_files( + build, + filelist, + "Illegal files:", + __pakfire_build_post_check_filesystem, + PAKFIRE_BUILD_ERROR_IF_NOT_EMPTY); +} + /* Hardening */ @@ -1274,6 +1304,11 @@ static int pakfire_build_run_post_build_checks(struct pakfire_build* build) { if (r) goto ERROR; + // Check filesystem layout + r = pakfire_build_post_check_filesystem(build, filelist); + if (r) + goto ERROR; + // Check hardening r = pakfire_build_post_check_hardening(build, filelist); if (r) diff --git a/src/libpakfire/fhs.c b/src/libpakfire/fhs.c new file mode 100644 index 00000000..73c258d6 --- /dev/null +++ b/src/libpakfire/fhs.c @@ -0,0 +1,226 @@ +/*############################################################################# +# # +# Pakfire - The IPFire package management system # +# Copyright (C) 2021 Pakfire development team # +# # +# This program is free software: you can redistribute it and/or modify # +# it under the terms of the GNU General Public License as published by # +# the Free Software Foundation, either version 3 of the License, or # +# (at your option) any later version. # +# # +# This program is distributed in the hope that it will be useful, # +# but WITHOUT ANY WARRANTY; without even the implied warranty of # +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # +# GNU General Public License for more details. # +# # +# You should have received a copy of the GNU General Public License # +# along with this program. If not, see . # +# # +#############################################################################*/ + +#include + +#include +#include +#include +#include +#include + +/* + This struct defines any FHS checks. + + They are being processed in order from top to bottom which is why we are starting + with some more prominent matches and have the less important stuff at the bottom. +*/ +static const struct pakfire_fhs_check { + const char* path; + enum pakfire_fhs_check_flags { + PAKFIRE_FHS_MUSTNOTEXIST = (1 << 0), + } flags; + const mode_t mode; +} pakfire_fhs_check[] = { + // /usr + { "/usr", 0, S_IFDIR|0755 }, + { "/usr/bin", 0, S_IFDIR|0755 }, + { "/usr/include", 0, S_IFDIR|0755 }, + { "/usr/lib", 0, S_IFDIR|0755 }, + { "/usr/lib64", 0, S_IFDIR|0755 }, + { "/usr/sbin", 0, S_IFDIR|0755 }, + { "/usr/share", 0, S_IFDIR|0755 }, + { "/usr/src", 0, S_IFDIR|0755 }, + + // /var + { "/var", 0, S_IFDIR|0755 }, + { "/var/cache", 0, S_IFDIR|0755 }, + { "/var/db", 0, S_IFDIR|0755 }, + { "/var/empty", 0, S_IFDIR|0755 }, + { "/var/lib", 0, S_IFDIR|0755 }, + { "/var/log", 0, S_IFDIR|0755 }, + { "/var/mail", 0, S_IFDIR|0755 }, + { "/var/opt", 0, S_IFDIR|0755 }, + { "/var/run", 0, S_IFLNK|0777 }, + { "/var/spool", 0, S_IFDIR|0755 }, + { "/var/tmp", 0, S_IFDIR|1755 }, + { "/var/tmp/**", PAKFIRE_FHS_MUSTNOTEXIST, 0 }, + + // /boot + { "/boot", 0, S_IFDIR|0755 }, + { "/boot/efi", 0, S_IFDIR|0755 }, + + // /dev (nothing may exist in it) + { "/dev", 0, S_IFDIR|0755 }, + { "/dev/**", PAKFIRE_FHS_MUSTNOTEXIST, 0 }, + + // /etc + { "/etc", 0, S_IFDIR|0755 }, + + // /home + { "/home", 0, S_IFDIR|0755 }, + { "/home/**", PAKFIRE_FHS_MUSTNOTEXIST, 0 }, + + // /opt + { "/opt", 0, S_IFDIR|0755 }, + // These directories belong to the "local administrator" + // https://refspecs.linuxfoundation.org/FHS_3.0/fhs/ch03s13.html + { "/opt/bin", PAKFIRE_FHS_MUSTNOTEXIST, 0 }, + { "/opt/doc", PAKFIRE_FHS_MUSTNOTEXIST, 0 }, + { "/opt/include", PAKFIRE_FHS_MUSTNOTEXIST, 0 }, + { "/opt/info", PAKFIRE_FHS_MUSTNOTEXIST, 0 }, + { "/opt/lib", PAKFIRE_FHS_MUSTNOTEXIST, 0 }, + { "/opt/man", PAKFIRE_FHS_MUSTNOTEXIST, 0 }, + + // /proc + { "/proc", 0, S_IFDIR|0755 }, + { "/proc/**", PAKFIRE_FHS_MUSTNOTEXIST, 0 }, + + // /run + { "/run", 0, S_IFDIR|0755 }, + + // /sys + { "/sys", 0, S_IFDIR|0755 }, + { "/sys/**", PAKFIRE_FHS_MUSTNOTEXIST, 0 }, + + // /tmp + { "/tmp", 0, S_IFDIR|1755 }, + { "/tmp/**", PAKFIRE_FHS_MUSTNOTEXIST, 0 }, + + // FHS Directories + { "/media", 0, S_IFDIR|0755 }, + { "/mnt", 0, S_IFDIR|0755 }, + { "/srv", 0, S_IFDIR|0755 }, + + // /bin, /sbin, /lib, and /lib64 have to be symlinks + { "/bin", 0, S_IFLNK|0777 }, + { "/lib", 0, S_IFLNK|0777 }, + { "/lib64", 0, S_IFLNK|0777 }, + { "/sbin", 0, S_IFLNK|0777 }, + + // There cannot be anything else in / + { "/*", PAKFIRE_FHS_MUSTNOTEXIST, 0 }, + + // Catch all so that we won't throw an error + { "/**", 0, 0 }, + + // Sentinel + { NULL }, +}; + +static const struct pakfire_fhs_check* pakfire_fhs_find_check( + struct pakfire* pakfire, const char* path) { + const struct pakfire_fhs_check* check = NULL; + int r; + + // Walk through all possible checks + for (check = pakfire_fhs_check; check->path; check++) { + r = pakfire_path_match(check->path, path); + switch (r) { + // No match + case 0: + continue; + + // Match! + case 1: + DEBUG(pakfire, "%s matches check '%s'\n", path, check->path); + + return check; + + // Error :( + default: + goto ERROR; + } + } + +ERROR: + ERROR(pakfire, "Could not find FHS entry for %s: %m\n", path); + + return NULL; +} + +static int pakfire_fhs_check_mode(struct pakfire* pakfire, + const struct pakfire_fhs_check* check, struct pakfire_file* file) { + // No mode defined. Skipping check... + if (!check->mode) + return 0; + + const char* path = pakfire_file_get_path(file); + + // Compare mode + const mode_t mode = pakfire_file_get_mode(file); + + // Check if mode matches straight away + if (check->mode == mode) + return 0; + + const mode_t check_type = check->mode & S_IFMT; + const mode_t check_perms = check->mode & ~S_IFMT; + + // Check the file type + if (check_type) { + if ((mode_t)pakfire_file_get_type(file) != check_type) { + ERROR(pakfire, "%s: Filetype does not match\n", path); + return 1; + } + } + + // Check the file perms + if (check_perms) { + if (pakfire_file_get_perms(file) != check_perms) { + ERROR(pakfire, "%s: Permissions do not match\n", path); + return 1; + } + } + + // Check passed + return 0; +} + +int pakfire_fhs_check_file(struct pakfire* pakfire, struct pakfire_file* file) { + const struct pakfire_fhs_check* check = NULL; + int r; + + // Get the file path + const char* path = pakfire_file_get_path(file); + if (!path) + return 1; + + // Find a check + check = pakfire_fhs_find_check(pakfire, path); + if (!check) { + ERROR(pakfire, "Could not match file %s: %m\n", path); + return 1; + } + + // Should this file exist at all? + if (check->flags & PAKFIRE_FHS_MUSTNOTEXIST) { + ERROR(pakfire, "%s must not exist here\n", path); + return 1; + } + + // Check type & mode + r = pakfire_fhs_check_mode(pakfire, check, file); + if (r) + return r; + + // Check passed! + return 0; +} diff --git a/src/libpakfire/include/pakfire/fhs.h b/src/libpakfire/include/pakfire/fhs.h new file mode 100644 index 00000000..5a28dde8 --- /dev/null +++ b/src/libpakfire/include/pakfire/fhs.h @@ -0,0 +1,29 @@ +/*############################################################################# +# # +# Pakfire - The IPFire package management system # +# Copyright (C) 2021 Pakfire development team # +# # +# This program is free software: you can redistribute it and/or modify # +# it under the terms of the GNU General Public License as published by # +# the Free Software Foundation, either version 3 of the License, or # +# (at your option) any later version. # +# # +# This program is distributed in the hope that it will be useful, # +# but WITHOUT ANY WARRANTY; without even the implied warranty of # +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # +# GNU General Public License for more details. # +# # +# You should have received a copy of the GNU General Public License # +# along with this program. If not, see . # +# # +#############################################################################*/ + +#ifndef PAKFIRE_FHS_H +#define PAKFIRE_FHS_H + +#include +#include + +int pakfire_fhs_check_file(struct pakfire* pakfire, struct pakfire_file* file); + +#endif /* PAKFIRE_FHS_H */