RS changes:

- add new "control" config directive, to let drivers restart drivers
  (by Jorrit Herder)
- fix bug causing system processes to be started twice sometimes
This commit is contained in:
David van Moolenbroek 2009-12-02 09:54:50 +00:00
parent 7c0cdc61bc
commit 4924d1a9b5
7 changed files with 244 additions and 62 deletions

View file

@ -1,3 +1,6 @@
#ifndef RS_H
#define RS_H
/*
minix/rs.h
@ -11,6 +14,14 @@ Interface to the reincarnation server
#define RSS_NR_PCI_ID 32
#define RSS_NR_PCI_CLASS 4
#define RSS_NR_SYSTEM 2
#define RSS_NR_CONTROL 8
/* Labels are copied over separately. */
struct rss_label
{
char *l_addr;
size_t l_len;
};
/* Arguments needed to start a new driver or server */
struct rs_start
@ -33,12 +44,13 @@ struct rs_start
int rss_nr_pci_class;
struct { u32_t class; u32_t mask; } rss_pci_class[RSS_NR_PCI_CLASS];
u32_t rss_system[RSS_NR_SYSTEM];
char *rss_label;
size_t rss_labellen;
struct rss_label rss_label;
char *rss_ipc;
size_t rss_ipclen;
#define RSS_VM_CALL_SIZE BITMAP_CHUNKS(VM_NCALLS)
bitchunk_t rss_vm[RSS_VM_CALL_SIZE];
int rss_nr_control;
struct rss_label rss_control[RSS_NR_CONTROL];
};
#define RF_COPY 0x01 /* Copy the brinary into RS to make it possible
@ -64,3 +76,4 @@ struct rs_pci
_PROTOTYPE( int minix_rs_lookup, (const char *name, endpoint_t *value));
#endif

View file

@ -9,6 +9,7 @@
#include "inc.h"
#include <timers.h>
#include <minix/rs.h>
#include "../../kernel/priv.h"
#include "../rs/manager.h"

View file

@ -25,6 +25,7 @@
#include <minix/sysutil.h>
#include <minix/keymap.h>
#include <minix/bitmap.h>
#include <minix/rs.h>
#include <archtypes.h>
#include <timers.h> /* For priv.h */

View file

@ -38,7 +38,6 @@ PUBLIC int main(void)
int result; /* result to return */
sigset_t sigset; /* system signal set */
int s;
uid_t euid;
/* Initialize the server, then go to work. */
init_server();
@ -73,8 +72,12 @@ PUBLIC int main(void)
sig_handler();
continue;
default: /* heartbeat notification */
if (rproc_ptr[who_p] != NULL) /* mark heartbeat time */
if (rproc_ptr[who_p] != NULL) { /* mark heartbeat time */
rproc_ptr[who_p]->r_alive_tm = m.NOTIFY_TIMESTAMP;
} else {
printf("Warning, RS got unexpected notify message from %d\n",
m.m_source);
}
}
}
@ -91,17 +94,7 @@ PUBLIC int main(void)
continue;
}
/* Only root can make calls to rs. unless it's RS_LOOKUP. */
euid= getnuid(m.m_source);
if (euid != 0 && call_nr != RS_LOOKUP)
{
printf("RS: got unauthorized request %d from endpoint %d\n",
call_nr, m.m_source);
m.m_type = EPERM;
reply(who_e, &m);
continue;
}
/* Handler functions are responsible for permission checking. */
switch(call_nr) {
case RS_UP: result = do_up(&m, FALSE, 0); break;
case RS_UP_COPY: result = do_up(&m, TRUE, 0); break;

View file

@ -1,5 +1,6 @@
/*
* Changes:
* Mar 02, 2009: Extended isolation policies (Jorrit N. Herder)
* Jul 22, 2005: Created (Jorrit N. Herder)
*/
@ -15,7 +16,6 @@
#include <minix/ds.h>
#include <minix/endpoint.h>
#include <minix/vm.h>
#include <minix/rs.h>
#include <lib.h>
#include <timers.h> /* For priv.h */
@ -26,6 +26,11 @@ struct rproc rproc[NR_SYS_PROCS]; /* system process table */
struct rproc *rproc_ptr[NR_PROCS]; /* mapping for fast access */
/* Prototypes for internal functions that do the hard work. */
FORWARD _PROTOTYPE( int caller_is_root, (endpoint_t endpoint) );
FORWARD _PROTOTYPE( int caller_can_control, (endpoint_t endpoint,
char *label) );
FORWARD _PROTOTYPE( int copy_label, (endpoint_t src_e,
struct rss_label *src_label, char *dst_label, size_t dst_len) );
FORWARD _PROTOTYPE( int start_service, (struct rproc *rp, int flags,
endpoint_t *ep) );
FORWARD _PROTOTYPE( int stop_service, (struct rproc *rp,int how) );
@ -48,7 +53,95 @@ PRIVATE int shutting_down = FALSE;
extern int rs_verbose;
/*===========================================================================*
* do_up *
* caller_is_root *
*===========================================================================*/
PRIVATE int caller_is_root(endpoint)
endpoint_t endpoint; /* caller endpoint */
{
uid_t euid;
/* Check if caller has root user ID. */
euid = getnuid(endpoint);
if (rs_verbose && euid != 0)
{
printf("RS: got unauthorized request from endpoint %d\n", endpoint);
}
return euid == 0;
}
/*===========================================================================*
* caller_can_control *
*===========================================================================*/
PRIVATE int caller_can_control(endpoint, label)
endpoint_t endpoint;
char *label;
{
int control_allowed = 0;
register struct rproc *rp;
int c;
char *progname;
/* Find name of binary for given label. */
for (rp = BEG_RPROC_ADDR; rp < END_RPROC_ADDR; rp++) {
if (strcmp(rp->r_label, label) == 0) {
break;
}
}
if (rp == END_RPROC_ADDR) 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. */
for (rp = BEG_RPROC_ADDR; rp < END_RPROC_ADDR; rp++) {
if (rp->r_proc_nr_e == endpoint) {
break;
}
}
if (rp == END_RPROC_ADDR) return 0;
if (rp->r_nr_control > 0) {
for (c = 0; c < rp->r_nr_control; c++) {
if (strcmp(rp->r_control[c], progname) == 0)
control_allowed = 1;
}
}
if (rs_verbose) {
printf("RS: allowing %u control over %s via policy: %s\n",
endpoint, label, control_allowed ? "yes" : "no");
}
return control_allowed;
}
/*===========================================================================*
* copy_label *
*===========================================================================*/
PRIVATE int copy_label(src_e, src_label, dst_label, dst_len)
endpoint_t src_e;
struct rss_label *src_label;
char *dst_label;
size_t dst_len;
{
int s, len;
len = MIN(dst_len-1, src_label->l_len);
s = sys_datacopy(src_e, (vir_bytes) src_label->l_addr,
SELF, (vir_bytes) dst_label, len);
if (s != OK) return s;
dst_label[len] = 0;
if (rs_verbose)
printf("RS: do_start: using label (custom) '%s'\n", dst_label);
return OK;
}
/*===========================================================================*
* do_up *
*===========================================================================*/
PUBLIC int do_up(m_ptr, do_copy, flags)
message *m_ptr; /* request message pointer */
@ -70,6 +163,9 @@ int flags; /* extra flags, if any */
int r;
endpoint_t ep; /* new endpoint no. */
/* This call requires special privileges. */
if (!caller_is_root(m_ptr->m_source)) return(EPERM);
/* See if there is a free entry in the table with system processes. */
for (slot_nr = 0; slot_nr < NR_SYS_PROCS; slot_nr++) {
rp = &rproc[slot_nr]; /* get pointer to slot */
@ -148,7 +244,7 @@ int flags; /* extra flags, if any */
/*===========================================================================*
* do_start *
* do_start *
*===========================================================================*/
PUBLIC int do_start(m_ptr)
message *m_ptr; /* request message pointer */
@ -169,10 +265,8 @@ message *m_ptr; /* request message pointer */
struct rproc *tmp_rp;
struct rs_start rs_start;
/* Get the request structure */
s= sys_datacopy(m_ptr->m_source, (vir_bytes) m_ptr->RS_CMD_ADDR,
SELF, (vir_bytes) &rs_start, sizeof(rs_start));
if (s != OK) return(s);
/* This call requires special privileges. */
if (!caller_is_root(m_ptr->m_source)) return(EPERM);
/* See if there is a free entry in the table with system processes. */
for (slot_nr = 0; slot_nr < NR_SYS_PROCS; slot_nr++) {
@ -186,6 +280,11 @@ message *m_ptr; /* request message pointer */
return ENOMEM;
}
/* Ok, there is space. Get the request structure. */
s= sys_datacopy(m_ptr->m_source, (vir_bytes) m_ptr->RS_CMD_ADDR,
SELF, (vir_bytes) &rs_start, sizeof(rs_start));
if (s != OK) return(s);
/* Obtain command name and parameters. This is a space-separated string
* that looks like "/sbin/service arg1 arg2 ...". Arguments are optional.
*/
@ -215,15 +314,12 @@ message *m_ptr; /* request message pointer */
rp->r_argv[arg_count] = NULL; /* end with NULL pointer */
rp->r_argc = arg_count;
if(rs_start.rss_label) {
int len;
if(rs_start.rss_label.l_len > 0) {
/* RS_START caller has supplied a custom label for this driver. */
len = MIN(sizeof(rp->r_label)-1, rs_start.rss_labellen);
s=sys_datacopy(m_ptr->m_source, (vir_bytes) rs_start.rss_label,
SELF, (vir_bytes) rp->r_label, len);
int s = copy_label(m_ptr->m_source, &rs_start.rss_label,
rp->r_label, sizeof(rp->r_label));
if(s != OK)
return s;
rp->r_label[len] = '\0';
if(rs_verbose)
printf("RS: do_start: using label (custom) '%s'\n", rp->r_label);
} else {
@ -243,6 +339,29 @@ message *m_ptr; /* request message pointer */
rp->r_argv[0], rp->r_label);
}
if(rs_start.rss_nr_control > 0) {
int i, s;
if (rs_start.rss_nr_control > RSS_NR_CONTROL)
{
printf("RS: do_start: too many control labels\n");
return EINVAL;
}
for (i=0; i<rs_start.rss_nr_control; i++) {
s = copy_label(m_ptr->m_source, &rs_start.rss_control[i],
rp->r_control[i], sizeof(rp->r_control[i]));
if(s != OK)
return s;
}
rp->r_nr_control = rs_start.rss_nr_control;
if (rs_verbose) {
printf("RS: do_start: control labels:");
for (i=0; i<rp->r_nr_control; i++)
printf(" %s", rp->r_control[i]);
printf("\n");
}
}
/* Check for duplicates */
for (slot_nr = 0; slot_nr < NR_SYS_PROCS; slot_nr++) {
tmp_rp = &rproc[slot_nr]; /* get pointer to slot */
@ -349,7 +468,7 @@ message *m_ptr; /* request message pointer */
#endif
}
if (rs_start.rss_nr_pci_id > MAX_NR_PCI_ID)
if (rs_start.rss_nr_pci_id > RSS_NR_PCI_ID)
{
printf("RS: do_start: too many PCI device IDs\n");
return EINVAL;
@ -363,7 +482,7 @@ message *m_ptr; /* request message pointer */
printf("RS: do_start: PCI %04x/%04x\n",
rp->r_pci_id[i].vid, rp->r_pci_id[i].did);
}
if (rs_start.rss_nr_pci_class > MAX_NR_PCI_CLASS)
if (rs_start.rss_nr_pci_class > RSS_NR_PCI_CLASS)
{
printf("RS: do_start: too many PCI class IDs\n");
return EINVAL;
@ -428,6 +547,9 @@ PUBLIC int do_down(message *m_ptr)
int s, proc;
char label[MAX_LABEL_LEN];
/* This call requires special privileges. */
if (!caller_is_root(m_ptr->m_source)) return(EPERM);
len= m_ptr->RS_CMD_LEN;
if (len >= sizeof(label))
return EINVAL; /* Too long */
@ -487,6 +609,12 @@ PUBLIC int do_restart(message *m_ptr)
if (s != OK) return(s);
label[len]= '\0';
/* This call requires special privileges. */
if (! (caller_can_control(m_ptr->m_source, label) ||
caller_is_root(m_ptr->m_source))) {
return(EPERM);
}
for (rp=BEG_RPROC_ADDR; rp<END_RPROC_ADDR; rp++) {
if ((rp->r_flags & RS_IN_USE) && strcmp(rp->r_label, label) == 0) {
if(rs_verbose) printf("RS: restarting '%s' (%d)\n", label, rp->r_pid);
@ -530,6 +658,12 @@ PUBLIC int do_refresh(message *m_ptr)
if (s != OK) return(s);
label[len]= '\0';
/* This call requires special privileges. */
if (! (caller_can_control(m_ptr->m_source, label) ||
caller_is_root(m_ptr->m_source))) {
return(EPERM);
}
for (rp=BEG_RPROC_ADDR; rp<END_RPROC_ADDR; rp++) {
if (rp->r_flags & RS_IN_USE && strcmp(rp->r_label, label) == 0) {
#if VERBOSE
@ -550,6 +684,9 @@ PUBLIC int do_refresh(message *m_ptr)
*===========================================================================*/
PUBLIC int do_shutdown(message *m_ptr)
{
/* This call requires special privileges. */
if (m_ptr != NULL && !caller_is_root(m_ptr->m_source)) return(EPERM);
/* Set flag so that RS server knows services shouldn't be restarted. */
shutting_down = TRUE;
return(OK);
@ -814,7 +951,7 @@ endpoint_t *endpoint;
case 0: /* child process */
/* Try to execute the binary that has an absolute path. If this fails,
* e.g., because the root file system cannot be read, try to strip of
* e.g., because the root file system cannot be read, try to strip off
* the path, and see if the command is in RS' current working dir.
*/
nice(rp->r_nice); /* Nice before setuid, to allow negative
@ -826,7 +963,7 @@ endpoint_t *endpoint;
{
execve(rp->r_argv[0], rp->r_argv, &null_env); /* POSIX execute */
file_only = strrchr(rp->r_argv[0], '/') + 1;
execve(file_only, rp->r_argv, &null_env); /* POSIX execute */
execve(file_only, rp->r_argv, &null_env); /* POSIX execute */
}
printf("RS: exec failed for %s: %d\n", rp->r_argv[0], errno);
slot_nr= rp-rproc;
@ -857,6 +994,7 @@ endpoint_t *endpoint;
rp->r_check_tm = 0; /* not checked yet */
getuptime(&rp->r_alive_tm); /* currently alive */
rp->r_stop_tm = 0; /* not exiting yet */
rp->r_backoff = 0; /* not to be restarted */
rproc_ptr[child_proc_nr_n] = rp; /* mapping for fast access */
/* If any of the calls below fail, the RS_EXITING flag is set. This implies
@ -994,6 +1132,9 @@ message *m_ptr;
size_t len;
int s;
/* This call requires special privileges. */
if (!caller_is_root(m_ptr->m_source)) return(EPERM);
switch(m_ptr->m1_i1) {
case SI_PROC_TAB:
src_addr = (vir_bytes) rproc;
@ -1329,7 +1470,7 @@ struct priv *privp;
src_bits_per_word= 8*sizeof(rp->r_call_mask[0]);
dst_bits_per_word= 8*sizeof(privp->s_k_call_mask[0]);
for (src_word= 0; src_word < MAX_NR_SYSTEM; src_word++)
for (src_word= 0; src_word < RSS_NR_SYSTEM; src_word++)
{
for (src_bit= 0; src_bit < src_bits_per_word; src_bit++)
{

View file

@ -12,9 +12,6 @@
#define MAX_NR_ARGS 4 /* maximum number of arguments */
#define MAX_RESCUE_DIR_LEN 64 /* maximum rescue dir length */
#define MAX_NR_PCI_ID 32 /* maximum number of PCI device IDs */
#define MAX_NR_PCI_CLASS 4 /* maximum number of PCI class IDs */
#define MAX_NR_SYSTEM 2 /* should match RSS_NR_SYSTEM */
#define MAX_IPC_LIST 256 /* Max size of list for IPC target
* process names
*/
@ -56,14 +53,15 @@ extern struct rproc {
uid_t r_uid;
int r_nice;
int r_nr_pci_id; /* Number of PCI devices IDs */
struct { u16_t vid; u16_t did; } r_pci_id[MAX_NR_PCI_ID];
struct { u16_t vid; u16_t did; } r_pci_id[RSS_NR_PCI_ID];
int r_nr_pci_class; /* Number of PCI class IDs */
struct { u32_t class; u32_t mask; } r_pci_class[MAX_NR_PCI_CLASS];
struct { u32_t class; u32_t mask; } r_pci_class[RSS_NR_PCI_CLASS];
u32_t r_call_mask[MAX_NR_SYSTEM];
u32_t r_call_mask[RSS_NR_SYSTEM];
char r_ipc_list[MAX_IPC_LIST];
#define R_VM_CALL_SIZE BITMAP_CHUNKS(VM_NCALLS)
bitchunk_t r_vm[R_VM_CALL_SIZE];
bitchunk_t r_vm[RSS_VM_CALL_SIZE];
int r_nr_control;
char r_control[RSS_NR_CONTROL][MAX_LABEL_LEN];
} rproc[NR_SYS_PROCS];
/* Mapping for fast access to the system process table. */

View file

@ -336,6 +336,7 @@ PRIVATE void fatal(char *fmt, ...)
#define KW_SYSTEM "system"
#define KW_IPC "ipc"
#define KW_VM "vm"
#define KW_CONTROL "control"
FORWARD void do_driver(config_t *cpe, config_t *config);
@ -370,27 +371,27 @@ PRIVATE void do_class(config_t *cpe, config_t *config)
{
if (!(cp->flags & CFG_SUBLIST))
{
fatal("do_class: expected list at %s:%d\n",
fatal("do_class: expected list at %s:%d",
cp->file, cp->line);
}
cp1= cp->list;
if ((cp1->flags & CFG_STRING) ||
(cp1->flags & CFG_SUBLIST))
{
fatal("do_class: expected word at %s:%d\n",
fatal("do_class: expected word at %s:%d",
cp1->file, cp1->line);
}
/* At this place we expect the word 'driver' */
if (strcmp(cp1->word, KW_DRIVER) != 0)
fatal("do_class: exected word '%S' at %s:%d\n",
fatal("do_class: exected word '%S' at %s:%d",
KW_DRIVER, cp1->file, cp1->line);
cp1= cp1->next;
if ((cp1->flags & CFG_STRING) ||
(cp1->flags & CFG_SUBLIST))
{
fatal("do_class: expected word at %s:%d\n",
fatal("do_class: expected word at %s:%d",
cp1->file, cp1->line);
}
@ -401,7 +402,7 @@ PRIVATE void do_class(config_t *cpe, config_t *config)
if (cp == NULL)
{
fatal(
"do_class: no entry found for class '%s' at %s:%d\n",
"do_class: no entry found for class '%s' at %s:%d",
cpe->word, cpe->file, cpe->line);
}
do_driver(cp1->next, config);
@ -838,7 +839,7 @@ PRIVATE void do_system(config_t *cpe)
if (call_nr < KERNEL_CALL)
{
fatal(
"do_system: bad call number %d in system tab for '%s'\n",
"do_system: bad call number %d in system tab for '%s'",
call_nr, system_tab[i].label);
}
call_nr -= KERNEL_CALL;
@ -849,13 +850,43 @@ PRIVATE void do_system(config_t *cpe)
if (word >= RSS_NR_SYSTEM)
{
fatal(
"do_system: RSS_NR_SYSTEM is too small (%d needed)\n",
"do_system: RSS_NR_SYSTEM is too small (%d needed)",
word+1);
}
rs_start.rss_system[word] |= mask;
}
}
PRIVATE void do_control(config_t *cpe)
{
int nr_control = 0;
/* Process a list of 'control' labels. */
for (; cpe; cpe= cpe->next)
{
if (cpe->flags & CFG_SUBLIST)
{
fatal("do_control: unexpected sublist at %s:%d",
cpe->file, cpe->line);
}
if (cpe->flags & CFG_STRING)
{
fatal("do_control: unexpected string at %s:%d",
cpe->file, cpe->line);
}
if (nr_control >= RSS_NR_CONTROL)
{
fatal(
"do_control: RSS_NR_CONTROL is too small (%d needed)",
nr_control+1);
}
rs_start.rss_control[nr_control].l_addr = cpe->word;
rs_start.rss_control[nr_control].l_len = strlen(cpe->word);
rs_start.rss_nr_control = ++nr_control;
}
}
PRIVATE void do_driver(config_t *cpe, config_t *config)
{
config_t *cp;
@ -865,13 +896,13 @@ PRIVATE void do_driver(config_t *cpe, config_t *config)
*/
if (!(cpe->flags & CFG_SUBLIST))
{
fatal("do_driver: expected list at %s:%d\n",
fatal("do_driver: expected list at %s:%d",
cpe->file, cpe->line);
}
if (cpe->next != NULL)
{
cpe= cpe->next;
fatal("do_driver: expected end of list at %s:%d\n",
fatal("do_driver: expected end of list at %s:%d",
cpe->file, cpe->line);
}
cpe= cpe->list;
@ -881,13 +912,13 @@ PRIVATE void do_driver(config_t *cpe, config_t *config)
{
if (!(cp->flags & CFG_SUBLIST))
{
fatal("do_driver: expected list at %s:%d\n",
fatal("do_driver: expected list at %s:%d",
cp->file, cp->line);
}
cpe= cp->list;
if ((cpe->flags & CFG_STRING) || (cpe->flags & CFG_SUBLIST))
{
fatal("do_driver: expected word at %s:%d\n",
fatal("do_driver: expected word at %s:%d",
cpe->file, cpe->line);
}
@ -936,7 +967,11 @@ PRIVATE void do_driver(config_t *cpe, config_t *config)
do_vm(cpe->next);
continue;
}
if (strcmp(cpe->word, KW_CONTROL) == 0)
{
do_control(cpe->next);
continue;
}
}
}
@ -957,25 +992,25 @@ PRIVATE void do_config(char *label, char *filename)
{
if (!(cp->flags & CFG_SUBLIST))
{
fatal("do_config: expected list at %s:%d\n",
fatal("do_config: expected list at %s:%d",
cp->file, cp->line);
}
cpe= cp->list;
if ((cpe->flags & CFG_STRING) || (cpe->flags & CFG_SUBLIST))
{
fatal("do_config: expected word at %s:%d\n",
fatal("do_config: expected word at %s:%d",
cpe->file, cpe->line);
}
/* At this place we expect the word 'driver' */
if (strcmp(cpe->word, KW_DRIVER) != 0)
fatal("do_config: exected word '%S' at %s:%d\n",
fatal("do_config: exected word '%S' at %s:%d",
KW_DRIVER, cpe->file, cpe->line);
cpe= cpe->next;
if ((cpe->flags & CFG_STRING) || (cpe->flags & CFG_SUBLIST))
{
fatal("do_config: expected word at %s:%d\n",
fatal("do_config: expected word at %s:%d",
cpe->file, cpe->line);
}
@ -987,7 +1022,7 @@ PRIVATE void do_config(char *label, char *filename)
{
fprintf(stderr, "service: driver '%s' not found in config\n",
label);
return;
exit(1);
}
cpe= cpe->next;
@ -1052,11 +1087,11 @@ PUBLIC int main(int argc, char **argv)
rs_start.rss_period= req_period;
rs_start.rss_script= req_script;
if(req_label) {
rs_start.rss_label = req_label;
rs_start.rss_labellen = strlen(req_label);
rs_start.rss_label.l_addr = req_label;
rs_start.rss_label.l_len = strlen(req_label);
} else {
rs_start.rss_label = progname;
rs_start.rss_labellen = strlen(progname);
rs_start.rss_label.l_addr = progname;
rs_start.rss_label.l_len = strlen(progname);
}
if (req_script)
rs_start.rss_scriptlen= strlen(req_script);