From: David van Moolenbroek Date: Wed, 2 Dec 2009 09:54:50 +0000 (+0000) Subject: RS changes: X-Git-Tag: v3.1.6~184 X-Git-Url: http://zhaoyanbai.com/repos/%24relpath%24doxygen.css?a=commitdiff_plain;h=4924d1a9b58caabb374d5b797091d1fd730366c1;p=minix.git 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 --- diff --git a/include/minix/rs.h b/include/minix/rs.h index c4fd65228..c07807dbb 100644 --- a/include/minix/rs.h +++ b/include/minix/rs.h @@ -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 diff --git a/servers/is/dmp_rs.c b/servers/is/dmp_rs.c index 4b2904b22..c3f738954 100644 --- a/servers/is/dmp_rs.c +++ b/servers/is/dmp_rs.c @@ -9,6 +9,7 @@ #include "inc.h" #include +#include #include "../../kernel/priv.h" #include "../rs/manager.h" diff --git a/servers/rs/inc.h b/servers/rs/inc.h index fe56dc625..b4c6ee566 100644 --- a/servers/rs/inc.h +++ b/servers/rs/inc.h @@ -25,6 +25,7 @@ #include #include #include +#include #include #include /* For priv.h */ diff --git a/servers/rs/main.c b/servers/rs/main.c index d6e75219f..72174bc3c 100644 --- a/servers/rs/main.c +++ b/servers/rs/main.c @@ -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; diff --git a/servers/rs/manager.c b/servers/rs/manager.c index 20643b69f..1528b2e0a 100644 --- a/servers/rs/manager.c +++ b/servers/rs/manager.c @@ -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 #include #include -#include #include #include /* 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; im_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; ir_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; rpr_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; rpr_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++) { diff --git a/servers/rs/manager.h b/servers/rs/manager.h index 8c64022b6..2c21e6e76 100644 --- a/servers/rs/manager.h +++ b/servers/rs/manager.h @@ -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. */ diff --git a/servers/rs/service.c b/servers/rs/service.c index 2e7872007..80c66e872 100644 --- a/servers/rs/service.c +++ b/servers/rs/service.c @@ -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);