From: Michael Gilbert Date: Sat, 24 Sep 2022 17:29:03 +0000 (+0100) Subject: safer selection of the temporary directory for wineserver X-Git-Tag: archive/raspbian/7.0_repack-10+rpi1~2^2^2~18 X-Git-Url: https://dgit.raspbian.org/?a=commitdiff_plain;h=60e42eac4207b93717a841d42a248a3bb617475d;p=wine.git safer selection of the temporary directory for wineserver bug-debian: https://bugs.debian.org/903622 bug-debian: https://bugs.debian.org/904041 bug-upstream: https://bugs.winehq.org/show_bug.cgi?id=39013 Gbp-Pq: Topic fixes Gbp-Pq: Name temporary-directory.patch --- diff --git a/dlls/ntdll/unix/server.c b/dlls/ntdll/unix/server.c index 9d0594d..868cd1a 100644 --- a/dlls/ntdll/unix/server.c +++ b/dlls/ntdll/unix/server.c @@ -24,6 +24,7 @@ #include "config.h" +#include #include #include #include @@ -1104,6 +1105,17 @@ int server_pipe( int fd[2] ) return ret; } +/* build a path from the specified dir and name */ +static char *ntdll_build_path( const char *dir, const char *name ) +{ + size_t len = strlen(dir); + char *ret = malloc( len + strlen(name) + 2 ); + + memcpy( ret, dir, len ); + if (len && ret[len-1] != '/') ret[len++] = '/'; + strcpy( ret + len, name ); + return ret; +} /*********************************************************************** * init_server_dir @@ -1113,16 +1125,113 @@ static const char *init_server_dir( dev_t dev, ino_t ino ) char *p, *dir; size_t len = sizeof("/server-") + 2 * sizeof(dev) + 2 * sizeof(ino) + 2; -#ifdef __ANDROID__ /* there's no /tmp dir on Android */ - len += strlen( config_dir ) + sizeof("/.wineserver"); - dir = malloc( len ); - strcpy( dir, config_dir ); - strcat( dir, "/.wineserver/server-" ); -#else - len += sizeof("/tmp/.wine-") + 12; - dir = malloc( len ); - sprintf( dir, "/tmp/.wine-%u/server-", getuid() ); -#endif + char *root = NULL; + char *run_dir = NULL; + const char *run_prefix = "/run/user"; + + /* use /run/user/$uid as wineserver's tmpdir if possible */ + run_dir = malloc( strlen(run_prefix) + 13 ); + sprintf( run_dir, "%s/%u", run_prefix, getuid() ); + if (opendir( run_dir )) + { + root = malloc( strlen(run_dir) + 6 ); + sprintf( root, "%s/wine", run_dir ); + } + free( run_dir ); + + /* otherwise, use a randomly named directory under TMPDIR */ + if (!root) + { + int error; + FILE *stream; + char *wineserver_file, *tmp_env, *tmp_dir; + mode_t mode = S_IRUSR; + + /* determine the temporary directory */ + tmp_env = secure_getenv("TMPDIR"); + if (tmp_env) + { + tmp_dir = malloc( strlen(tmp_env) + 1 ); + strcpy( tmp_dir, tmp_env ); + } + else + { + const char *tmp_default = "/tmp"; + tmp_dir = malloc( strlen(tmp_default) + 1 ); + strcpy( tmp_dir, tmp_default ); + } + + /* remove existing wineserver tmpdir file if permissions are wrong */ + wineserver_file = ntdll_build_path( config_dir, "wineserver" ); + if ( access( wineserver_file, F_OK ) != -1 ) + { + struct stat statbuf; + mode_t mode_mask = S_IRWXU | S_IRWXG | S_IRWXO; + error = stat( wineserver_file, &statbuf ); + if (error != 0) + fatal_error("error reading wineserver tmpdir file permissions\n"); + if ((statbuf.st_mode & mode_mask) != mode) + { + error = remove( wineserver_file ); + if (error != 0) + fatal_error("error removing wineserver tmpdir file\n"); + } + } + + /* create or read the name of the directory */ + stream = fopen( wineserver_file, "r" ); + if (!stream) + { + int n, fd; + + /* create a new randomized name for the directory */ + root = mkdtemp( ntdll_build_path( tmp_dir, "wine-XXXXXX" ) ); + if (!root) + fatal_error("unable to create wineserver tmpdir\n"); + + /* save location of the chosen temporary directory */ + fd = creat( wineserver_file, mode ); + if (fd < 0) + fatal_error("error opening file descriptor for wineserver tmpdir file\n"); + stream = fdopen( fd, "w" ); + if (!stream) + fatal_error("error opening wineserver tmpdir file\n"); + n = fputs( root + strlen(tmp_dir) + 1, stream ); + if (n < 0) + fatal_error("error writing to wineserver tmpdir file\n"); + error = fclose( stream ); + if (error != 0) + fatal_error("error closing wineserver tmpdir file\n"); + } + else + { + char *tmp_wineserver; + size_t length = 0; + ssize_t nread; + + /* try to read a previously generated wineserver tmpdir */ + nread = getline( &tmp_wineserver, &length, stream ); + error = fclose( stream ); + if (error != 0) + fatal_error("error closing wineserver tmpdir file\n"); + + /* if something went wrong, remove the broken file */ + if (nread < 0) + { + remove( wineserver_file ); + fatal_error("fixed a temporary directory error, please try running the same command again\n"); + } + + /* build the full path to the temporary directory */ + root = ntdll_build_path( tmp_dir, tmp_wineserver ); + } + free( tmp_dir ); + free( wineserver_file ); + } + dir = malloc( strlen(root) + len ); + sprintf( dir, "%s/server-", root ); + free( root ); + p = dir + strlen( dir ); if (dev != (unsigned long)dev) p += sprintf( p, "%lx%08lx-", (unsigned long)((unsigned long long)dev >> 32), (unsigned long)dev ); diff --git a/libs/wine/config.c b/libs/wine/config.c index 23c76fd..a8a3980 100644 --- a/libs/wine/config.c +++ b/libs/wine/config.c @@ -382,6 +382,8 @@ static void init_server_dir( dev_t dev, ino_t ino ) { char *p, *root; + fatal_error("called obsolete init_server_dir\n"); + #ifdef __ANDROID__ /* there's no /tmp dir on Android */ root = build_path( config_dir, ".wineserver" ); #else diff --git a/server/request.c b/server/request.c index 7021741..a3d5f06 100644 --- a/server/request.c +++ b/server/request.c @@ -20,6 +20,7 @@ #include "config.h" +#include #include #include #include @@ -609,11 +610,23 @@ static void create_dir( const char *name, struct stat *st ) if (st->st_mode & 077) fatal_error( "%s must not be accessible by other users\n", name ); } +static char *server_build_path( const char *dir, const char *name ) +{ + size_t len = strlen(dir); + char *ret = malloc( len + strlen(name) + 2 ); + + memcpy( ret, dir, len ); + if (len && ret[len-1] != '/') ret[len++] = '/'; + strcpy( ret + len, name ); + return ret; +} + /* create the server directory and chdir to it */ static char *create_server_dir( int force ) { + const char *server_root_prefix = "/run/user"; const char *prefix = getenv( "WINEPREFIX" ); - char *p, *config_dir; + char *p, *config_dir, *run_dir; struct stat st, st2; size_t len = sizeof("/server-") + 2 * sizeof(st.st_dev) + 2 * sizeof(st.st_ino) + 2; @@ -663,9 +676,117 @@ static char *create_server_dir( int force ) strcpy( server_dir, config_dir ); strcat( server_dir, "/.wineserver" ); #else - len += sizeof("/tmp/.wine-") + 12; - if (!(server_dir = malloc( len ))) fatal_error( "out of memory\n" ); - sprintf( server_dir, "/tmp/.wine-%u", getuid() ); + /* use /run/user/$uid as wineserver's tmpdir by default */ + if (!(run_dir = malloc( strlen(server_root_prefix) + 13 ))) + fatal_error( "out of memory\n" ); + sprintf( run_dir, "%s/%u", server_root_prefix, getuid() ); + + if (opendir( run_dir )) /* use /run as the temporary directory */ + { + len += strlen(run_dir) + 6; + if (!(server_dir = malloc( len ))) + fatal_error( "out of memory\n" ); + sprintf( server_dir, "%s/wine", run_dir ); + } + else /* use a randomly named directory in TMPDIR */ + { + int error; + FILE *stream; + char *wineserver_file, *tmp_dir, *tmp_env, *tmp_root; + mode_t mode = S_IRUSR; + + /* determine the temporary directory */ + tmp_env = secure_getenv("TMPDIR"); + if (tmp_env) + { + if (!(tmp_dir = malloc( strlen(tmp_env) + 1 ))) + fatal_error( "out of memory\n" ); + strcpy( tmp_dir, tmp_env ); + } + else + { + const char *tmp_default = "/tmp"; + if (!(tmp_dir = malloc( strlen(tmp_default) + 1 ))) + fatal_error( "out of memory\n" ); + strcpy( tmp_dir, tmp_default ); + } + + /* remove existing wineserver tmpdir file if permissions are wrong */ + wineserver_file = server_build_path( config_dir, "wineserver" ); + if ( access( wineserver_file, F_OK ) != -1 ) + { + struct stat statbuf; + mode_t mode_mask = S_IRWXU | S_IRWXG | S_IRWXO; + error = stat( wineserver_file, &statbuf ); + if (error != 0) + fatal_error("error reading wineserver tmpdir file permissions\n"); + if ((statbuf.st_mode & mode_mask) != mode) + { + error = remove( wineserver_file ); + if (error != 0) + fatal_error("error removing wineserver tmpdir file\n"); + } + } + + /* create or read the name of the directory */ + stream = fopen( wineserver_file, "r" ); + if (!stream) + { + int n, fd; + + /* create a new randomized name for the directory */ + tmp_root = mkdtemp( server_build_path( tmp_dir, "wine-XXXXXX" ) ); + if (!tmp_root) + fatal_error("unable to create wineserver tmpdir\n"); + + /* save location of the chosen temporary directory */ + fd = creat( wineserver_file, mode ); + if (fd < 0) + fatal_error("error opening file descriptor for wineserver tmpdir file\n"); + stream = fdopen( fd, "w" ); + if (!stream) + fatal_error("error opening wineserver tmpdir file\n"); + n = fputs( tmp_root + strlen(tmp_dir) + 1, stream ); + if (n < 0) + fatal_error("error writing to wineserver tmpdir file\n"); + error = fclose( stream ); + if (error != 0) + fatal_error("error closing wineserver tmpdir file\n"); + } + else + { + char *tmp_wineserver; + size_t length = 0; + ssize_t nread; + + /* try to read a previously generated wineserver tmpdir */ + nread = getline( &tmp_wineserver, &length, stream ); + error = fclose( stream ); + if (error != 0) + fatal_error("error closing wineserver tmpdir file\n"); +/* if something went wrong, remove the broken file */ + if (nread < 0) + { + remove( wineserver_file ); + fatal_error("fixed a temporary directory error, please try running the same command again\n"); + } + + /* build the full path to the temporary directory */ + tmp_root = server_build_path( tmp_dir, tmp_wineserver ); + } + + /* copy the path into its final destination */ + len += strlen(tmp_root) + 1; + if (!(server_dir = malloc( len ))) + fatal_error( "out of memory\n" ); + strcpy( server_dir, tmp_root ); + + /* free temporaries */ + free( tmp_dir ); + free( tmp_root ); + free( wineserver_file ); + } + free( run_dir ); #endif create_dir( server_dir, &st2 );