From 06ff935ec3ad2290025b555ff32b590680af565f Mon Sep 17 00:00:00 2001 From: Karel Zak Date: Wed, 8 Nov 2017 16:47:40 +0100 Subject: libmount: fix access() utab write test The commit c08396c7691e1e6a04b6b45892e7e4612ceed8d7 replaces open(O_CREATE) with ecaccess(). Unfortunately, another code depends on the original behavior. * let's make utab when really necessary rather than in the try_write() test * __mnt_new_table_from_file() returns NULL if tab-file does not exists. This is incorrect for tab_update.c stuff. We need empty table in this case. * we can check /run/mount/ directory for write access if eaccess(filename) return ENOENT (because file does not exist) Signed-off-by: Karel Zak --- libmount/src/mountP.h | 2 +- libmount/src/tab_parse.c | 7 ++++--- libmount/src/tab_update.c | 11 ++++++----- libmount/src/utils.c | 42 +++++++++++++++++++++++++++++++----------- 4 files changed, 42 insertions(+), 20 deletions(-) (limited to 'libmount/src') diff --git a/libmount/src/mountP.h b/libmount/src/mountP.h index e01de337d..b00426d67 100644 --- a/libmount/src/mountP.h +++ b/libmount/src/mountP.h @@ -242,7 +242,7 @@ struct libmnt_table { void *userdata; }; -extern struct libmnt_table *__mnt_new_table_from_file(const char *filename, int fmt); +extern struct libmnt_table *__mnt_new_table_from_file(const char *filename, int fmt, int empty_for_enoent); /* * Tab file format diff --git a/libmount/src/tab_parse.c b/libmount/src/tab_parse.c index b17a22913..02dd0c961 100644 --- a/libmount/src/tab_parse.c +++ b/libmount/src/tab_parse.c @@ -838,7 +838,7 @@ int mnt_table_parse_dir(struct libmnt_table *tb, const char *dirname) return __mnt_table_parse_dir(tb, dirname); } -struct libmnt_table *__mnt_new_table_from_file(const char *filename, int fmt) +struct libmnt_table *__mnt_new_table_from_file(const char *filename, int fmt, int empty_for_enoent) { struct libmnt_table *tb; struct stat st; @@ -846,7 +846,8 @@ struct libmnt_table *__mnt_new_table_from_file(const char *filename, int fmt) if (!filename) return NULL; if (stat(filename, &st)) - return NULL; + return empty_for_enoent ? mnt_new_table() : NULL; + tb = mnt_new_table(); if (tb) { DBG(TAB, ul_debugobj(tb, "new tab for file: %s", filename)); @@ -875,7 +876,7 @@ struct libmnt_table *mnt_new_table_from_file(const char *filename) if (!filename) return NULL; - return __mnt_new_table_from_file(filename, MNT_FMT_GUESS); + return __mnt_new_table_from_file(filename, MNT_FMT_GUESS, 0); } /** diff --git a/libmount/src/tab_update.c b/libmount/src/tab_update.c index e95713301..23a5a8bc5 100644 --- a/libmount/src/tab_update.c +++ b/libmount/src/tab_update.c @@ -571,6 +571,7 @@ leave: unlink(uq); /* be paranoid */ free(uq); + DBG(UPDATE, ul_debugobj(upd, "%s: done [rc=%d]", upd->filename, rc)); return rc; } @@ -699,7 +700,7 @@ static int update_add_entry(struct libmnt_update *upd, struct libmnt_lock *lc) return -MNT_ERR_LOCK; tb = __mnt_new_table_from_file(upd->filename, - upd->userspace_only ? MNT_FMT_UTAB : MNT_FMT_MTAB); + upd->userspace_only ? MNT_FMT_UTAB : MNT_FMT_MTAB, 1); if (tb) rc = add_file_entry(tb, upd); if (lc) @@ -725,7 +726,7 @@ static int update_remove_entry(struct libmnt_update *upd, struct libmnt_lock *lc return -MNT_ERR_LOCK; tb = __mnt_new_table_from_file(upd->filename, - upd->userspace_only ? MNT_FMT_UTAB : MNT_FMT_MTAB); + upd->userspace_only ? MNT_FMT_UTAB : MNT_FMT_MTAB, 1); if (tb) { struct libmnt_fs *rem = mnt_table_find_target(tb, upd->target, MNT_ITER_BACKWARD); if (rem) { @@ -754,7 +755,7 @@ static int update_modify_target(struct libmnt_update *upd, struct libmnt_lock *l return -MNT_ERR_LOCK; tb = __mnt_new_table_from_file(upd->filename, - upd->userspace_only ? MNT_FMT_UTAB : MNT_FMT_MTAB); + upd->userspace_only ? MNT_FMT_UTAB : MNT_FMT_MTAB, 1); if (tb) { struct libmnt_fs *cur = mnt_table_find_target(tb, mnt_fs_get_srcpath(upd->fs), MNT_ITER_BACKWARD); @@ -791,7 +792,7 @@ static int update_modify_options(struct libmnt_update *upd, struct libmnt_lock * return -MNT_ERR_LOCK; tb = __mnt_new_table_from_file(upd->filename, - upd->userspace_only ? MNT_FMT_UTAB : MNT_FMT_MTAB); + upd->userspace_only ? MNT_FMT_UTAB : MNT_FMT_MTAB, 1); if (tb) { struct libmnt_fs *cur = mnt_table_find_target(tb, mnt_fs_get_target(fs), @@ -894,7 +895,7 @@ int mnt_update_already_done(struct libmnt_update *upd, struct libmnt_lock *lc) } tb = __mnt_new_table_from_file(upd->filename, - upd->userspace_only ? MNT_FMT_UTAB : MNT_FMT_MTAB); + upd->userspace_only ? MNT_FMT_UTAB : MNT_FMT_MTAB, 1); if (lc) mnt_unlock_file(lc); if (!tb) diff --git a/libmount/src/utils.c b/libmount/src/utils.c index 711d1683e..5db5494d3 100644 --- a/libmount/src/utils.c +++ b/libmount/src/utils.c @@ -645,18 +645,37 @@ done: return rc; } -static int try_write(const char *filename) +static int try_write(const char *filename, const char *directory) { int rc = 0; if (!filename) return -EINVAL; + DBG(UTILS, ul_debug("try write %s dir: %s", filename, directory)); + #ifdef HAVE_EACCESS - if (eaccess(filename, R_OK|W_OK) != 0) - rc = -errno; -#else + /* Try eaccess() first, because open() is overkill, may be monitored by + * audit and we don't want to fill logs by our checks... + */ + if (eaccess(filename, R_OK|W_OK) == 0) { + DBG(UTILS, ul_debug(" access OK")); + return 0; + } else if (errno != ENOENT) { + DBG(UTILS, ul_debug(" access FAILED")); + return -errno; + } else if (directory) { + /* file does not exist; try if directory is writable */ + if (eaccess(directory, R_OK|W_OK) != 0) + rc = -errno; + + DBG(UTILS, ul_debug(" access %s [%s]", rc ? "FAILED" : "OK", directory)); + return rc; + } else +#endif { + DBG(UTILS, ul_debug(" doing open-write test")); + int fd = open(filename, O_RDWR|O_CREAT|O_CLOEXEC, S_IWUSR|S_IRUSR|S_IRGRP|S_IROTH); if (fd < 0) @@ -664,7 +683,6 @@ static int try_write(const char *filename) else close(fd); } -#endif return rc; } @@ -698,7 +716,7 @@ int mnt_has_regular_mtab(const char **mtab, int *writable) /* file exists */ if (S_ISREG(st.st_mode)) { if (writable) - *writable = !try_write(filename); + *writable = !try_write(filename, NULL); DBG(UTILS, ul_debug("%s: writable", filename)); return 1; } @@ -707,7 +725,7 @@ int mnt_has_regular_mtab(const char **mtab, int *writable) /* try to create the file */ if (writable) { - *writable = !try_write(filename); + *writable = !try_write(filename, NULL); if (*writable) { DBG(UTILS, ul_debug("%s: writable", filename)); return 1; @@ -747,7 +765,7 @@ int mnt_has_regular_utab(const char **utab, int *writable) /* file exists */ if (S_ISREG(st.st_mode)) { if (writable) - *writable = !try_write(filename); + *writable = !try_write(filename, NULL); return 1; } goto done; /* it's not a regular file */ @@ -764,11 +782,13 @@ int mnt_has_regular_utab(const char **utab, int *writable) rc = mkdir(dirname, S_IWUSR| S_IRUSR|S_IRGRP|S_IROTH| S_IXUSR|S_IXGRP|S_IXOTH); - free(dirname); - if (rc && errno != EEXIST) + if (rc && errno != EEXIST) { + free(dirname); goto done; /* probably EACCES */ + } - *writable = !try_write(filename); + *writable = !try_write(filename, dirname); + free(dirname); if (*writable) return 1; } -- cgit v1.2.3-55-g7522