autofs-5.1.6 - fix autofs mount options construction From: Ian Kent There's an off by one length error in the autofs mount options construction. Consolidate the options construction into make_options_string() and use snprintf() to verify the options length calculation is correct. Signed-off-by: Ian Kent --- CHANGELOG | 1 + daemon/direct.c | 46 ++----------------------- daemon/indirect.c | 23 +----------- include/mounts.h | 3 +- lib/mounts.c | 98 +++++++++++++++++++++++++++++++++++++++++++++-------- 5 files changed, 92 insertions(+), 79 deletions(-) diff --git a/CHANGELOG b/CHANGELOG index 90f67336..2565b04d 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -10,6 +10,7 @@ xx/xx/2020 autofs-5.1.7 - fix trailing dollar sun entry expansion. - initialize struct addrinfo for getaddrinfo() calls. - fix quoted string length calc in expandsunent(). +- fix autofs mount options construction. 07/10/2019 autofs-5.1.6 - support strictexpire mount option. diff --git a/daemon/direct.c b/daemon/direct.c index b82d6e95..c4948729 100644 --- a/daemon/direct.c +++ b/daemon/direct.c @@ -348,29 +348,10 @@ int do_mount_autofs_direct(struct autofs_point *ap, } if (!mp->options) { - mp->options = make_options_string(ap->path, ap->kpipefd, str_direct); + mp->options = make_options_string(ap->path, + ap->kpipefd, str_direct, ap->flags); if (!mp->options) return 0; - - if ((ap->flags & MOUNT_FLAG_STRICTEXPIRE) && - ((get_kver_major() == 5 && get_kver_minor() > 3) || - (get_kver_major() > 5))) { - char *tmp = realloc(mp->options, strlen(mp->options) + 12); - if (tmp) { - strcat(tmp, ",strictexpire"); - mp->options = tmp; - } - } - - if ((ap->flags & MOUNT_FLAG_IGNORE) && - ((get_kver_major() == 5 && get_kver_minor() > 4) || - (get_kver_major() > 5))) { - char *tmp = realloc(mp->options, strlen(mp->options) + 7); - if (tmp) { - strcat(tmp, ",ignore"); - mp->options = tmp; - } - } } /* In case the directory doesn't exist, try to mkdir it */ @@ -676,29 +657,10 @@ int mount_autofs_offset(struct autofs_point *ap, struct mapent *me, const char * } if (!mp->options) { - mp->options = make_options_string(ap->path, ap->kpipefd, str_offset); + mp->options = make_options_string(ap->path, + ap->kpipefd, str_offset, ap->flags); if (!mp->options) return MOUNT_OFFSET_OK; - - if ((ap->flags & MOUNT_FLAG_STRICTEXPIRE) && - ((get_kver_major() == 5 && get_kver_minor() > 3) || - (get_kver_major() > 5))) { - char *tmp = realloc(mp->options, strlen(mp->options) + 12); - if (tmp) { - strcat(tmp, ",strictexpire"); - mp->options = tmp; - } - } - - if ((ap->flags & MOUNT_FLAG_IGNORE) && - ((get_kver_major() == 5 && get_kver_minor() > 4) || - (get_kver_major() > 5))) { - char *tmp = realloc(mp->options, strlen(mp->options) + 7); - if (tmp) { - strcat(tmp, ",ignore"); - mp->options = tmp; - } - } } strcpy(mountpoint, root); diff --git a/daemon/indirect.c b/daemon/indirect.c index 32257323..43bcb346 100644 --- a/daemon/indirect.c +++ b/daemon/indirect.c @@ -78,32 +78,13 @@ static int do_mount_autofs_indirect(struct autofs_point *ap, const char *root) } } - options = make_options_string(ap->path, ap->kpipefd, str_indirect); + options = make_options_string(ap->path, + ap->kpipefd, str_indirect, ap->flags); if (!options) { error(ap->logopt, "options string error"); goto out_err; } - if ((ap->flags & MOUNT_FLAG_STRICTEXPIRE) && - ((get_kver_major() == 5 && get_kver_minor() > 3) || - (get_kver_major() > 5))) { - char *tmp = realloc(options, strlen(options) + 12); - if (tmp) { - strcat(tmp, ",strictexpire"); - options = tmp; - } - } - - if ((ap->flags & MOUNT_FLAG_IGNORE) && - ((get_kver_major() == 5 && get_kver_minor() > 4) || - (get_kver_major() > 5))) { - char *tmp = realloc(options, strlen(options) + 7); - if (tmp) { - strcat(tmp, ",ignore"); - options = tmp; - } - } - /* In case the directory doesn't exist, try to mkdir it */ if (mkdir_path(root, mp_mode) < 0) { if (errno != EEXIST && errno != EROFS) { diff --git a/include/mounts.h b/include/mounts.h index 1214aed9..c8fddf00 100644 --- a/include/mounts.h +++ b/include/mounts.h @@ -94,7 +94,8 @@ void free_amd_entry_list(struct list_head *entries); unsigned int query_kproto_ver(void); unsigned int get_kver_major(void); unsigned int get_kver_minor(void); -char *make_options_string(char *path, int kernel_pipefd, const char *extra); +char *make_options_string(char *path, int pipefd, + const char *type, unsigned int flags); char *make_mnt_name_string(char *path); int ext_mount_add(struct list_head *, const char *, unsigned int); int ext_mount_remove(struct list_head *, const char *); diff --git a/lib/mounts.c b/lib/mounts.c index 83d053c8..a2d1f149 100644 --- a/lib/mounts.c +++ b/lib/mounts.c @@ -599,43 +599,111 @@ void free_amd_entry_list(struct list_head *entries) } } +static int cacl_max_options_len(unsigned int flags) +{ + unsigned int kver_major = get_kver_major(); + unsigned int kver_minor = get_kver_minor(); + int max_len; + + /* %d and %u are maximum lenght of 10 and mount type is maximum + * length of 9 (e. ",indirect"). + * The base temaplate is "fd=%d,pgrp=%u,minproto=5,maxproto=%d" + * plus the length of mount type plus 1 for the NULL. + */ + max_len = 79 + 1; + + if (kver_major < 5 || (kver_major == 5 && kver_minor < 4)) + goto out; + + /* maybe add ",strictexpire" */ + if (flags & MOUNT_FLAG_STRICTEXPIRE) + max_len += 13; + + if (kver_major == 5 && kver_minor < 5) + goto out; + + /* maybe add ",ignore" */ + if (flags & MOUNT_FLAG_IGNORE) + max_len += 7; +out: + return max_len; +} + /* * Make common autofs mount options string */ -char *make_options_string(char *path, int pipefd, const char *extra) +char *make_options_string(char *path, int pipefd, + const char *type, unsigned int flags) { + unsigned int kver_major = get_kver_major(); + unsigned int kver_minor = get_kver_minor(); char *options; - int len; + int max_len, len, new; + + max_len = cacl_max_options_len(flags); - options = malloc(MAX_OPTIONS_LEN + 1); + options = malloc(max_len); if (!options) { logerr("can't malloc options string"); return NULL; } - if (extra) - len = snprintf(options, MAX_OPTIONS_LEN, + if (type) + len = snprintf(options, max_len, options_template_extra, pipefd, (unsigned) getpgrp(), - AUTOFS_MAX_PROTO_VERSION, extra); + AUTOFS_MAX_PROTO_VERSION, type); else - len = snprintf(options, MAX_OPTIONS_LEN, options_template, + len = snprintf(options, max_len, options_template, pipefd, (unsigned) getpgrp(), AUTOFS_MAX_PROTO_VERSION); - if (len >= MAX_OPTIONS_LEN) { - logerr("buffer to small for options - truncated"); - len = MAX_OPTIONS_LEN - 1; + if (len < 0) + goto error_out; + + if (len >= max_len) + goto truncated; + + if (kver_major < 5 || (kver_major == 5 && kver_minor < 4)) + goto out; + + /* maybe add ",strictexpire" */ + if (flags & MOUNT_FLAG_STRICTEXPIRE) { + new = snprintf(options + len, + max_len, "%s", ",strictexpire"); + if (new < 0) + goto error_out; + len += new; + if (len >= max_len) + goto truncated; } - if (len < 0) { - logerr("failed to malloc autofs mount options for %s", path); - free(options); - return NULL; + if (kver_major == 5 && kver_minor < 5) + goto out; + + /* maybe add ",ignore" */ + if (flags & MOUNT_FLAG_IGNORE) { + new = snprintf(options + len, + max_len, "%s", ",ignore"); + if (new < 0) + goto error_out; + len += new; + if (len >= max_len) + goto truncated; } +out: options[len] = '\0'; - return options; + +truncated: + logerr("buffer to small for options - truncated"); + len = max_len -1; + goto out; + +error_out: + logerr("error constructing mount options string for %s", path); + free(options); + return NULL; } char *make_mnt_name_string(char *path)