system.conf: base ipc permissions on process names rather than labels

From now on, the "ipc" directive in system.conf refers to process names
instead of labels, similar to the "control" directive. The old, more
fine-grained approach is deemed unnecessary and cumbersome at this time.

As side effects, this patch unbreaks late IPC permission computation as
well as the filter driver.
This commit is contained in:
David van Moolenbroek 2010-12-07 12:16:31 +00:00
parent a7285dfabc
commit 7bef45ad3b
3 changed files with 77 additions and 66 deletions

View file

@ -50,15 +50,15 @@ Many system services run with root privileges (uid \fB0\fR).
The default user is service (uid \fB12\fR). The default user is service (uid \fB12\fR).
.RE .RE
.PP .PP
\fBipc\fR \fI<ALL|ALL_SYS|NONE|label1 label2...labelN>\fR\fB;\fR \fBipc\fR \fI<ALL|ALL_SYS|NONE|name1 name2...nameN>\fR\fB;\fR
.PP .PP
.RS .RS
specifies the list of ipc targets (processes and kernel) the system service can specifies the list of ipc targets (processes and kernel) the system service can
talk to. \fIALL\fR allows all the possible targets, \fIALL_SYS\fR is similar but talk to. \fIALL\fR allows all the possible targets, \fIALL_SYS\fR is similar but
excludes user processes. When an explicit list is given, each target excludes user processes. When an explicit list is given, each target
must be identified by its label (assigned to the corresponding system service). must be identified by its process (binary) name.
Exceptions are user processes (use pseudo-label \fIUSER\fR) and Exceptions are user processes (use pseudo-name \fIUSER\fR) and
the kernel for kernel calls (use pseudo-label \fISYSTEM\fR). The default is the kernel for kernel calls (use pseudo-name \fISYSTEM\fR). The default is
\fIALL_SYS\fR. \fIALL_SYS\fR.
.RE .RE
.PP .PP
@ -158,11 +158,11 @@ specifies the PCI classes the system service is allowed to use
The default is to allow no PCI classes. The default is to allow no PCI classes.
.RE .RE
.PP .PP
\fBcontrol\fR \fI<label1 label2...labelN>\fR\fB;\fR \fBcontrol\fR \fI<name1 name2...nameN>\fR\fB;\fR
.PP .PP
.RS .RS
specifies the list of system services (identified by their labels) that are specifies the list of system services (identified by their process names) that
allowed to control the system service. A controller service can ask RS are allowed to control the system service. A controller service can ask RS
to perform privileged actions like immediately restarting the service. to perform privileged actions like immediately restarting the service.
The default is to allow no controller services. The default is to allow no controller services.
.RE .RE

View file

@ -12,7 +12,7 @@
/*===========================================================================* /*===========================================================================*
* caller_is_root * * caller_is_root *
*===========================================================================*/ *===========================================================================*/
PUBLIC int caller_is_root(endpoint) PRIVATE int caller_is_root(endpoint)
endpoint_t endpoint; /* caller endpoint */ endpoint_t endpoint; /* caller endpoint */
{ {
uid_t euid; uid_t euid;
@ -30,43 +30,41 @@ endpoint_t endpoint; /* caller endpoint */
/*===========================================================================* /*===========================================================================*
* caller_can_control * * caller_can_control *
*===========================================================================*/ *===========================================================================*/
PUBLIC int caller_can_control(endpoint, label) PRIVATE int caller_can_control(endpoint, target_rp)
endpoint_t endpoint; endpoint_t endpoint;
char *label; struct rproc *target_rp;
{ {
int control_allowed = 0; int control_allowed = 0;
register struct rproc *rp; register struct rproc *rp;
register struct rprocpub *rpub; register struct rprocpub *rpub;
char *proc_name;
int c; int c;
char *progname;
/* Find name of binary for given label. */ proc_name = target_rp->r_pub->proc_name;
rp = lookup_slot_by_label(label);
if (!rp) return 0;
progname = strrchr(rp->r_argv[0], '/');
if (progname != NULL)
progname++;
else
progname = rp->r_argv[0];
/* Check if label is listed in caller's isolation policy. */ /* Check if label is listed in caller's isolation policy. */
for (rp = BEG_RPROC_ADDR; rp < END_RPROC_ADDR; rp++) { for (rp = BEG_RPROC_ADDR; rp < END_RPROC_ADDR; rp++) {
if (!(rp->r_flags & RS_IN_USE))
continue;
rpub = rp->r_pub; rpub = rp->r_pub;
if (rpub->endpoint == endpoint) { if (rpub->endpoint == endpoint) {
break; break;
} }
} }
if (rp == END_RPROC_ADDR) return 0; if (rp == END_RPROC_ADDR) return 0;
if (rp->r_nr_control > 0) {
for (c = 0; c < rp->r_nr_control; c++) { for (c = 0; c < rp->r_nr_control; c++) {
if (strcmp(rp->r_control[c], progname) == 0) if (strcmp(rp->r_control[c], proc_name) == 0) {
control_allowed = 1; control_allowed = 1;
break;
} }
} }
if (rs_verbose) if (rs_verbose)
printf("RS: allowing %u control over %s via policy: %s\n", printf("RS: allowing %u control over %s via policy: %s\n",
endpoint, label, control_allowed ? "yes" : "no"); endpoint, target_rp->r_pub->label,
control_allowed ? "yes" : "no");
return control_allowed; return control_allowed;
} }
@ -86,7 +84,7 @@ struct rproc *rp;
/* Caller should be either root or have control privileges. */ /* Caller should be either root or have control privileges. */
call_allowed = caller_is_root(caller); call_allowed = caller_is_root(caller);
if(rp) { if(rp) {
call_allowed |= caller_can_control(caller, rp->r_pub->label); call_allowed |= caller_can_control(caller, rp);
} }
if(!call_allowed) { if(!call_allowed) {
return EPERM; return EPERM;
@ -1828,14 +1826,14 @@ struct rproc *rp;
/*===========================================================================* /*===========================================================================*
* get_next_label * * get_next_name *
*===========================================================================*/ *===========================================================================*/
PUBLIC char *get_next_label(ptr, label, caller_label) PRIVATE char *get_next_name(ptr, name, caller_label)
char *ptr; char *ptr;
char *label; char *name;
char *caller_label; char *caller_label;
{ {
/* Get the next label from the list of (IPC) labels. /* Get the next name from the list of (IPC) program names.
*/ */
char *p, *q; char *p, *q;
size_t len; size_t len;
@ -1856,12 +1854,12 @@ char *caller_label;
if (len > RS_MAX_LABEL_LEN) if (len > RS_MAX_LABEL_LEN)
{ {
printf( printf(
"rs:get_next_label: bad ipc list entry '%.*s' for %s: too long\n", "rs:get_next_name: bad ipc list entry '%.*s' for %s: too long\n",
len, p, caller_label); len, p, caller_label);
continue; continue;
} }
memcpy(label, p, len); memcpy(name, p, len);
label[len]= '\0'; name[len]= '\0';
return q; /* found another */ return q; /* found another */
} }
@ -1879,9 +1877,8 @@ struct priv *privp;
/* Add IPC send permissions to a process based on that process's IPC /* Add IPC send permissions to a process based on that process's IPC
* list. * list.
*/ */
char label[RS_MAX_LABEL_LEN+1], *p; char name[RS_MAX_LABEL_LEN+1], *p;
struct rproc *tmp_rp; struct rproc *rrp;
struct rprocpub *tmp_rpub;
endpoint_t endpoint; endpoint_t endpoint;
int r; int r;
int priv_id; int priv_id;
@ -1891,29 +1888,48 @@ struct priv *privp;
rpub = rp->r_pub; rpub = rp->r_pub;
p = rp->r_ipc_list; p = rp->r_ipc_list;
while ((p = get_next_label(p, label, rpub->label)) != NULL) { while ((p = get_next_name(p, name, rpub->label)) != NULL) {
if (strcmp(label, "SYSTEM") == 0) if (strcmp(name, "SYSTEM") == 0)
endpoint= SYSTEM; endpoint= SYSTEM;
else if (strcmp(label, "USER") == 0) else if (strcmp(name, "USER") == 0)
endpoint= INIT_PROC_NR; /* all user procs */ endpoint= INIT_PROC_NR; /* all user procs */
else else
{ {
/* Try to find process */ /* Set a privilege bit for every process matching the
tmp_rp = lookup_slot_by_label(label); * given process name. It is perfectly fine if this
if (!tmp_rp) * loop does not find any matches, as the target
continue; * process(es) may not have been started yet. See
tmp_rpub = tmp_rp->r_pub; * add_backward_ipc() below.
endpoint= tmp_rpub->endpoint; */
for (rrp=BEG_RPROC_ADDR; rrp<END_RPROC_ADDR; rrp++) {
if (!(rrp->r_flags & RS_IN_USE))
continue;
if (!strcmp(rrp->r_pub->proc_name, name)) {
#if PRIV_DEBUG
printf(" RS: add_forward_ipc: setting"
" sendto bit for %d...\n",
rrp->r_pub->endpoint);
#endif
priv_id= rrp->r_priv.s_id;
set_sys_bit(privp->s_ipc_to, priv_id);
}
}
continue;
} }
/* This code only applies to the exception cases. */
if ((r = sys_getpriv(&priv, endpoint)) < 0) if ((r = sys_getpriv(&priv, endpoint)) < 0)
{ {
printf( printf(
"add_forward_ipc: unable to get priv_id for '%s': %d\n", "add_forward_ipc: unable to get priv_id for '%s': %d\n",
label, r); name, r);
continue; continue;
} }
#if PRIV_DEBUG #if PRIV_DEBUG
printf(" RS: add_forward_ipc: setting sendto bit for %d...\n", printf(" RS: add_forward_ipc: setting sendto bit for %d...\n",
endpoint); endpoint);
@ -1937,41 +1953,38 @@ struct priv *privp;
* add these permissions now because the current process may not yet * add these permissions now because the current process may not yet
* have existed at the time that the other process was initialized. * have existed at the time that the other process was initialized.
*/ */
char label[RS_MAX_LABEL_LEN+1], *p; char name[RS_MAX_LABEL_LEN+1], *p;
struct rproc *rrp; struct rproc *rrp;
struct rprocpub *rrpub; struct rprocpub *rrpub;
int priv_id, found; char *proc_name;
int priv_id;
proc_name = rp->r_pub->proc_name;
for (rrp=BEG_RPROC_ADDR; rrp<END_RPROC_ADDR; rrp++) { for (rrp=BEG_RPROC_ADDR; rrp<END_RPROC_ADDR; rrp++) {
if (!(rrp->r_flags & RS_IN_USE)) if (!(rrp->r_flags & RS_IN_USE))
continue; continue;
/* If an IPC target list was provided for the process being /* If an IPC target list was provided for the process being
* checked here, make sure that the label of the new process * checked here, make sure that the name of the new process
* is in that process's list. * is in that process's list. There may be multiple matches.
*/ */
if (rrp->r_ipc_list[0]) { if (rrp->r_ipc_list[0]) {
found = 0;
rrpub = rrp->r_pub; rrpub = rrp->r_pub;
p = rrp->r_ipc_list; p = rrp->r_ipc_list;
while ((p = get_next_label(p, label, while ((p = get_next_name(p, name,
rrpub->label)) != NULL) { rrpub->label)) != NULL) {
if (!strcmp(rrpub->label, label)) { if (!strcmp(proc_name, name)) {
found = 1; #if PRIV_DEBUG
break; printf(" RS: add_backward_ipc: setting"
" sendto bit for %d...\n",
rrpub->endpoint);
#endif
priv_id= rrp->r_priv.s_id;
set_sys_bit(privp->s_ipc_to, priv_id);
} }
} }
if (!found)
continue;
#if PRIV_DEBUG
printf(" RS: add_backward_ipc: setting sendto bit for %d...\n",
rrpub->endpoint);
#endif
priv_id= rrp->r_priv.s_id;
set_sys_bit(privp->s_ipc_to, priv_id);
} }
} }
} }

View file

@ -27,8 +27,6 @@ _PROTOTYPE( int do_getsysinfo, (message *m));
_PROTOTYPE( int do_lookup, (message *m)); _PROTOTYPE( int do_lookup, (message *m));
/* manager.c */ /* manager.c */
_PROTOTYPE( int caller_is_root, (endpoint_t endpoint) );
_PROTOTYPE( int caller_can_control, (endpoint_t endpoint, char *label) );
_PROTOTYPE( int check_call_permission, (endpoint_t caller, int call, _PROTOTYPE( int check_call_permission, (endpoint_t caller, int call,
struct rproc *rp) ); struct rproc *rp) );
_PROTOTYPE( int copy_rs_start, (endpoint_t src_e, char *src_rs_start, _PROTOTYPE( int copy_rs_start, (endpoint_t src_e, char *src_rs_start,