Allow users to have homedir as a symbolic link but mount on the homedir

Also do not error out on setfsuid if errno == success.  This breaks on systems
that use file capabilities rather then on setuid apps.
This commit is contained in:
Dan Walsh 2013-10-09 17:28:37 -04:00 committed by Stephen Smalley
parent a387e158f5
commit e4488ecd87
1 changed files with 18 additions and 4 deletions

View File

@ -617,8 +617,8 @@ static int cleanup_tmpdir(const char *tmpdir, const char *src,
free(cmdbuf); cmdbuf = NULL; free(cmdbuf); cmdbuf = NULL;
/* remove runtime temporary directory */ /* remove runtime temporary directory */
if ((uid_t)setfsuid(0) != pwd->pw_uid) { if ((uid_t)setfsuid(0) != 0) {
fprintf(stderr, _("Unable to switch to root to clear tmp dir\n")); /* setfsuid does not return errror, but this check makes code checkers happy */
rc++; rc++;
} }
@ -833,6 +833,7 @@ int main(int argc, char **argv) {
char *tmpdir_s = NULL; /* tmpdir spec'd by user in argv[] */ char *tmpdir_s = NULL; /* tmpdir spec'd by user in argv[] */
char *tmpdir_r = NULL; /* tmpdir created by seunshare */ char *tmpdir_r = NULL; /* tmpdir created by seunshare */
struct stat st_curhomedir;
struct stat st_homedir; struct stat st_homedir;
struct stat st_tmpdir_s; struct stat st_tmpdir_s;
struct stat st_tmpdir_r; struct stat st_tmpdir_r;
@ -931,8 +932,11 @@ int main(int argc, char **argv) {
/* Changing fsuid is usually required when user-specified directory is /* Changing fsuid is usually required when user-specified directory is
* on an NFS mount. It's also desired to avoid leaking info about * on an NFS mount. It's also desired to avoid leaking info about
* existence of the files not accessible to the user. */ * existence of the files not accessible to the user. */
if ((uid_t)setfsuid(uid) != 0) if (((uid_t)setfsuid(uid) != 0) && (errno != 0)) {
fprintf(stderr, _("Error: unable to setfsuid %m\n"));
return -1; return -1;
}
/* verify homedir and tmpdir */ /* verify homedir and tmpdir */
if (homedir_s && ( if (homedir_s && (
@ -961,6 +965,7 @@ int main(int argc, char **argv) {
char *display = NULL; char *display = NULL;
char *LANG = NULL; char *LANG = NULL;
int rc = -1; int rc = -1;
char *resolved_path = NULL;
if (unshare(CLONE_NEWNS) < 0) { if (unshare(CLONE_NEWNS) < 0) {
perror(_("Failed to unshare")); perror(_("Failed to unshare"));
@ -977,8 +982,16 @@ int main(int argc, char **argv) {
/* assume fsuid==ruid after this point */ /* assume fsuid==ruid after this point */
if ((uid_t)setfsuid(uid) != 0) goto childerr; if ((uid_t)setfsuid(uid) != 0) goto childerr;
resolved_path = realpath(pwd->pw_dir,NULL);
if (! resolved_path) goto childerr;
if (verify_directory(resolved_path, NULL, &st_curhomedir) < 0)
goto childerr;
if (check_owner_uid(uid, resolved_path, &st_curhomedir) < 0)
goto childerr;
/* mount homedir and tmpdir, in this order */ /* mount homedir and tmpdir, in this order */
if (homedir_s && seunshare_mount(homedir_s, pwd->pw_dir, if (homedir_s && seunshare_mount(homedir_s, resolved_path,
&st_homedir) != 0) goto childerr; &st_homedir) != 0) goto childerr;
if (tmpdir_s && seunshare_mount(tmpdir_r, "/tmp", if (tmpdir_s && seunshare_mount(tmpdir_r, "/tmp",
&st_tmpdir_r) != 0) goto childerr; &st_tmpdir_r) != 0) goto childerr;
@ -1033,6 +1046,7 @@ int main(int argc, char **argv) {
execv(argv[optind], argv + optind); execv(argv[optind], argv + optind);
fprintf(stderr, _("Failed to execute command %s: %s\n"), argv[optind], strerror(errno)); fprintf(stderr, _("Failed to execute command %s: %s\n"), argv[optind], strerror(errno));
childerr: childerr:
free(resolved_path);
free(display); free(display);
free(LANG); free(LANG);
exit(-1); exit(-1);