From f6161c72d1810db34f83d4570906859fc432e506 Mon Sep 17 00:00:00 2001 From: Jennifer Averett Date: Fri, 3 Jan 2003 18:14:09 +0000 Subject: 2003-01-03 Till Straumann * ChangeLog, base_fs.c, getpwent.c, privateenv.c Per PR303, Fix violation of node_access copy syemantics --- cpukit/libcsupport/src/base_fs.c | 33 ++++++++++- cpukit/libcsupport/src/getpwent.c | 18 ------ cpukit/libcsupport/src/privateenv.c | 106 +++++++++++++++++++++++++++++++----- 3 files changed, 125 insertions(+), 32 deletions(-) (limited to 'cpukit/libcsupport') diff --git a/cpukit/libcsupport/src/base_fs.c b/cpukit/libcsupport/src/base_fs.c index 119f38d794..61151eef07 100644 --- a/cpukit/libcsupport/src/base_fs.c +++ b/cpukit/libcsupport/src/base_fs.c @@ -49,6 +49,7 @@ void rtems_filesystem_initialize( void ) int status; rtems_filesystem_mount_table_entry_t *entry; rtems_filesystem_mount_table_t *mt; + rtems_filesystem_location_info_t loc; /* * Set the default umask to "022". @@ -75,8 +76,38 @@ void rtems_filesystem_initialize( void ) rtems_fatal_error_occurred( 0xABCD0002 ); rtems_filesystem_link_counts = 0; + + /* setup the 'current' and 'root' directories + * + * NOTE: cloning the pathlocs is not strictly + * necessary. Since we implicitely let + * all threads that don't call + * libio_set_private_env() share the same + * (initial) 'root' and 'current' locs, + * we (also implicitely) assume that the + * root filesystem doesn't care about + * reference counts. + * I just inserted the code snippet below + * to remind everybody of the fact by + * making it more explicit... + * Ideally, every thread would have to + * call either share_private_env() or + * set_private_env() - but then: that's + * gonna hit performance. + * + * Till Straumann, 10/25/2002 + */ rtems_filesystem_root = entry->mt_fs_root; - rtems_filesystem_current = rtems_filesystem_root; + /* Clone the root pathloc */ + rtems_filesystem_evaluate_path("/", 0, &loc, 0); + rtems_filesystem_root = loc; + /* One more clone for the current node */ + rtems_filesystem_evaluate_path("/", 0, &loc, 0); + rtems_filesystem_current = loc; + + /* Note: the global_env's refcnt doesn't matter + * as the global env is never released + */ /* diff --git a/cpukit/libcsupport/src/getpwent.c b/cpukit/libcsupport/src/getpwent.c index 00ae4a47f6..b2b4531b0d 100644 --- a/cpukit/libcsupport/src/getpwent.c +++ b/cpukit/libcsupport/src/getpwent.c @@ -185,21 +185,17 @@ static int getpw_r( { FILE *fp; int match; - rtems_user_env_t * aux=rtems_current_user_env; /* save */ init_etc_passwd_group(); - rtems_current_user_env=&rtems_global_user_env; /* set root */ if ((fp = fopen("/etc/passwd", "r")) == NULL) { errno = EINVAL; - rtems_current_user_env=aux; /* restore */ return -1; } for(;;) { if (!scanpw(fp, pwd, buffer, bufsize)) { errno = EINVAL; fclose(fp); - rtems_current_user_env=aux; /* restore */ return -1; } if (name) { @@ -211,13 +207,11 @@ static int getpw_r( if (match) { fclose(fp); *result = pwd; - rtems_current_user_env=aux; /* restore */ return 0; } } fclose(fp); errno = EINVAL; - rtems_current_user_env=aux; /* restore */ return -1; } @@ -276,14 +270,11 @@ struct passwd *getpwent() void setpwent(void) { - rtems_user_env_t * aux=rtems_current_user_env; /* save */ init_etc_passwd_group(); - rtems_current_user_env=&rtems_global_user_env; /* set root */ if (passwd_fp != NULL) fclose(passwd_fp); passwd_fp = fopen("/etc/passwd", "r"); - rtems_current_user_env=aux; /* restore */ } void endpwent(void) @@ -353,21 +344,17 @@ static int getgr_r( { FILE *fp; int match; - rtems_user_env_t * aux=rtems_current_user_env; /* save */ init_etc_passwd_group(); - rtems_current_user_env=&rtems_global_user_env; /* set root */ if ((fp = fopen("/etc/group", "r")) == NULL) { errno = EINVAL; - rtems_current_user_env=aux; /* restore */ return -1; } for(;;) { if (!scangr(fp, grp, buffer, bufsize)) { errno = EINVAL; fclose(fp); - rtems_current_user_env=aux; /* restore */ return -1; } if (name) { @@ -379,13 +366,11 @@ static int getgr_r( if (match) { fclose(fp); *result = grp; - rtems_current_user_env=aux; /* restore */ return 0; } } fclose(fp); errno = EINVAL; - rtems_current_user_env=aux; /* restore */ return -1; } @@ -444,14 +429,11 @@ struct group *getgrent() void setgrent(void) { - rtems_user_env_t * aux=rtems_current_user_env; /* save */ init_etc_passwd_group(); - rtems_current_user_env=&rtems_global_user_env; /* set root */ if (group_fp != NULL) fclose(group_fp); group_fp = fopen("/etc/group", "r"); - rtems_current_user_env=aux; /* restore */ } void endgrent(void) diff --git a/cpukit/libcsupport/src/privateenv.c b/cpukit/libcsupport/src/privateenv.c index 93dff453c5..d4e5608be1 100644 --- a/cpukit/libcsupport/src/privateenv.c +++ b/cpukit/libcsupport/src/privateenv.c @@ -23,25 +23,75 @@ #include #include +extern Chain_Control rtems_filesystem_mount_table_control; + +#define THE_ROOT_FS_LOC \ + (((rtems_filesystem_mount_table_entry_t*)\ + rtems_filesystem_mount_table_control.first)->mt_fs_root) + +/* cleanup a user environment + * NOTE: this must be called with + * thread dispatching disabled! + */ +static void +free_user_env(rtems_user_env_t *env) +{ + if (env != &rtems_global_user_env +#ifdef HAVE_USERENV_REFCNT + && --env->refcnt <= 0 +#endif + ) { + rtems_filesystem_freenode( &env->current_directory); + rtems_filesystem_freenode( &env->root_directory); + free(env); + } +} + rtems_status_code rtems_libio_set_private_env(void) { - rtems_status_code sc; - rtems_id task_id; + rtems_status_code sc; + rtems_id task_id; + rtems_filesystem_location_info_t loc; sc=rtems_task_ident(RTEMS_SELF,0,&task_id); if (sc != RTEMS_SUCCESSFUL) return sc; /* Only for the first time a malloc is necesary */ - if (rtems_current_user_env==&rtems_global_user_env) { - sc = rtems_task_variable_add(RTEMS_SELF,(void*)&rtems_current_user_env,free); - if (sc != RTEMS_SUCCESSFUL) return sc; - rtems_current_user_env = malloc(sizeof(rtems_user_env_t)); - if (!rtems_current_user_env) + if (rtems_current_user_env==&rtems_global_user_env) { + rtems_user_env_t *tmp = malloc(sizeof(rtems_user_env_t)); + if (!tmp) return RTEMS_NO_MEMORY; + +#ifdef HAVE_USERENV_REFCNT + tmp->refcnt = 1; +#endif + + sc = rtems_task_variable_add(RTEMS_SELF,(void*)&rtems_current_user_env,free_user_env); + if (sc != RTEMS_SUCCESSFUL) { + /* don't use free_user_env because the pathlocs are + * not initialized yet + */ + free(tmp); + return sc; + } + rtems_current_user_env = tmp; }; - /* the side effect desired . chroot("/") */ *rtems_current_user_env = rtems_global_user_env; /* get the global values*/ rtems_current_user_env->task_id=task_id; /* mark the local values*/ + + /* get a clean root */ + rtems_filesystem_root = THE_ROOT_FS_LOC; + + /* Clone the pathlocs. In contrast to most other + * code we must _not_ free the original locs because + * what we are trying to do here is forking off + * clones. + */ + + rtems_filesystem_evaluate_path("/", 0, &loc, 0); + rtems_filesystem_root = loc; + rtems_filesystem_evaluate_path("/", 0, &loc, 0); + rtems_filesystem_current = loc; return RTEMS_SUCCESSFUL; } @@ -51,6 +101,21 @@ rtems_status_code rtems_libio_set_private_env(void) { * Task_id (remote) and RTEMS_SELF(current). */ +/* NOTE: + * + * THIS CODE HAS NO PROTECTION IMPLEMENTED + * + * Tasks who wish to share their environments must + * + * a) assert that no participants are concurrently + * executing + * libio_share_private_env() and/or libio_set_private_env() + * + * b) mutex access to rtems_filesystem_current, rtems_filesytem_root + * while changing any of those (chdir(), chroot()). + */ + +#ifndef HAVE_USERENV_REFCNT rtems_status_code rtems_libio_share_private_env(rtems_id task_id) { rtems_status_code sc; rtems_user_env_t * shared_user_env; @@ -61,21 +126,36 @@ rtems_status_code rtems_libio_share_private_env(rtems_id task_id) { if (rtems_current_user_env->task_id==current_task_id) { /* kill the current user env & task_var*/ - free(rtems_current_user_env); + rtems_user_env_t *tmp = rtems_current_user_env; sc = rtems_task_variable_delete(RTEMS_SELF,(void*)&rtems_current_user_env); if (sc != RTEMS_SUCCESSFUL) return sc; + free_user_env(tmp); }; + /* AT THIS POINT, rtems_current_user_env is DANGLING */ + sc = rtems_task_variable_get(task_id,(void*)&rtems_current_user_env, (void*)&shared_user_env ); - if (sc != RTEMS_SUCCESSFUL) return sc; + if (sc != RTEMS_SUCCESSFUL) + goto bailout; - /* don't free(NULL'ed) at the task_delete. It is a shared var... */ - sc = rtems_task_variable_add(RTEMS_SELF,(void*)&rtems_current_user_env,NULL); - if (sc != RTEMS_SUCCESSFUL) return sc; + sc = rtems_task_variable_add(RTEMS_SELF,(void*)&rtems_current_user_env,free_user_env); + if (sc != RTEMS_SUCCESSFUL) + goto bailout; /* the current_user_env is the same pointer that remote env */ rtems_current_user_env = shared_user_env; + /* increase the reference count */ +#ifdef HAVE_USERENV_REFCNT + rtems_current_user_env->refcnt++; +#endif + return RTEMS_SUCCESSFUL; + +bailout: + /* fallback to the global env */ + rtems_current_user_env = &rtems_global_user_env; + return sc; } +#endif -- cgit v1.2.3