Skip to content

Commit f2dbda0

Browse files
committed
Fix: do not rely on DAC_OVERRIDE capability on Linux despite being root
It turns out, for example, that SELinux will prevent this capability for confined processes running as root. It then means that sbd cannot access, as a client, files used for joining two local communication sides within libqb-arranged IPC mechanism in case those files do not have permissions to explicitly allow file-based access with credentials of this client -- which is exactly what happens when the IPC servers are pacemaker daemons not run as root on their own. Solution is two-phased: 1. have sbd add respective non-privileged group corresponding to the server side of the IPC -- this patch 2. ensure this server side (pacemaker) does allow group-derived access (i.e., the access permissions for group are as relaxed as needed, umask notwithstanding) -- outside of the sbd's scope Signed-off-by: Jan Pokorný <[email protected]>
1 parent f949aa8 commit f2dbda0

File tree

1 file changed

+92
-0
lines changed

1 file changed

+92
-0
lines changed

src/sbd-pacemaker.c

+92
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,11 @@
4545
#include <libgen.h>
4646
#include <sys/utsname.h>
4747

48+
#ifdef __linux__
49+
#include <grp.h> /* getgrnam_r, initgroups */
50+
#include <pwd.h> /* getpwuid_r */
51+
#endif
52+
4853
#include <config.h>
4954

5055
#include <crm_config.h>
@@ -449,6 +454,80 @@ clean_up(int rc)
449454
return;
450455
}
451456

457+
#ifdef __linux__
458+
#define CLUSTER_GROUP "haclient"
459+
/* Try to add well-known cluster stack group (CLUSTER_GROUP) as a supplementary
460+
group to this root-privileged process for good measure (see the call site);
461+
returns 0 in case of success, respective positive exit status (different
462+
from 0, 1, and EXIT_MD_IO_FAIL...EXIT_MD_REQUEST_CRASHDUMP) otherwise. */
463+
static int
464+
add_cluster_group()
465+
{
466+
int rc = 0;
467+
long gr_limit = -1, pw_limit = -1, limit;
468+
char *buf;
469+
struct group group, *group_result;
470+
struct passwd passwd, *passwd_result;
471+
gid_t cluster_gid;
472+
473+
limit = sysconf(_SC_PAGESIZE);
474+
limit = (limit > 0) ? limit : 4096; /* assume sufficient, just in case */
475+
gr_limit = sysconf(_SC_GETGR_R_SIZE_MAX);
476+
gr_limit = (gr_limit > 0) ? gr_limit : limit;
477+
pw_limit = sysconf(_SC_GETPW_R_SIZE_MAX);
478+
limit = (gr_limit >= pw_limit) ? gr_limit : pw_limit;
479+
480+
if ((buf = malloc(limit)) == NULL) {
481+
return 74; /* EX_IOERR */
482+
}
483+
484+
do {
485+
rc = getgrnam_r(CLUSTER_GROUP, &group, buf, limit, &group_result);
486+
} while (rc == -1 && errno == EINTR);
487+
if (rc == -1 || group_result == NULL) {
488+
if (rc == -1) {
489+
cl_perror("Unable to get group entry for %s", CLUSTER_GROUP);
490+
rc = 69; /* EX_UNAVAILABLE */
491+
} else {
492+
cl_log(LOG_ERR, "Unable to get group entry for %s", CLUSTER_GROUP);
493+
rc = 78; /* EX_CONFIG */
494+
}
495+
goto bail;
496+
}
497+
cluster_gid = group.gr_gid;
498+
499+
do {
500+
rc = getpwuid_r(0, &passwd, buf, limit, &passwd_result);
501+
} while (rc == -1 && errno == EINTR);
502+
if (rc == -1 || passwd_result == NULL) {
503+
if (rc == -1) {
504+
cl_perror("Unable to get passwd entry for UID=0");
505+
rc = 69; /* EX_UNAVAILABLE */
506+
} else {
507+
cl_log(LOG_ERR, "Unable to get passwd entry for UID=0");
508+
rc = 78; /* EX_CONFIG */
509+
}
510+
goto bail;
511+
}
512+
513+
/* this is supposed to be root, hence (1) shall succeed and
514+
(2) the root shall not gain any new unwanted group-based
515+
access over what it already has per its standard supplementary
516+
groups even if they have been explicitly dropped by now (not
517+
the case now; root is usually just in its own group, too) */
518+
rc = initgroups(passwd.pw_name, cluster_gid);
519+
if (rc == -1) {
520+
cl_perror("Unable to set supplementary group %s", CLUSTER_GROUP);
521+
rc = (errno == EPERM) ? 77 /* EX_NOPERM */
522+
: 74 /* EX_IOERR */;
523+
}
524+
525+
bail:
526+
free(buf);
527+
return rc;
528+
}
529+
#endif
530+
452531
int
453532
servant_pcmk(const char *diskname, int mode, const void* argp)
454533
{
@@ -459,6 +538,19 @@ servant_pcmk(const char *diskname, int mode, const void* argp)
459538
set_proc_title("sbd: watcher: Pacemaker");
460539
setenv("PCMK_watchdog", "true", 1);
461540

541+
#ifdef __linux__
542+
/* since we run this as root, we may actually be prevented from
543+
accessing hacluster:haclient owned shared IPC mmap'd files of,
544+
e.g., pacemakerd-based ("CIB daemon") in some cased where
545+
root is not "all powerful" (e.g. under strict SELinux
546+
confinement not allowing a DAC_OVERRIDE for any reasons)
547+
TODO: first check if CAP_DAC_OVERRIDE is missing? */
548+
if ((exit_code = add_cluster_group()) > 0) {
549+
cl_log(LOG_CRIT, "Unable to ensure Pacemaker can be watched");
550+
clean_up(exit_code);
551+
}
552+
#endif
553+
462554
if(debug == 0) {
463555
/* We don't want any noisy crm messages */
464556
set_crm_log_level(LOG_CRIT);

0 commit comments

Comments
 (0)