VPP-83 Allow non-privileged clients to use the vpp binary API.
Use the command line argument "api-segment { uid <nnn> gid <nnn> }" 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 <dave@barachs.net>
This commit is contained in:
parent
8d9e80583f
commit
db0cf7963b
26
svm/svm.c
26
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)
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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,
|
||||
|
@ -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;
|
||||
|
@ -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
|
||||
static volatile int * cursizep;
|
||||
|
||||
vm->queue_signal_pending = 0;
|
||||
vlib_process_signal_event
|
||||
(vm, memclnt_node.index, /* event_type */ 0, /* event_data */ 0);
|
||||
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;
|
||||
}
|
||||
|
||||
|
@ -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. */
|
||||
|
@ -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)
|
||||
{
|
||||
|
@ -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;
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user