summaryrefslogtreecommitdiff
path: root/lib
diff options
context:
space:
mode:
authorColin Watson <cjwatson@debian.org>2016-12-09 21:45:32 +0000
committerColin Watson <cjwatson@debian.org>2016-12-10 23:52:04 +0000
commit31552334cecee82809059ec598a37d9ea82683f0 (patch)
treeb0acc92e0b7c002cef4fd862c0b2466533aea31f /lib
parentc7f7daa9b2ffbbf4c45a2b168802a51acc2263c0 (diff)
Eliminate dangerous setgid-root directories
man-db has created its cache directories as setgid root for nearly 20 years. This seems to have originated in https://bugs.debian.org/26002. However, this has some dangerous consequences, such as: http://www.halfdog.net/Security/2015/SetgidDirectoryPrivilegeEscalation/ It seems best to arrange for cache files and directories to be man:man rather than man:root. To do this reliably, as well as adjusting various chown and chmod calls, we make man and mandb be setgid man as well as setuid man (except in the --disable-setuid case). This is a much simpler and safer solution to the original problem, and doesn't introduce any interesting new privilege since the man group's only real purpose is to be the man user's primary group and nothing in cache directories is group-writeable. * configure.ac (AC_CHECK_FUNCS): Add lchown. * lib/security.c (init_security): Record initial real and effective group IDs as well as user IDs. (drop_effective_privs, regain_effective_privs): Update gid. * lib/xchown.c (xlchown) [HAVE_LCHOWN]: New function. * lib/xchown.c (xlchown) [HAVE_LCHOWN]: Add prototype. * m4/man-arg-setuid.m4: Set man_mode to 6755 rather than 4755 in the --enable-setuid case. * src/Makefile.am (install-exec-hook): Check for man_mode being 6755 rather than 4755. Set the group of man and mandb as well as their owner. * src/check_mandirs.c (chown_if_possible): New function. This is somewhat more careful than previous implementations, changes the group as well as the user if possible, and prefers lchown if it is available. (mkcatdirs): Drop S_ISGID from cat directories. Use chown_if_possible. (fix_permissions, fix_permissions_tree): New functions to remove setgid bit from existing cat directories. (testmandirs): Call fix_permissions_tree. * src/check_mandirs.h (chown_if_possible): Add prototype. * src/man.c (commit_tmp_cat): Set cat file group as well as owner. * src/mandb.c (check_chown): Remove. (do_chown): Stop taking a uid parameter. Use chown_if_possible. (mandb): Use chown_if_possible for CACHEDIR.TAG. Set ownership and permissions of CACHEDIR.TAG even if it already exists. (process_manpath): Set ownership of database files even if they have not been changed.
Diffstat (limited to 'lib')
-rw-r--r--lib/security.c8
-rw-r--r--lib/xchown.c10
-rw-r--r--lib/xchown.h3
3 files changed, 21 insertions, 0 deletions
diff --git a/lib/security.c b/lib/security.c
index 21734b8a..362db598 100644
--- a/lib/security.c
+++ b/lib/security.c
@@ -61,6 +61,9 @@
uid_t ruid; /* initial real user id */
uid_t euid; /* initial effective user id */
uid_t uid; /* current euid */
+gid_t rgid; /* initial real group id */
+gid_t egid; /* initial effective group id */
+gid_t gid; /* current egid */
static struct passwd *man_owner;
@@ -79,6 +82,9 @@ void init_security (void)
ruid = getuid ();
uid = euid = geteuid ();
debug ("ruid=%d, euid=%d\n", (int) ruid, (int) euid);
+ rgid = getgid ();
+ gid = egid = getegid ();
+ debug ("rgid=%d, egid=%d\n", (int) rgid, (int) egid);
priv_drop_count = 0;
drop_effective_privs ();
}
@@ -119,6 +125,7 @@ void drop_effective_privs (void)
if (idpriv_temp_drop ())
gripe_set_euid ();
uid = ruid;
+ gid = rgid;
}
priv_drop_count++;
@@ -146,6 +153,7 @@ void regain_effective_privs (void)
gripe_set_euid ();
uid = euid;
+ gid = egid;
}
#endif /* SECURE_MAN_UID */
}
diff --git a/lib/xchown.c b/lib/xchown.c
index 760cd748..7f284faa 100644
--- a/lib/xchown.c
+++ b/lib/xchown.c
@@ -37,3 +37,13 @@ void xchown (const char *path, uid_t owner, gid_t group)
if (rc)
error (FATAL, 0, _("can't chown %s"), path);
}
+
+#ifdef HAVE_LCHOWN
+void xlchown (const char *path, uid_t owner, gid_t group)
+{
+ int rc;
+ rc = lchown (path, owner, group);
+ if (rc)
+ error (FATAL, 0, _("can't chown %s"), path);
+}
+#endif
diff --git a/lib/xchown.h b/lib/xchown.h
index 2193ee80..8a035b2d 100644
--- a/lib/xchown.h
+++ b/lib/xchown.h
@@ -22,5 +22,8 @@
#define _XCHOWN_H
void xchown (const char *path, uid_t owner, gid_t group);
+#ifdef HAVE_LCHOWN
+void xlchown (const char *path, uid_t owner, gid_t group);
+#endif /* HAVE_LCHOWN */
#endif /* _XCHOWN_H */