From f9906424d4be8cc274f4eab1a2264f264ec0ebe0 Mon Sep 17 00:00:00 2001 From: Karel Zak Date: Mon, 16 Jan 2012 12:09:36 +0100 Subject: [PATCH] libmount: add post-mount checks to detect ro/rw Signed-off-by: Karel Zak --- libmount/src/context_loopdev.c | 3 +-- libmount/src/context_mount.c | 40 +++++++++++++++++++++++++++++----- libmount/src/mountP.h | 2 ++ libmount/src/utils.c | 35 +++++++++++++++++++++++++++++ 4 files changed, 72 insertions(+), 8 deletions(-) diff --git a/libmount/src/context_loopdev.c b/libmount/src/context_loopdev.c index 8e9ed93aa5..a379587090 100644 --- a/libmount/src/context_loopdev.c +++ b/libmount/src/context_loopdev.c @@ -289,8 +289,7 @@ int mnt_context_setup_loopdev(struct libmnt_context *cxt) * mount planned read-write, but loopdev is read-only, * let's fix mount options... */ - cxt->mountflags |= MS_RDONLY; - + mnt_context_set_mflags(cxt, cxt->mountflags | MS_RDONLY); /* we have to keep the device open until mount(1), * otherwise it will auto-cleared by kernel diff --git a/libmount/src/context_mount.c b/libmount/src/context_mount.c index 6f2a3dc116..9d5933c564 100644 --- a/libmount/src/context_mount.c +++ b/libmount/src/context_mount.c @@ -455,10 +455,6 @@ static int do_mount(struct libmnt_context *cxt, const char *try_type) rc = mnt_fs_set_fstype(fs, try_type); } - /* TODO: check if the result is really read-only/read-write - * and if necessary update cxt->mountflags - */ - return rc; } @@ -591,6 +587,7 @@ int mnt_context_prepare_mount(struct libmnt_context *cxt) int mnt_context_do_mount(struct libmnt_context *cxt) { const char *type; + int res; assert(cxt); assert(cxt->fs); @@ -607,9 +604,40 @@ int mnt_context_do_mount(struct libmnt_context *cxt) type = mnt_fs_get_fstype(cxt->fs); if (type) - return do_mount(cxt, NULL); + res = do_mount(cxt, NULL); + else + res = do_mount_by_pattern(cxt, cxt->fstype_pattern); + + if (mnt_context_get_status(cxt) + && !(cxt->flags & MNT_FL_FAKE) + && !cxt->helper) { + /* + * Mounted by mount(2), do some post-mount checks + * + * Kernel allows to use MS_RDONLY for bind mounts, but the + * read-only request could be silently ignored. Check it to + * avoid 'ro' in mtab and 'rw' in /proc/mounts. + */ + if ((cxt->mountflags & MS_BIND) + && (cxt->mountflags & MS_RDONLY) + && !mnt_is_readonly(mnt_context_get_target(cxt))) + + mnt_context_set_mflags(cxt, + cxt->mountflags & ~MS_RDONLY); + + + /* Kernel can silently add MS_RDONLY flag when mounting file + * system that does not have write support. Check this to avoid + * 'ro' in /proc/mounts and 'rw' in mtab. + */ + if (!(cxt->mountflags & (MS_RDONLY | MS_PROPAGATION | MS_MOVE)) + && mnt_is_readonly(mnt_context_get_target(cxt))) + + mnt_context_set_mflags(cxt, + cxt->mountflags | MS_RDONLY); + } - return do_mount_by_pattern(cxt, cxt->fstype_pattern); + return res; } /** diff --git a/libmount/src/mountP.h b/libmount/src/mountP.h index c321702b68..05a13d5de6 100644 --- a/libmount/src/mountP.h +++ b/libmount/src/mountP.h @@ -129,6 +129,8 @@ extern int mnt_run_test(struct libmnt_test *tests, int argc, char *argv[]); extern int endswith(const char *s, const char *sx); extern int startswith(const char *s, const char *sx); +extern int mnt_is_readonly(const char *path); + extern int mnt_parse_offset(const char *str, size_t len, uintmax_t *res); extern int mnt_chdir_to_parent(const char *target, char **filename); diff --git a/libmount/src/utils.c b/libmount/src/utils.c index b3bb8dce45..cbaabc6c4c 100644 --- a/libmount/src/utils.c +++ b/libmount/src/utils.c @@ -145,6 +145,41 @@ err: return rc; } +/* + * Check if @path is on read-only filesystem independently on file permissions. + */ +int mnt_is_readonly(const char *path) +{ + if (access(path, W_OK) == 0) + return 0; + if (errno == EROFS) + return 1; + if (errno != EACCES) + return 0; + +#ifdef HAVE_FUTIMENS + /* + * access(2) returns EACCES on read-only FS: + * + * - for set-uid application if one component of the path is not + * accessible for the current rUID. (Note that euidaccess(2) does not + * check for EROFS at all). + * + * - for read-write filesystem with read-only VFS node (aka -o remount,ro,bind) + */ + { + struct timespec times[2]; + + times[0].tv_nsec = UTIME_NOW; /* atime */ + times[1].tv_nsec = UTIME_OMIT; /* mtime */ + + if (utimensat(AT_FDCWD, path, times, 0) == -1) + return errno == EROFS; + } +#endif + return 0; +} + /** * mnt_mangle: * @str: string -- 2.39.5