Skip to content

Commit 84e06b1

Browse files
committed
bin/xbps-pkgdb: check file and symlink owners & perms
1 parent 3417a94 commit 84e06b1

8 files changed

Lines changed: 363 additions & 29 deletions

File tree

bin/xbps-pkgdb/Makefile

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,5 +5,6 @@ BIN = xbps-pkgdb
55
OBJS = main.o check.o check_pkg_files.o
66
OBJS += check_pkg_alternatives.o check_pkg_rundeps.o
77
OBJS += check_pkg_symlinks.o check_pkg_unneeded.o
8+
OBJS += check_files.o
89

910
include $(TOPDIR)/mk/prog.mk

bin/xbps-pkgdb/check_files.c

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
#include <assert.h>
2+
#include <errno.h>
3+
#include <string.h>
4+
#include <sys/stat.h>
5+
6+
#include "defs.h"
7+
8+
int
9+
file_mode_check(const char *file, const mode_t mode) {
10+
struct stat sb;
11+
12+
assert(file != NULL);
13+
assert(mode);
14+
15+
if (lstat(file, &sb) == -1)
16+
return -errno;
17+
18+
if (sb.st_mode != mode)
19+
return ERANGE;
20+
21+
return 0;
22+
}
23+
24+
int
25+
file_user_check(struct idtree * idt, const char *file, const char *user) {
26+
struct stat sb;
27+
char *act_user;
28+
29+
assert(file != NULL);
30+
assert(user != NULL);
31+
32+
if (lstat(file, &sb) == -1)
33+
return -errno;
34+
35+
act_user = idtree_username(idt, sb.st_uid);
36+
return strcmp(user, act_user) == 0 ? 0 : ERANGE;
37+
}
38+
39+
int
40+
file_group_check(struct idtree * idt, const char *file, const char *grp) {
41+
struct stat sb;
42+
char *act_grp;
43+
44+
assert(file != NULL);
45+
assert(grp != NULL);
46+
47+
if (lstat(file, &sb) == -1)
48+
return -errno;
49+
50+
act_grp = idtree_groupname(idt, sb.st_gid);
51+
return strcmp(grp, act_grp) == 0 ? 0 : ERANGE;
52+
}

bin/xbps-pkgdb/check_pkg_files.c

Lines changed: 88 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,11 @@
4343
* o Check the hash for all installed files, except
4444
* configuration files (which is expected if they are modified).
4545
*
46-
* o Compares stored file modification time.
46+
* o Check the mode for all installed files, except configuration files.
47+
*
48+
* o Check the user for all installed files, except configuration files.
49+
*
50+
* o Check the group for all installed files, except configuration files.
4751
*
4852
* Return 0 if test ran successfully, 1 otherwise and -1 on error.
4953
*/
@@ -55,10 +59,12 @@ check_pkg_files(struct xbps_handle *xhp, const char *pkgname, void *arg)
5559
xbps_object_t obj;
5660
xbps_object_iterator_t iter;
5761
xbps_dictionary_t pkg_filesd = arg;
58-
const char *file = NULL, *sha256 = NULL;
62+
const char *file = NULL, *sha256 = NULL, *user = NULL, *group = NULL;
5963
char *path;
60-
bool mutable, test_broken = false;
64+
bool mutable, test_broken = false, noexist = false;
6165
int rv = 0, errors = 0;
66+
mode_t mode = 0;
67+
struct idtree *idt = NULL;
6268

6369
array = xbps_dictionary_get(pkg_filesd, "files");
6470
if (array != NULL && xbps_array_count(array) > 0) {
@@ -67,44 +73,104 @@ check_pkg_files(struct xbps_handle *xhp, const char *pkgname, void *arg)
6773
return -1;
6874

6975
while ((obj = xbps_object_iterator_next(iter))) {
76+
noexist = mutable = false;
77+
7078
xbps_dictionary_get_cstring_nocopy(obj, "file", &file);
7179
/* skip noextract files */
7280
if (xhp->noextract && xbps_patterns_match(xhp->noextract, file))
7381
continue;
7482
path = xbps_xasprintf("%s/%s", xhp->rootdir, file);
75-
xbps_dictionary_get_cstring_nocopy(obj,
76-
"sha256", &sha256);
83+
84+
xbps_dictionary_get_bool(obj, "mutable", &mutable);
85+
86+
/* check sha256 */
87+
xbps_dictionary_get_cstring_nocopy(obj, "sha256", &sha256);
7788
rv = xbps_file_sha256_check(path, sha256);
7889
switch (rv) {
7990
case 0:
80-
free(path);
8191
break;
8292
case ENOENT:
83-
xbps_error_printf("%s: unexistent file %s.\n",
84-
pkgname, file);
85-
free(path);
86-
test_broken = true;
93+
xbps_error_printf("%s: unexistent file %s.\n", pkgname, file);
94+
test_broken = noexist = true;
8795
break;
8896
case ERANGE:
89-
mutable = false;
90-
xbps_dictionary_get_bool(obj,
91-
"mutable", &mutable);
9297
if (!mutable) {
93-
xbps_error_printf("%s: hash mismatch "
94-
"for %s.\n", pkgname, file);
98+
xbps_error_printf("%s: hash mismatch for %s.\n", pkgname, file);
9599
test_broken = true;
96100
}
97-
free(path);
98101
break;
99102
default:
100-
xbps_error_printf(
101-
"%s: can't check `%s' (%s)\n",
102-
pkgname, file, strerror(rv));
103-
free(path);
103+
xbps_error_printf("%s: can't check `%s' (%s)\n", pkgname, file, strerror(rv));
104104
break;
105105
}
106-
}
107-
xbps_object_iterator_release(iter);
106+
107+
if (noexist) {
108+
free(path);
109+
continue;
110+
}
111+
112+
/* check mode */
113+
mode = 0;
114+
if (xbps_dictionary_get_uint32(obj, "mode", &mode)) {
115+
rv = file_mode_check(path, mode);
116+
switch (rv) {
117+
case 0:
118+
break;
119+
case ERANGE:
120+
if (!mutable) {
121+
xbps_error_printf("%s: mode mismatch for %s.\n", pkgname, file);
122+
test_broken = true;
123+
}
124+
break;
125+
default:
126+
xbps_error_printf("%s: can't check `%s' (%s)\n", pkgname, file, strerror(-rv));
127+
break;
128+
}
129+
}
130+
131+
/* check user */
132+
user = NULL;
133+
xbps_dictionary_get_cstring_nocopy(obj, "user", &user);
134+
if (user == NULL)
135+
user = "root";
136+
rv = file_user_check(idt, path, user);
137+
switch (rv) {
138+
case 0:
139+
break;
140+
case ERANGE:
141+
if (!mutable) {
142+
xbps_error_printf("%s: user mismatch for %s.\n", pkgname, file);
143+
test_broken = true;
144+
}
145+
break;
146+
default:
147+
xbps_error_printf("%s: can't check `%s' (%s)\n", pkgname, file, strerror(-rv));
148+
break;
149+
}
150+
151+
/* check group */
152+
group = NULL;
153+
xbps_dictionary_get_cstring_nocopy(obj, "group", &group);
154+
if (group == NULL)
155+
group = "root";
156+
rv = file_group_check(idt, path, group);
157+
switch (rv) {
158+
case 0:
159+
break;
160+
case ERANGE:
161+
if (!mutable) {
162+
xbps_error_printf("%s: group mismatch for %s.\n", pkgname, file);
163+
test_broken = true;
164+
}
165+
break;
166+
default:
167+
xbps_error_printf("%s: can't check `%s' (%s)\n", pkgname, file, strerror(-rv));
168+
break;
169+
}
170+
171+
free(path);
172+
}
173+
xbps_object_iterator_release(iter);
108174
}
109175
if (test_broken) {
110176
xbps_error_printf("%s: files check FAILED.\n", pkgname);

bin/xbps-pkgdb/check_pkg_symlinks.c

Lines changed: 45 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -41,9 +41,11 @@
4141
* The following task is accomplished in this file:
4242
*
4343
* o Check for target file in symlinks, so that we can check that
44-
* they have not been modified.
44+
* they have not been modified or broken.
4545
*
46-
* returns 0 if test ran successfully, 1 otherwise and -1 on error.
46+
* o Check for symlink ownership.
47+
*
48+
* returns 0 if test ran successfully and -1 on error.
4749
*/
4850

4951
int
@@ -52,14 +54,16 @@ check_pkg_symlinks(struct xbps_handle *xhp, const char *pkgname, void *arg)
5254
xbps_array_t array;
5355
xbps_object_t obj;
5456
xbps_dictionary_t filesd = arg;
57+
bool test_broken = false;
5558
int rv = 0;
59+
struct idtree *idt = NULL;
5660

5761
array = xbps_dictionary_get(filesd, "links");
5862
if (array == NULL)
5963
return 0;
6064

6165
for (unsigned int i = 0; i < xbps_array_count(array); i++) {
62-
const char *file = NULL, *tgt = NULL;
66+
const char *file = NULL, *tgt = NULL, *user = NULL, *group = NULL;
6367
char path[PATH_MAX], *lnk = NULL;
6468

6569
obj = xbps_array_get(array, i);
@@ -83,16 +87,51 @@ check_pkg_symlinks(struct xbps_handle *xhp, const char *pkgname, void *arg)
8387
snprintf(path, sizeof(path), "%s/%s", xhp->rootdir, file);
8488
if ((lnk = xbps_symlink_target(xhp, path, tgt)) == NULL) {
8589
xbps_error_printf("%s: broken symlink %s (target: %s)\n", pkgname, file, tgt);
86-
rv = -1;
90+
test_broken = true;
8791
continue;
8892
}
8993
if (strcmp(lnk, tgt)) {
9094
xbps_warn_printf("%s: modified symlink %s "
9195
"points to %s (shall be %s)\n",
9296
pkgname, file, lnk, tgt);
93-
rv = -1;
97+
test_broken = true;
98+
}
99+
100+
user = NULL;
101+
xbps_dictionary_get_cstring_nocopy(obj, "user", &user);
102+
if (user == NULL)
103+
user = "root";
104+
rv = file_user_check(idt, path, user);
105+
switch (rv) {
106+
case 0:
107+
break;
108+
case ERANGE:
109+
xbps_error_printf("%s: user mismatch for %s.\n", pkgname, file);
110+
test_broken = true;
111+
break;
112+
default:
113+
xbps_error_printf("%s: can't check `%s' (%s)\n", pkgname, file, strerror(-rv));
114+
break;
94115
}
116+
117+
group = NULL;
118+
xbps_dictionary_get_cstring_nocopy(obj, "group", &group);
119+
if (group == NULL)
120+
group = "root";
121+
rv = file_group_check(idt, path, group);
122+
switch (rv) {
123+
case 0:
124+
break;
125+
case ERANGE:
126+
xbps_error_printf("%s: group mismatch for %s.\n", pkgname, file);
127+
test_broken = true;
128+
break;
129+
default:
130+
xbps_error_printf("%s: can't check `%s' (%s)\n", pkgname, file, strerror(-rv));
131+
break;
132+
}
133+
95134
free(lnk);
96135
}
97-
return rv;
136+
return test_broken ? -1 : 0;
98137
}

bin/xbps-pkgdb/defs.h

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,8 @@
2929
#include <sys/time.h>
3030
#include <xbps.h>
3131

32+
#include "idtree.h"
33+
3234
/* from check.c */
3335
int check_pkg_integrity(struct xbps_handle *, xbps_dictionary_t, const char *);
3436
int check_pkg_integrity_all(struct xbps_handle *);
@@ -45,4 +47,9 @@ CHECK_PKG_DECL(alternatives);
4547
/* from convert.c */
4648
void convert_pkgdb_format(struct xbps_handle *);
4749

50+
/* from check_files.c */
51+
int file_mode_check(const char *, const mode_t);
52+
int file_user_check(struct idtree *, const char *, const char *);
53+
int file_group_check(struct idtree *, const char *, const char *);
54+
4855
#endif /* !_XBPS_PKGDB_DEFS_H_ */

include/idtree.h

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
#ifndef IDTREE_H
2+
#define IDTREE_H
3+
4+
#include <sys/types.h>
5+
6+
struct idtree {
7+
long id;
8+
char *name;
9+
struct idtree *left, *right;
10+
int level;
11+
};
12+
13+
char * idtree_username(struct idtree *, uid_t);
14+
char * idtree_groupname(struct idtree *, gid_t);
15+
16+
#endif /* IDTREE_H */

lib/Makefile

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ LIBFETCH_INCS = fetch/common.h
3232
LIBFETCH_GEN = fetch/ftperr.h fetch/httperr.h
3333

3434
# External code used by libxbps
35-
EXTOBJS = external/dewey.o external/fexec.o external/mkpath.o
35+
EXTOBJS = external/dewey.o external/fexec.o external/mkpath.o external/idtree.o
3636

3737
# libxbps
3838
OBJS = package_configure.o package_config_files.o package_orphans.o

0 commit comments

Comments
 (0)