diff options
author | Martin Pärtel <martin.partel@gmail.com> | 2023-11-10 12:43:20 +0200 |
---|---|---|
committer | Martin Pärtel <martin.partel@gmail.com> | 2023-11-10 12:43:20 +0200 |
commit | 165d5ab56fc4eeb8cea1e98206ec5f6064c6246e (patch) | |
tree | fa67591ea29e4d93ab145f5a653df638f98e4899 | |
parent | 3f57fa69448ad68f31cf62cf75b5a9b2e5096c05 (diff) | |
download | bindfs-165d5ab56fc4eeb8cea1e98206ec5f6064c6246e.tar.gz |
Avoid undefined behaviour if uid_t/gid_t is signed.
This drops support for CentOS 7 because its GCC is too old
to support `__builtin_add_overflow`, and its EOL'ing in about
half a year anyway.
Fixes #143
-rw-r--r-- | ChangeLog | 5 | ||||
-rw-r--r-- | src/bindfs.c | 74 | ||||
-rw-r--r-- | vagrant/centos7/Vagrantfile | 23 |
3 files changed, 47 insertions, 55 deletions
@@ -1,3 +1,8 @@ +2023-11-10 Martin Pärtel <martin dot partel at gmail dot com> + + * Fixed undefined behaviour on platforms where `uid_t` or `gid_t` + is signed (issue #143, thanks @hartwork!) + 2023-11-09 Martin Pärtel <martin dot partel at gmail dot com> * Support negative --{uid,gid}-offset (issue #142) diff --git a/src/bindfs.c b/src/bindfs.c index dd32800..b4a1f5a 100644 --- a/src/bindfs.c +++ b/src/bindfs.c @@ -243,10 +243,11 @@ static int chown_new_file(const char *path, struct fuse_context *fc, int (*chown static int delete_file(const char *path, int (*target_delete_func)(const char *)); /* Apply offsets with overflow checking. */ -static int apply_uid_offset(uid_t *uid); -static int apply_gid_offset(gid_t *gid); -static int unapply_uid_offset(uid_t *uid); -static int unapply_gid_offset(gid_t *gid); +static bool apply_uid_offset(uid_t *uid); +static bool apply_gid_offset(gid_t *gid); +static bool unapply_uid_offset(uid_t *uid); +static bool unapply_gid_offset(gid_t *gid); +static bool bounded_add(int64_t* a, int64_t b, int64_t max); #ifdef __linux__ static size_t round_up_buffer_size_for_direct_io(size_t size); @@ -635,48 +636,57 @@ static int delete_file(const char *path, int (*target_delete_func)(const char *) return 0; } -static int apply_uid_offset(uid_t *uid) { - uid_t result = *uid + (uid_t)settings.uid_offset; - if (0 <= result && result <= UID_T_MAX) { - *uid = result; - return 1; +static bool apply_uid_offset(uid_t *uid) { + int64_t value = (int64_t)*uid; + if (bounded_add(&value, settings.uid_offset, UID_T_MAX)) { + *uid = (uid_t)value; + return true; } else { - DPRINTF("UID %ld overflowed while applying offset", (int64_t)*uid); - return 0; + DPRINTF("UID %ld out of bounds after applying offset", value); + return false; } } -static int apply_gid_offset(gid_t *gid) { - gid_t result = *gid + (gid_t)settings.gid_offset; - if (0 <= result && result <= GID_T_MAX) { - *gid = result; - return 1; +static bool apply_gid_offset(gid_t *gid) { + int64_t value = (int64_t)*gid; + if (bounded_add(&value, settings.gid_offset, GID_T_MAX)) { + *gid = (uid_t)value; + return true; } else { - DPRINTF("GID %ld overflowed while applying offset", (int64_t)*gid); - return 0; + DPRINTF("GID %ld out of bounds after applying offset", value); + return false; } } -static int unapply_uid_offset(uid_t *uid) { - uid_t result = *uid - (uid_t)settings.uid_offset; - if (0 <= result && result <= UID_T_MAX) { - *uid = result; - return 1; +static bool unapply_uid_offset(uid_t *uid) { + int64_t value = (int64_t)*uid; + if (bounded_add(&value, -settings.uid_offset, UID_T_MAX)) { + *uid = (uid_t)value; + return true; } else { - DPRINTF("UID %ld underflowed while applying offset", (int64_t)*uid); - return 0; + DPRINTF("UID %ld out of bounds after unapplying offset", value); + return false; } } -static int unapply_gid_offset(gid_t *gid) { - gid_t result = *gid - (gid_t)settings.gid_offset; - if (0 <= result && result <= GID_T_MAX) { - *gid = result; - return 1; +static bool unapply_gid_offset(gid_t *gid) { + int64_t value = (int64_t)*gid; + if (bounded_add(&value, -settings.gid_offset, GID_T_MAX)) { + *gid = (uid_t)value; + return true; } else { - DPRINTF("GID %ld underflowed while applying offset", (int64_t)*gid); - return 0; + DPRINTF("GID %ld out of bounds after unapplying offset", value); + return false; + } +} + +static bool bounded_add(int64_t* a, int64_t b, int64_t max) { + int64_t result; + if (!__builtin_add_overflow(*a, b, &result) && 0 <= result && result <= max) { + *a = result; + return true; } + return false; } #ifdef __linux__ diff --git a/vagrant/centos7/Vagrantfile b/vagrant/centos7/Vagrantfile deleted file mode 100644 index aa2ea0b..0000000 --- a/vagrant/centos7/Vagrantfile +++ /dev/null @@ -1,23 +0,0 @@ -# -*- mode: ruby -*- -# vi: set ft=ruby : - -Vagrant.configure("2") do |config| - config.vm.box = "centos/7" - - config.vm.synced_folder ".", "/vagrant", disabled: true - config.vm.synced_folder "../../", "/bindfs", - type: "rsync", - rsync__auto: false, - rsync__exclude: ["vagrant"], - rsync__args: ["-av", "--delete-after"] - - config.vm.provider "virtualbox" do |v| - v.name = "bindfs-centos7" - end - - config.vm.provision "shell", inline: <<-SHELL - yum install -y fuse fuse-devel gcc make pkg-config ruby valgrind - usermod -G fuse -a vagrant - echo user_allow_other > /etc/fuse.conf - SHELL -end |