0

To ensure consistency on power outage, files can be updated as follows (pseudocode):

echo original_contents > file
echo new_contents > /tmp_dir_in_same_fs/file.tmp
mv /tmp_dir_in_same_fs/file.tmp file

Now the thing is, if the files are in a folder root-owned, that rename operation gets a permission denied:

mkdir the_dir
echo original_contents > the_dir/file
echo new_contents > file.tmp
sudo chown root:root the_dir
sudo chmod 755 the_dir
mv file.tmp the_dir/file # permission denied

while:

echo new_contents > the_dir/file

works (but it's not as safe when it comes to consistency on power loss).

So I'm thinking about writing a small SUID program rename_suid that will just check that the source & target files have the proper ownership, so the replacement can be performed.

Here's a proposed implementation:

/*! \file rename_suid.c
    \brief rename file with SUID, provided target file is owned
    by calling user and source file mode mode matches the target file's.

    \license https://creativecommons.org/licenses/by-sa/3.0/
    © cJ-so-rs@zougloub.eu 2018
*/

#include <stdio.h>
#include <errno.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>


int main(int argc, char ** argv)
{
    int res;

    if (argc != 3) {
        fprintf(stderr, "Usage: %s <source> <target>\n", argv[0]);
        return EINVAL;
    }

    char const * src = argv[1];
    char const * dst = argv[2];
    struct stat stat_src;
    struct stat stat_dst;
    int uid = getuid();
    int euid = geteuid();

    if (euid != 0) {
        fprintf(stderr, "I am not root EUID, trouble ahead\n");
    }

    res = stat(src, &stat_src);
    if (res != 0) {
        perror("Cannot stat source file");
        return errno;
    }

    res = stat(dst, &stat_dst);
    if (res != 0) {
        perror("Cannot stat target file");
        return errno;
    }

    if (stat_src.st_uid != uid) {
        perror("Bad source uid");
        return EPERM
    }

    if (stat_dst.st_uid != uid) {
        perror("Bad target uid");
        return EPERM;
    }

    if (stat_src.st_mode != stat_dst.st_mode) {
        fprintf(stderr, "Inconsistent source-target modes\n");
        return EPERM;
    }

    res = rename(src, dst);
    if (res != 0) {
        perror("Cannot rename");
    }

    return errno;
}

The question is... am I missing something:

  • Is there another solution to the problem?
  • If not, does a similar tool exist?
  • If such this tool is the only solution, could it, by its principle of operation, cause unforeseen security issues?
  • Any (security) problem with the proposed implementation?

Thanks,

4

0 回答 0