예제 #1
0
파일: proc.c 프로젝트: matrach/PRoot
/**
 * This function emulates the @result of readlink("@referer") with
 * respect to @tracee, where @referer is a strict subpath of "/proc".
 * This function returns the length of @result if the readlink was
 * emulated, 0 otherwise.
 *
 * Unlike readlink(), this function includes the nul terminating byte
 * to @result (but this byte is not counted in the returned value).
 */
size_t readlink_proc2(const Tracee *tracee, char result[PATH_MAX], const char referer[PATH_MAX])
{
	Action action;
	char base[PATH_MAX];
	char *component;

	assert(compare_paths("/proc", referer) == PATH1_IS_PREFIX);

	/* It's safe to use strrchr() here since @referer was
	 * previously canonicalized.  */
	strcpy(base, referer);
	component = strrchr(base, '/');

	/* These cases are not possible: @referer is supposed to be a
	 * canonicalized subpath of "/proc".  */
	assert(component != NULL && component != base);

	component[0] = '\0';
	component++;
	if (component[0] == '\0')
		return 0;

	action = readlink_proc(tracee, result, base, component, PATH1_IS_PREFIX);
	return (action == CANONICALIZE ? strlen(result) : 0);
}
예제 #2
0
파일: path.c 프로젝트: ivoire/PRoot
/**
 * Check if the translated @host_path belongs to the guest rootfs,
 * that is, isn't from a binding.
 */
bool belongs_to_guestfs(const Tracee *tracee, const char *host_path)
{
	Comparison comparison;

	comparison = compare_paths(get_root(tracee), host_path);
	return (comparison == PATHS_ARE_EQUAL || comparison == PATH1_IS_PREFIX);
}
예제 #3
0
/**
 * Bind content of @vectors over /proc/{@ptracee->pid}/auxv.  This
 * function returns -1 if an error occurred, otherwise 0.
 */
static int bind_proc_pid_auxv(const Tracee *ptracee)
{
	word_t vectors_address;
	ElfAuxVector *vectors;

	const char *guest_path;
	const char *host_path;
	Binding *binding;
	int status;

	vectors_address = get_elf_aux_vectors_address(ptracee);
	if (vectors_address == 0)
		return -1;

	vectors = fetch_elf_aux_vectors(ptracee, vectors_address);
	if (vectors == NULL)
		return -1;

	/* Path to these ELF auxiliary vectors.  */
	guest_path = talloc_asprintf(ptracee->ctx, "/proc/%d/auxv", ptracee->pid);
	if (guest_path == NULL)
		return -1;

	/* Remove binding to this path, if any.  It contains ELF
	 * auxiliary vectors of the previous execve(2).  */
	binding = get_binding(ptracee, GUEST, guest_path);
	if (binding != NULL && compare_paths(binding->guest.path, guest_path) == PATHS_ARE_EQUAL) {
		remove_binding_from_all_lists(ptracee, binding);
		TALLOC_FREE(binding);
	}

	host_path = create_temp_file(ptracee->ctx, "auxv");
	if (host_path == NULL)
		return -1;

	status = fill_file_with_auxv(ptracee, host_path, vectors);
	if (status < 0)
		return -1;

	/* Note: this binding will be removed once ptracee gets freed.  */
	binding = insort_binding3(ptracee, ptracee->life_context, host_path, guest_path);
	if (binding == NULL)
		return -1;

	/* This temporary file (host_path) will be removed once the
	 * binding is freed.  */
	talloc_reparent(ptracee->ctx, binding, host_path);

	return 0;
}
예제 #4
0
int is_virtual_path ( char const* path ) {

	size_t len = 0;
	ZIPFSVirtualPath* cursor = sVirtualPaths;
	
	for ( ; cursor; cursor = cursor->mNext ) {
	
		char* test = cursor->mPath;
		len = compare_paths ( test, path );
		
		if ( !test [ len ]) return 1;
	}
	return 0;
}
예제 #5
0
//----------------------------------------------------------------//
char* zipfs_get_rel_path ( char const* path ) {

	size_t depth = 0;
	size_t i = 0;
	size_t same;

	if ( !path ) return 0;
	
	if ( path [ 0 ] == '.' ) {
		return zipfs_bless_path ( path );
	}
	
	if ( !(( path [ 0 ] == '/' ) || ( path [ 0 ] == '\\' ) || ( path [ 0 ] == ':' ))) {
		ZIPFSString_Set ( sBuffer, "./" );
		ZIPFSString_Append ( sBuffer, path );
		zipfs_bless_path ( sBuffer->mMem );
		return sBuffer->mMem;
	}

	// store the expanded path in sBuffer
	zipfs_get_abs_filepath ( path );

	same = compare_paths ( path, sWorkingPath->mMem );
	if ( same == 0 ) {
		return zipfs_bless_path ( path );
	}

	// count the number of steps up in the current directory
	for ( i = same; sWorkingPath->mMem [ i ]; ++i ) {
		if (  sWorkingPath->mMem [ i ] == '/' ) {
			depth++;
		}
	}

	ZIPFSString_Shift ( sBuffer, same, sBuffer->mStrLen - same, depth * 3 );

	sBuffer->mStrLen = sBuffer->mStrLen - same + ( depth * 3 );
	sBuffer->mMem [ sBuffer->mStrLen ] = 0;

	for ( i = 0; i < depth; ++i ) {
	
		size_t j = i * 3;
	
		sBuffer->mMem [ j + 0 ] = '.';
		sBuffer->mMem [ j + 1 ] = '.';
		sBuffer->mMem [ j + 2 ] = '/';
	}
	
	return sBuffer->mMem;
}
예제 #6
0
ZIPFSVirtualPath* find_virtual_path ( char const* path ) {

	size_t len = 0;

	ZIPFSVirtualPath* cursor = sVirtualPaths;
	for ( ; cursor; cursor = cursor->mNext ) {
	
		char* test = cursor->mPath;
		len = compare_paths ( test, path );
		
		if ( !( test [ len ] || path [ len ])) break;
	}
	return cursor;
}
예제 #7
0
파일: binding.c 프로젝트: matrach/PRoot
/**
 * Print all bindings (verbose purpose).
 */
static void print_bindings(const Tracee *tracee)
{
	const Binding *binding;

	if (tracee->fs->bindings.guest == NULL)
		return;

	CIRCLEQ_FOREACH_(tracee, binding, GUEST) {
		if (compare_paths(binding->host.path, binding->guest.path) == PATHS_ARE_EQUAL)
			notice(tracee, INFO, USER, "binding = %s", binding->host.path);
		else
			notice(tracee, INFO, USER, "binding = %s:%s",
				binding->host.path, binding->guest.path);
	}
}
예제 #8
0
ZIPFSVirtualPath* find_next_virtual_subdir ( char const* path, ZIPFSVirtualPath* cursor ) {

	size_t len = 0;
	
	cursor = cursor ? cursor->mNext : sVirtualPaths;
	
	for ( ; cursor; cursor = cursor->mNext ) {
	
		char* test = cursor->mPath;
		len = compare_paths ( test, path );
		
		if ( test [ len ] && ( !path [ len ])) {
			return cursor;
		}		
	}
	return 0;
}
예제 #9
0
ZIPFSVirtualPath* find_best_virtual_path ( char const* path ) {

	size_t len = 0;
	size_t bestlen = 0;
	ZIPFSVirtualPath* best = 0;
	ZIPFSVirtualPath* cursor = sVirtualPaths;
	
	for ( ; cursor; cursor = cursor->mNext ) {
	
		char* test = cursor->mPath;
		len = compare_paths ( test, path );
	
		if (( !test [ len ]) && ( len > bestlen )) {
			best = cursor;
			bestlen = len;
		}		
	}
	return best;
}
예제 #10
0
파일: binding.c 프로젝트: matrach/PRoot
/**
 * Get the binding for the given @path (relatively to the given
 * binding @side).
 */
static const Binding *get_binding(Tracee *tracee, Side side, const char path[PATH_MAX])
{
	const Binding *binding;
	size_t path_length = strlen(path);

	/* Sanity checks.  */
	assert(path != NULL && path[0] == '/');

	CIRCLEQ_FOREACH_(tracee, binding, side) {
		Comparison comparison;
		const Path *ref;

		switch (side) {
		case GUEST:
			ref = &binding->guest;
			break;

		case HOST:
			ref = &binding->host;
			break;

		default:
			assert(0);
			return NULL;
		}

		comparison = compare_paths2(ref->path, ref->length, path, path_length);
		if (   comparison != PATHS_ARE_EQUAL
		    && comparison != PATH1_IS_PREFIX)
			continue;

		/* Avoid false positive when a prefix of the rootfs is
		 * used as an asymmetric binding, ex.:
		 *
		 *     proot -m /usr:/location /usr/local/slackware
		 */
		if (   side == HOST
		    && compare_paths(get_root(tracee), "/") != PATHS_ARE_EQUAL
		    && belongs_to_guestfs(tracee, path))
				continue;

		return binding;
	}
예제 #11
0
파일: database.c 프로젝트: lewellyn/crap
file_t * database_find_file (const database_t * db, const char * path)
{
    // We maintain the invariants:  All items below index low are before path.
    // All items at or above index high are after path.  If path is present,
    // then its index is between low (inclusive) and high (exclusive).
    ssize_t low = 0;
    ssize_t high = db->files_end - db->files;

    while (high > low) {
        ssize_t mid = (low + high) >> 1;
        int c = compare_paths (db->files[mid].path, path);
        if (c == 0)
            return db->files + mid;
        if (c < 0)
            low = mid + 1;
        else
            high = mid;
    }

    return NULL;
}
예제 #12
0
void bcp_implementation::output_license_info()
{
   std::pair<const license_info*, int> licenses = get_licenses();

   std::map<int, license_data>::const_iterator i, j;
   i = m_license_data.begin();
   j = m_license_data.end();

   std::ofstream os(m_dest_path.string().c_str());
   if(!os)
   {
      std::string msg("Error opening ");
      msg += m_dest_path.string();
      msg += " for output.";
      std::runtime_error e(msg);
      boost::throw_exception(e);
   }
   os <<
      "<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.0 Transitional//EN\">\n"
      "<html>\n"
      "<head>\n"
      "<title>Boost Licence Dependency Information";
   if(m_module_list.size() == 1)
   {
      os << " for " << *(m_module_list.begin());
   }
   os <<
      "</title>\n"
      "</head>\n"
      "<body>\n"
      "<H1>Boost Licence Dependency Information";
   if(m_module_list.size() == 1)
   {
      os << " for " << *(m_module_list.begin());
   }
   os <<
      "</H1>\n"
      "<H2>Contents</h2>\n"
      "<pre><a href=\"#input\">Input Information</a>\n";
   if(!m_bsl_summary_mode)
      os << "<a href=\"#summary\">Licence Summary</a>\n";
   os << "<a href=\"#details\">Licence Details</a>\n";

   while(i != j)
   {
      // title:
      os << "   <A href=\"#" << make_link_target(licenses.first[i->first].license_name)
         << "\">" << licenses.first[i->first].license_name << "</a>\n";
      ++i;
   }

   os << "<a href=\"#files\">Files with no recognised license</a>\n"
      "<a href=\"#authors\">Files with no recognised copyright holder</a>\n";
   if(!m_bsl_summary_mode)
   {
      os <<
      "Moving to the Boost Software License...\n"
      "  <a href=\"#bsl-converted\">Files that can be automatically converted to the Boost Software License</a>\n"
      "  <a href=\"#to-bsl\">Files that can be manually converted to the Boost Software License</a>\n"
      "  <a href=\"#not-to-bsl\">Files that can <b>NOT</b> be moved to the Boost Software License</a>\n"
      "  <a href=\"#need-bsl-authors\">Authors we need to move to the Boost Software License</a>\n"
      "<a href=\"#copyright\">Copyright Holder Information</a>\n";
   }
   os <<
      "<a href=\"#depend\">File Dependency Information</a>\n"
      "</pre>";

   //
   // input Information:
   //
   os << "<a name=\"input\"></a><h2>Input Information</h2>\n";
   if(m_scan_mode)
      os << "<P>The following files were scanned for boost dependencies:<BR>";
   else
      os << "<P>The following Boost modules were checked:<BR>";

   std::list<std::string>::const_iterator si = m_module_list.begin();
   std::list<std::string>::const_iterator sj = m_module_list.end();
   while(si != sj)
   {
      os << *si << "<BR>";
      ++si;
   }
   os << "</p><p>The Boost path was: <code>" << m_boost_path.string() << "</code></P>";
   //
   // extract the boost version number from the boost directory tree,
   // not from this app (which may have been built from a previous
   // version):
   //
   fileview version_file(m_boost_path / "boost/version.hpp");
   static const boost::regex version_regex(
      "^[[:blank:]]*#[[:blank:]]*define[[:blank:]]+BOOST_VERSION[[:blank:]]+(\\d+)");
   boost::cmatch what;
   if(boost::regex_search(version_file.begin(), version_file.end(), what, version_regex))
   {
      int version = boost::lexical_cast<int>(what.str(1));
      os << "<p>The Boost version is: " << version / 100000 << "." << version / 100 % 1000 << "." << version % 100 << "</P>\n";
   }

   //
   // output each license:
   //
   i = m_license_data.begin();
   j = m_license_data.end();
   if(!m_bsl_summary_mode)
   {
      //
      // start with the summary:
      //
      os << "<a name=\"summary\"></a><h2>Licence Summary</h2>\n";
      while(i != j)
      {
         // title:
         os <<
            "<H3>" << licenses.first[i->first].license_name << "</H3>\n";
         // license text:
         os << "<BLOCKQUOTE>" << licenses.first[i->first].license_text << "</BLOCKQUOTE>";
         // Copyright holders:
         os << "<P>This license is used by " << i->second.authors.size()
            << " authors and " << i->second.files.size()
            << " files <a href=\"#" << make_link_target(licenses.first[i->first].license_name) << "\">(see details)</a>";
         os << "</P></BLOCKQUOTE>\n";
         ++i;
      }
   }
   //
   // and now the details:
   //
   i = m_license_data.begin();
   j = m_license_data.end();
   int license_index = 0;
   os << "<a name=\"details\"></a><h2>Licence Details</h2>\n";
   while(i != j)
   {
      // title:
      os <<
         "<H3><A name=\"" << make_link_target(licenses.first[i->first].license_name)
         << "\"></a>" << licenses.first[i->first].license_name << "</H3>\n";
      // license text:
      os << "<BLOCKQUOTE>" << licenses.first[i->first].license_text << "</BLOCKQUOTE>";
      if(!m_bsl_summary_mode || (license_index >= 3))
      {
         // Copyright holders:
         os << "<P>This license is used by the following " << i->second.authors.size() << " copyright holders:</P>\n<BLOCKQUOTE><P>";
         std::set<std::string>::const_iterator x, y;
         x = i->second.authors.begin();
         y = i->second.authors.end();
         while(x != y)
         {
            os << *x << "<BR>\n";
            ++x;
         }
         os << "</P></BLOCKQUOTE>\n";
         // Files using this license:
         os << "<P>This license applies to the following " << i->second.files.size() << " files:</P>\n<BLOCKQUOTE><P>";
         std::set<fs::path, path_less>::const_iterator m, n;
         m = i->second.files.begin();
         n = i->second.files.end();
         while(m != n)
         {
            os << split_path(m_boost_path, *m) << "<br>\n";
            ++m;
         }
         os << "</P></BLOCKQUOTE>\n";
      }
      else
      {
         os << "<P>This license is used by " << i->second.authors.size() << " authors (list omitted for brevity).</P>\n";
         os << "<P>This license applies to " << i->second.files.size() << " files (list omitted for brevity).</P>\n";
      }
      ++license_index;
      ++i;
   }
   //
   // Output list of files not found to be under license control:
   //
   os << "<h2><a name=\"files\"></a>Files With No Recognisable Licence</h2>\n"
      "<P>The following " << m_unknown_licenses.size() << " files had no recognisable license information:</P><BLOCKQUOTE><P>\n";
   std::set<fs::path, path_less>::const_iterator i2, j2;
   i2 = m_unknown_licenses.begin();
   j2 = m_unknown_licenses.end();
   while(i2 != j2)
   {
      os << split_path(m_boost_path, *i2) << "<br>\n";
      ++i2;
   }
   os << "</p></BLOCKQUOTE>";
   //
   // Output list of files with no found copyright holder:
   //
   os << "<h2><a name=\"authors\"></a>Files With No Recognisable Copyright Holder</h2>\n"
      "<P>The following " << m_unknown_authors.size() << " files had no recognisable copyright holder:</P>\n<BLOCKQUOTE><P>";
   i2 = m_unknown_authors.begin();
   j2 = m_unknown_authors.end();
   while(i2 != j2)
   {
      os << split_path(m_boost_path, *i2) << "<br>\n";
      ++i2;
   }
   os << "</p></BLOCKQUOTE>";
   if(!m_bsl_summary_mode)
   {
      //
      // Output list of files that have been moved over to the Boost
      // Software License, along with enough information for human
      // verification.
      //
      os << "<h2><a name=\"bsl-converted\"></a>Files that can be automatically converted to the Boost Software License</h2>\n"
         << "<P>The following " << m_converted_to_bsl.size() << " files can be automatically converted to the Boost Software License, but require manual verification before they can be committed to CVS:</P>\n";
      if (!m_converted_to_bsl.empty())
      {
         typedef std::map<fs::path, std::pair<std::string, std::string>, path_less>
            ::const_iterator conv_iterator;
         conv_iterator i = m_converted_to_bsl.begin(),
                        ie = m_converted_to_bsl.end();
         int file_num = 1;
         while (i != ie)
         {
            os << "<P>[" << file_num << "] File: <tt>" << split_path(m_boost_path, i->first)
               << "</tt><br>\n<table border=\"1\">\n  <tr>\n    <td><pre>"
               << i->second.first << "</pre></td>\n    <td><pre>"
               << i->second.second << "</pre></td>\n  </tr>\n</table>\n";
            ++i;
            ++file_num;
         }
      }
      //
      // Output list of files that could be moved over to the Boost Software License
      //
      os << "<h2><a name=\"to-bsl\"></a>Files that could be converted to the Boost Software License</h2>\n"
      "<P>The following " << m_can_migrate_to_bsl.size() << " files could be manually converted to the Boost Software License, but have not yet been:</P>\n<BLOCKQUOTE><P>";
      i2 = m_can_migrate_to_bsl.begin();
      j2 = m_can_migrate_to_bsl.end();
      while(i2 != j2)
      {
         os << split_path(m_boost_path, *i2) << "<br>\n";
         ++i2;
      }
      os << "</p></BLOCKQUOTE>";
      //
      // Output list of files that can not be moved over to the Boost Software License
      //
      os << "<h2><a name=\"not-to-bsl\"></a>Files that can NOT be converted to the Boost Software License</h2>\n"
      "<P>The following " << m_cannot_migrate_to_bsl.size() << " files cannot be converted to the Boost Software License because we need the permission of more authors:</P>\n<BLOCKQUOTE><P>";
      i2 = m_cannot_migrate_to_bsl.begin();
      j2 = m_cannot_migrate_to_bsl.end();
      while(i2 != j2)
      {
         os << split_path(m_boost_path, *i2) << "<br>\n";
         ++i2;
      }
      os << "</p></BLOCKQUOTE>";
      //
      // Output list of authors that we need permission for to move to the BSL
      //
      os << "<h2><a name=\"need-bsl-authors\"></a>Authors we need for the BSL</h2>\n"
         "<P>Permission of the following authors is needed before we can convert to the Boost Software License. The list of authors that have given their permission is contained in <code>more/blanket-permission.txt</code>.</P>\n<BLOCKQUOTE><P>";
      std::copy(m_authors_for_bsl_migration.begin(), m_authors_for_bsl_migration.end(),
               std::ostream_iterator<std::string>(os, "<br>\n"));
      os << "</p></BLOCKQUOTE>";
      //
      // output a table of copyright information:
      //
      os << "<H2><a name=\"copyright\"></a>Copyright Holder Information</H2><table border=\"1\">\n";
      std::map<std::string, std::set<fs::path, path_less> >::const_iterator ad, ead;
      ad = m_author_data.begin();
      ead = m_author_data.end();
      while(ad != ead)
      {
         os << "<tr><td>" << ad->first << "</td><td>";
         std::set<fs::path, path_less>::const_iterator fi, efi;
         fi = ad->second.begin();
         efi = ad->second.end();
         while(fi != efi)
         {
            os << split_path(m_boost_path, *fi) << " ";
            ++fi;
         }
         os << "</td></tr>\n";
         ++ad;
      }
      os << "</table>\n";
   }

   //
   // output file dependency information:
   //
   os << "<H2><a name=\"depend\"></a>File Dependency Information</H2><BLOCKQUOTE><pre>\n";
   std::map<fs::path, fs::path, path_less>::const_iterator dep, last_dep;
   std::set<fs::path, path_less>::const_iterator fi, efi;
   fi = m_copy_paths.begin();
   efi = m_copy_paths.end();
   // if in summary mode, just figure out the "bad" files and print those only:
   std::set<fs::path, path_less> bad_paths;
   if(m_bsl_summary_mode)
   {
      bad_paths.insert(m_unknown_licenses.begin(), m_unknown_licenses.end());
      bad_paths.insert(m_unknown_authors.begin(), m_unknown_authors.end());
      bad_paths.insert(m_can_migrate_to_bsl.begin(), m_can_migrate_to_bsl.end());
      bad_paths.insert(m_cannot_migrate_to_bsl.begin(), m_cannot_migrate_to_bsl.end());
      typedef std::map<fs::path, std::pair<std::string, std::string>, path_less>
         ::const_iterator conv_iterator;
      conv_iterator i = m_converted_to_bsl.begin(),
                     ie = m_converted_to_bsl.end();
      while(i != ie)
      {
         bad_paths.insert(i->first);
         ++i;
      }
      fi = bad_paths.begin();
      efi = bad_paths.end();
      os << "<P>For brevity, only files not under the BSL are shown</P>\n";
   }
   while(fi != efi)
   {
      os << split_path(m_boost_path, *fi);
      dep = m_dependencies.find(*fi);
      last_dep = m_dependencies.end();
      std::set<fs::path, path_less> seen_deps;
      if (dep != last_dep)
        while(true)
          {
            os << " -> ";
            if(fs::exists(m_boost_path / dep->second))
              os << split_path(m_boost_path, dep->second);
            else if(fs::exists(dep->second))
              os << split_path(fs::path(), dep->second);
            else
              os << dep->second.string();
            if(seen_deps.find(dep->second) != seen_deps.end())
              {
                os << " <I>(Circular dependency!)</I>";
                break; // circular dependency!!!
              }
            seen_deps.insert(dep->second);
            last_dep = dep;
            dep = m_dependencies.find(dep->second);
            if((dep == m_dependencies.end()) || (0 == compare_paths(dep->second, last_dep->second)))
              break;
          }
      os << "\n";
      ++fi;
   }
   os << "</pre></BLOCKQUOTE>\n";

   os << "</body></html>\n";

   if(!os)
   {
      std::string msg("Error writing to ");
      msg += m_dest_path.string();
      msg += ".";
      std::runtime_error e(msg);
      boost::throw_exception(e);
   }

}
예제 #13
0
/**
 * Copy in @guest_path the canonicalization (see `man 3 realpath`) of
 * @user_path regarding to @tracee->root.  The path to canonicalize
 * could be either absolute or relative to @guest_path. When the last
 * component of @user_path is a link, it is dereferenced only if
 * @deref_final is true -- it is useful for syscalls like lstat(2).
 * The parameter @recursion_level should be set to 0 unless you know
 * what you are doing. This function returns -errno if an error
 * occured, otherwise it returns 0.
 */
int canonicalize(Tracee *tracee, const char *user_path, bool deref_final,
		 char guest_path[PATH_MAX], unsigned int recursion_level)
{
	char scratch_path[PATH_MAX];
	Finality finality;
	const char *cursor;
	int status;

	/* Avoid infinite loop on circular links.  */
	if (recursion_level > MAXSYMLINKS)
		return -ELOOP;

	/* Sanity checks.  */
	assert(user_path != NULL);
	assert(guest_path != NULL);
	assert(user_path != guest_path);

	if (strnlen(guest_path, PATH_MAX) >= PATH_MAX)
		return -ENAMETOOLONG;

	if (user_path[0] != '/') {
		/* Ensure 'guest_path' contains an absolute base of
		 * the relative `user_path`.  */
		if (guest_path[0] != '/')
			return -EINVAL;
	}
	else
		strcpy(guest_path, "/");

	/* Canonicalize recursely 'user_path' into 'guest_path'.  */
	cursor = user_path;
	finality = NOT_FINAL;
	while (!IS_FINAL(finality)) {
		Comparison comparison;
		char component[NAME_MAX];
		char host_path[PATH_MAX];

		finality = next_component(component, &cursor);
		status = (int) finality;
		if (status < 0)
			return status;

		if (strcmp(component, ".") == 0) {
			if (IS_FINAL(finality))
				finality = FINAL_DOT;
			continue;
		}

		if (strcmp(component, "..") == 0) {
			pop_component(guest_path);
			if (IS_FINAL(finality))
				finality = FINAL_SLASH;
			continue;
		}

		status = join_paths(2, scratch_path, guest_path, component);
		if (status < 0)
			return status;

		/* Resolve bindings and check that a non-final
		 * component exists and either is a directory or is a
		 * symlink.  For this latter case, we check that the
		 * symlink points to a directory once it is
		 * canonicalized, at the end of this loop.  */
		status = substitute_binding_stat(tracee, finality, recursion_level, scratch_path, host_path);
		if (status < 0)
			return status;

		/* Nothing special to do if it's not a link or if we
		 * explicitly ask to not dereference 'user_path', as
		 * required by syscalls like lstat(2). Obviously, this
		 * later condition does not apply to intermediate path
		 * components.  Errors are explicitly ignored since
		 * they should be handled by the caller. */
		if (status <= 0 || (finality == FINAL_NORMAL && !deref_final)) {
			strcpy(scratch_path, guest_path);
			status = join_paths(2, guest_path, scratch_path, component);
			if (status < 0)
				return status;
			continue;
		}

		/* It's a link, so we have to dereference *and*
		 * canonicalize to ensure we are not going outside the
		 * new root.  */
		comparison = compare_paths("/proc", guest_path);
		switch (comparison) {
		case PATHS_ARE_EQUAL:
		case PATH1_IS_PREFIX:
			/* Some links in "/proc" are generated
			 * dynamically by the kernel.  PRoot has to
			 * emulate some of them.  */
			status = readlink_proc(tracee, scratch_path,
					       guest_path, component, comparison);
			switch (status) {
			case CANONICALIZE:
				/* The symlink is already dereferenced,
				 * now canonicalize it.  */
				goto canon;

			case DONT_CANONICALIZE:
				/* If and only very final, this symlink
				 * shouldn't be dereferenced nor canonicalized.  */
				if (finality == FINAL_NORMAL) {
					strcpy(guest_path, scratch_path);
					return 0;
				}
				break;

			default:
				if (status < 0)
					return status;
			}

		default:
			break;
		}

		status = readlink(host_path, scratch_path, sizeof(scratch_path));
		if (status < 0)
			return status;
		else if (status == sizeof(scratch_path))
			return -ENAMETOOLONG;
		scratch_path[status] = '\0';

		/* Remove the leading "root" part if needed, it's
		 * useful for "/proc/self/cwd/" for instance.  */
		status = detranslate_path(tracee, scratch_path, host_path);
		if (status < 0)
			return status;

	canon:
		/* Canonicalize recursively the referee in case it
		 * is/contains a link, moreover if it is not an
		 * absolute link then it is relative to
		 * 'guest_path'. */
		status = canonicalize(tracee, scratch_path, true, guest_path, recursion_level + 1);
		if (status < 0)
			return status;

		/* Check that a non-final canonicalized/dereferenced
		 * symlink exists and is a directory.  */
		status = substitute_binding_stat(tracee, finality, recursion_level, guest_path, host_path);
		if (status < 0)
			return status;

		/* Here, 'guest_path' shouldn't be a symlink anymore,
		 * unless it is a named file descriptor.  */
		assert(status != 1 || sscanf(guest_path, "/proc/%*d/fd/%d", &status) == 1);
	}

	/* At the exit stage of the first level of recursion,
	 * `guest_path` is fully canonicalized but a terminating '/'
	 * or a terminating '.' may be required to keep the initial
	 * semantic of `user_path`.  */
	if (recursion_level == 0) {
		switch (finality) {
		case FINAL_NORMAL:
			break;

		case FINAL_SLASH:
			strcpy(scratch_path, guest_path);
			status = join_paths(2, guest_path, scratch_path, "");
			if (status < 0)
				return status;
			break;

		case FINAL_DOT:
			strcpy(scratch_path, guest_path);
			status = join_paths(2, guest_path, scratch_path, ".");
			if (status < 0)
				return status;
			break;

		default:
			assert(0);
		}
	}

	return 0;
}
예제 #14
0
파일: exit.c 프로젝트: meefik/PRoot
/**
 * Translate the output arguments of the current @tracee's syscall in
 * the @tracee->pid process area. This function sets the result of
 * this syscall to @tracee->status if an error occured previously
 * during the translation, that is, if @tracee->status is less than 0.
 */
void translate_syscall_exit(Tracee *tracee)
{
	word_t syscall_number;
	word_t syscall_result;
	int status;

	status = notify_extensions(tracee, SYSCALL_EXIT_START, 0, 0);
	if (status < 0) {
		poke_reg(tracee, SYSARG_RESULT, (word_t) status);
		goto end;
	}
	if (status > 0)
		return;

	/* Set the tracee's errno if an error occured previously during
	 * the translation. */
	if (tracee->status < 0) {
		poke_reg(tracee, SYSARG_RESULT, (word_t) tracee->status);
		goto end;
	}

	/* Translate output arguments:
	 * - break: update the syscall result register with "status"
	 * - goto end: nothing else to do.
	 */
	syscall_number = get_sysnum(tracee, ORIGINAL);
	syscall_result = peek_reg(tracee, CURRENT, SYSARG_RESULT);
	switch (syscall_number) {
	case PR_brk:
		translate_brk_exit(tracee);
		goto end;

	case PR_getcwd: {
		char path[PATH_MAX];
		size_t new_size;
		size_t size;
		word_t output;

		size = (size_t) peek_reg(tracee, ORIGINAL, SYSARG_2);
		if (size == 0) {
			status = -EINVAL;
			break;
		}

		/* Ensure cwd still exists.  */
		status = translate_path(tracee, path, AT_FDCWD, ".", false);
		if (status < 0)
			break;

		new_size = strlen(tracee->fs->cwd) + 1;
		if (size < new_size) {
			status = -ERANGE;
			break;
		}

		/* Overwrite the path.  */
		output = peek_reg(tracee, ORIGINAL, SYSARG_1);
		status = write_data(tracee, output, tracee->fs->cwd, new_size);
		if (status < 0)
			break;

		/* The value of "status" is used to update the returned value
		 * in translate_syscall_exit().  */
		status = new_size;
		break;
	}

	case PR_accept:
	case PR_accept4:
		/* Nothing special to do if no sockaddr was specified.  */
		if (peek_reg(tracee, ORIGINAL, SYSARG_2) == 0)
			goto end;
		/* Fall through.  */
	case PR_getsockname:
	case PR_getpeername: {
		word_t sock_addr;
		word_t size_addr;
		word_t max_size;

		/* Error reported by the kernel.  */
		if ((int) syscall_result < 0)
			goto end;

		sock_addr = peek_reg(tracee, ORIGINAL, SYSARG_2);
		size_addr = peek_reg(tracee, MODIFIED, SYSARG_3);
		max_size  = peek_reg(tracee, MODIFIED, SYSARG_6);

		status = translate_socketcall_exit(tracee, sock_addr, size_addr, max_size);
		if (status < 0)
			break;

		/* Don't overwrite the syscall result.  */
		goto end;
	}

#define SYSARG_ADDR(n) (args_addr + ((n) - 1) * sizeof_word(tracee))

#define POKE_WORD(addr, value)			\
	poke_word(tracee, addr, value);		\
	if (errno != 0)	{			\
		status = -errno;		\
		break;				\
	}

#define PEEK_WORD(addr)				\
	peek_word(tracee, addr);		\
	if (errno != 0) {			\
		status = -errno;		\
		break;				\
	}

	case PR_socketcall: {
		word_t args_addr;
		word_t sock_addr;
		word_t size_addr;
		word_t max_size;

		args_addr = peek_reg(tracee, ORIGINAL, SYSARG_2);

		switch (peek_reg(tracee, ORIGINAL, SYSARG_1)) {
		case SYS_ACCEPT:
		case SYS_ACCEPT4:
			/* Nothing special to do if no sockaddr was specified.  */
			sock_addr = PEEK_WORD(SYSARG_ADDR(2));
			if (sock_addr == 0)
				goto end;
			/* Fall through.  */
		case SYS_GETSOCKNAME:
		case SYS_GETPEERNAME:
			/* Handle these cases below.  */
			status = 1;
			break;

		case SYS_BIND:
		case SYS_CONNECT:
			/* Restore the initial parameters: this memory was
			 * overwritten at the enter stage.  Remember: POKE_WORD
			 * puts -errno in status and breaks if an error
			 * occured.  */
			POKE_WORD(SYSARG_ADDR(2), peek_reg(tracee, MODIFIED, SYSARG_5));
			POKE_WORD(SYSARG_ADDR(3), peek_reg(tracee, MODIFIED, SYSARG_6));

			status = 0;
			break;

		default:
			status = 0;
			break;
		}

		/* Error reported by the kernel or there's nothing else to do.  */
		if ((int) syscall_result < 0 || status == 0)
			goto end;

		/* An error occured in SYS_BIND or SYS_CONNECT.  */
		if (status < 0)
			break;

		/* Remember: PEEK_WORD puts -errno in status and breaks if an
		 * error occured.  */
		sock_addr = PEEK_WORD(SYSARG_ADDR(2));
		size_addr = PEEK_WORD(SYSARG_ADDR(3));
		max_size  = peek_reg(tracee, MODIFIED, SYSARG_6);

		status = translate_socketcall_exit(tracee, sock_addr, size_addr, max_size);
		if (status < 0)
			break;

		/* Don't overwrite the syscall result.  */
		goto end;
	}

#undef SYSARG_ADDR
#undef PEEK_WORD
#undef POKE_WORD

	case PR_fchdir:
	case PR_chdir:
		/* These syscalls are fully emulated, see enter.c for details
		 * (like errors).  */
		status = 0;
		break;

	case PR_rename:
	case PR_renameat: {
		char old_path[PATH_MAX];
		char new_path[PATH_MAX];
		ssize_t old_length;
		ssize_t new_length;
		Comparison comparison;
		Reg old_reg;
		Reg new_reg;
		char *tmp;

		/* Error reported by the kernel.  */
		if ((int) syscall_result < 0)
			goto end;

		if (syscall_number == PR_rename) {
			old_reg = SYSARG_1;
			new_reg = SYSARG_2;
		}
		else {
			old_reg = SYSARG_2;
			new_reg = SYSARG_4;
		}

		/* Get the old path, then convert it to the same
		 * "point-of-view" as tracee->fs->cwd (guest).  */
		status = read_path(tracee, old_path, peek_reg(tracee, MODIFIED, old_reg));
		if (status < 0)
			break;

		status = detranslate_path(tracee, old_path, NULL);
		if (status < 0)
			break;
		old_length = (status > 0 ? status - 1 : (ssize_t) strlen(old_path));

		/* Nothing special to do if the moved path is not the
		 * current working directory.  */
		comparison = compare_paths(old_path, tracee->fs->cwd);
		if (comparison != PATH1_IS_PREFIX && comparison != PATHS_ARE_EQUAL) {
			status = 0;
			break;
		}

		/* Get the new path, then convert it to the same
		 * "point-of-view" as tracee->fs->cwd (guest).  */
		status = read_path(tracee, new_path, peek_reg(tracee, MODIFIED, new_reg));
		if (status < 0)
			break;

		status = detranslate_path(tracee, new_path, NULL);
		if (status < 0)
			break;
		new_length = (status > 0 ? status - 1 : (ssize_t) strlen(new_path));

		/* Sanity check.  */
		if (strlen(tracee->fs->cwd) >= PATH_MAX) {
			status = 0;
			break;
		}
		strcpy(old_path, tracee->fs->cwd);

		/* Update the virtual current working directory.  */
		substitute_path_prefix(old_path, old_length, new_path, new_length);

		tmp = talloc_strdup(tracee->fs, old_path);
		if (tmp == NULL) {
			status = -ENOMEM;
			break;
		}

		TALLOC_FREE(tracee->fs->cwd);
		tracee->fs->cwd = tmp;

		status = 0;
		break;
	}

	case PR_readlink:
	case PR_readlinkat: {
		char referee[PATH_MAX];
		char referer[PATH_MAX];
		size_t old_size;
		size_t new_size;
		size_t max_size;
		word_t input;
		word_t output;

		/* Error reported by the kernel.  */
		if ((int) syscall_result < 0)
			goto end;

		old_size = syscall_result;

		if (syscall_number == PR_readlink) {
			output   = peek_reg(tracee, ORIGINAL, SYSARG_2);
			max_size = peek_reg(tracee, ORIGINAL, SYSARG_3);
			input    = peek_reg(tracee, MODIFIED, SYSARG_1);
		}
		else {
			output   = peek_reg(tracee, ORIGINAL,  SYSARG_3);
			max_size = peek_reg(tracee, ORIGINAL, SYSARG_4);
			input    = peek_reg(tracee, MODIFIED, SYSARG_2);
		}

		if (max_size > PATH_MAX)
			max_size = PATH_MAX;

		if (max_size == 0) {
			status = -EINVAL;
			break;
		}

		/* The kernel does NOT put the NULL terminating byte for
		 * readlink(2).  */
		status = read_data(tracee, referee, output, old_size);
		if (status < 0)
			break;
		referee[old_size] = '\0';

		/* Not optimal but safe (path is fully translated).  */
		status = read_path(tracee, referer, input);
		if (status < 0)
			break;

		if (status >= PATH_MAX) {
			status = -ENAMETOOLONG;
			break;
		}

		status = detranslate_path(tracee, referee, referer);
		if (status < 0)
			break;

		/* The original path doesn't require any transformation, i.e
		 * it is a symetric binding.  */
		if (status == 0)
			goto end;

		/* Overwrite the path.  Note: the output buffer might be
		 * initialized with zeros but it was updated with the kernel
		 * result, and then with the detranslated result.  This later
		 * might be shorter than the former, so it's safier to add a
		 * NULL terminating byte when possible.  This problem was
		 * exposed by IDA Demo 6.3.  */
		if ((size_t) status < max_size) {
			new_size = status - 1;
			status = write_data(tracee, output, referee, status);
		}
		else {
			new_size = max_size;
			status = write_data(tracee, output, referee, max_size);
		}
		if (status < 0)
			break;

		/* The value of "status" is used to update the returned value
		 * in translate_syscall_exit().  */
		status = new_size;
		break;
	}

#if defined(ARCH_X86_64)
	case PR_uname: {
		struct utsname utsname;
		word_t address;
		size_t size;

		if (get_abi(tracee) != ABI_2)
			goto end;

		/* Error reported by the kernel.  */
		if ((int) syscall_result < 0)
			goto end;

		address = peek_reg(tracee, ORIGINAL, SYSARG_1);

		status = read_data(tracee, &utsname, address, sizeof(utsname));
		if (status < 0)
			break;

		/* Some 32-bit programs like package managers can be
		 * confused when the kernel reports "x86_64".  */
		size = sizeof(utsname.machine);
		strncpy(utsname.machine, "i686", size);
		utsname.machine[size - 1] = '\0';

		status = write_data(tracee, address, &utsname, sizeof(utsname));
		if (status < 0)
			break;

		status = 0;
		break;
	}
#endif

	case PR_execve:
		translate_execve_exit(tracee);
		goto end;

	case PR_ptrace:
		status = translate_ptrace_exit(tracee);
		break;

	case PR_wait4:
	case PR_waitpid:
		if (tracee->as_ptracer.waits_in != WAITS_IN_PROOT)
			goto end;

		status = translate_wait_exit(tracee);
		break;

	case PR_setrlimit:
	case PR_prlimit64:
		/* Error reported by the kernel.  */
		if ((int) syscall_result < 0)
			goto end;

		status = translate_setrlimit_exit(tracee, syscall_number == PR_prlimit64);
		if (status < 0)
			break;

		/* Don't overwrite the syscall result.  */
		goto end;

	default:
		goto end;
	}

	poke_reg(tracee, SYSARG_RESULT, (word_t) status);

end:
	status = notify_extensions(tracee, SYSCALL_EXIT_END, status, 0);
	if (status < 0)
		poke_reg(tracee, SYSARG_RESULT, (word_t) status);
}
예제 #15
0
 bool operator()(const fs::path& a, const fs::path& b)const
 { return compare_paths(a, b) < 0; }
예제 #16
0
파일: path.c 프로젝트: ivoire/PRoot
/**
 * Remove/substitute the leading part of a "translated" @path.  It
 * returns 0 if no transformation is required (ie. symmetric binding),
 * otherwise it returns the size in bytes of the updated @path,
 * including the end-of-string terminator.  On error it returns
 * -errno.
 */
int detranslate_path(Tracee *tracee, char path[PATH_MAX], const char t_referrer[PATH_MAX])
{
	size_t prefix_length;
	ssize_t new_length;

	bool sanity_check;
	bool follow_binding;

	/* Sanity check.  */
	if (strnlen(path, PATH_MAX) >= PATH_MAX)
		return -ENAMETOOLONG;

	/* Don't try to detranslate relative paths (typically the
	 * target of a relative symbolic link). */
	if (path[0] != '/')
		return 0;

	/* Is it a symlink?  */
	if (t_referrer != NULL) {
		Comparison comparison;

		sanity_check = false;
		follow_binding = false;

		/* In some cases bindings have to be resolved.  */
		comparison = compare_paths("/proc", t_referrer);
		if (comparison == PATH1_IS_PREFIX) {
			/* Some links in "/proc" are generated
			 * dynamically by the kernel.  PRoot has to
			 * emulate some of them.  */
			char proc_path[PATH_MAX];
			strcpy(proc_path, path);
			new_length = readlink_proc2(tracee, proc_path, t_referrer);
			if (new_length < 0)
				return new_length;
			if (new_length != 0) {
				strcpy(path, proc_path);
				return new_length + 1;
			}

			/* Always resolve bindings for symlinks in
			 * "/proc", they always point to the emulated
			 * file-system namespace by design. */
			follow_binding = true;
		}
		else if (!belongs_to_guestfs(tracee, t_referrer)) {
			const char *binding_referree;
			const char *binding_referrer;

			binding_referree = get_path_binding(tracee, HOST, path);
			binding_referrer = get_path_binding(tracee, HOST, t_referrer);
			assert(binding_referrer != NULL);

			/* Resolve bindings for symlinks that belong
			 * to a binding and point to the same binding.
			 * For example, if "-b /lib:/foo" is specified
			 * and the symlink "/lib/a -> /lib/b" exists
			 * in the host rootfs namespace, then it
			 * should appear as "/foo/a -> /foo/b" in the
			 * guest rootfs namespace for consistency
			 * reasons.  */
			if (binding_referree != NULL) {
				comparison = compare_paths(binding_referree, binding_referrer);
				follow_binding = (comparison == PATHS_ARE_EQUAL);
			}
		}
	}
	else {
		sanity_check = true;
		follow_binding = true;
	}

	if (follow_binding) {
		switch (substitute_binding(tracee, HOST, path)) {
		case 0:
			return 0;
		case 1:
			return strlen(path) + 1;
		default:
			break;
		}
	}

	switch (compare_paths(get_root(tracee), path)) {
	case PATH1_IS_PREFIX:
		/* Remove the leading part, that is, the "root".  */
		prefix_length = strlen(get_root(tracee));

		/* Special case when path to the guest rootfs == "/". */
		if (prefix_length == 1)
			prefix_length = 0;

		new_length = strlen(path) - prefix_length;
		memmove(path, path + prefix_length, new_length);

		path[new_length] = '\0';
		break;

	case PATHS_ARE_EQUAL:
		/* Special case when path == root. */
		new_length = 1;
		strcpy(path, "/");
		break;

	default:
		/* Ensure the path is within the new root.  */
		if (sanity_check)
			return -EPERM;
		else
			return 0;
	}

	return new_length + 1;
}
예제 #17
0
inline bool equal_paths(const fs::path& a, const fs::path& b)
{ return compare_paths(a, b) == 0; }
예제 #18
0
static struct combine_diff_path *intersect_paths(struct combine_diff_path *curr, int n, int num_parent)
{
	struct diff_queue_struct *q = &diff_queued_diff;
	struct combine_diff_path *p, **tail = &curr;
	int i, cmp;

	if (!n) {
		for (i = 0; i < q->nr; i++) {
			int len;
			const char *path;
			if (diff_unmodified_pair(q->queue[i]))
				continue;
			path = q->queue[i]->two->path;
			len = strlen(path);
			p = xmalloc(combine_diff_path_size(num_parent, len));
			p->path = (char *) &(p->parent[num_parent]);
			memcpy(p->path, path, len);
			p->path[len] = 0;
			p->next = NULL;
			memset(p->parent, 0,
			       sizeof(p->parent[0]) * num_parent);

			hashcpy(p->oid.hash, q->queue[i]->two->sha1);
			p->mode = q->queue[i]->two->mode;
			hashcpy(p->parent[n].oid.hash, q->queue[i]->one->sha1);
			p->parent[n].mode = q->queue[i]->one->mode;
			p->parent[n].status = q->queue[i]->status;
			*tail = p;
			tail = &p->next;
		}
		return curr;
	}

	/*
	 * paths in curr (linked list) and q->queue[] (array) are
	 * both sorted in the tree order.
	 */
	i = 0;
	while ((p = *tail) != NULL) {
		cmp = ((i >= q->nr)
		       ? -1 : compare_paths(p, q->queue[i]->two));

		if (cmp < 0) {
			/* p->path not in q->queue[]; drop it */
			*tail = p->next;
			free(p);
			continue;
		}

		if (cmp > 0) {
			/* q->queue[i] not in p->path; skip it */
			i++;
			continue;
		}

		hashcpy(p->parent[n].oid.hash, q->queue[i]->one->sha1);
		p->parent[n].mode = q->queue[i]->one->mode;
		p->parent[n].status = q->queue[i]->status;

		tail = &p->next;
		i++;
	}
	return curr;
}
예제 #19
0
파일: proc.c 프로젝트: matrach/PRoot
/**
 * This function emulates the @result of readlink("@base/@component")
 * with respect to @tracee, where @base belongs to "/proc" (according
 * to @comparison).  This function returns -errno on error, an enum
 * @action otherwise (c.f. above).
 *
 * Unlike readlink(), this function includes the nul terminating byte
 * to @result.
 */
Action readlink_proc(const Tracee *tracee, char result[PATH_MAX],
			const char base[PATH_MAX], const char component[NAME_MAX],
			Comparison comparison)
{
	const Tracee *known_tracee;
	char proc_path[64]; /* 64 > sizeof("/proc//fd/") + 2 * sizeof(#ULONG_MAX) */
	int status;
	pid_t pid;

	assert(comparison == compare_paths("/proc", base));

	/* Remember: comparison = compare_paths("/proc", base)  */
	switch (comparison) {
	case PATHS_ARE_EQUAL:
		/* Substitute "/proc/self" with "/proc/<PID>".  */
		if (strcmp(component, "self") != 0)
			return DEFAULT;

		status = snprintf(result, PATH_MAX, "/proc/%d", tracee->pid);
		if (status < 0 || status >= PATH_MAX)
			return -EPERM;

		return CANONICALIZE;

	case PATH1_IS_PREFIX:
		/* Handle "/proc/<PID>" below, where <PID> is process
		 * monitored by PRoot.  */
		break;

	default:
		return DEFAULT;
	}

	pid = atoi(base + strlen("/proc/"));
	if (pid == 0)
		return DEFAULT;

	known_tracee = get_tracee(pid, false);
	if (!known_tracee)
		return DEFAULT;

	/* Handle links in "/proc/<PID>/".  */
	status = snprintf(proc_path, sizeof(proc_path), "/proc/%d", pid);
	if (status < 0 || status >= sizeof(proc_path))
		return -EPERM;

	comparison = compare_paths(proc_path, base);
	switch (comparison) {
	case PATHS_ARE_EQUAL:
#define SUBSTITUTE(name, field)					\
		do {						\
			if (strcmp(component, #name) != 0)	\
				break;				\
								\
			status = strlen(known_tracee->field);	\
			if (status >= PATH_MAX)			\
				return -EPERM;			\
								\
			strncpy(result, known_tracee->field, status + 1); \
			return CANONICALIZE;			\
		} while (0)

		/* Substitute link "/proc/<PID>/???" with the content
		 * of tracee->???.  */
		SUBSTITUTE(exe, exe);
		SUBSTITUTE(cwd, fs->cwd);
		//SUBSTITUTE(root);
#undef SUBSTITUTE
		return DEFAULT;

	case PATH1_IS_PREFIX:
		/* Handle "/proc/<PID>/???" below.  */
		break;

	default:
		return DEFAULT;
	}

	/* Handle links in "/proc/<PID>/fd/".  */
	status = snprintf(proc_path, sizeof(proc_path), "/proc/%d/fd", pid);
	if (status < 0 || status >= sizeof(proc_path))
		return -EPERM;

	comparison = compare_paths(proc_path, base);
	switch (comparison) {
		char *end_ptr;

	case PATHS_ARE_EQUAL:
		/* Sanity check: a number is expected.  */
		errno = 0;
		(void) strtol(component, &end_ptr, 10);
		if (errno != 0 || end_ptr == component)
			return -EPERM;

		/* Don't dereference "/proc/<PID>/fd/???" now: they
		 * can point to anonymous pipe, socket, ...  otherwise
		 * they point to a path already canonicalized by the
		 * kernel.
		 *
		 * Note they are still correctly detranslated in
		 * syscall/exit.c if a monitored process uses
		 * readlink() against any of them.  */
		status = snprintf(result, PATH_MAX, "%s/%s", base, component);
		if (status < 0 || status >= PATH_MAX)
			return -EPERM;

		return DONT_CANONICALIZE;

	default:
		return DEFAULT;
	}

	return DEFAULT;
}
예제 #20
0
파일: fake_id0.c 프로젝트: AQBoy/PRoot
/**
 * Force current @tracee's syscall to behave as if executed by "root".
 * This function returns -errno if an error occured, otherwise 0.
 */
static int handle_sysexit_end(Tracee *tracee)
{
	word_t sysnum;

	sysnum = get_sysnum(tracee, ORIGINAL);
	switch (sysnum) {
	case PR_chroot: {
		char path[PATH_MAX];
		word_t result;
		word_t input;
		int status;

		/* Override only permission errors.  */
		result = peek_reg(tracee, CURRENT, SYSARG_RESULT);
		if ((int) result != -EPERM)
			return 0;

		input = peek_reg(tracee, MODIFIED, SYSARG_1);

		status = read_path(tracee, path, input);
		if (status < 0)
			return status;

		/* Only "new rootfs == current rootfs" is supported yet.  */
		status = compare_paths(get_root(tracee), path);
		if (status != PATHS_ARE_EQUAL)
			return 0;

		/* Force success.  */
		poke_reg(tracee, SYSARG_RESULT, 0);
		return 0;
	}

	case PR_setresuid:
	case PR_setresgid:
	case PR_setresuid32:
	case PR_setresgid32:
	case PR_mknod:
	case PR_capset:
	case PR_setxattr:
	case PR_chmod:
	case PR_chown:
	case PR_fchmod:
	case PR_fchown:
	case PR_lchown:
	case PR_chown32:
	case PR_fchown32:
	case PR_lchown32:
	case PR_fchmodat:
	case PR_fchownat: {
		word_t result;

		/* Override only permission errors.  */
		result = peek_reg(tracee, CURRENT, SYSARG_RESULT);
		if ((int) result != -EPERM)
			return 0;

		/* Force success.  */
		poke_reg(tracee, SYSARG_RESULT, 0);
		return 0;
	}

	case PR_getresuid:
	case PR_getresuid32:
	case PR_getresgid:
	case PR_getresgid32:
		poke_mem(tracee, peek_reg(tracee, ORIGINAL, SYSARG_1), 0);
		if (errno != 0)
			return -EFAULT;

		poke_mem(tracee, peek_reg(tracee, ORIGINAL, SYSARG_2), 0);
		if (errno != 0)
			return -EFAULT;

		poke_mem(tracee, peek_reg(tracee, ORIGINAL, SYSARG_3), 0);
		if (errno != 0)
			return -EFAULT;

		/* Force success.  */
		poke_reg(tracee, SYSARG_RESULT, 0);
		return 0;

	case PR_fstatat64:
	case PR_newfstatat:
	case PR_stat64:
	case PR_lstat64:
	case PR_fstat64:
	case PR_stat:
	case PR_lstat:
	case PR_fstat: {
		word_t result;
		word_t address;
		word_t uid, gid;
		Reg sysarg;

		/* Override only if it succeed.  */
		result = peek_reg(tracee, CURRENT, SYSARG_RESULT);
		if (result != 0)
			return 0;

		/* Get the address of the 'stat' structure.  */
		if (sysnum == PR_fstatat64 || sysnum == PR_newfstatat)
			sysarg = SYSARG_3;
		else
			sysarg = SYSARG_2;

		address = peek_reg(tracee, ORIGINAL, sysarg);

		/* Get the uid & gid values from the 'stat' structure.  */
		uid = peek_mem(tracee, address + offsetof_stat_uid(tracee));
		if (errno != 0)
			uid = 0; /* Not fatal.  */

		gid = peek_mem(tracee, address + offsetof_stat_gid(tracee));
		if (errno != 0)
			gid = 0; /* Not fatal.  */

		/* These values are 32-bit width, even on 64-bit architecture.  */
		uid &= 0xFFFFFFFF;
		gid &= 0xFFFFFFFF;

		/* Override only if the file is owned by the current user.
		 * Errors are not fatal here.  */
		if (uid == getuid())
			poke_mem(tracee, address + offsetof_stat_uid(tracee), 0);
		if (gid == getgid())
			poke_mem(tracee, address + offsetof_stat_gid(tracee), 0);

		return 0;
	}

	case PR_getuid:
	case PR_getgid:
	case PR_getegid:
	case PR_geteuid:
	case PR_getuid32:
	case PR_getgid32:
	case PR_geteuid32:
	case PR_getegid32:
	case PR_setuid:
	case PR_setgid:
	case PR_setfsuid:
	case PR_setfsgid:
	case PR_setuid32:
	case PR_setgid32:
	case PR_setfsuid32:
	case PR_setfsgid32:
		/* Force success.  */
		poke_reg(tracee, SYSARG_RESULT, 0);
		return 0;

	default:
		return 0;
	}
}