Merge branch 'bug11946'

This commit is contained in:
Nick Mathewson
2014-05-14 22:51:51 -04:00
7 changed files with 126 additions and 12 deletions
+5
View File
@@ -0,0 +1,5 @@
o Minor bugfixes (sandbox):
- Handle failures in getpwnam()/getpwuid() when running with the
User option set and the Linux syscall sandbox enabled. Fixes bug
11946; bugfix on 0.2.5.1-alpha.
+105 -4
View File
@@ -1702,6 +1702,107 @@ log_credential_status(void)
}
#endif
#ifndef _WIN32
/** Cached struct from the last getpwname() call we did successfully. */
static struct passwd *passwd_cached = NULL;
/** Helper: copy a struct passwd object.
*
* We only copy the fields pw_uid, pw_gid, pw_name, pw_dir. Tor doesn't use
* any others, and I don't want to run into incompatibilities.
*/
static struct passwd *
tor_passwd_dup(const struct passwd *pw)
{
struct passwd *new_pw = tor_malloc_zero(sizeof(struct passwd));
if (pw->pw_name)
new_pw->pw_name = tor_strdup(pw->pw_name);
if (pw->pw_dir)
new_pw->pw_dir = tor_strdup(pw->pw_dir);
new_pw->pw_uid = pw->pw_uid;
new_pw->pw_gid = pw->pw_gid;
return new_pw;
}
/** Helper: free one of our cached 'struct passwd' values. */
static void
tor_passwd_free(struct passwd *pw)
{
if (!pw)
return;
tor_free(pw->pw_name);
tor_free(pw->pw_dir);
tor_free(pw);
}
/** Wrapper around getpwnam() that caches result. Used so that we don't need
* to give the sandbox access to /etc/passwd.
*
* The following fields alone will definitely be copied in the output: pw_uid,
* pw_gid, pw_name, pw_dir. Other fields are not present in cached values.
*
* When called with a NULL argument, this function clears storage associated
* with static variables it uses.
**/
const struct passwd *
tor_getpwnam(const char *username)
{
struct passwd *pw;
if (username == NULL) {
tor_passwd_free(passwd_cached);
passwd_cached = NULL;
return NULL;
}
if ((pw = getpwnam(username))) {
tor_passwd_free(passwd_cached);
passwd_cached = tor_passwd_dup(pw);
log_notice(LD_GENERAL, "Caching new entry %s for %s",
passwd_cached->pw_name, username);
return pw;
}
/* Lookup failed */
if (! passwd_cached || ! passwd_cached->pw_name)
return NULL;
if (! strcmp(username, passwd_cached->pw_name))
return passwd_cached;
return NULL;
}
/** Wrapper around getpwnam() that can use cached result from
* tor_getpwnam(). Used so that we don't need to give the sandbox access to
* /etc/passwd.
*
* The following fields alone will definitely be copied in the output: pw_uid,
* pw_gid, pw_name, pw_dir. Other fields are not present in cached values.
*/
const struct passwd *
tor_getpwuid(uid_t uid)
{
struct passwd *pw;
if ((pw = getpwuid(uid))) {
return pw;
}
/* Lookup failed */
if (! passwd_cached)
return NULL;
if (uid == passwd_cached->pw_uid)
return passwd_cached;
return NULL;
}
#endif
/** Call setuid and setgid to run as <b>user</b> and switch to their
* primary group. Return 0 on success. On failure, log and return -1.
*/
@@ -1709,7 +1810,7 @@ int
switch_id(const char *user)
{
#ifndef _WIN32
struct passwd *pw = NULL;
const struct passwd *pw = NULL;
uid_t old_uid;
gid_t old_gid;
static int have_already_switched_id = 0;
@@ -1730,7 +1831,7 @@ switch_id(const char *user)
old_gid = getgid();
/* Lookup the user and group information, if we have a problem, bail out. */
pw = getpwnam(user);
pw = tor_getpwnam(user);
if (pw == NULL) {
log_warn(LD_CONFIG, "Error setting configured user: %s not found", user);
return -1;
@@ -1901,10 +2002,10 @@ tor_disable_debugger_attach(void)
char *
get_user_homedir(const char *username)
{
struct passwd *pw;
const struct passwd *pw;
tor_assert(username);
if (!(pw = getpwnam(username))) {
if (!(pw = tor_getpwnam(username))) {
log_err(LD_CONFIG,"User \"%s\" not found.", username);
return NULL;
}
+5
View File
@@ -633,6 +633,11 @@ int switch_id(const char *user);
char *get_user_homedir(const char *username);
#endif
#ifndef _WIN32
const struct passwd *tor_getpwnam(const char *username);
const struct passwd *tor_getpwuid(uid_t uid);
#endif
int get_parent_directory(char *fname);
char *make_path_absolute(char *fname);
+5 -5
View File
@@ -1871,7 +1871,7 @@ check_private_dir(const char *dirname, cpd_check_t check,
char *f;
#ifndef _WIN32
int mask;
struct passwd *pw = NULL;
const struct passwd *pw = NULL;
uid_t running_uid;
gid_t running_gid;
#else
@@ -1918,7 +1918,7 @@ check_private_dir(const char *dirname, cpd_check_t check,
if (effective_user) {
/* Look up the user and group information.
* If we have a problem, bail out. */
pw = getpwnam(effective_user);
pw = tor_getpwnam(effective_user);
if (pw == NULL) {
log_warn(LD_CONFIG, "Error setting configured user: %s not found",
effective_user);
@@ -1932,13 +1932,13 @@ check_private_dir(const char *dirname, cpd_check_t check,
}
if (st.st_uid != running_uid) {
struct passwd *pw = NULL;
const struct passwd *pw = NULL;
char *process_ownername = NULL;
pw = getpwuid(running_uid);
pw = tor_getpwuid(running_uid);
process_ownername = pw ? tor_strdup(pw->pw_name) : tor_strdup("<unknown>");
pw = getpwuid(st.st_uid);
pw = tor_getpwuid(st.st_uid);
log_warn(LD_FS, "%s is not owned by this user (%s, %d) but by "
"%s (%d). Perhaps you are running Tor as the wrong user?",
+2 -2
View File
@@ -1017,7 +1017,7 @@ connection_listener_new(const struct sockaddr *listensockaddr,
tor_socket_t s = TOR_INVALID_SOCKET; /* the socket we're going to make */
or_options_t const *options = get_options();
#if defined(HAVE_PWD_H) && defined(HAVE_SYS_UN_H)
struct passwd *pw = NULL;
const struct passwd *pw = NULL;
#endif
uint16_t usePort = 0, gotPort = 0;
int start_reading = 0;
@@ -1157,7 +1157,7 @@ connection_listener_new(const struct sockaddr *listensockaddr,
}
#ifdef HAVE_PWD_H
if (options->User) {
pw = getpwnam(options->User);
pw = tor_getpwnam(options->User);
if (pw == NULL) {
log_warn(LD_NET,"Unable to chown() %s socket: user %s not found.",
address, options->User);
+1 -1
View File
@@ -1492,7 +1492,7 @@ getinfo_helper_misc(control_connection_t *conn, const char *question,
*answer = tor_strdup("");
#else
int myUid = geteuid();
struct passwd *myPwEntry = getpwuid(myUid);
const struct passwd *myPwEntry = tor_getpwuid(myUid);
if (myPwEntry) {
*answer = tor_strdup(myPwEntry->pw_name);
+3
View File
@@ -2548,6 +2548,9 @@ tor_free_all(int postfork)
free_cell_pool();
if (!postfork) {
tor_tls_free_all();
#ifndef _WIN32
tor_getpwnam(NULL);
#endif
}
/* stuff in main.c */