]>
git.ipfire.org Git - people/stevee/pakfire.git/blob - src/libpakfire/fhs.c
1 /*#############################################################################
3 # Pakfire - The IPFire package management system #
4 # Copyright (C) 2021 Pakfire development team #
6 # This program is free software: you can redistribute it and/or modify #
7 # it under the terms of the GNU General Public License as published by #
8 # the Free Software Foundation, either version 3 of the License, or #
9 # (at your option) any later version. #
11 # This program is distributed in the hope that it will be useful, #
12 # but WITHOUT ANY WARRANTY; without even the implied warranty of #
13 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the #
14 # GNU General Public License for more details. #
16 # You should have received a copy of the GNU General Public License #
17 # along with this program. If not, see <http://www.gnu.org/licenses/>. #
19 #############################################################################*/
23 #include <pakfire/fhs.h>
24 #include <pakfire/file.h>
25 #include <pakfire/logging.h>
26 #include <pakfire/pakfire.h>
27 #include <pakfire/util.h>
30 This struct defines any FHS checks.
32 They are being processed in order from top to bottom which is why we are starting
33 with some more prominent matches and have the less important stuff at the bottom.
35 static const struct pakfire_fhs_check
{
41 enum pakfire_fhs_check_flags
{
42 PAKFIRE_FHS_MUSTNOTEXIST
= (1 << 0),
43 PAKFIRE_FHS_NOEXEC
= (1 << 1),
45 } pakfire_fhs_check
[] = {
47 { "/usr", S_IFDIR
, 0755, "root", "root", 0 },
48 { "/usr/bin", S_IFDIR
, 0755, "root", "root", 0 },
49 { "/usr/include", S_IFDIR
, 0755, "root", "root", 0 },
50 { "/usr/lib", S_IFDIR
, 0755, "root", "root", 0 },
51 { "/usr/lib64", S_IFDIR
, 0755, "root", "root", 0 },
52 { "/usr/sbin", S_IFDIR
, 0755, "root", "root", 0 },
53 { "/usr/share", S_IFDIR
, 0755, "root", "root", 0 },
54 { "/usr/src", S_IFDIR
, 0755, "root", "root", 0 },
56 // Allow no further files in /usr & /usr/src
57 { "/usr/*", 0, 0, NULL
, NULL
, PAKFIRE_FHS_MUSTNOTEXIST
},
58 { "/usr/src/**", 0, 0, NULL
, NULL
, PAKFIRE_FHS_MUSTNOTEXIST
},
60 // There cannot be any subdirectories in /usr/bin & /usr/sbin
61 { "/usr/bin/*", S_IFDIR
, 0, NULL
, NULL
, PAKFIRE_FHS_MUSTNOTEXIST
},
62 { "/usr/sbin/*", S_IFDIR
, 0, NULL
, NULL
, PAKFIRE_FHS_MUSTNOTEXIST
},
64 // Permitted setuid binaries
65 { "/usr/bin/passwd", S_IFREG
, 4755, "root", "root", 0 },
66 { "/usr/bin/su", S_IFREG
, 4755, "root", "root", 0 },
67 { "/usr/bin/sudo", S_IFREG
, 4755, "root", "root", 0 },
69 // Any files in /usr/{,s}bin must be owned by root and have 0755
70 { "/usr/bin/*", S_IFREG
, 0755, "root", "root", 0 },
71 { "/usr/sbin/*", S_IFREG
, 0755, "root", "root", 0 },
73 // Shared Libraries must be executable
74 { "/usr/lib64/*.so.*", S_IFREG
, 0755, "root", "root", 0 },
75 { "/usr/lib64/**/*.so", S_IFREG
, 0755, "root", "root", 0 },
77 // Shared Libraries must not exist in /usr/lib
78 { "/usr/lib/*.so*", S_IFREG
, 0, NULL
, NULL
, PAKFIRE_FHS_MUSTNOTEXIST
},
80 // /usr/include: Ensure that:
81 // * All files are non-executable and belong to root
82 // * All directories have 0755 and belong to root
83 { "/usr/include/**", S_IFREG
, 0644, "root", "root", 0 },
84 { "/usr/include/**", S_IFDIR
, 0755, "root", "root", 0 },
86 // Firmware must not be executable
87 { "/usr/lib/firmware/**", S_IFREG
, 0644, "root", "root", 0 },
88 { "/usr/lib/firmware/**", S_IFDIR
, 0755, "root", "root", 0 },
90 // /usr/share cannot have any exectuable files
91 { "/usr/share/**", S_IFREG
, 0, NULL
, NULL
, PAKFIRE_FHS_NOEXEC
},
94 { "/var", S_IFDIR
, 0755, "root", "root", 0 },
95 { "/var/cache", S_IFDIR
, 0755, "root", "root", 0 },
96 { "/var/db", S_IFDIR
, 0755, "root", "root", 0 },
97 { "/var/empty", S_IFDIR
, 0755, "root", "root", 0 },
98 { "/var/lib", S_IFDIR
, 0755, "root", "root", 0 },
99 { "/var/log", S_IFDIR
, 0755, "root", "root", 0 },
100 { "/var/mail", S_IFDIR
, 0755, "root", "root", 0 },
101 { "/var/opt", S_IFDIR
, 0755, "root", "root", 0 },
102 { "/var/run", S_IFLNK
, 0755, "root", "root", 0 },
103 { "/var/spool", S_IFDIR
, 0755, "root", "root", 0 },
104 { "/var/tmp", S_IFDIR
, 0755, "root", "root", 0 },
106 // Do not allow any subdirectories in /var
107 { "/var/*", 0, 0, NULL
, NULL
, PAKFIRE_FHS_MUSTNOTEXIST
},
108 { "/var/empty/**", 0, 0, NULL
, NULL
, PAKFIRE_FHS_MUSTNOTEXIST
},
109 { "/var/tmp/**", 0, 0, NULL
, NULL
, PAKFIRE_FHS_MUSTNOTEXIST
},
111 // No files in /var may be executable
112 { "/var/**", S_IFREG
, 0, NULL
, NULL
, PAKFIRE_FHS_NOEXEC
},
115 { "/boot", S_IFDIR
, 0755, "root", "root", 0 },
116 { "/boot/efi", S_IFDIR
, 0755, "root", "root", 0 },
118 // All files in /boot must be owned by root
119 { "/boot/**", S_IFREG
, 0, "root", "root", 0, },
120 { "/boot/**", S_IFDIR
, 0, "root", "root", 0, },
122 // /dev (nothing may exist in it)
123 { "/dev", S_IFDIR
, 0755, "root", "root", 0 },
124 { "/dev/**", 0, 0, NULL
, NULL
, PAKFIRE_FHS_MUSTNOTEXIST
},
127 { "/etc", S_IFDIR
, 0755, "root", "root", 0 },
130 { "/home", S_IFDIR
, 0755, "root", "root", 0 },
131 { "/home/**", 0, 0, NULL
, NULL
, PAKFIRE_FHS_MUSTNOTEXIST
},
134 { "/opt", S_IFDIR
, 0755, "root", "root", 0 },
135 // These directories belong to the "local administrator"
136 // https://refspecs.linuxfoundation.org/FHS_3.0/fhs/ch03s13.html
137 { "/opt/bin", 0, 0, NULL
, NULL
, PAKFIRE_FHS_MUSTNOTEXIST
},
138 { "/opt/doc", 0, 0, NULL
, NULL
, PAKFIRE_FHS_MUSTNOTEXIST
},
139 { "/opt/include", 0, 0, NULL
, NULL
, PAKFIRE_FHS_MUSTNOTEXIST
},
140 { "/opt/info", 0, 0, NULL
, NULL
, PAKFIRE_FHS_MUSTNOTEXIST
},
141 { "/opt/lib", 0, 0, NULL
, NULL
, PAKFIRE_FHS_MUSTNOTEXIST
},
142 { "/opt/man", 0, 0, NULL
, NULL
, PAKFIRE_FHS_MUSTNOTEXIST
},
145 { "/proc", S_IFDIR
, 0755, "root", "root", 0 },
146 { "/proc/**", 0, 0, NULL
, NULL
, PAKFIRE_FHS_MUSTNOTEXIST
},
149 { "/root", S_IFDIR
, 0700, "root", "root", 0 },
150 { "/root/.*", S_IFREG
, 0644, "root", "root", 0 },
151 { "/root/**", 0, 0, NULL
, NULL
, PAKFIRE_FHS_MUSTNOTEXIST
},
154 { "/run", S_IFDIR
, 0755, "root", "root", 0 },
155 { "/run/**", 0, 0, NULL
, NULL
, PAKFIRE_FHS_MUSTNOTEXIST
},
158 { "/sys", S_IFDIR
, 0755, "root", "root", 0 },
159 { "/sys/**", 0, 0, NULL
, NULL
, PAKFIRE_FHS_MUSTNOTEXIST
},
162 { "/tmp", S_IFDIR
, 1755, "root", "root", 0 },
163 { "/tmp/**", 0, 0, NULL
, NULL
, PAKFIRE_FHS_MUSTNOTEXIST
},
166 { "/media", S_IFDIR
, 0755, "root", "root", 0 },
167 { "/mnt", S_IFDIR
, 0755, "root", "root", 0 },
168 { "/srv", S_IFDIR
, 0755, "root", "root", 0 },
170 // /bin, /sbin, /lib, and /lib64 have to be symlinks
171 { "/bin", S_IFLNK
, 0777, NULL
, NULL
, 0 },
172 { "/lib", S_IFLNK
, 0777, NULL
, NULL
, 0 },
173 { "/lib64", S_IFLNK
, 0777, NULL
, NULL
, 0 },
174 { "/sbin", S_IFLNK
, 0777, NULL
, NULL
, 0 },
176 // There cannot be anything else in /
177 { "/*", 0, 0, NULL
, NULL
, PAKFIRE_FHS_MUSTNOTEXIST
},
179 // Catch all so that we won't throw an error
180 { "/**", 0, 0, NULL
, NULL
, 0 },
186 static const struct pakfire_fhs_check
* pakfire_fhs_find_check(
187 struct pakfire
* pakfire
, struct pakfire_file
* file
) {
188 const struct pakfire_fhs_check
* check
= NULL
;
191 // Fetch the file type
192 const mode_t type
= pakfire_file_get_type(file
);
195 const char* path
= pakfire_file_get_path(file
);
197 // Walk through all possible checks
198 for (check
= pakfire_fhs_check
; check
->path
; check
++) {
199 // Skip this check if the filetype doesn't match
200 if (check
->type
&& check
->type
!= type
)
204 r
= pakfire_path_match(check
->path
, path
);
212 DEBUG(pakfire
, "%s matches check '%s'\n", path
, check
->path
);
223 ERROR(pakfire
, "Could not find FHS entry for %s: %m\n", path
);
228 static int pakfire_fhs_check_world_writable(
229 struct pakfire
* pakfire
, struct pakfire_file
* file
) {
230 // Run this check only for regular files
231 switch (pakfire_file_get_type(file
)) {
240 const char* path
= pakfire_file_get_path(file
);
243 const mode_t perms
= pakfire_file_get_perms(file
);
245 // Check that none of the executable bits are set
246 if ((perms
& (S_IWUSR
|S_IWGRP
|S_IWOTH
)) == (S_IWUSR
|S_IWGRP
|S_IWOTH
)) {
247 DEBUG(pakfire
, "%s is world-writable\n", path
);
254 static int pakfire_fhs_check_perms(struct pakfire
* pakfire
,
255 const struct pakfire_fhs_check
* check
, struct pakfire_file
* file
) {
256 // No permissions defined. Skipping check...
260 const char* path
= pakfire_file_get_path(file
);
263 const mode_t perms
= pakfire_file_get_perms(file
);
265 // Check if they match
266 if (check
->perms
!= perms
) {
267 DEBUG(pakfire
, "%s: Permissions do not match\n", path
);
275 static int pakfire_fhs_check_ownership(struct pakfire
* pakfire
,
276 const struct pakfire_fhs_check
* check
, struct pakfire_file
* file
) {
277 const char* path
= pakfire_file_get_path(file
);
281 const char* uname
= pakfire_file_get_uname(file
);
285 if (strcmp(check
->uname
, uname
) != 0) {
286 DEBUG(pakfire
, "%s: uname does not match\n", path
);
293 const char* gname
= pakfire_file_get_gname(file
);
297 if (strcmp(check
->gname
, gname
) != 0) {
298 DEBUG(pakfire
, "%s: gname does not match\n", path
);
307 static int pakfire_fhs_check_noexec(struct pakfire
* pakfire
,
308 const struct pakfire_fhs_check
* check
, struct pakfire_file
* file
) {
309 // Skip this check if PAKFIRE_FHS_NOEXEC is not set
310 if (!(check
->flags
& PAKFIRE_FHS_NOEXEC
))
314 const char* path
= pakfire_file_get_path(file
);
317 const mode_t perms
= pakfire_file_get_perms(file
);
319 // Check that none of the executable bits are set
320 if (perms
& (S_IXUSR
|S_IXGRP
|S_IXOTH
)) {
321 DEBUG(pakfire
, "%s must not be executable\n", path
);
328 int pakfire_fhs_check_file(struct pakfire
* pakfire
, struct pakfire_file
* file
) {
329 const struct pakfire_fhs_check
* check
= NULL
;
333 const char* path
= pakfire_file_get_path(file
);
337 // Check for world-writable permissions
338 r
= pakfire_fhs_check_world_writable(pakfire
, file
);
343 check
= pakfire_fhs_find_check(pakfire
, file
);
345 ERROR(pakfire
, "Could not match file %s: %m\n", path
);
349 // Should this file exist at all?
350 if (check
->flags
& PAKFIRE_FHS_MUSTNOTEXIST
) {
351 ERROR(pakfire
, "%s must not exist here\n", path
);
356 r
= pakfire_fhs_check_perms(pakfire
, check
, file
);
361 r
= pakfire_fhs_check_ownership(pakfire
, check
, file
);
365 // Check for PAKFIRE_FHS_NOEXEC
366 r
= pakfire_fhs_check_noexec(pakfire
, check
, file
);