From c40fdee1c634403769d77a928f5bd28a14bce702 Mon Sep 17 00:00:00 2001 From: Matthew Blecker Date: Fri, 15 May 2020 13:13:30 -0700 Subject: i2c-pseudo: Bring in FROMLIST v3 revision. This is mostly a copy of: https://lore.kernel.org/linux-i2c/20200511234817.59365-1-matthewb@google.com/ https://patchwork.ozlabs.org/project/linux-i2c/patch/20200511234817.59365-1-matthewb@google.com/ Changes in this diff: - Move anprintf() into i2c-pseudo.c. - Use sizeof_field() instead of FIELD_SIZEOF(). - Add CONST_STRLEN macro for i2cp_cmds[].cmd_size values, because on some architectures strlen("literal") is not a compile-time constant. - Use stream_open() instead of nonseekable_open(). - When copy_from_user() returns non-zero, return -EFAULT instead of 0. BRANCH=none BUG=none TEST=With Linux 5.2: $ make $ make clean $ ./install Signed-off-by: Matthew Blecker Change-Id: Idd2b7a2c5630e95de3021c1920ded4cf303db721 Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/platform/ec/+/2205293 Reviewed-by: Harry Cutts --- extra/i2c_pseudo/anprintf.h | 144 ------------------------------------------ extra/i2c_pseudo/i2c-pseudo.c | 122 +++++++++++++++++++++++++++++++---- 2 files changed, 108 insertions(+), 158 deletions(-) delete mode 100644 extra/i2c_pseudo/anprintf.h (limited to 'extra') diff --git a/extra/i2c_pseudo/anprintf.h b/extra/i2c_pseudo/anprintf.h deleted file mode 100644 index c2d66c494b..0000000000 --- a/extra/i2c_pseudo/anprintf.h +++ /dev/null @@ -1,144 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 - -#include -#include -#include -#include -#include - -/* - * vanprintf - Format a string and place it into a newly allocated buffer. - * @out: Address of the pointer to place the buffer address into. Will only be - * written to with a successful positive return value. - * @max_size: If non-negative, the maximum buffer size that this function will - * attempt to allocate. If the formatted string including trailing null - * character would not fit, no buffer will be allocated, and an error will - * be returned. (Thus max_size of 0 will always result in an error.) - * @gfp: GFP flags for kmalloc(). - * @fmt: The format string to use. - * @ap: Arguments for the format string. - * - * Return value meanings: - * - * >=0: A buffer of this size was allocated and its address written to *out. - * The caller now owns the buffer and is responsible for freeing it with - * kfree(). The final character in the buffer, not counted in this - * return value, is the trailing null. This is the same return value - * meaning as snprintf(3). - * - * <0: An error occurred. Negate the return value for the error number. - * @out will not have been written to. Errors that might come from - * snprintf(3) may come from this function as well. Additionally, the - * following errors may occur from this function: - * - * ERANGE: A buffer larger than @max_size would be needed to fit the - * formatted string including its trailing null character. - * - * ENOMEM: Allocation of the output buffer failed. - * - * ENOTRECOVERABLE: An unexpected condition occurred. This may indicate - * a bug. - */ -static ssize_t vanprintf(char **out, ssize_t max_size, gfp_t gfp, - const char *fmt, va_list ap) -{ - int ret; - ssize_t buf_size; - char *buf = NULL; - va_list args1; - - va_copy(args1, ap); - ret = vsnprintf(NULL, 0, fmt, ap); - if (ret < 0) { - pr_err("%s: Formatting failed with error %d.\n", __func__, - -ret); - goto fail_before_args1; - } - if (max_size >= 0 && ret > max_size) { - ret = -ERANGE; - goto fail_before_args1; - } - - buf_size = ret + 1; - buf = kmalloc(buf_size, gfp); - if (buf == NULL) { - pr_err("%s: kmalloc(%zd, %u) returned NULL\n", __func__, - buf_size, gfp); - ret = -ENOMEM; - goto fail_before_args1; - } - - ret = vsnprintf(buf, buf_size, fmt, args1); - va_end(args1); - if (ret < 0) { - pr_err("%s: Second formatting pass produced error %d after the first pass succeeded. This is a bug.\n", - __func__, -ret); - goto fail_after_args1; - } - if (ret + 1 != buf_size) { - pr_err("%s: Second formatting pass produced a different formatted output size than the first. This is a bug. Will return -ENOTRECOVERABLE. first_sans_null=%zd second_sans_null=%d\n", - __func__, buf_size - 1, ret); - ret = -ENOTRECOVERABLE; - goto fail_after_args1; - } - - *out = buf; - return ret; - - fail_before_args1: - va_end(args1); - fail_after_args1: - kfree(buf); - if (ret >= 0) { - pr_err("%s: Jumped to failure cleanup section with non-negative return value %d set. This is a bug. Will return -ENOTRECOVERABLE instead.\n", - __func__, ret); - ret = -ENOTRECOVERABLE; - } - return ret; -} - -/* - * anprintf - Format a string and place it into a newly allocated buffer. - * @out: Address of the pointer to place the buffer address into. Will only be - * written to with a successful positive return value. - * @max_size: If non-negative, the maximum buffer size that this function will - * attempt to allocate. If the formatted string including trailing null - * character would not fit, no buffer will be allocated, and an error will - * be returned. (Thus max_size of 0 will always result in an error.) - * @gfp: GFP flags for kmalloc(). - * @fmt: The format string to use. - * @...: Arguments for the format string. - * - * Return value meanings: - * - * >=0: A buffer of this size was allocated and its address written to *out. - * The caller now owns the buffer and is responsible for freeing it with - * kfree(). The final character in the buffer, not counted in this - * return value, is the trailing null. This is the same return value - * meaning as snprintf(3). - * - * <0: An error occurred. Negate the return value for the error number. - * @out will not have been written to. Errors that might come from - * snprintf(3) may come from this function as well. Additionally, the - * following errors may occur from this function: - * - * ERANGE: A buffer larger than @max_size would be needed to fit the - * formatted string including its trailing null character. - * - * ENOMEM: Allocation of the output buffer failed. - * - * ENOTRECOVERABLE: An unexpected condition occurred. This may indicate - * a bug. - */ -__attribute__((__format__(__printf__, 4, 5))) -static ssize_t anprintf(char **out, ssize_t max_size, gfp_t gfp, - const char *fmt, ...) -{ - ssize_t ret; - va_list args; - - va_start(args, fmt); - ret = vanprintf(out, max_size, gfp, fmt, args); - va_end(args); - return ret; -} diff --git a/extra/i2c_pseudo/i2c-pseudo.c b/extra/i2c_pseudo/i2c-pseudo.c index 2fbac6dc1f..69fc9dbc52 100644 --- a/extra/i2c_pseudo/i2c-pseudo.c +++ b/extra/i2c_pseudo/i2c-pseudo.c @@ -27,8 +27,7 @@ #include #include #include - -#include "anprintf.h" +#include /* Minimum i2cp_limit module parameter value. */ #define I2CP_ADAPTERS_MIN 0 @@ -102,8 +101,10 @@ static const char i2cp_ctrlr_data_sep_char = ':'; #define STRING_NEQ(in_str, in_size, other_str) \ (in_size != strlen(other_str) || memcmp(other_str, in_str, in_size)) -#define STR_HELPER(x) #x -#define STR(x) STR_HELPER(x) +#define STR_HELPER(num) #num +#define STR(num) STR_HELPER(num) + +#define CONST_STRLEN(str) (sizeof(str) - 1) /* * The number of pseudo I2C adapters permitted. This default value can be @@ -657,7 +658,7 @@ struct i2cp_cmd_mxfer_reply_data { }; struct i2cp_cmd_set_name_suffix_data { - char name_suffix[FIELD_SIZEOF(struct i2c_adapter, name)]; + char name_suffix[sizeof_field(struct i2c_adapter, name)]; size_t name_suffix_len; }; @@ -754,6 +755,97 @@ struct i2cp_rsp_master_xfer { size_t buf_start_plus_one; }; +/* vanprintf - See anprintf() documentation. */ +static ssize_t vanprintf(char **out, ssize_t max_size, gfp_t gfp, + const char *fmt, va_list ap) +{ + int ret; + ssize_t buf_size; + char *buf = NULL; + va_list args1; + + va_copy(args1, ap); + ret = vsnprintf(NULL, 0, fmt, ap); + if (ret < 0) + goto fail_before_args1; + if (max_size >= 0 && ret > max_size) { + ret = -ERANGE; + goto fail_before_args1; + } + + buf_size = ret + 1; + buf = kmalloc(buf_size, gfp); + if (buf == NULL) { + ret = -ENOMEM; + goto fail_before_args1; + } + + ret = vsnprintf(buf, buf_size, fmt, args1); + va_end(args1); + if (ret < 0) + goto fail_after_args1; + if (ret + 1 != buf_size) { + ret = -ENOTRECOVERABLE; + goto fail_after_args1; + } + + *out = buf; + return ret; + + fail_before_args1: + va_end(args1); + fail_after_args1: + kfree(buf); + if (ret >= 0) + ret = -ENOTRECOVERABLE; + return ret; +} + +/* + * anprintf - Format a string and place it into a newly allocated buffer. + * @out: Address of the pointer to place the buffer address into. Will only be + * written to with a successful positive return value. + * @max_size: If non-negative, the maximum buffer size that this function will + * attempt to allocate. If the formatted string including trailing null + * character would not fit, no buffer will be allocated, and an error will + * be returned. (Thus max_size of 0 will always result in an error.) + * @gfp: GFP flags for kmalloc(). + * @fmt: The format string to use. + * @...: Arguments for the format string. + * + * Return value meanings: + * + * >=0: A buffer of this size was allocated and its address written to *out. + * The caller now owns the buffer and is responsible for freeing it with + * kfree(). The final character in the buffer, not counted in this + * return value, is the trailing null. This is the same return value + * meaning as snprintf(3). + * + * <0: An error occurred. Negate the return value for the error number. + * @out will not have been written to. Errors that might come from + * snprintf(3) may come from this function as well. Additionally, the + * following errors may occur from this function: + * + * ERANGE: A buffer larger than @max_size would be needed to fit the + * formatted string including its trailing null character. + * + * ENOMEM: Allocation of the output buffer failed. + * + * ENOTRECOVERABLE: An unexpected condition occurred. This may indicate + * a bug. + */ +static ssize_t anprintf(char **out, ssize_t max_size, gfp_t gfp, + const char *fmt, ...) +{ + ssize_t ret; + va_list args; + + va_start(args, fmt); + ret = vanprintf(out, max_size, gfp, fmt, args); + va_end(args); + return ret; +} + static ssize_t i2cp_rsp_buffer_formatter(void *data, char **out) { struct i2cp_rsp_buffer *rsp_buf; @@ -1763,7 +1855,7 @@ static int i2cp_cmd_set_timeout_cmd_completer(void *data, static const struct i2cp_cmd i2cp_cmds[] = { [I2CP_CMD_MXFER_REPLY_IDX] = { .cmd_string = I2CP_MXFER_REPLY_CMD, - .cmd_size = strlen(I2CP_MXFER_REPLY_CMD), + .cmd_size = CONST_STRLEN(I2CP_MXFER_REPLY_CMD), .data_creator = i2cp_cmd_mxfer_reply_data_creator, .data_shutdown = i2cp_cmd_mxfer_reply_data_shutdown, .data_destroyer = i2cp_cmd_mxfer_reply_data_destroyer, @@ -1773,35 +1865,35 @@ static const struct i2cp_cmd i2cp_cmds[] = { }, [I2CP_CMD_ADAP_START_IDX] = { .cmd_string = I2CP_ADAP_START_CMD, - .cmd_size = strlen(I2CP_ADAP_START_CMD), + .cmd_size = CONST_STRLEN(I2CP_ADAP_START_CMD), .header_receiver = i2cp_cmd_adap_start_header_receiver, .data_receiver = i2cp_cmd_adap_start_data_receiver, .cmd_completer = i2cp_cmd_adap_start_cmd_completer, }, [I2CP_CMD_ADAP_SHUTDOWN_IDX] = { .cmd_string = I2CP_ADAP_SHUTDOWN_CMD, - .cmd_size = strlen(I2CP_ADAP_SHUTDOWN_CMD), + .cmd_size = CONST_STRLEN(I2CP_ADAP_SHUTDOWN_CMD), .header_receiver = i2cp_cmd_adap_shutdown_header_receiver, .data_receiver = i2cp_cmd_adap_shutdown_data_receiver, .cmd_completer = i2cp_cmd_adap_shutdown_cmd_completer, }, [I2CP_CMD_GET_NUMBER_IDX] = { .cmd_string = I2CP_GET_NUMBER_CMD, - .cmd_size = strlen(I2CP_GET_NUMBER_CMD), + .cmd_size = CONST_STRLEN(I2CP_GET_NUMBER_CMD), .header_receiver = i2cp_cmd_get_number_header_receiver, .data_receiver = i2cp_cmd_get_number_data_receiver, .cmd_completer = i2cp_cmd_get_number_cmd_completer, }, [I2CP_CMD_GET_PSEUDO_ID_IDX] = { .cmd_string = I2CP_GET_PSEUDO_ID_CMD, - .cmd_size = strlen(I2CP_GET_PSEUDO_ID_CMD), + .cmd_size = CONST_STRLEN(I2CP_GET_PSEUDO_ID_CMD), .header_receiver = i2cp_cmd_get_pseudo_id_header_receiver, .data_receiver = i2cp_cmd_get_pseudo_id_data_receiver, .cmd_completer = i2cp_cmd_get_pseudo_id_cmd_completer, }, [I2CP_CMD_SET_NAME_SUFFIX_IDX] = { .cmd_string = I2CP_SET_NAME_SUFFIX_CMD, - .cmd_size = strlen(I2CP_SET_NAME_SUFFIX_CMD), + .cmd_size = CONST_STRLEN(I2CP_SET_NAME_SUFFIX_CMD), .data_creator = i2cp_cmd_set_name_suffix_data_creator, .data_destroyer = i2cp_cmd_set_name_suffix_data_destroyer, .header_receiver = i2cp_cmd_set_name_suffix_header_receiver, @@ -1810,7 +1902,7 @@ static const struct i2cp_cmd i2cp_cmds[] = { }, [I2CP_CMD_SET_TIMEOUT_IDX] = { .cmd_string = I2CP_SET_TIMEOUT_CMD, - .cmd_size = strlen(I2CP_SET_TIMEOUT_CMD), + .cmd_size = CONST_STRLEN(I2CP_SET_TIMEOUT_CMD), .data_creator = i2cp_cmd_set_timeout_data_creator, .data_destroyer = i2cp_cmd_set_timeout_data_destroyer, .header_receiver = i2cp_cmd_set_timeout_header_receiver, @@ -2114,7 +2206,7 @@ static int i2cp_cdev_open(struct inode *inodep, struct file *filep) this_pseudo = i2cp_device; /* I2C pseudo adapter controllers are not seekable. */ - nonseekable_open(inodep, filep); + stream_open(inodep, filep); /* Refuse fsnotify events. Modeled after /dev/ptmx implementation. */ filep->f_mode |= FMODE_NONOTIFY; @@ -2810,8 +2902,10 @@ static ssize_t i2cp_cdev_write(struct file *filep, const char __user *buf, ret = -ENOMEM; goto free_kbuf; } - if (copy_from_user(kbuf, buf, count)) + if (copy_from_user(kbuf, buf, count)) { + ret = -EFAULT; goto free_kbuf; + } start = kbuf; remaining = count; -- cgit v1.2.1