diff --git a/src/logging/spindle_logd.cc b/src/logging/spindle_logd.cc index 62618e62..c1accf3b 100644 --- a/src/logging/spindle_logd.cc +++ b/src/logging/spindle_logd.cc @@ -265,6 +265,7 @@ class TestVerifier { if (strstr(filename, ".so") == NULL && strstr(filename, "retzero") == NULL && + strstr(filename, "bin") == NULL && strstr(filename, ".py") == NULL) return true; bool is_from_temp = (strstr(filename, location) != NULL) && (strncmp(filename, "/__not_exist", 12) != 0); diff --git a/src/server/auditserver/ldcs_audit_server_handlers.c b/src/server/auditserver/ldcs_audit_server_handlers.c index 8a42f40c..0c1ee0c4 100644 --- a/src/server/auditserver/ldcs_audit_server_handlers.c +++ b/src/server/auditserver/ldcs_audit_server_handlers.c @@ -311,11 +311,11 @@ static int handle_client_myrankinfo_msg(ldcs_process_data_t *procdata, int nc, l **/ static int handle_client_file_request(ldcs_process_data_t *procdata, int nc, ldcs_message_t *msg) { - char *pathname; + char *pathname, *last_slash; char file[MAX_PATH_LEN]; char dir[MAX_PATH_LEN]; int is_stat, is_lstat; - int is_loader, is_dso; + int is_loader, is_dso, dir_ends_w_slash = 0; file[0] = '\0'; dir[0] = '\0'; pathname = msg->data; @@ -330,21 +330,23 @@ static int handle_client_file_request(ldcs_process_data_t *procdata, int nc, ldc debug_printf3("Remapping request of %s --> %s\n", pathname, globalname); pathname = globalname; } - - parseFilenameNoAlloc(pathname, file, dir, MAX_PATH_LEN); - /* do initial check of query, parse the filename and store info */ assert(nc != -1); ldcs_client_t *client = procdata->client_table + nc; - addCWDToDir(client->remote_pid, dir, MAX_PATH_LEN); - reducePath(dir); + + /* do initial check of query, parse the filename and store info */ + parseFilenameNoAlloc2(pathname, file, dir, MAX_PATH_LEN, client->remote_pid); + + last_slash = strrchr(dir, '/'); + dir_ends_w_slash = (last_slash && last_slash[1] == '\0'); GCC7_DISABLE_WARNING("-Wformat-truncation"); GCC7_DISABLE_WARNING("-Wstringop-overflow"); strncpy(client->query_filename, file, MAX_PATH_LEN+1); strncpy(client->query_dirname, dir, MAX_PATH_LEN+1); - snprintf(client->query_globalpath, MAX_PATH_LEN+1, "%s/%s", - client->query_dirname, client->query_filename); + debug_printf3("dirname = '%s'\n", client->query_dirname); + snprintf(client->query_globalpath, MAX_PATH_LEN+1, "%s%s%s", + client->query_dirname, dir_ends_w_slash ? "" : "/", client->query_filename); GCC7_ENABLE_WARNING; GCC7_ENABLE_WARNING; @@ -375,8 +377,8 @@ static handle_file_result_t handle_howto_directory(ldcs_process_data_t *procdata int responsible; cache_dir_result = ldcs_cache_findDirInCache(dir); - debug_printf2("Looked for dir in cache... %s\n", - ldcs_cache_result_to_str(cache_dir_result)); + debug_printf2("Looked for dir %s in cache... %s\n", + dir, ldcs_cache_result_to_str(cache_dir_result)); if (cache_dir_result == LDCS_CACHE_DIR_PARSED_AND_EXISTS) { /* Directory was found */ @@ -2246,24 +2248,27 @@ static int handle_fileexist_test(ldcs_process_data_t *procdata, int nc) static int handle_client_fileexist_msg(ldcs_process_data_t *procdata, int nc, ldcs_message_t *msg) { ldcs_client_t *client; - char *pathname; + char *pathname, *last_slash; char file[MAX_PATH_LEN]; char dir[MAX_PATH_LEN]; + int dir_ends_w_slash; file[0] = '\0'; dir[0] = '\0'; pathname = msg->data; - parseFilenameNoAlloc(pathname, file, dir, MAX_PATH_LEN); assert(nc != -1); client = procdata->client_table + nc; - addCWDToDir(client->remote_pid, dir, MAX_PATH_LEN); - reducePath(dir); + parseFilenameNoAlloc2(pathname, file, dir, MAX_PATH_LEN, client->remote_pid); + + last_slash = strrchr(dir, '/'); + dir_ends_w_slash = (last_slash && last_slash[1] == '\0'); GCC7_DISABLE_WARNING("-Wformat-truncation"); strncpy(client->query_filename, file, MAX_PATH_LEN); strncpy(client->query_dirname, dir, MAX_PATH_LEN); - snprintf(client->query_globalpath, MAX_PATH_LEN, "%s/%s", client->query_dirname, client->query_filename); + snprintf(client->query_globalpath, MAX_PATH_LEN, "%s%s%s", client->query_dirname, + dir_ends_w_slash ? "" : "/", client->query_filename); GCC7_ENABLE_WARNING client->query_localpath = NULL; diff --git a/src/utils/pathfn.c b/src/utils/pathfn.c index ac5ace48..d53b3376 100644 --- a/src/utils/pathfn.c +++ b/src/utils/pathfn.c @@ -73,7 +73,12 @@ int parseFilenameNoAlloc(const char *name, char *file, char *dir, int result_siz if (size >= result_size) size = result_size-1; strncpy(dir, name, size); - dir[size] = '\0'; + if (size == 0 && last_slash == name) { + dir[0] = '/'; + size = 1; + } + dir[size] = '\0'; + } else { strncpy(file, name, result_size); @@ -93,6 +98,9 @@ int reducePath(char *dir) int dir_len = strlen(dir); char tmpdir[MAX_PATH_LEN+1]; + if (strcmp(dir, "/") == 0) + return 0; + while (dir[slash_begin]) { slash_end = slash_begin+1; while (dir[slash_end] != '\0' && dir[slash_end] != '/') slash_end++; @@ -138,3 +146,104 @@ char *concatStrings(const char *str1, int str1_len, const char *str2, int str2_l return buffer; } +static int addCWD(pid_t pid, const char *dir, char *target, int result_size) +{ + char cwd_loc[64]; + int result; + + if (dir[0] == '/') + return 0; + + snprintf(cwd_loc, sizeof(cwd_loc)-1, "/proc/%d/cwd", pid); + result = readlink(cwd_loc, target, result_size-1); + if (result == -1) { + int error = errno; + err_printf("Could not read CWD from %s: %s\n", cwd_loc, strerror(error)); + return -1; + } + return 0; +} + +int parseFilenameNoAlloc2(const char *name, char *file, char *dir, int result_size, pid_t pid) +{ + int result; + int dir_end, is_absolute, cur, last_slash; + int component_start, component_end, component_size; + char path_component[MAX_PATH_LEN]; + + memset(file, 0, result_size); + memset(dir, 0, result_size); + + is_absolute = name[0] == '/'; + + /* Add CWD to 'dir' if we're a relative path */ + if (!is_absolute) { + result = addCWD(pid, name, dir, result_size); + if (result == -1) { + err_printf("Aborting path parsing of %s\n", name); + return -1; + } + dir_end = strlen(dir); + if (dir_end > 1 && dir[dir_end-1] != '/') { + dir[dir_end] = '/'; + dir_end++; + } + } + else { + dir[0] = '/'; + dir_end = 1; + } + + /* Go through each path component in 'name' and add it to 'dir'. Resolve ./ and //// + path components as we do so. + Do not resolve .. path components. That needs readlink access to do correctly. + */ + cur = 0; + while (name[cur] != '\0') { + while (name[cur] == '/') cur++; + component_start = cur; + if (name[component_start] == '\0') + break; + while (name[cur] != '/' && name[cur] != '\0') cur++; + component_end = cur; + component_size = component_end - component_start; + strncpy(path_component, name+component_start, component_size); + path_component[component_size] = '\0'; + + if (strcmp(path_component, ".") == 0) { + //Nothing needed + } + /* + else if (strcmp(path_component, "..") == 0) { + while (dir_end > 1 && dir[dir_end-1] == '/') dir_end--; + while (dir_end > 1 && dir[dir_end-1] != '/') dir_end--; + dir[dir_end] = '\0'; + } + */ + else if (path_component[0] != '\0') { + strncpy(dir+dir_end, path_component, component_size); + dir_end += component_size; + dir[dir_end] = '/'; + dir_end++; + dir[dir_end] = '\0'; + } + } + /* Remove the trailing slash we always added to the end of dir. */ + if (dir_end > 1 && dir[dir_end-1] == '/') + dir[dir_end-1] = '\0'; + + /* Copy the final component out of dir and to file */ + last_slash = dir_end; + while (last_slash > 0 && dir[last_slash] != '/') last_slash--; + strncpy(file, dir+last_slash+1, result_size); + + /* Truncate that final slash that seperated the dir and file + (unless it's a root file system file/dir like "/bin" */ + if (last_slash > 0) + dir[last_slash] = '\0'; + else + dir[1] = '\0'; + + return 0; +} + diff --git a/src/utils/pathfn.h b/src/utils/pathfn.h index c396c1ce..e2fce609 100644 --- a/src/utils/pathfn.h +++ b/src/utils/pathfn.h @@ -24,6 +24,7 @@ extern "C" { #endif int parseFilenameNoAlloc(const char *name, char *file, char *dir, int result_size); +int parseFilenameNoAlloc2(const char *name, char *file, char *dir, int result_size, pid_t pid); int addCWDToDir(pid_t pid, char *dir, int result_size); int reducePath(char *dir); char *concatStrings(const char *str1, int str1_len, const char *str2, int str2_len); diff --git a/testsuite/Makefile.am b/testsuite/Makefile.am index e663f12c..0ba9638f 100644 --- a/testsuite/Makefile.am +++ b/testsuite/Makefile.am @@ -1,7 +1,7 @@ noinst_PROGRAMS = libgenerator ABS_TEST_DIR = $(abspath $(top_builddir)/testsuite) -BUILT_SOURCES = libtest10.so libtest11.so libtest12.so libtest13.so libtest14.so libtest15.so libtest16.so libtest17.so libtest18.so libtest19.so libtest20.so libtest50.so libtest100.so libtest500.so libtest1000.so libtest2000.so libtest4000.so libtest6000.so libtest8000.so libtest10000.so libtls1.c libtls2.c libtls3.c libtls4.c libtls5.c libtls6.c libtls7.c libtls8.c libtls9.c libtls10.c libtls11.c libtls12.c libtls13.c libtls14.c libtls15.c libtls16.c libtls17.c libtls18.c libtls19.c libtls20.c libsymlink.so libdepC.so libdepB.so libdepA.so libcxxexceptB.so libcxxexceptA.so origin_dir/liboriginlib.so origin_dir/origin_subdir/liborigintarget.so libtestoutput.so libfuncdict.so runTests run_driver run_driver_rm spindle.rc preload_file_list test_driver test_driver_libs retzero_rx retzero_r retzero_x retzero_ badinterp hello_r.py hello_x.py hello_rx.py hello_.py hello_l.py badlink.py spindle_exec_test spindle_deactivated.sh liblocal.so symbind_test interpreter_test interpreter_test_dir/interpreter_test_perl +BUILT_SOURCES = libtest10.so libtest11.so libtest12.so libtest13.so libtest14.so libtest15.so libtest16.so libtest17.so libtest18.so libtest19.so libtest20.so libtest50.so libtest100.so libtest500.so libtest1000.so libtest2000.so libtest4000.so libtest6000.so libtest8000.so libtest10000.so libtls1.c libtls2.c libtls3.c libtls4.c libtls5.c libtls6.c libtls7.c libtls8.c libtls9.c libtls10.c libtls11.c libtls12.c libtls13.c libtls14.c libtls15.c libtls16.c libtls17.c libtls18.c libtls19.c libtls20.c libsymlink.so libdepC.so libdepB.so libdepA.so libcxxexceptB.so libcxxexceptA.so origin_dir/liboriginlib.so origin_dir/origin_subdir/liborigintarget.so libtestoutput.so libfuncdict.so runTests run_driver run_driver_rm spindle.rc preload_file_list test_driver test_driver_libs retzero_rx retzero_r retzero_x retzero_ badinterp hello_r.py hello_x.py hello_rx.py hello_.py hello_l.py badlink.py spindle_exec_test spindle_deactivated.sh liblocal.so symbind_test interpreter_test interpreter_test_dir/interpreter_test_perl alias/aliastest.py if BGQ_BLD DYNAMIC_FLAG=-dynamic @@ -380,6 +380,9 @@ badlink.py: ln -fs noexist.py $@; \ fi +alias/aliastest.py: + $(AM_V_GEN)mkdir -p alias/real1/real2 ; echo "fail" > alias/aliastest.py ; echo "pass" > alias/real1/aliastest.py ; ln -s real1/real2 alias/lnk + spindle_deactivated.sh: spindle_deactivated_template.sh $(AM_V_GEN)cp $< $@; chmod 700 $@ @@ -417,4 +420,4 @@ interpreter_test_dir/interpreter_test_perl: interpreter_test_perl_template inter interpreter_test: interpreter_test_template $(AM_V_GEN)cp $< $@; chmod 700 $@ -CLEANFILES = libtest10.c libtest11.c libtest12.c libtest13.c libtest14.c libtest15.c libtest16.c libtest17.c libtest18.c libtest19.c libtest20.c libtest10.so libtest50.c libtest50.so libtest100.c libtest100.so libtest500.c libtest500.so libtest1000.c libtest1000.so libtest2000.c libtest2000.so libtest4000.c libtest4000.so libtest6000.c libtest6000.so libtest8000.c libtest8000.so libtest10000.c libtest10000.so libsymlink.so libdepA.so libdepB.so libdepC.so libcxxexceptA.so libcxxexceptB.so libtestoutput.so libfuncdict.so runTests run_driver run_driver_rm spindle.rc test_driver test_driver_libs preload_file_list retzero_rx retzero_r retzero_x retzero_ badinterp hello_r.py hello_x.py hello_rx.py hello_.py hello_l.py badlink.py libtls1.c libtls2.c libtls3.c libtls4.c libtls5.c libtls6.c libtls7.c libtls8.c libtls9.c libtls10.c libtls11.c libtls12.c libtls13.c libtls14.c libtls15.c libtls16.c libtls17.c libtls18.c libtls19.c libtls20.c libtls1.so libtls2.so libtls3.so libtls4.so libtls5.so libtls6.so libtls7.so libtls8.so libtls9.so libtls10.so libtls11.so libtls12.so libtls13.so libtls14.so libtls15.so libtls16.so libtls17.so libtls18.so libtls19.so libtls20.so symbind_test libsymbind_a.so libsymbind_b.so libsymbind_c.so libsymbind_d.so libsymbind_e.so libsymbind_f.so libsymbind_g.so interpreter_test interpreter_test_dir/interpreter_test_perl +CLEANFILES = libtest10.c libtest11.c libtest12.c libtest13.c libtest14.c libtest15.c libtest16.c libtest17.c libtest18.c libtest19.c libtest20.c libtest10.so libtest50.c libtest50.so libtest100.c libtest100.so libtest500.c libtest500.so libtest1000.c libtest1000.so libtest2000.c libtest2000.so libtest4000.c libtest4000.so libtest6000.c libtest6000.so libtest8000.c libtest8000.so libtest10000.c libtest10000.so libsymlink.so libdepA.so libdepB.so libdepC.so libcxxexceptA.so libcxxexceptB.so libtestoutput.so libfuncdict.so runTests run_driver run_driver_rm spindle.rc test_driver test_driver_libs preload_file_list retzero_rx retzero_r retzero_x retzero_ badinterp hello_r.py hello_x.py hello_rx.py hello_.py hello_l.py badlink.py libtls1.c libtls2.c libtls3.c libtls4.c libtls5.c libtls6.c libtls7.c libtls8.c libtls9.c libtls10.c libtls11.c libtls12.c libtls13.c libtls14.c libtls15.c libtls16.c libtls17.c libtls18.c libtls19.c libtls20.c libtls1.so libtls2.so libtls3.so libtls4.so libtls5.so libtls6.so libtls7.so libtls8.so libtls9.so libtls10.so libtls11.so libtls12.so libtls13.so libtls14.so libtls15.so libtls16.so libtls17.so libtls18.so libtls19.so libtls20.so symbind_test libsymbind_a.so libsymbind_b.so libsymbind_c.so libsymbind_d.so libsymbind_e.so libsymbind_f.so libsymbind_g.so interpreter_test interpreter_test_dir/interpreter_test_perl alias diff --git a/testsuite/Makefile.in b/testsuite/Makefile.in index 9c225322..9d513046 100644 --- a/testsuite/Makefile.in +++ b/testsuite/Makefile.in @@ -355,7 +355,8 @@ BUILT_SOURCES = libtest10.so libtest11.so libtest12.so libtest13.so \ retzero_r retzero_x retzero_ badinterp hello_r.py hello_x.py \ hello_rx.py hello_.py hello_l.py badlink.py spindle_exec_test \ spindle_deactivated.sh liblocal.so symbind_test \ - interpreter_test interpreter_test_dir/interpreter_test_perl + interpreter_test interpreter_test_dir/interpreter_test_perl \ + alias/aliastest.py @BGQ_BLD_FALSE@DYNAMIC_FLAG = @BGQ_BLD_TRUE@DYNAMIC_FLAG = -dynamic @BGQ_BLD_FALSE@IS_BLUEGENE = false @@ -395,7 +396,7 @@ CLEANFILES = libtest10.c libtest11.c libtest12.c libtest13.c \ libsymbind_a.so libsymbind_b.so libsymbind_c.so \ libsymbind_d.so libsymbind_e.so libsymbind_f.so \ libsymbind_g.so interpreter_test \ - interpreter_test_dir/interpreter_test_perl + interpreter_test_dir/interpreter_test_perl alias all: $(BUILT_SOURCES) $(MAKE) $(AM_MAKEFLAGS) all-am @@ -1055,6 +1056,9 @@ badlink.py: ln -fs noexist.py $@; \ fi +alias/aliastest.py: + $(AM_V_GEN)mkdir -p alias/real1/real2 ; echo "fail" > alias/aliastest.py ; echo "pass" > alias/real1/aliastest.py ; ln -s real1/real2 alias/lnk + spindle_deactivated.sh: spindle_deactivated_template.sh $(AM_V_GEN)cp $< $@; chmod 700 $@ diff --git a/testsuite/test_driver.c b/testsuite/test_driver.c index 13f63fea..acdc54e5 100644 --- a/testsuite/test_driver.c +++ b/testsuite/test_driver.c @@ -827,6 +827,7 @@ static int run_execs() #define STAT 1 #define LSTAT 2 #define FSTAT 4 +#define SPINDLE_STAT 8 static dev_t device; static int run_stat_test(const char *file, int flags, mode_t prot, int expected) { @@ -836,7 +837,7 @@ static int run_stat_test(const char *file, int flags, mode_t prot, int expected) const char *statname = NULL; if (expected == 0) - test_printf("dlstart %s\n", file); + test_printf("dlstart %s\n", file[0] != '/' ? file : file+1); if (flags & LSTAT) { statname = "lstat"; result = lstat(file, &buf); @@ -851,21 +852,25 @@ static int run_stat_test(const char *file, int flags, mode_t prot, int expected) statname = "stat"; result = stat(file, &buf); } + else if (flags & SPINDLE_STAT) { + statname = "spindle_stat"; + result = spindle_stat(file, &buf); + } if (result == -1) result = errno; if (fd != -1) close(fd); if (result != expected) { - err_printf("Expected return value %d, got return value %d from %s test of %s\n", - expected, result, statname, file); + err_printf("Expected return value %d, got return value %d (%s) from %s test of %s\n", + expected, result, strerror(result), statname, file); return -1; } if (result) //Expected error return, do not test buf return 0; - if (buf.st_dev != device) { + if (buf.st_dev != device && !(flags & SPINDLE_STAT)) { err_printf("Expected device %d, got device %d on %s test of %s\n", (int) device, (int) buf.st_dev, statname, file); return -1; @@ -875,7 +880,7 @@ static int run_stat_test(const char *file, int flags, mode_t prot, int expected) prot, buf.st_mode & 0700, statname, file); return -1; } - + return 0; } @@ -937,6 +942,8 @@ static int run_stats() result |= run_stat_test("badlink.py", LSTAT, 0700, 0); result |= run_stat_test(".", LSTAT, 0000, 0); result |= run_stat_test(NULL, LSTAT, 0000, EFAULT); + + result |= run_stat_test("/bin", SPINDLE_STAT, 0000, 0); return result; } @@ -1022,6 +1029,88 @@ static int run_readlinks() return result; } +static int run_alias_test(char *path, int expected_err) { + int fd, result, error; + char buffer[5]; + fd = open(path, O_RDONLY); + if (fd == -1) { + error = errno; + if (!expected_err) { + err_printf("alias_test %s: open expected success, but got error %s (%d)\n", path, strerror(error), error); + return -1; + } + else if (error != expected_err) { + err_printf("alias_test %s: open returned wrong error. Expected %s (%d), got %s (%d)\n", + path, strerror(expected_err), expected_err, strerror(error), error); + return -1; + } + else { + return 0; + } + } + if (fd >= 0 && expected_err) { + err_printf("alias_test %s: open expected error %s (%d), but returned succcess\n", path, strerror(expected_err), expected_err); + close(fd); + return -1; + } + + result = read(fd, buffer, 4); + if (result == -1) { + error = errno; + err_printf("alias_test %s: error reading from buffer: %s (%d)\n", path, strerror(error), error); + close(fd); + return -1; + } + + buffer[4] = '\0'; + if (strcmp(buffer, "pass") != 0) { + err_printf("alias_test %s: Did not read correct file. Got string '%s' from file\n", path, buffer); + close(fd); + return -1; + } + + close(fd); + return 0; +} + +int run_alias_tests() +{ + int result = 0, i; + int slashes_in_cwd = 0; + char path[4096]; + char cwd[4096]; + char slashes[4096]; + + if (chdir_mode) + return 0; + + slashes[0] = '\0'; + getcwd(cwd, 4096); + + for (i = 0; cwd[i] != '\0'; i++) + if (cwd[i] == '/') slashes_in_cwd++; + + for (i = 0; i < slashes_in_cwd + 2; i++) { + strncat(slashes, "../", 4096 - (i * 3)); + } + + result |= run_alias_test("alias/lnk/../aliastest.py", 0); + result |= run_alias_test("./alias/real1/aliastest.py", 0); + result |= run_alias_test("./alias/real1/real2/../aliastest.py", 0); + result |= run_alias_test("./alias////./lnk//../////./aliastest.py", 0); + result |= run_alias_test("alias/lnk/../real2/../aliastest.py", 0); + + snprintf(path, 4096, "%s/alias/real1/aliastest.py", cwd); + result |= run_alias_test(path, 0); + + snprintf(path, 4096, "/%s/alias/real1/aliastest.py", cwd); + result |= run_alias_test(path, 0); + + snprintf(path, 4096, "%s/%s/alias/real1/aliastest.py", slashes, cwd); + result |= run_alias_test(path, 0); + + return result; +} void push_cwd() { @@ -1366,7 +1455,11 @@ int run_test() run_readlinks(); if (had_error) return -1; - + + run_alias_tests(); + if (had_error) + return -1; + check_libraries(); if (had_error) return -1;