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:
parent
a7285dfabc
commit
7bef45ad3b
3 changed files with 77 additions and 66 deletions
|
@ -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
|
||||||
|
|
|
@ -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);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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,
|
||||||
|
|
Loading…
Reference in a new issue