diff --git a/scratchbox2/execs/sb_exec.c b/scratchbox2/execs/sb_exec.c index 61ae917..635e1b4 100644 --- a/scratchbox2/execs/sb_exec.c +++ b/scratchbox2/execs/sb_exec.c @@ -1462,6 +1462,17 @@ static int prepare_exec(const char *exec_fn_name, exec_policy_name = (mapping_result.mres_exec_policy_name ? strdup(mapping_result.mres_exec_policy_name) : NULL); STOP_AND_REPORT_PROCESSCLOCK(SB_LOGLEVEL_INFO, &clk3, mapped_file); + + if (mapping_result.mres_errno) { + int saved_errno = mapping_result.mres_errno; + SB_LOG(SB_LOGLEVEL_DEBUG, + "Mapping failed (%s) => errno=%d", + my_file, mapping_result.mres_errno); + free_mapping_results(&mapping_result); + errno = saved_errno; + ret = -1; + goto out; + } free_mapping_results(&mapping_result); @@ -1664,8 +1675,10 @@ static int prepare_exec(const char *exec_fn_name, *new_file = mapped_file; *new_argv = my_argv; *new_envp = my_envp; + err = errno; STOP_AND_REPORT_PROCESSCLOCK(SB_LOGLEVEL_INFO, &clk1, orig_file); if (info.pt_interp) free(info.pt_interp); + errno = err; return(ret); } @@ -1712,15 +1725,17 @@ int do_exec(int *result_errno_ptr, &type, &new_file, &new_argv, &new_envp); if (SB_LOG_IS_ACTIVE(SB_LOGLEVEL_DEBUG)) { + int saved_errno = errno; /* find out and log if preprocessing did something */ compare_and_log_strvec_changes("argv", orig_argv, new_argv); compare_and_log_strvec_changes("envp", my_envp_copy, new_envp); + errno = saved_errno; } if (r < 0) { + *result_errno_ptr = errno; SB_LOG(SB_LOGLEVEL_DEBUG, "EXEC denied by prepare_exec(), %s", orig_file); - *result_errno_ptr = errno; STOP_AND_REPORT_PROCESSCLOCK(SB_LOGLEVEL_INFO, &clk1, "Exec denied"); return(r); /* exec denied */ } diff --git a/scratchbox2/include/mapping.h b/scratchbox2/include/mapping.h index 94dea88..ca5c841 100644 --- a/scratchbox2/include/mapping.h +++ b/scratchbox2/include/mapping.h @@ -73,18 +73,22 @@ extern void free_mapping_results(mapping_results_t *res); extern void force_path_to_mapping_result(mapping_results_t *res, const char *path); +#define SBOX_MAP_PATH_DONT_RESOLVE_FINAL_SYMLINK 0x01 +#define SBOX_MAP_PATH_ALLOW_NONEXISTENT 0x02 + extern void sbox_map_path(const char *func_name, const char *path, - int dont_resolve_final_symlink, mapping_results_t *res, uint32_t classmask); + uint32_t flags, mapping_results_t *res, uint32_t classmask); extern void sbox_map_path_at(const char *func_name, int dirfd, - const char *path, int dont_resolve_final_symlink, + const char *path, uint32_t flags, mapping_results_t *res, uint32_t classmask); extern char *sbox_virtual_path_to_abs_virtual_path( const char *binary_name, const char *func_name, uint32_t fn_class, - const char *virtual_orig_path); + const char *virtual_orig_path, + int *res_errno); extern void sbox_map_path_for_sb2show(const char *binary_name, const char *func_name, const char *path, mapping_results_t *res); @@ -94,7 +98,7 @@ extern void sbox_map_path_for_exec(const char *func_name, const char *path, extern void custom_map_path(const char *binary_name, const char *func_name, const char *virtual_path, - int dont_resolve_final_symlink, uint32_t fn_class, + uint32_t flags, uint32_t fn_class, mapping_results_t *res, ruletree_object_offset_t rule_list_offset); extern char *custom_map_abstract_path( diff --git a/scratchbox2/pathmapping/pathlistutils.c b/scratchbox2/pathmapping/pathlistutils.c index 1cc3fe6..ce79a7e 100644 --- a/scratchbox2/pathmapping/pathlistutils.c +++ b/scratchbox2/pathmapping/pathlistutils.c @@ -188,23 +188,24 @@ struct path_entry *split_path_to_path_entries( } do { + int len; + next_slash = strchr(start, '/'); + if (next_slash) { + len = next_slash - start; + } else { + /* no more slashes */ + len = strlen(start); + } /* ignore empty strings resulting from // */ - if (next_slash != start) { + if (len == 0) { + /* but notice if there is trailing slash */ + if (!next_slash) + flags |= PATH_FLAGS_HAS_TRAILING_SLASH; + } else { struct path_entry *new; - int len; - - if (next_slash) { - len = next_slash - start; - if (!next_slash[1]) { - flags |= PATH_FLAGS_HAS_TRAILING_SLASH; - next_slash = NULL; - } - } else { - /* no more slashes */ - len = strlen(start); - } + new = malloc(sizeof(struct path_entry) + len); if(!first) first = new; if (!new) abort(); @@ -400,7 +401,12 @@ char *clean_and_log_fs_mapping_result( * recursive calls to sb_path_resolution. */ remove_dots_from_path_list(&list); - clean_dotdots_from_path(ctx, &list); + if (clean_dotdots_from_path(ctx, &list)) { + SB_LOG(result_log_level, "fail: %s '%s'", + ctx->pmc_func_name, abs_clean_virtual_path); + free_path_list(&list); + return(NULL); + } break; } cleaned_host_path = path_list_to_string(&list); diff --git a/scratchbox2/pathmapping/pathmapping.h b/scratchbox2/pathmapping/pathmapping.h index 8f14414..089ee3c 100644 --- a/scratchbox2/pathmapping/pathmapping.h +++ b/scratchbox2/pathmapping/pathmapping.h @@ -86,6 +86,9 @@ typedef struct path_mapping_context_s { uint32_t pmc_fn_class; const char *pmc_virtual_orig_path; int pmc_dont_resolve_final_symlink; + int pmc_file_must_exist; + int pmc_must_be_directory; + int pmc_allow_nonexistent; struct sb2context *pmc_sb2ctx; /* for paths_ruletree_mapping.c: */ @@ -151,7 +154,7 @@ extern ruletree_object_offset_t ruletree_get_mapping_requirements( extern void remove_dots_from_path_list(struct path_entry_list *listp); /* "complex" path cleaning (may call path resolution recursively): */ -extern void clean_dotdots_from_path( +extern int clean_dotdots_from_path( const path_mapping_context_t *ctx, struct path_entry_list *abs_path); @@ -160,7 +163,7 @@ extern void sbox_map_path_internal__lua_engine( const char *binary_name, const char *func_name, const char *virtual_orig_path, - int dont_resolve_final_symlink, + uint32_t flags, int process_path_for_exec, uint32_t fn_class, mapping_results_t *res); @@ -170,7 +173,7 @@ extern void sbox_map_path_internal__c_engine( const char *binary_name, const char *func_name, const char *virtual_orig_path, - int dont_resolve_final_symlink, + uint32_t flags, int process_path_for_exec, uint32_t fn_class, mapping_results_t *res, diff --git a/scratchbox2/pathmapping/pathmapping_interf.c b/scratchbox2/pathmapping/pathmapping_interf.c index 095f697..fdc0c90 100644 --- a/scratchbox2/pathmapping/pathmapping_interf.c +++ b/scratchbox2/pathmapping/pathmapping_interf.c @@ -29,7 +29,7 @@ static void fwd_map_path( const char *binary_name, const char *func_name, const char *virtual_path, - int dont_resolve_final_symlink, + uint32_t flags, int exec_mode, uint32_t fn_class, mapping_results_t *res) @@ -49,7 +49,7 @@ static void fwd_map_path( START_PROCESSCLOCK(SB_LOGLEVEL_INFO, &clk1, "fwd_map_path"); sbox_map_path_internal__c_engine(sb2ctx, binary_name, func_name, virtual_path, - dont_resolve_final_symlink, 0, fn_class, res, 0); + flags, 0, fn_class, res, 0); if (res->mres_errormsg) { SB_LOG(SB_LOGLEVEL_NOTICE, "C path mapping engine failed (%s) (%s)", @@ -70,7 +70,7 @@ void custom_map_path( const char *binary_name, const char *func_name, const char *virtual_path, - int dont_resolve_final_symlink, + uint32_t flags, uint32_t fn_class, mapping_results_t *res, ruletree_object_offset_t rule_list_offset) @@ -91,7 +91,7 @@ void custom_map_path( sbox_map_path_internal__c_engine(sb2ctx, binary_name, func_name, virtual_path, - dont_resolve_final_symlink, 0, fn_class, res, rule_list_offset); + flags, 0, fn_class, res, rule_list_offset); if (res->mres_fallback_to_lua_mapping_engine && (res->mres_fallback_to_lua_mapping_engine[0] == '#')) { @@ -217,20 +217,20 @@ void sbox_map_path_for_sb2show( } fwd_map_path(binary_name, func_name, virtual_path, - 0/*dont_resolve_final_symlink*/, 0/*exec_mode*/, fn_class, res); + 0/*flags*/, 0/*exec_mode*/, fn_class, res); } void sbox_map_path( const char *func_name, const char *virtual_path, - int dont_resolve_final_symlink, + uint32_t flags, mapping_results_t *res, uint32_t classmask) { fwd_map_path( (sbox_binary_name ? sbox_binary_name : "UNKNOWN"), func_name, virtual_path, - dont_resolve_final_symlink, 0/*exec_mode*/, classmask, res); + flags, 0/*exec_mode*/, classmask, res); } @@ -238,7 +238,7 @@ void sbox_map_path_at( const char *func_name, int dirfd, const char *virtual_path, - int dont_resolve_final_symlink, + uint32_t flags, mapping_results_t *res, uint32_t classmask) { @@ -259,7 +259,7 @@ void sbox_map_path_at( fwd_map_path( (sbox_binary_name ? sbox_binary_name : "UNKNOWN"), func_name, virtual_path, - dont_resolve_final_symlink, 0/*exec_mode*/, classmask, res); + flags, 0/*exec_mode*/, classmask, res); return; } @@ -281,7 +281,7 @@ void sbox_map_path_at( fwd_map_path( (sbox_binary_name ? sbox_binary_name : "UNKNOWN"), func_name, - virtual_abs_path_at_fd, dont_resolve_final_symlink, 0/*exec_mode*/, classmask, res); + virtual_abs_path_at_fd, flags, 0/*exec_mode*/, classmask, res); free(virtual_abs_path_at_fd); return; @@ -307,7 +307,7 @@ void sbox_map_path_for_exec( fwd_map_path( (sbox_binary_name ? sbox_binary_name : "UNKNOWN"), func_name, - virtual_path, 0/*dont_resolve_final_symlink*/, 1/*exec mode*/, + virtual_path, 0/*flags*/, 1/*exec mode*/, SB2_INTERFACE_CLASS_EXEC, res); } diff --git a/scratchbox2/pathmapping/pathresolution.c b/scratchbox2/pathmapping/pathresolution.c index 28d9504..b1a0fc2 100644 --- a/scratchbox2/pathmapping/pathresolution.c +++ b/scratchbox2/pathmapping/pathresolution.c @@ -84,6 +84,7 @@ #include "libsb2.h" #include "exported.h" #include "sb2_vperm.h" +#include "sb2_stat.h" #ifdef EXTREME_DEBUGGING #include @@ -169,12 +170,24 @@ static ruletree_object_offset_t sb_path_resolution( * by accident. * Can be used for both virtual paths and host paths. */ -void clean_dotdots_from_path( +int clean_dotdots_from_path( const path_mapping_context_t *ctx, struct path_entry_list *abs_path) { struct path_entry *work; int path_has_nontrivial_dotdots = 0; + path_mapping_context_t ctx2; + + /* Don't propagate pmc_dont_resolve_final_symlink flag + * to further recursive path resolution: + * we need to resolve final symlink before ".." component. + * Also, path before ".." must be an existing directory. + */ + ctx2 = *ctx; + ctx2.pmc_dont_resolve_final_symlink = 0; + ctx2.pmc_file_must_exist = 1; + ctx2.pmc_must_be_directory = 1; + ctx = &ctx2; if (SB_LOG_IS_ACTIVE(SB_LOGLEVEL_NOISE)) { char *tmp_path_buf = path_list_to_string(abs_path); @@ -315,6 +328,16 @@ void clean_dotdots_from_path( } free_path_list(&abs_path_to_parent); + if (resolved_parent_location.mres_errno) { + int err = resolved_parent_location.mres_errno; + SB_LOG(SB_LOGLEVEL_NOISE, + "clean_dotdots_from_path: <3>:errno=%d", + err); + free(orig_path_to_parent); + free_mapping_results(&resolved_parent_location); + return(err); + } + /* mres_result_buf contains an absolute path, * unless the result was longer than PATH_MAX */ if (strcmp(orig_path_to_parent, @@ -355,8 +378,7 @@ void clean_dotdots_from_path( free_mapping_results(&resolved_parent_location); /* restart from the beginning of the new path: */ - clean_dotdots_from_path(ctx, abs_path); - return; + return(clean_dotdots_from_path(ctx, abs_path)); } SB_LOG(SB_LOGLEVEL_NOISE, @@ -384,6 +406,7 @@ void clean_dotdots_from_path( "clean_dotdots_from_path: result->'%s'", tmp_path_buf); free(tmp_path_buf); } + return(0); } /* ========== ========== */ @@ -613,8 +636,54 @@ static ruletree_object_offset_t sb_path_resolution( link_dest[link_len] = '\0'; virtual_path_work_ptr->pe_link_dest = strdup(link_dest); virtual_path_work_ptr->pe_flags |= PATH_FLAGS_IS_SYMLINK; - } else { + } else if (errno == EINVAL) { + /* was not a symlink */ + if (ctx->pmc_must_be_directory && + virtual_path_work_ptr->pe_next == NULL) { + /* must be a directory, check it */ + struct stat statbuf; + if (real_stat(prefix_mapping_result_host_path, &statbuf) < 0) { + resolved_virtual_path_res->mres_errno = errno; + SB_LOG(SB_LOGLEVEL_NOISE, + "Path resolution failed, unable to stat directory, errno=%d", + resolved_virtual_path_res->mres_errno); + free(prefix_mapping_result_host_path); + return(0); + } + if (!S_ISDIR(statbuf.st_mode)) { + resolved_virtual_path_res->mres_errno = ENOTDIR; + SB_LOG(SB_LOGLEVEL_NOISE, + "Path resolution failed, last component is not a directory"); + free(prefix_mapping_result_host_path); + return(0); + } + } virtual_path_work_ptr->pe_flags |= PATH_FLAGS_NOT_SYMLINK; + } else if (errno == ENOENT && + !ctx->pmc_file_must_exist && + (virtual_path_work_ptr->pe_next == NULL)) { + /* this is last component, + * and it's not required to exist. + */ + SB_LOG(SB_LOGLEVEL_NOISE2, + "Last component doesn't exist [%d] '%s'", + component_index, virtual_path_work_ptr->pe_path_component); + } else if (errno == ENOENT && + ctx->pmc_allow_nonexistent) { + /* this is not last component, + * but it's still not required to exist. + */ + SB_LOG(SB_LOGLEVEL_NOISE3, + "Component doesn't exist [%d] '%s'", + component_index, virtual_path_work_ptr->pe_path_component); + } else { + /* any other errno valus is error */ + resolved_virtual_path_res->mres_errno = errno; + SB_LOG(SB_LOGLEVEL_NOISE, + "Path resolution failed, errno=%d", + resolved_virtual_path_res->mres_errno); + free(prefix_mapping_result_host_path); + return(0); } } @@ -731,6 +800,7 @@ static ruletree_object_offset_t sb_path_resolution_resolve_symlink( ruletree_object_offset_t rule_offs; struct path_entry *rest_of_virtual_path = NULL; struct path_entry_list new_abs_virtual_link_dest_path_list; + int err; new_abs_virtual_link_dest_path_list.pl_first = NULL; @@ -877,7 +947,15 @@ static ruletree_object_offset_t sb_path_resolution_resolve_symlink( break; case 2: /* .. */ remove_dots_from_path_list(&new_abs_virtual_link_dest_path_list); - clean_dotdots_from_path(ctx, &new_abs_virtual_link_dest_path_list); + err = clean_dotdots_from_path(ctx, &new_abs_virtual_link_dest_path_list); + if (err) { + SB_LOG(SB_LOGLEVEL_DEBUG, + "unable to clean \"..\" from path, errno=%d", + err); + free_path_list(&new_abs_virtual_link_dest_path_list); + resolved_virtual_path_res->mres_errno = err; + return(0); + } break; } @@ -993,7 +1071,7 @@ static int relative_virtual_path_to_abs_path( set_flags_in_path_entries(cwd_entries, PATH_FLAGS_NOT_SYMLINK); path_list->pl_first = append_path_entries( cwd_entries, path_list->pl_first); - path_list->pl_flags |= cwd_flags; + path_list->pl_flags |= cwd_flags & ~PATH_FLAGS_HAS_TRAILING_SLASH; #if 0 SB_LOG(SB_LOGLEVEL_DEBUG, "relative_virtual_path_to_abs_path: abs.path is '%s'", @@ -1018,12 +1096,14 @@ char *sbox_virtual_path_to_abs_virtual_path( const char *binary_name, const char *func_name, uint32_t fn_class, - const char *virtual_orig_path) + const char *virtual_orig_path, + int *res_errno) { path_mapping_context_t ctx; struct path_entry_list abs_virtual_path_list; char *result = NULL; char host_cwd[PATH_MAX + 1]; + int err; clear_path_entry_list(&abs_virtual_path_list); @@ -1093,7 +1173,16 @@ char *sbox_virtual_path_to_abs_virtual_path( break; case 2: /* .. */ remove_dots_from_path_list(&abs_virtual_path_list); - clean_dotdots_from_path(&ctx, &abs_virtual_path_list); + err = clean_dotdots_from_path(&ctx, &abs_virtual_path_list); + if (err) { + SB_LOG(SB_LOGLEVEL_DEBUG, + "unable to clean \"..\" from path, errno=%d", + err); + free_path_list(&abs_virtual_path_list); + *res_errno = err; + result = NULL; + goto out; + } break; } @@ -1143,7 +1232,7 @@ void sbox_map_path_internal__c_engine( const char *binary_name, const char *func_name, const char *virtual_orig_path, - int dont_resolve_final_symlink, + uint32_t flags, int process_path_for_exec, uint32_t fn_class, mapping_results_t *res, @@ -1153,6 +1242,7 @@ void sbox_map_path_internal__c_engine( path_mapping_context_t ctx; char host_cwd[PATH_MAX + 1]; /* used only if virtual_orig_path is relative */ struct path_entry_list abs_virtual_path_for_rule_selection_list; + int err; clear_path_entry_list(&abs_virtual_path_for_rule_selection_list); clear_path_mapping_context(&ctx); @@ -1160,7 +1250,9 @@ void sbox_map_path_internal__c_engine( ctx.pmc_func_name = func_name; ctx.pmc_fn_class = fn_class; ctx.pmc_virtual_orig_path = virtual_orig_path; - ctx.pmc_dont_resolve_final_symlink = dont_resolve_final_symlink; + ctx.pmc_dont_resolve_final_symlink = + flags & SBOX_MAP_PATH_DONT_RESOLVE_FINAL_SYMLINK; + ctx.pmc_allow_nonexistent = flags & SBOX_MAP_PATH_ALLOW_NONEXISTENT; ctx.pmc_sb2ctx = sb2ctx; #if 0 /* see comment at pathmapping_interf.c/custom_map_path() */ ctx.pmc_rule_list_offset = rule_list_offset; @@ -1268,7 +1360,14 @@ void sbox_map_path_internal__c_engine( break; case 2: /* .. */ remove_dots_from_path_list(&abs_virtual_path_for_rule_selection_list); - clean_dotdots_from_path(&ctx, &abs_virtual_path_for_rule_selection_list); + err = clean_dotdots_from_path(&ctx, &abs_virtual_path_for_rule_selection_list); + if (err) { + SB_LOG(SB_LOGLEVEL_DEBUG, + "unable to clean \"..\" from path, errno=%d", + err); + res->mres_errno = err; + return; + } break; } diff --git a/scratchbox2/pathmapping/paths_ruletree_mapping.c b/scratchbox2/pathmapping/paths_ruletree_mapping.c index 24e41ae..cdf8490 100644 --- a/scratchbox2/pathmapping/paths_ruletree_mapping.c +++ b/scratchbox2/pathmapping/paths_ruletree_mapping.c @@ -826,6 +826,12 @@ char *ruletree_translate_path( } else { char *new_host_path = clean_and_log_fs_mapping_result(ctx, abs_clean_virtual_path, result_log_level, host_path, *flagsp); + if (new_host_path == NULL) { + SB_LOG(result_log_level, + "Mapping failed ('%s')", + abs_clean_virtual_path); + *errormsgp = "Mapping failed"; + } free(host_path); host_path = new_host_path; } diff --git a/scratchbox2/preload/chrootgate.c b/scratchbox2/preload/chrootgate.c index 4f70218..a42f508 100644 --- a/scratchbox2/preload/chrootgate.c +++ b/scratchbox2/preload/chrootgate.c @@ -62,12 +62,19 @@ int chroot_gate(int *result_errno_ptr, /* sbox_virtual_path_to_abs_virtual_path() will clean it */ new_chroot_path = sbox_virtual_path_to_abs_virtual_path( sbox_binary_name, realfnname, SB2_INTERFACE_CLASS_CHROOT, - path2); + path2, result_errno_ptr); } else { /* "path" is relative to CWD. */ new_chroot_path = sbox_virtual_path_to_abs_virtual_path( sbox_binary_name, realfnname, SB2_INTERFACE_CLASS_CHROOT, + path, result_errno_ptr); + } + + if (new_chroot_path == NULL) { + SB_LOG(SB_LOGLEVEL_DEBUG, + "chroot: unable to make virtual path absolute: %s", path); + goto free_mapping_results_and_return_minus1; } if (!strcmp(new_chroot_path, "/")) { diff --git a/scratchbox2/preload/gen-interface.pl b/scratchbox2/preload/gen-interface.pl index f231dd1..fbc35ba 100755 --- a/scratchbox2/preload/gen-interface.pl +++ b/scratchbox2/preload/gen-interface.pl @@ -63,6 +63,14 @@ # NOTE: THIS MUST BE USED BEFORE THE map() OR map_at() MODIFIERS! # - "resolve_final_symlink" is the opposite of "dont_resolve_final_symlink" # (and it is on by default) +# - "allow_nonexistent" is used to prefix "map" modifiers where the +# whole pathname (not just the last component) is allowed to refer +# to nonexistent file in nonexistent directory. +# NOTE: THIS MUST BE USED BEFORE THE map() OR map_at() MODIFIERS! +# - "allow_nonexistent_if(condition)" conditionally +# allows the pathname to refer to nonexistent file in nonexistent directory +# (see "allow_nonexistent") +# NOTE: THIS MUST BE USED BEFORE THE map() OR map_at() MODIFIERS! # - "postprocess(varname)" can be used to call postprocessor functions for # mapped variables. # - "return(expr)" can be used to alter the return value. @@ -485,6 +493,30 @@ sub class_list_to_expr { return ('('.join(' | ',@class_arr).')'); } +sub expr_to_flagexpr { + my $expr = shift; + my $flag = shift; + return "0" if ($expr eq "0"); + return $flag if $expr eq "1"; + return "($expr ? $flag : 0)"; +} + +sub flagexpr_join { + my $result = "0"; + foreach my $flagexpr (@_) { + if ($flagexpr eq "0") { + # zero flag, leave result as is + } elsif ($result eq "0") { + # zero result, replace with flag + $result = $flagexpr; + } else { + # non-zero result and flag, join with | + $result .= " | $flagexpr"; + } + } + return $result; +} + # Process the modifier section coming from the original input line. # This returns undef if failed, or a structure containing code fragments # and other information for the actual code generation phase. @@ -513,6 +545,7 @@ sub process_wrap_or_gate_modifiers { 'mapped_params_by_orig_name' => {}, 'mapping_results_by_orig_name' => {}, 'dont_resolve_final_symlink' => 0, + 'allow_nonexistent' => 0, 'postprocess_vars' => [], 'return_expr' => undef, @@ -563,7 +596,11 @@ sub process_wrap_or_gate_modifiers { my $param_to_be_mapped = $1; my $new_name = "mapped__".$param_to_be_mapped; - my $no_symlink_resolve = $mods->{'dont_resolve_final_symlink'}; + my $no_symlink_resolve = + expr_to_flagexpr($mods->{'dont_resolve_final_symlink'}, "SBOX_MAP_PATH_DONT_RESOLVE_FINAL_SYMLINK"); + my $allow_nonexistent = + expr_to_flagexpr($mods->{'allow_nonexistent'}, "SBOX_MAP_PATH_ALLOW_NONEXISTENT"); + my $flags = flagexpr_join($no_symlink_resolve, $allow_nonexistent); $mods->{'mapped_params_by_orig_name'}->{$param_to_be_mapped} = "res_$new_name.mres_result_path"; $mods->{'mapping_results_by_orig_name'}->{$param_to_be_mapped} = "res_$new_name"; @@ -574,7 +611,7 @@ sub process_wrap_or_gate_modifiers { "\tclear_mapping_results_struct(&res_$new_name);\n". "\tsbox_map_path(__func__, ". "$param_to_be_mapped, ". - "$no_symlink_resolve, ". + "$flags, ". "&res_$new_name, classmask);\n". "\tif (res_$new_name.mres_errno) {\n". "\t\tSB_LOG(SB_LOGLEVEL_DEBUG, \"mapping failed, errno %d\",". @@ -615,7 +652,11 @@ sub process_wrap_or_gate_modifiers { my $new_name = "mapped__".$param_to_be_mapped; my $ro_flag = $param_to_be_mapped."_is_readonly"; - my $no_symlink_resolve = $mods->{'dont_resolve_final_symlink'}; + my $no_symlink_resolve = + expr_to_flagexpr($mods->{'dont_resolve_final_symlink'}, "SBOX_MAP_PATH_DONT_RESOLVE_FINAL_SYMLINK"); + my $allow_nonexistent = + expr_to_flagexpr($mods->{'allow_nonexistent'}, "SBOX_MAP_PATH_ALLOW_NONEXISTENT"); + my $flags = flagexpr_join($no_symlink_resolve, $allow_nonexistent); $mods->{'mapped_params_by_orig_name'}->{$param_to_be_mapped} = "res_$new_name.mres_result_path"; $mods->{'mapping_results_by_orig_name'}->{$param_to_be_mapped} = "res_$new_name"; @@ -626,7 +667,7 @@ sub process_wrap_or_gate_modifiers { "\tsbox_map_path_at(__func__, ". "$fd_param, ". "$param_to_be_mapped, ". - "$no_symlink_resolve, ". + "$flags, ". "&res_$new_name, classmask);\n". "\tif (res_$new_name.mres_errno) {\n". "\t\terrno = res_$new_name.mres_errno;\n". @@ -682,6 +723,11 @@ sub process_wrap_or_gate_modifiers { } elsif($modifiers[$i] =~ m/^dont_resolve_final_symlink_if\((.*)\)$/) { my $condition = $1; $mods->{'dont_resolve_final_symlink'} = "($condition)"; + } elsif($modifiers[$i] eq 'allow_nonexistent') { + $mods->{'allow_nonexistent'} = 1; + } elsif($modifiers[$i] =~ m/^allow_nonexistent_if\((.*)\)$/) { + my $condition = $1; + $mods->{'allow_nonexistent'} = "($condition)"; } elsif(($modifiers[$i] =~ m/^optional_arg_is_create_mode\((.*)\)$/) && ($fn->{'has_varargs'})) { my $va_list_condition = $1; diff --git a/scratchbox2/preload/miscgates.c b/scratchbox2/preload/miscgates.c index 36f34cf..2cfacdb 100644 --- a/scratchbox2/preload/miscgates.c +++ b/scratchbox2/preload/miscgates.c @@ -63,7 +63,7 @@ FTS * fts_open_gate( clear_mapping_results_struct(&res); path = *p; sbox_map_path(realfnname, path, - 0/*dont_resolve_final_symlink*/, &res, + 0/*flags*/, &res, SB2_INTERFACE_CLASS_FTSOPEN); if (res.mres_result_path) { /* Mapped OK */ @@ -354,7 +354,7 @@ static char *check_and_prepare_glob_pattern( */ if (*pattern == '/') { /* if absolute path in pattern.. */ mapped__pattern = sbox_map_path(realfnname, pattern, - NULL/*RO-flag*/, 0/*dont_resolve_final_symlink*/, + NULL/*RO-flag*/, 0/*flags*/, SB2_INTERFACE_CLASS_GLOB); if (!strcmp(mapped__pattern, pattern)) { /* no change */ diff --git a/scratchbox2/preload/network.c b/scratchbox2/preload/network.c index 7ea3017..74e2a06 100644 --- a/scratchbox2/preload/network.c +++ b/scratchbox2/preload/network.c @@ -52,12 +52,13 @@ typedef struct { char mapped_printable_dst_addr[200]; } mapped_sockaddr_t; -static void map_sockaddr_un( +static int map_sockaddr_un( const char *realfnname, const struct sockaddr_un *orig_serv_addr_un, mapped_sockaddr_t *output_addr) { mapping_results_t res; + int result = 0; if (!*orig_serv_addr_un->sun_path) { /* an "abstract" local domain socket. @@ -71,7 +72,7 @@ static void map_sockaddr_un( snprintf(output_addr->mapped_printable_dst_addr, sizeof(output_addr->mapped_printable_dst_addr), ""); - return; + return(0); } SB_LOG(SB_LOGLEVEL_DEBUG, "%s: checking AF_UNIX addr '%s'", @@ -84,8 +85,14 @@ static void map_sockaddr_un( clear_mapping_results_struct(&res); /* FIXME: implement if(pathname_is_readonly!=0)... */ sbox_map_path(realfnname, orig_serv_addr_un->sun_path, - 0/*dont_resolve_final_symlink*/, &res, SB2_INTERFACE_CLASS_SOCKADDR); - if (res.mres_result_path == NULL) { + 0/*flags*/, &res, SB2_INTERFACE_CLASS_SOCKADDR); + if (res.mres_errno != 0) { + result = res.mres_errno; + SB_LOG(SB_LOGLEVEL_DEBUG, + "%s: Failed to map AF_UNIX address '%s': errno=%d", + realfnname, orig_serv_addr_un->sun_path, result); + } else if (res.mres_result_path == NULL) { + result = EINVAL; SB_LOG(SB_LOGLEVEL_ERROR, "%s: Failed to map AF_UNIX address '%s'", realfnname, orig_serv_addr_un->sun_path); @@ -96,6 +103,7 @@ static void map_sockaddr_un( output_addr->mapped_sockaddr_un = *orig_serv_addr_un; if (sizeof(output_addr->mapped_sockaddr_un.sun_path) <= strlen(res.mres_result_path)) { + result = ENAMETOOLONG; SB_LOG(SB_LOGLEVEL_ERROR, "%s: Mapped AF_UNIX address (%s) is too long", realfnname, res.mres_result_path); @@ -114,6 +122,7 @@ static void map_sockaddr_un( } } free_mapping_results(&res); + return(result); } /* returns 0 if success, errno code if failed */ @@ -358,9 +367,18 @@ static int map_sockaddr( case AF_UNIX: output_addr->mapped_addrlen = input_addrlen; - map_sockaddr_un(realfnname, + inet_mapping_result = map_sockaddr_un(realfnname, (const struct sockaddr_un*)input_addr, output_addr); + if (inet_mapping_result != 0) { + /* return error */ + *result_errno_ptr = inet_mapping_result; + SB_LOG(SB_LOGLEVEL_NETWORK, + "%s: denied (%s), errno=%d", + realfnname, output_addr->orig_printable_dst_addr, + inet_mapping_result); + return(MAP_SOCKADDR_OPERATION_DENIED); + } SB_LOG(SB_LOGLEVEL_DEBUG, "%s: orig addr.len=%d, mapped_addrlen=%d", __func__, input_addrlen, output_addr->mapped_addrlen); return (MAP_SOCKADDR_MAPPED); diff --git a/scratchbox2/preload/sb_l10n.c b/scratchbox2/preload/sb_l10n.c index b7a303e..971b1a2 100644 --- a/scratchbox2/preload/sb_l10n.c +++ b/scratchbox2/preload/sb_l10n.c @@ -37,7 +37,9 @@ char *bindtextdomain_gate(int *result_errno_ptr, clear_mapping_results_struct(&res); if (dirname != NULL) { - sbox_map_path(realfn_name, dirname, 0, &res, SB2_INTERFACE_CLASS_L10N); + sbox_map_path(realfn_name, dirname, + SBOX_MAP_PATH_ALLOW_NONEXISTENT, &res, + SB2_INTERFACE_CLASS_L10N); assert(res.mres_result_path != NULL); mapped_dirname = res.mres_result_path;