From db0cf7963b971ebb393d105a0a29fa7bd926521c Mon Sep 17 00:00:00 2001 From: Dave Barach Date: Tue, 31 May 2016 14:05:46 -0400 Subject: VPP-83 Allow non-privileged clients to use the vpp binary API. Use the command line argument "api-segment { uid gid }" to configure shared memory segment file ownership. Defaults to uid = gid = 0. Shared-memory segments are explicitly set to 0770 mode, aka "rwxrwx---". Change-Id: Ic5d596b68139add61e7de6ace035c57dfd030111 Signed-off-by: Dave Barach --- svm/svm.c | 26 +++++++++++++------ svm/svm.h | 4 +++ vlib-api/vlibapi/api.h | 4 +++ vlib-api/vlibapi/api_shared.c | 8 ++++++ vlib-api/vlibmemory/api.h | 2 ++ vlib-api/vlibmemory/memory_shared.c | 43 +++++++++++++++---------------- vlib-api/vlibmemory/memory_vlib.c | 50 ++++++++++++++++++++----------------- vlib/vlib/main.c | 9 ++++--- vpp/api/api.c | 13 +++++++--- vpp/api/gmon.c | 10 +++++++- 10 files changed, 108 insertions(+), 61 deletions(-) diff --git a/svm/svm.c b/svm/svm.c index 62f317aafb4..b50aa8207ef 100644 --- a/svm/svm.c +++ b/svm/svm.c @@ -391,6 +391,11 @@ void *svm_map_region (svm_map_region_args_t *a) svm_fd = shm_open((char *) shm_name, O_RDWR | O_CREAT | O_EXCL, 0777); if (svm_fd >= 0) { + if (fchmod (svm_fd, 0770) < 0) + clib_unix_warning ("segment chmod"); + /* This turns out to fail harmlessly if the client starts first */ + if (fchown (svm_fd, a->uid, a->gid) < 0) + clib_unix_warning ("segment chown [ok if client starts first]"); vec_free(shm_name); @@ -615,18 +620,19 @@ static void svm_mutex_cleanup (void) } } -static void svm_region_init_internal (char *root_path) +static void svm_region_init_internal (char *root_path, int uid, int gid) { svm_region_t *rp; - svm_map_region_args_t *a=0; + svm_map_region_args_t _a, *a=&_a; u64 ticks = clib_cpu_time_now(); uword randomize_baseva; /* guard against klutz calls */ - root_rp_refcount++; if (root_rp) return; + root_rp_refcount++; + atexit(svm_mutex_cleanup); /* Randomize the shared-VM base at init time */ @@ -635,12 +641,14 @@ static void svm_region_init_internal (char *root_path) else randomize_baseva = (ticks & 3) * MMAP_PAGESIZE; - vec_validate(a,0); + memset (a, 0, sizeof (*a)); a->root_path = root_path; a->name = SVM_GLOBAL_REGION_NAME; a->baseva = SVM_GLOBAL_REGION_BASEVA + randomize_baseva; a->size = SVM_GLOBAL_REGION_SIZE; a->flags = SVM_FLAGS_NODATA; + a->uid = uid; + a->gid = gid; rp = svm_map_region (a); ASSERT(rp); @@ -663,18 +671,22 @@ static void svm_region_init_internal (char *root_path) svm_pop_heap (oldheap); } region_unlock(rp); - vec_free (a); root_rp = rp; } void svm_region_init (void) { - svm_region_init_internal (0); + svm_region_init_internal (0, 0 /* uid */, 0 /* gid */); } void svm_region_init_chroot (char *root_path) { - svm_region_init_internal (root_path); + svm_region_init_internal (root_path, 0 /* uid */, 0 /* gid */); +} + +void svm_region_init_chroot_uid_gid (char *root_path, int uid, int gid) +{ + svm_region_init_internal (root_path, uid, gid); } void *svm_region_find_or_create (svm_map_region_args_t *a) diff --git a/svm/svm.h b/svm/svm.h index 5f112cb83dc..bca23792059 100644 --- a/svm/svm.h +++ b/svm/svm.h @@ -74,6 +74,9 @@ typedef struct svm_map_region_args_ { uword flags; char *backing_file; uword backing_mmap_size; + /* uid, gid to own the svm region(s) */ + int uid; + int gid; } svm_map_region_args_t; @@ -108,6 +111,7 @@ typedef struct { void *svm_region_find_or_create (svm_map_region_args_t *a); void svm_region_init(void); void svm_region_init_chroot(char *root_path); +void svm_region_init_chroot_uid_gid(char *root_path, int uid, int gid); void svm_region_exit (void); void svm_region_unmap(void *rp_arg); void svm_client_scan (char *root_path); diff --git a/vlib-api/vlibapi/api.h b/vlib-api/vlibapi/api.h index 1f45a05738c..419210f7056 100644 --- a/vlib-api/vlibapi/api.h +++ b/vlib-api/vlibapi/api.h @@ -134,6 +134,10 @@ typedef struct { /* vector of message ranges */ vl_api_msg_range_t *msg_ranges; + /* gid for the api shared memory region */ + int api_gid; + int api_uid; + /* Client-only data structures */ unix_shared_memory_queue_t *vl_input_queue; diff --git a/vlib-api/vlibapi/api_shared.c b/vlib-api/vlibapi/api_shared.c index 308f0028e25..0600e621a4e 100644 --- a/vlib-api/vlibapi/api_shared.c +++ b/vlib-api/vlibapi/api_shared.c @@ -647,6 +647,14 @@ vl_api_init (vlib_main_t *vm) once = 1; am->region_name = "/unset"; + /* + * Eventually passed to fchown, -1 => "current user" + * instead of 0 => "root". A very fine disctinction at best. + */ + if (am->api_uid == 0) + am->api_uid = -1; + if (am->api_gid == 0) + am->api_gid = -1; return (0); } diff --git a/vlib-api/vlibmemory/api.h b/vlib-api/vlibmemory/api.h index 516d321ff53..1231944d752 100644 --- a/vlib-api/vlibmemory/api.h +++ b/vlib-api/vlibmemory/api.h @@ -133,6 +133,8 @@ int vl_client_api_map (char *region_name); void vl_client_api_unmap (void); void vl_set_memory_region_name (char *name); void vl_set_memory_root_path (char *root_path); +void vl_set_memory_uid (int uid); +void vl_set_memory_gid (int gid); void vl_enable_disable_memory_api (vlib_main_t *vm, int yesno); void vl_client_disconnect_from_vlib (void); int vl_client_connect_to_vlib(char *svm_name, char *client_name, diff --git a/vlib-api/vlibmemory/memory_shared.c b/vlib-api/vlibmemory/memory_shared.c index a32194310a4..71150fdc9cb 100644 --- a/vlib-api/vlibmemory/memory_shared.c +++ b/vlib-api/vlibmemory/memory_shared.c @@ -197,9 +197,23 @@ void vl_set_memory_root_path (char *name) am->root_path = name; } +void vl_set_memory_uid (int uid) +{ + api_main_t *am = &api_main; + + am->api_uid = uid; +} + +void vl_set_memory_gid (int gid) +{ + api_main_t *am = &api_main; + + am->api_gid = gid; +} + int vl_map_shmem (char *region_name, int is_vlib) { - svm_map_region_args_t *a = 0; + svm_map_region_args_t _a, *a = &_a; svm_region_t *vlib_rp, *root_rp; void *oldheap; vl_shmem_hdr_t *shmem_hdr=0; @@ -210,16 +224,16 @@ int vl_map_shmem (char *region_name, int is_vlib) if (is_vlib == 0) svm_region_init_chroot(am->root_path); - vec_validate (a, 0); + memset (a, 0, sizeof (*a)); a->name = region_name; a->size = 16<<20; a->flags = SVM_FLAGS_MHEAP; + a->uid = am->api_uid; + a->gid = am->api_gid; vlib_rp = svm_region_find_or_create (a); - vec_free (a); - if (vlib_rp == 0) return (-2); @@ -273,25 +287,8 @@ int vl_map_shmem (char *region_name, int is_vlib) /* Clean up the root region client list */ pthread_mutex_lock (&root_rp->mutex); svm_client_scan_this_region_nolock (root_rp); - pthread_mutex_unlock (&root_rp->mutex); - } else { - pthread_mutex_unlock (&vlib_rp->mutex); - /* - * Make sure the vlib app is really there... - * Wait up to 100 seconds... - */ - for (i = 0; i < 10000; i++) { - /* Yup, it's there, off we go... */ - if (kill (am->shmem_hdr->vl_pid, 0) >= 0) - break; - - ts.tv_sec = 0; - ts.tv_nsec = 10000*1000; /* 10 ms */ - while (nanosleep(&ts, &tsrem) < 0) - ts = tsrem; - } - } - + } + pthread_mutex_unlock (&vlib_rp->mutex); am->vlib_rp = vlib_rp; vec_add1(am->mapped_shmem_regions, vlib_rp); return 0; diff --git a/vlib-api/vlibmemory/memory_vlib.c b/vlib-api/vlibmemory/memory_vlib.c index 0cac49d7997..0fef64c8dec 100644 --- a/vlib-api/vlibmemory/memory_vlib.c +++ b/vlib-api/vlibmemory/memory_vlib.c @@ -343,7 +343,6 @@ typedef enum { static u64 vector_rate_histogram[SLEEP_N_BUCKETS]; -static void memclnt_queue_signal (int signum); static void memclnt_queue_callback (vlib_main_t *vm); static uword @@ -362,8 +361,6 @@ memclnt_process (vlib_main_t * vm, f64 vector_rate; vlib_set_queue_signal_callback (vm, memclnt_queue_callback); - am->vlib_signal = SIGUSR1; - signal (am->vlib_signal, memclnt_queue_signal); if ((rv = memory_api_init(am->region_name)) < 0) { clib_warning("memory_api_init returned %d, wait for godot...", rv); @@ -458,6 +455,7 @@ memclnt_process (vlib_main_t * vm, } event_type = vlib_process_wait_for_event_or_clock (vm, sleep_time); + vm->queue_signal_pending = 0; vlib_process_get_events (vm, 0 /* event_data */); if (vlib_time_now (vm) > dead_client_scan_time) { @@ -621,27 +619,33 @@ VLIB_REGISTER_NODE (memclnt_node,static) = { .state = VLIB_NODE_STATE_DISABLED, }; -static void -memclnt_queue_signal (int signum) -{ - vlib_main_t * vm = vlib_get_main(); - - vm->queue_signal_pending = 1; - vm->api_queue_nonempty = 1; -} - static void memclnt_queue_callback (vlib_main_t *vm) { -#if 0 - /* If we need to manually suspend / resume the memclnt process */ - vlib_node_t * n = vlib_get_node (vm, memclnt_node.index); - vlib_process_t * p = vlib_get_process_from_node (vm, n); -#endif - - vm->queue_signal_pending = 0; - vlib_process_signal_event - (vm, memclnt_node.index, /* event_type */ 0, /* event_data */ 0); + static volatile int * cursizep; + + if (PREDICT_FALSE (cursizep == 0)) + { + api_main_t *am = &api_main; + vl_shmem_hdr_t *shmem_hdr = am->shmem_hdr; + unix_shared_memory_queue_t * q; + + if (shmem_hdr == 0) + return; + + q = shmem_hdr->vl_input_queue; + if (q == 0) + return; + cursizep = &q->cursize; + } + + if (*cursizep >= 1) + { + vm->queue_signal_pending = 1; + vm->api_queue_nonempty = 1; + vlib_process_signal_event (vm, memclnt_node.index, + /* event_type */ 0, /* event_data */ 0); + } } void vl_enable_disable_memory_api (vlib_main_t *vm, int enable) @@ -1049,8 +1053,8 @@ clib_error_t * vlibmemory_init (vlib_main_t * vm) { api_main_t *am = &api_main; - /* Normally NULL, can be set by cmd line "chroot {prefix foo}" */ - svm_region_init_chroot (am->root_path); + /* Normally NULL / 0, set by cmd line "api-segment" */ + svm_region_init_chroot_uid_gid (am->root_path, am->api_uid, am->api_gid); return 0; } diff --git a/vlib/vlib/main.c b/vlib/vlib/main.c index 18273bf6586..24504e74080 100644 --- a/vlib/vlib/main.c +++ b/vlib/vlib/main.c @@ -1414,9 +1414,8 @@ static void vlib_main_loop (vlib_main_t * vm) /* frame */ 0, cpu_time_now); - if (PREDICT_FALSE(vm->queue_signal_pending)) - if (vm->queue_signal_callback) - vm->queue_signal_callback (vm); + if (PREDICT_TRUE (vm->queue_signal_pending == 0)) + vm->queue_signal_callback (vm); /* Next handle interrupts. */ { @@ -1533,11 +1532,15 @@ vlib_main_configure (vlib_main_t * vm, unformat_input_t * input) VLIB_EARLY_CONFIG_FUNCTION (vlib_main_configure, "vlib"); +static void dummy_queue_signal_callback (vlib_main_t * vm) { } + /* Main function. */ int vlib_main (vlib_main_t * vm, unformat_input_t * input) { clib_error_t * error; + vm->queue_signal_callback = dummy_queue_signal_callback; + clib_time_init (&vm->clib_time); /* Turn on event log. */ diff --git a/vpp/api/api.c b/vpp/api/api.c index 7aa898c6e30..0d27d582bca 100644 --- a/vpp/api/api.c +++ b/vpp/api/api.c @@ -6087,9 +6087,10 @@ vpe_api_init (vlib_main_t *vm) VLIB_INIT_FUNCTION(vpe_api_init); static clib_error_t * -chroot_config (vlib_main_t * vm, unformat_input_t * input) +api_segment_config (vlib_main_t * vm, unformat_input_t * input) { u8 * chroot_path; + int uid, gid; while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT) { @@ -6098,13 +6099,17 @@ chroot_config (vlib_main_t * vm, unformat_input_t * input) vec_add1 (chroot_path, 0); vl_set_memory_root_path ((char *)chroot_path); } + else if (unformat (input, "uid %d", &uid)) + vl_set_memory_uid (uid); + else if (unformat (input, "gid %d", &gid)) + vl_set_memory_gid (gid); else - return clib_error_return (0, "unknown input `%U'", - format_unformat_error, input); + return clib_error_return (0, "unknown input `%U'", + format_unformat_error, input); } return 0; } -VLIB_EARLY_CONFIG_FUNCTION (chroot_config, "chroot"); +VLIB_EARLY_CONFIG_FUNCTION (api_segment_config, "api-segment"); void * get_unformat_vnet_sw_interface (void) { diff --git a/vpp/api/gmon.c b/vpp/api/gmon.c index 8ab890fceb4..9d37155f005 100644 --- a/vpp/api/gmon.c +++ b/vpp/api/gmon.c @@ -165,6 +165,13 @@ gmon_init (vlib_main_t *vm) api_main_t * am = &api_main; pid_t *swp = 0; f64 *v = 0; + clib_error_t * error; + + if ((error = vlib_call_init_function(vm, vpe_api_init))) + return(error); + + /* Make sure that /global-vm is owned as directed */ + svm_region_init_chroot_uid_gid (am->root_path, am->api_uid, am->api_gid); gm->vlib_main = vm; gm->svmdb_client = svmdb_map_chroot(am->root_path); @@ -223,7 +230,8 @@ static clib_error_t *gmon_exit (vlib_main_t *vm) *gm->vpef_pid_ptr = 0; *gm->input_rate_ptr = 0.0; *gm->sig_error_rate_ptr = 0.0; - svmdb_unmap (gm->svmdb_client); + svm_region_unmap ((void *) gm->svmdb_client->db_rp); + vec_free(gm->svmdb_client); } return 0; } -- cgit 1.2.3-korg