Commit 23d53913 authored by Daniel Black's avatar Daniel Black

MDEV-27038 Custom configuration file procedure does not work with Docker Desktop for Windows 10+

Docker when mounting a configuration file into a Windows exposes the
file with permission 0777. These world writable files are ignored by
by MariaDB.

Add the access check such that filesystem RO or immutable file is
counted as sufficient protection on the file.

Test:
$ mkdir /tmp/src
$ vi /tmp/src/my.cnf
$ chmod 666 /tmp/src/my.cnf
$ mkdir /tmp/dst
$ sudo mount --bind /tmp/src /tmp/dst -o ro
$ ls -la /tmp/dst
total 4
drwxr-xr-x.  2 dan  dan   60 Jun 15 15:12 .
drwxrwxrwt. 25 root root 660 Jun 15 15:13 ..
-rw-rw-rw-.  1 dan  dan   10 Jun 15 15:12 my.cnf
$ mount | grep dst
tmpfs on /tmp/dst type tmpfs (ro,seclabel,nr_inodes=1048576,inode64)

strace client/mariadb --defaults-file=/tmp/dst/my.cnf

newfstatat(AT_FDCWD, "/tmp/dst/my.cnf", {st_mode=S_IFREG|0666, st_size=10, ...}, 0) = 0
access("/tmp/dst/my.cnf", W_OK)         = -1 EROFS (Read-only file system)
openat(AT_FDCWD, "/tmp/dst/my.cnf", O_RDONLY|O_CLOEXEC) = 3

The one failing test, but this isn't a regression, just not a total fix:

$ chmod u-w /tmp/src/my.cnf
$ ls -la /tmp/src/my.cnf
-r--rw-rw-. 1 dan dan 18 Jun 16 10:22 /tmp/src/my.cnf
$ strace -fe trace=access client/mariadb --defaults-file=/tmp/dst/my.cnf
access("/etc/ld.so.preload", R_OK)      = -1 ENOENT (No such file or directory)
access("/etc/system-fips", F_OK)        = -1 ENOENT (No such file or directory)
access("/tmp/dst/my.cnf", W_OK)         = -1 EACCES (Permission denied)
Warning: World-writable config file '/tmp/dst/my.cnf' is ignored

Windows test (Docker Desktop ~4.21) which was the important one to fix:

dan@LAPTOP-5B5P7RCK:~$ docker run --rm  -v /mnt/c/Users/danie/Desktop/conf:/etc/mysql/conf.d/:ro -e MARIADB_ROOT_PASSWORD=bob quay.io/m
ariadb-foundation/mariadb-devel:10.4-MDEV-27038-ro-mounts-pkgtest ls -la /etc/mysql/conf.d
total 4
drwxrwxrwx 1 root root  512 Jun 15 13:57 .
drwxr-xr-x 4 root root 4096 Jun 15 07:32 ..
-rwxrwxrwx 1 root root   43 Jun 15 13:56 myapp.cnf

root@a59b38b45af1:/# strace -fe trace=access mariadb
access("/etc/ld.so.preload", R_OK)      = -1 ENOENT (No such file or directory)
access("/etc/mysql/conf.d/myapp.cnf", W_OK) = -1 EROFS (Read-only file system)
parent 7a5c984f
...@@ -786,12 +786,27 @@ static int search_default_file_with_ext(Process_option_func opt_handler, ...@@ -786,12 +786,27 @@ static int search_default_file_with_ext(Process_option_func opt_handler,
if (!my_stat(name,&stat_info,MYF(0))) if (!my_stat(name,&stat_info,MYF(0)))
return 1; return 1;
/* /*
Ignore world-writable regular files. Ignore world-writable regular files (exceptions apply).
This is mainly done to protect us to not read a file created by This is mainly done to protect us to not read a file that may be
the mysqld server, but the check is still valid in most context. modified by anyone.
Also check access so that read only mounted (EROFS)
or immutable files (EPERM) that are suitable protections.
The main case we are allowing is a container readonly volume mount
from a filesystem that doesn't have unix permissions. This will
have a 0777 permission and access will set errno = EROFS.
Note if a ROFS has a file with permissions 04n6, access sets errno
EACCESS, rather the ROFS, so in this case we'll error, even though
the ROFS is protecting the file.
An ideal, race free, implementation would do fstat / fstatvfs / ioctl
for permission, read only filesystem, and immutability resprectively.
*/ */
if ((stat_info.st_mode & S_IWOTH) && if ((stat_info.st_mode & S_IWOTH) &&
(stat_info.st_mode & S_IFMT) == S_IFREG) (stat_info.st_mode & S_IFMT) == S_IFREG &&
(access(name, W_OK) == 0 || (errno != EROFS && errno != EPERM)))
{ {
fprintf(stderr, "Warning: World-writable config file '%s' is ignored\n", fprintf(stderr, "Warning: World-writable config file '%s' is ignored\n",
name); name);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment