]> git.ipfire.org Git - thirdparty/util-linux.git/commitdiff
libmount: fix access() utab write test
authorKarel Zak <kzak@redhat.com>
Wed, 8 Nov 2017 15:47:40 +0000 (16:47 +0100)
committerKarel Zak <kzak@redhat.com>
Wed, 8 Nov 2017 16:03:59 +0000 (17:03 +0100)
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 <kzak@redhat.com>
libmount/src/mountP.h
libmount/src/tab_parse.c
libmount/src/tab_update.c
libmount/src/utils.c

index e01de337df0cdea0d92c6afc878971c48f9c5da0..b00426d672c0701fe744aa8abb39d57fad009d69 100644 (file)
@@ -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
index b17a229139b86edb01f5d2cf91add88542cc2e5b..02dd0c961861214f30be8afa6eb2a94623e2c0eb 100644 (file)
@@ -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);
 }
 
 /**
index e957133014b2a7f0a0c4268c655b1e5650b916e7..23a5a8bc53ad16421129148dd15c655b90761825 100644 (file)
@@ -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)
index 711d1683e2c42002ab738a15a8a24d91c7de7643..5db5494d3adb7af2a97b01a0dab7b6e6b73f9f8c 100644 (file)
@@ -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;
        }