From 81a1b89260825fc75bd60ed556e9ff3c40b79bab Mon Sep 17 00:00:00 2001 From: Chanwoo Choi Date: Mon, 14 Mar 2022 11:42:14 +0900 Subject: [PATCH 01/16] resource: process: Check return value of nla_put_u32 Change-Id: I2b31cd1d531d3ca219b535efed5e39c1a1a74698 Signed-off-by: Chanwoo Choi --- src/resource/resource-process.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/resource/resource-process.c b/src/resource/resource-process.c index d4940aa..831f3b5 100644 --- a/src/resource/resource-process.c +++ b/src/resource/resource-process.c @@ -351,7 +351,9 @@ static int query_taskstats(struct taskstats *stats, int cmd_type, pid_t pid) genlmsg_put(msg, NL_AUTO_PID, NL_AUTO_SEQ, ret, 0, 0, TASKSTATS_CMD_GET, TASKSTATS_VERSION); - nla_put_u32(msg, cmd_type, pid); + ret = nla_put_u32(msg, cmd_type, pid); + if (ret < 0) + goto err_genl_close; ret = nl_send_auto_complete(sock, msg); nlmsg_free(msg); -- 2.7.4 From 8c98239629e4b49f934de535f881bff26cc52ae9 Mon Sep 17 00:00:00 2001 From: Chanwoo Choi Date: Mon, 14 Mar 2022 16:46:05 +0900 Subject: [PATCH 02/16] util: kernel: Fix overflow issue when multiply operation Change-Id: Ia9bce7fbc4adabafa76e788d78450ce38866d7cf Signed-off-by: Chanwoo Choi --- src/util/kernel.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/util/kernel.c b/src/util/kernel.c index a68e05b..b01594b 100644 --- a/src/util/kernel.c +++ b/src/util/kernel.c @@ -184,7 +184,7 @@ int kernel_get_memory_info(const char *key, u_int64_t *val) if (!strncmp(buf, key, strlen(key))) { sscanf(buf, "%*s %"PRIu64, val); if (strstr(buf, "kB")) - *val *= 1024; + *val = (u_int64_t)(*val * 1024); break; } } -- 2.7.4 From 63c2ed14f3c81be63e529359716da406502bfdd9 Mon Sep 17 00:00:00 2001 From: Dongwoo Lee Date: Tue, 15 Mar 2022 20:19:20 +0900 Subject: [PATCH 03/16] util: Add resource_attr_supported_always() function This provides common callback to is_supported operation of attribute for supporting always available attributes. Change-Id: Iba5058e03cf583693a897684093cf5d35573be33 Signed-off-by: Dongwoo Lee --- include/util/resource.h | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/include/util/resource.h b/include/util/resource.h index ec1f496..18ce421 100644 --- a/include/util/resource.h +++ b/include/util/resource.h @@ -172,6 +172,13 @@ struct resource_attribute_value * get_resource_attr_value(struct resource *resource, u_int64_t attr_id); bool is_resource_attr_supported(struct resource *resource, u_int64_t attr_id); +static inline bool +resource_attr_supported_always(const struct resource *resource, + const struct resource_attribute *attr) +{ + return true; +} + int get_resource_attr_int(struct resource *resource, u_int64_t attr_id, int32_t *data); int get_resource_attr_int64(struct resource *resource, u_int64_t attr_id, int64_t *data); int get_resource_attr_uint(struct resource *resource, u_int64_t attr_id, u_int32_t *data); -- 2.7.4 From 188670cec19879d3c35df2024509083f4546cc3c Mon Sep 17 00:00:00 2001 From: Dongwoo Lee Date: Mon, 14 Mar 2022 02:33:54 -0700 Subject: [PATCH 04/16] util: kernel: Add functions for getting procfs stat fields This adds new functions for getting procfs stat fields of certain process id as like below prototype: int kernel_get_process_stat_fields(pid_t pid, char *buffer, int buf_len, char **stat_fields) - pid: target process id - buffer: string buffer for retrieving procfs stat, each field of stat_fileds points out some index within this buffer area. Thus, life time of stat_fields are determined by this. - buf_len: length of provided buffer - stat_fields: string array of retrieved fields, this should be declared as (char *)[PROCESS_STAT_FIELD_MAX] type. Signed-off-by: Dongwoo Lee Change-Id: I23008751fdd17ddd17d9e756e1f0d7394bee5f98 --- include/util/kernel.h | 12 ++++++++++++ src/util/kernel.c | 28 ++++++++++++++++++++++++++++ 2 files changed, 40 insertions(+) diff --git a/include/util/kernel.h b/include/util/kernel.h index f268e93..9846466 100644 --- a/include/util/kernel.h +++ b/include/util/kernel.h @@ -34,6 +34,15 @@ struct cpu_stat { int64_t soft_irq; }; +enum { + PROCESS_STAT_FIELD_PID, + PROCESS_STAT_FIELD_COMM, + PROCESS_STAT_FIELD_STATE, + PROCESS_STAT_FIELD_PPID, + PROCESS_STAT_FIELD_PGID, + PROCESS_STAT_FIELD_MAX, +}; + int kernel_get_online_cpu_num(void); int kernel_get_possible_cpu_num(void); @@ -43,4 +52,7 @@ int kernel_get_per_cpu_stat(struct cpu_stat *cpus, int num_possible_cpus, int kernel_get_memory_info(const char *key, u_int64_t *val); int kernel_get_memory_total(u_int64_t *val); + +int kernel_get_process_stat_fields(pid_t pid, char *buffer, int buf_len, + char *stat_fields[PROCESS_STAT_FIELD_MAX]); #endif diff --git a/src/util/kernel.c b/src/util/kernel.c index b01594b..3eae652 100644 --- a/src/util/kernel.c +++ b/src/util/kernel.c @@ -210,3 +210,31 @@ int kernel_get_memory_total(u_int64_t *val) return 0; } + +int kernel_get_process_stat_fields(pid_t pid, char *buffer, int buf_len, + char *stat_fields[PROCESS_STAT_FIELD_MAX]) +{ + char path[BUFF_MAX]; + char *pbuffer; + FILE *fd; + int i; + + snprintf(path, BUFF_MAX, "/proc/%d/stat", pid); + + fd = fopen(path, "r"); + if (!fd) { + _E("failed to open process %d stat", pid); + return -EIO; + } + + pbuffer = fgets(buffer, buf_len, fd); + if (!pbuffer) { + _E("failed to read process %d stat", pid); + return -EIO; + } + + for (i = 0; i < PROCESS_STAT_FIELD_MAX; i++) + stat_fields[i] = strsep(&pbuffer, " "); + + return 0; +} -- 2.7.4 From ccad6ebb738b3c88a3d0d9b9ff813c96f531f9a8 Mon Sep 17 00:00:00 2001 From: Dongwoo Lee Date: Fri, 11 Mar 2022 19:11:48 +0900 Subject: [PATCH 05/16] resource: process: Add PGID and PPID attributes Change-Id: I6516546b9e1603095070e02b299f8e904e1aa63f Signed-off-by: Dongwoo Lee --- lib/tmonitor/tmonitor.h | 2 ++ src/resource/resource-process.c | 49 +++++++++++++++++++++++++++++++++-------- 2 files changed, 42 insertions(+), 9 deletions(-) diff --git a/lib/tmonitor/tmonitor.h b/lib/tmonitor/tmonitor.h index 9252ba5..ae859c6 100644 --- a/lib/tmonitor/tmonitor.h +++ b/lib/tmonitor/tmonitor.h @@ -117,6 +117,8 @@ extern "C" { #define PROCESS_ATTR_DISK_READ_BPS BIT(4) /* DATA_TYPE_UINT */ #define PROCESS_ATTR_DISK_WRITE_BPS BIT(5) /* DATA_TYPE_UINT */ #define PROCESS_ATTR_COMM BIT(6) /* DATA_TYPE_STRING */ +#define PROCESS_ATTR_PGID BIT(7) /* DATA_TYPE_INT */ +#define PROCESS_ATTR_PPID BIT(8) /* DATA_TYPE_INT */ #define PROCESS_CTRL_TGID BIT(0) diff --git a/src/resource/resource-process.c b/src/resource/resource-process.c index 831f3b5..fbfbd6c 100644 --- a/src/resource/resource-process.c +++ b/src/resource/resource-process.c @@ -30,6 +30,8 @@ struct process_context { pid_t tgid; + pid_t ppid; + pid_t pgid; char comm[TS_COMM_LEN]; struct taskstats prev; struct taskstats curr; @@ -179,12 +181,11 @@ static int process_get_disk_bps(const struct resource *res, return 0; } -static int process_get_comm(const struct resource *res, +static int process_get_context_data(const struct resource *res, const struct resource_attribute *attr, void *data) { struct process_context *ctx; - char *buf = (char *)data; if (!res || !res->priv || !attr || !data) return -EINVAL; @@ -196,7 +197,17 @@ static int process_get_comm(const struct resource *res, return -EINVAL; } - strncpy(buf, ctx->comm, TS_COMM_LEN); + switch (attr->id) { + case PROCESS_ATTR_COMM: + strncpy((char *)data, ctx->comm, TS_COMM_LEN); + break; + case PROCESS_ATTR_PGID: + *((int *)data) = ctx->pgid; + break; + case PROCESS_ATTR_PPID: + *((int *)data) = ctx->ppid; + break; + } return 0; } @@ -249,7 +260,21 @@ static const struct resource_attribute process_attrs[] = { .id = PROCESS_ATTR_COMM, .type = DATA_TYPE_STRING, .ops = { - .get = process_get_comm, + .get = process_get_context_data, + }, + }, { + .name = "PROCESS_ATTR_PGID", + .id = PROCESS_ATTR_PGID, + .type = DATA_TYPE_INT, + .ops = { + .get = process_get_context_data, + }, + }, { + .name = "PROCESS_ATTR_PPID", + .id = PROCESS_ATTR_PPID, + .type = DATA_TYPE_INT, + .ops = { + .get = process_get_context_data, }, }, }; @@ -433,7 +458,8 @@ static int process_setup_tgid(const struct resource *res, const struct resource_control *ctrl, const void *data) { - struct taskstats stats; + char buf[BUFF_MAX]; + char *stat_fields[PROCESS_STAT_FIELD_MAX]; struct process_context *ctx; u_int64_t total_memory; int ret; @@ -453,13 +479,18 @@ static int process_setup_tgid(const struct resource *res, /* update initial status */ ret = update_taskstats(ctx); if (ret < 0) - return -EINVAL; + return ret; - ret = query_taskstats(&stats, TASKSTATS_CMD_ATTR_PID, ctx->tgid); + ret = kernel_get_process_stat_fields(ctx->tgid, buf, BUFF_MAX, stat_fields); if (ret < 0) - return -EINVAL; + return ret; + + /* save comm with removing parentheses */ + strncpy(ctx->comm, stat_fields[PROCESS_STAT_FIELD_COMM] + 1, + strlen(stat_fields[PROCESS_STAT_FIELD_COMM]) - 2 /* '(', ')' */); - memcpy(ctx->comm, stats.ac_comm, TS_COMM_LEN); + ctx->pgid = atoi(stat_fields[PROCESS_STAT_FIELD_PGID]); + ctx->ppid = atoi(stat_fields[PROCESS_STAT_FIELD_PPID]); return 0; } -- 2.7.4 From b414039c3ccbd12c47be9bae9409f4f0afd1d044 Mon Sep 17 00:00:00 2001 From: Dongwoo Lee Date: Tue, 15 Mar 2022 12:45:22 +0900 Subject: [PATCH 06/16] lib: tmonitor: Add get APIs for array type attributes This adds internal API for getting array type attributes as below: - tmonitor_get_array_int - tmonitor_get_array_int64 - tmonitor_get_array_uint - tmonitor_get_array_uint64 - tmonitor_get_array_double - tmonitor_get_array_string Since users get dynamically allocated array with length by just passing pointer of pointer for each data type, it should be freed after use. Change-Id: I8f72ff5c6ceebcc4eda8998f2ad4fed47f71e3d5 Signed-off-by: Dongwoo Lee --- include/util/request.h | 1 + lib/tmonitor/tmonitor.c | 179 ++++++++++++++++++++++++++++++++++++++++++ lib/tmonitor/tmonitor.h | 16 ++++ src/monitor/request-handler.c | 129 ++++++++++++++++++++++++------ 4 files changed, 302 insertions(+), 23 deletions(-) diff --git a/include/util/request.h b/include/util/request.h index a0bb183..f9316a6 100644 --- a/include/util/request.h +++ b/include/util/request.h @@ -39,6 +39,7 @@ enum { REQUEST_GET_VALUE_UINT64, REQUEST_GET_VALUE_DOUBLE, REQUEST_GET_VALUE_STRING, + REQUEST_GET_VALUE_ARRAY, REQUEST_MAX, }; diff --git a/lib/tmonitor/tmonitor.c b/lib/tmonitor/tmonitor.c index fa6b22b..d53c655 100644 --- a/lib/tmonitor/tmonitor.c +++ b/lib/tmonitor/tmonitor.c @@ -640,3 +640,182 @@ int tmonitor_get_value_string(int id, int resource_id, u_int64_t attr_id, char * return ret; } + +static int +tmonitor_get_array(int id, int res_id, u_int64_t attr_id, int data_type, void **array, int *length) +{ + char buffer[MAX_BUF_SIZE + 1]; + char _array_str[MAX_BUF_SIZE]; + char *array_item, *array_str = _array_str; + int array_len, array_type; + int buffer_len; + int response_req; + int ret, i; + + buffer_len = sprintf(buffer, "%d:%d:%"PRIu64, + REQUEST_GET_VALUE_ARRAY, res_id, attr_id); + if (send(id, buffer, buffer_len, 0) < 0) { + _E("[libpass] error occurred while sending buffer"); + return -EIO; + } + + /* wait for response */ + buffer_len = recv(id, buffer, MAX_BUF_SIZE, 0); + if (buffer_len <= 0) { + _E("[libpass] socket disconnected"); + return -EIO; + } + + buffer[buffer_len] = '\0'; + if (sscanf(buffer, "%d:%d|%d|%[^:]:%d", &response_req, + &array_type, &array_len, array_str, &ret) < 5) + return -EINVAL; + + if (response_req != REQUEST_GET_VALUE_ARRAY) { + _E("[libpass] wrong response"); + return -EINVAL; + } + + if (data_type != array_type) { + _E("[libpass] wrong data type"); + return -EINVAL; + } + + switch (array_type) { + case DATA_TYPE_INT: + { + int32_t *new_array = malloc(array_len * sizeof(int32_t)); + + if (!new_array) + return -ENOMEM; + + for (i = 0; (array_item = strsep(&array_str, ",")) != NULL; i++) + new_array[i] = strtol(array_item, NULL, 10); + + *array = (void *)new_array; + *length = array_len; + break; + } + case DATA_TYPE_INT64: + { + int64_t *new_array = malloc(array_len * sizeof(int64_t)); + + if (!new_array) + return -ENOMEM; + + for (i = 0; (array_item = strsep(&array_str, ",")) != NULL; i++) + new_array[i] = strtoll(array_item, NULL, 10); + + *array = (void *)new_array; + *length = array_len; + break; + } + case DATA_TYPE_UINT: + { + u_int32_t *new_array = malloc(array_len * sizeof(u_int32_t)); + + if (!new_array) + return -ENOMEM; + + for (i = 0; (array_item = strsep(&array_str, ",")) != NULL; i++) + new_array[i] = strtoul(array_item, NULL, 10); + + *array = (void *)new_array; + *length = array_len; + break; + } + case DATA_TYPE_UINT64: + { + u_int64_t *new_array = malloc(array_len * sizeof(u_int64_t)); + + if (!new_array) + return -ENOMEM; + + for (i = 0; (array_item = strsep(&array_str, ",")) != NULL; i++) + new_array[i] = strtoull(array_item, NULL, 10); + + *array = (void *)new_array; + *length = array_len; + break; + } + case DATA_TYPE_DOUBLE: + { + double *new_array = malloc(array_len * sizeof(double)); + + if (!new_array) + return -ENOMEM; + + for (i = 0; (array_item = strsep(&array_str, ",")) != NULL; i++) + new_array[i] = strtod(array_item, NULL); + + *array = (void *)new_array; + *length = array_len; + break; + } + case DATA_TYPE_STRING: + { + char **new_array = calloc(array_len, sizeof(char *)); + + if (!new_array) + return -ENOMEM; + + for (i = 0; (array_item = strsep(&array_str, ",")) != NULL; i++) { + char *new_item = g_strdup(array_item); + + if (!new_item) { + for (int j = i - 1; j >= 0; j--) + free(new_array[j]); + free(new_array); + return -ENOMEM; + } + + new_array[i] = new_item; + } + + *array = (void *)new_array; + *length = array_len; + break; + } + default: + _E("[libpass] not supported array data type"); + return -EINVAL; + } + + return ret; +} + +EXPORT +int tmonitor_get_array_int(int id, int res_id, u_int64_t attr_id, int32_t **array, int *length) +{ + return tmonitor_get_array(id, res_id, attr_id, DATA_TYPE_INT, (void **)array, length); +} + +EXPORT +int tmonitor_get_array_int64(int id, int res_id, u_int64_t attr_id, int64_t **array, int *length) +{ + return tmonitor_get_array(id, res_id, attr_id, DATA_TYPE_INT64, (void **)array, length); +} + +EXPORT +int tmonitor_get_array_uint(int id, int res_id, u_int64_t attr_id, u_int32_t **array, int *length) +{ + return tmonitor_get_array(id, res_id, attr_id, DATA_TYPE_UINT, (void **)array, length); +} + +EXPORT +int tmonitor_get_array_uint64(int id, int res_id, u_int64_t attr_id, u_int64_t **array, int *length) +{ + return tmonitor_get_array(id, res_id, attr_id, DATA_TYPE_UINT64, (void **)array, length); +} + +EXPORT +int tmonitor_get_array_double(int id, int res_id, u_int64_t attr_id, double **array, int *length) +{ + return tmonitor_get_array(id, res_id, attr_id, DATA_TYPE_DOUBLE, (void **)array, length); +} + +EXPORT +int tmonitor_get_array_string(int id, int res_id, u_int64_t attr_id, char ***array, int *length) +{ + return tmonitor_get_array(id, res_id, attr_id, DATA_TYPE_STRING, (void **)array, length); +} diff --git a/lib/tmonitor/tmonitor.h b/lib/tmonitor/tmonitor.h index ae859c6..d64ad51 100644 --- a/lib/tmonitor/tmonitor.h +++ b/lib/tmonitor/tmonitor.h @@ -226,6 +226,22 @@ int tmonitor_get_value_uint64(int id, int resource_id, u_int64_t attr, u_int64_t int tmonitor_get_value_double(int id, int resource_id, u_int64_t attr, double *value); int tmonitor_get_value_string(int id, int resource_id, u_int64_t attr, char *value); +/** + * @brief Get [int/int64/uint/uint64/double/string] array of resource attribute + * @param[in] Tizen monitor id + * @param[in] Resource id + * @param[in] Resource attribute id + * @param[out] Array retrieved from resource attribute + * @param[out] Length of array + * @return @ 0 on success, otherwise a negative error value + */ +int tmonitor_get_array_int(int id, int res_id, u_int64_t attr, int32_t **array, int *length); +int tmonitor_get_array_int64(int id, int res_id, u_int64_t attr, int64_t **array, int *length); +int tmonitor_get_array_uint(int id, int res_id, u_int64_t attr, u_int32_t **array, int *length); +int tmonitor_get_array_uint64(int id, int res_id, u_int64_t attr, u_int64_t **array, int *length); +int tmonitor_get_array_double(int id, int res_id, u_int64_t attr, double **array, int *length); +int tmonitor_get_array_string(int id, int res_id, u_int64_t attr, char ***array, int *length); + #ifdef __cplusplus } #endif diff --git a/src/monitor/request-handler.c b/src/monitor/request-handler.c index 82d598a..edaabdb 100644 --- a/src/monitor/request-handler.c +++ b/src/monitor/request-handler.c @@ -402,6 +402,30 @@ static int handle_request_get_value_string(struct request_client *client, char * return get_resource_attr_string(res, attr_id, value); } +static int +handle_request_get_value_array(struct request_client *client, char *args, struct array_value **arr) +{ + struct resource *res; + int resource_id; + u_int64_t attr_id; + + if (!client || !args) + return -ENOENT; + + /** + * Format of REQUEST_GET_VALUE_ARRAY args: + * - + */ + if (sscanf(args, "%d:%"PRIu64, &resource_id, &attr_id) < 2) + return -EINVAL; + + res = get_resource_by_id(client, resource_id); + if (!res) + return -EINVAL; + + return get_resource_attr_array(res, attr_id, arr); +} + static int split_request_type_and_args(char *buffer, char **args) { char *request_type_str; @@ -413,13 +437,21 @@ static int split_request_type_and_args(char *buffer, char **args) return atoi(request_type_str); } +#define ADD_RESPONSE(__buf__, __remain__, __format__, ...) { \ + int __len__ = snprintf(__buf__, __remain__, __format__, __VA_ARGS__); \ + __buf__ += __len__; \ + __remain__ -= __len__; \ + if (__remain__ < 0) \ + _E("failed to add response"); \ +} \ + static void handle_request(struct request_client *client, char *buffer) { char _response[REQUEST_BUFFER_MAX]; char *response = _response; char *args; int request_type; - int ret, len; + int ret; int buffer_len = REQUEST_BUFFER_MAX; request_type = split_request_type_and_args(buffer, &args); @@ -428,9 +460,7 @@ static void handle_request(struct request_client *client, char *buffer) * Format of response * - */ - len = snprintf(response, buffer_len, "%d:", request_type); - response += len; - buffer_len -= len; + ADD_RESPONSE(response, buffer_len, "%d:", request_type); switch (request_type) { case REQUEST_CREATE_RESOURCE: @@ -484,9 +514,7 @@ static void handle_request(struct request_client *client, char *buffer) if (ret < 0) _D("failed to get value"); - len = snprintf(response, buffer_len, "%d:", value); - response += len; - buffer_len -= len; + ADD_RESPONSE(response, buffer_len, "%d:", value); } break; case REQUEST_GET_VALUE_INT64: @@ -497,9 +525,7 @@ static void handle_request(struct request_client *client, char *buffer) if (ret < 0) _D("failed to get value"); - len = snprintf(response, buffer_len, "%"PRId64":", value); - response += len; - buffer_len -= len; + ADD_RESPONSE(response, buffer_len, "%"PRId64":", value); } break; case REQUEST_GET_VALUE_UINT: @@ -510,9 +536,7 @@ static void handle_request(struct request_client *client, char *buffer) if (ret < 0) _D("failed to get value"); - len = snprintf(response, buffer_len, "%u:", value); - response += len; - buffer_len -= len; + ADD_RESPONSE(response, buffer_len, "%u:", value); } break; case REQUEST_GET_VALUE_UINT64: @@ -523,9 +547,7 @@ static void handle_request(struct request_client *client, char *buffer) if (ret < 0) _D("failed to get value"); - len = snprintf(response, buffer_len, "%"PRIu64":", value); - response += len; - buffer_len -= len; + ADD_RESPONSE(response, buffer_len, "%"PRIu64":", value); } break; case REQUEST_GET_VALUE_DOUBLE: @@ -536,9 +558,7 @@ static void handle_request(struct request_client *client, char *buffer) if (ret < 0) _D("failed to get value"); - len = snprintf(response, buffer_len, "%lf:", value); - response += len; - buffer_len -= len; + ADD_RESPONSE(response, buffer_len, "%lf:", value); } break; case REQUEST_GET_VALUE_STRING: @@ -549,9 +569,72 @@ static void handle_request(struct request_client *client, char *buffer) if (ret < 0) _D("failed to get value"); - len = snprintf(response, buffer_len, "%s:", value); - response += len; - buffer_len -= len; + ADD_RESPONSE(response, buffer_len, "%s:", value); + } + break; + case REQUEST_GET_VALUE_ARRAY: + { + struct array_value *array; + int i; + + ret = handle_request_get_value_array(client, args, &array); + if (ret < 0) + _D("failed to get value"); + + if (array->length == 0) { + ADD_RESPONSE(response, buffer_len, "%d|%d|:", + array->type, array->length); + break; + } + + ADD_RESPONSE(response, buffer_len, "%d|%d|", array->type, array->length); + + switch (array->type) { + case DATA_TYPE_INT: + for (i = 0; i < array->length - 1; i++) + ADD_RESPONSE(response, buffer_len, "%d,", + ((int32_t *)array->data)[i]); + ADD_RESPONSE(response, buffer_len, "%d:", + ((int32_t *)array->data)[i]); + break; + case DATA_TYPE_INT64: + for (i = 0; i < array->length - 1; i++) + ADD_RESPONSE(response, buffer_len, "%"PRId64",", + ((int64_t *)array->data)[i]); + ADD_RESPONSE(response, buffer_len, "%"PRId64":", + ((int64_t *)array->data)[i]); + break; + case DATA_TYPE_UINT: + for (i = 0; i < array->length - 1; i++) + ADD_RESPONSE(response, buffer_len, "%u,", + ((u_int32_t *)array->data)[i]); + ADD_RESPONSE(response, buffer_len, "%u:", + ((u_int32_t *)array->data)[i]); + break; + case DATA_TYPE_UINT64: + for (i = 0; i < array->length - 1; i++) + ADD_RESPONSE(response, buffer_len, "%"PRIu64",", + ((u_int64_t *)array->data)[i]); + ADD_RESPONSE(response, buffer_len, "%"PRIu64":", + ((u_int64_t *)array->data)[i]); + break; + case DATA_TYPE_DOUBLE: + for (i = 0; i < array->length - 1; i++) + ADD_RESPONSE(response, buffer_len, "%lf,", + ((double *)array->data)[i]); + ADD_RESPONSE(response, buffer_len, "%lf:", + ((double *)array->data)[i]); + break; + case DATA_TYPE_STRING: + for (i = 0; i < array->length - 1; i++) + ADD_RESPONSE(response, buffer_len, "%s,", + ((char **)array->data)[i]); + ADD_RESPONSE(response, buffer_len, "%s:", + ((char **)array->data)[i]); + break; + default: + _E("Not supported data type"); + } } break; default: @@ -559,7 +642,7 @@ static void handle_request(struct request_client *client, char *buffer) ret = -EINVAL; break; } - snprintf(response, buffer_len, "%d", ret); + ADD_RESPONSE(response, buffer_len, "%d", ret); if (send(client->socket_fd, _response, strlen(_response), 0) < 0) _E("Failed to send respones, error: %s", strerror(errno)); -- 2.7.4 From fe69c53880ffdd25f802835a30a3ff916e59ea5e Mon Sep 17 00:00:00 2001 From: Dongwoo Lee Date: Mon, 21 Mar 2022 13:10:15 +0900 Subject: [PATCH 07/16] util: kernel: Fix to close files after use Change-Id: I91c2869f4c8bcf9ff80bf9691d357088d80dce88 Signed-off-by: Dongwoo Lee --- src/util/kernel.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/util/kernel.c b/src/util/kernel.c index 3eae652..a0f267c 100644 --- a/src/util/kernel.c +++ b/src/util/kernel.c @@ -229,6 +229,7 @@ int kernel_get_process_stat_fields(pid_t pid, char *buffer, int buf_len, pbuffer = fgets(buffer, buf_len, fd); if (!pbuffer) { + fclose(fd); _E("failed to read process %d stat", pid); return -EIO; } @@ -236,5 +237,7 @@ int kernel_get_process_stat_fields(pid_t pid, char *buffer, int buf_len, for (i = 0; i < PROCESS_STAT_FIELD_MAX; i++) stat_fields[i] = strsep(&pbuffer, " "); + fclose(fd); + return 0; } -- 2.7.4 From 3c3c861f69383c90245f1e4060f1756658535a63 Mon Sep 17 00:00:00 2001 From: Dongwoo Lee Date: Mon, 14 Mar 2022 10:43:38 +0900 Subject: [PATCH 08/16] resource: Add process group resource driver This resource is pseudo-device driver which provides information of related process group. Controls: - PROCESS_GROUP_CTRL_ROOT_PID: pid of top-level process in a group what we want to see. Atrributes: - PROCESS_GROUP_ATTR_LIST: array of pid which includes all processes related with root pid. if root pid is negative, list contains all processes. Change-Id: I0b7a85dd7d8f2bd4628e17c8db923dd4abd112a8 Signed-off-by: Dongwoo Lee --- CMakeLists.txt | 1 + lib/tmonitor/tmonitor.h | 6 + src/resource/resource-process-group.c | 245 ++++++++++++++++++++++++++++++++++ 3 files changed, 252 insertions(+) create mode 100644 src/resource/resource-process-group.c diff --git a/CMakeLists.txt b/CMakeLists.txt index b100c63..b1bf42e 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -48,6 +48,7 @@ SET(SRCS src/resource/resource-system.c src/resource/resource-battery.c src/resource/resource-process.c + src/resource/resource-process-group.c src/monitor/monitor.c src/monitor/monitor-thread.c src/monitor/monitor-command.c diff --git a/lib/tmonitor/tmonitor.h b/lib/tmonitor/tmonitor.h index d64ad51..5cda25d 100644 --- a/lib/tmonitor/tmonitor.h +++ b/lib/tmonitor/tmonitor.h @@ -40,6 +40,7 @@ extern "C" { #define RESOURCE_TYPE_PROCESS 6 #define RESOURCE_TYPE_DISPLAY 7 #define RESOURCE_TYPE_SYSTEM 8 +#define RESOURCE_TYPE_PROCESS_GROUP 9 #define RESOURCE_TYPE_NONSTANDARD 99 /** @@ -122,6 +123,11 @@ extern "C" { #define PROCESS_CTRL_TGID BIT(0) +/* Process List Resource */ +#define PROCESS_GROUP_ATTR_LIST BIT(0) /* DATA_TYPE_ARRAY */ + +#define PROCESS_GROUP_CTRL_ROOT_PID BIT(0) + /** * @brief Initialize the tizen monitor * @return @c positive integer as tizen monitor id on success, otherwise a negative error value diff --git a/src/resource/resource-process-group.c b/src/resource/resource-process-group.c new file mode 100644 index 0000000..a7fc7e1 --- /dev/null +++ b/src/resource/resource-process-group.c @@ -0,0 +1,245 @@ +/* + * PASS (Power Aware System Service) - Process Group Resource Driver + * + * Copyright (c) 2022 Samsung Electronics Co., Ltd. + * + * Licensed under the Apache License, Version 2.0 (the License); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include +#include + +#include + +#define PROC_DIR_PATH "/proc/" + +struct process_info { + pid_t pid; + pid_t ppid; + struct process_info *parent; +}; + +static int process_group_get_list(const struct resource *res, + const struct resource_attribute *attr, + void *data) +{ + struct process_info *pi, *target_pi, *parent_pi; + struct dirent *task_entry; + struct array_value *list = data; + char *statfields[PROCESS_STAT_FIELD_MAX]; + char buf[BUFF_MAX]; + GHashTableIter iter; + gpointer key, value; + GHashTable *process_hash; + GArray *process_array; + DIR *task_dir; + int i, ret = 0; + int *data_array; + pid_t pid; + + if (!res || !res->priv || !attr || !data) + return -EINVAL; + + task_dir = opendir(PROC_DIR_PATH); + if (!task_dir) + return -ESRCH; + + process_hash = g_hash_table_new_full(g_int_hash, g_int_equal, NULL, free); + if (!process_hash) { + ret = -ENOMEM; + goto out_close; + } + + /* create list of all processes */ + while ((task_entry = readdir(task_dir)) != NULL) { + const char *name = task_entry->d_name; + + if (task_entry->d_type != DT_DIR && task_entry->d_type != DT_UNKNOWN) + continue; + + if (name[0] < '0' || name[0] > '9') + continue; + + pid = atoi(name); + + ret = kernel_get_process_stat_fields(pid, buf, BUFF_MAX, statfields); + if (ret < 0) + continue; /* process might be terminated */ + + pi = calloc(1, sizeof(struct process_info)); + if (!pi) { + ret = -ENOMEM; + goto out_free_hash; + } + + pi->pid = pid; + pi->ppid = atoi(statfields[PROCESS_STAT_FIELD_PPID]); + + if (g_hash_table_contains(process_hash, (gpointer)&pi->ppid)) { + parent_pi = g_hash_table_lookup(process_hash, (gpointer)&pi->ppid); + + pi->parent = parent_pi; + } + + g_hash_table_insert(process_hash, (gpointer)&pi->pid, (gpointer)pi); + } + + target_pi = res->priv; + + process_array = g_array_new(false, false, sizeof(int)); + if (!process_array) { + ret = -ENOMEM; + goto out_free_hash; + } + + if (target_pi->pid < 0) { + /* just add all processes into array if parent pid is negative */ + g_hash_table_iter_init(&iter, process_hash); + while (g_hash_table_iter_next(&iter, &key, &value)) { + pi = (struct process_info *)value; + g_array_append_val(process_array, pi->pid); + } + } else { + g_hash_table_iter_init(&iter, process_hash); + while (g_hash_table_iter_next(&iter, &key, &value)) { + pi = (struct process_info *)value; + + if (target_pi->pid == pi->pid || target_pi->pid == pi->ppid) { + g_array_append_val(process_array, pi->pid); + continue; + } + + parent_pi = pi->parent; + while (parent_pi != NULL) { + if (parent_pi->ppid == target_pi->pid) { + g_array_append_val(process_array, pi->pid); + break; + } + parent_pi = parent_pi->parent; + } + } + } + + if (list->data) + free(list->data); + + data_array = list->data = malloc(sizeof(int) * process_array->len); + if (!data_array) { + ret = -ENOMEM; + goto out_free_array; + } + list->type = DATA_TYPE_INT; + list->length = process_array->len; + + for (i = 0; i < list->length; i++) + data_array[i] = g_array_index(process_array, int, i); + +out_free_array: + g_array_free(process_array, true); +out_free_hash: + g_hash_table_destroy(process_hash); +out_close: + closedir(task_dir); + + return ret; +} + +static const struct resource_attribute process_group_attrs[] = { + { + .name = "PROCESS_GROUP_ATTR_LIST", + .id = PROCESS_GROUP_ATTR_LIST, + .type = DATA_TYPE_ARRAY, + .ops = { + .get = process_group_get_list, + .is_supported = resource_attr_supported_always, + }, + }, +}; + +static int process_group_setup_root_pid(const struct resource *res, + const struct resource_control *ctrl, + const void *data) +{ + struct process_info *target; + char *statfields[PROCESS_STAT_FIELD_MAX]; + char buf[BUFF_MAX]; + int target_pid; + int ret; + + if (!res || !res->priv || !ctrl) + return -EINVAL; + + target = res->priv; + + target_pid = (int)(intptr_t)data; + + ret = kernel_get_process_stat_fields(target_pid, buf, BUFF_MAX, statfields); + if (ret < 0) { + _E("target process pid is not valid"); + target->pid = -1; + target->ppid = -1; + return ret; + } + + target->pid = atoi(statfields[PROCESS_STAT_FIELD_PID]); + target->ppid = atoi(statfields[PROCESS_STAT_FIELD_PPID]); + + return 0; +} + +static const struct resource_control process_group_ctrls[] = { + { + .name = "PROCESS_GROUP_CTRL_ROOT_PID", + .id = PROCESS_GROUP_CTRL_ROOT_PID, + .ops = { + .set = process_group_setup_root_pid, + }, + }, +}; + +static int process_group_init(struct resource *res) +{ + struct process_info *target; + + target = malloc(sizeof(struct process_info)); + if (!target) + return -ENOMEM; + + target->pid = -1; + target->ppid = -1; + + res->priv = target; + + return 0; +} + +static void process_group_exit(struct resource *res) +{ + if (res && res->priv) + free(res->priv); +} + +static const struct resource_driver process_group_driver = { + .name = "PROCESS_GROUP", + .type = RESOURCE_TYPE_PROCESS_GROUP, + .attrs = process_group_attrs, + .num_attrs = ARRAY_SIZE(process_group_attrs), + .ctrls = process_group_ctrls, + .num_ctrls = ARRAY_SIZE(process_group_ctrls), + .ops = { + .init = process_group_init, + .exit = process_group_exit, + }, +}; +RESOURCE_DRIVER_REGISTER(&process_group_driver) -- 2.7.4 From b09db144d8f774b03eb9a28a57754132adc64535 Mon Sep 17 00:00:00 2001 From: Chanwoo Choi Date: Mon, 21 Mar 2022 13:16:50 +0900 Subject: [PATCH 09/16] monitor: request-handler: Replace with strerror_r to fix vulnerability issue Change-Id: I399fe56e8305df1ed3aef2b7e55677ea2b463313 Signed-off-by: Chanwoo Choi --- src/monitor/request-handler.c | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/src/monitor/request-handler.c b/src/monitor/request-handler.c index edaabdb..b70f504 100644 --- a/src/monitor/request-handler.c +++ b/src/monitor/request-handler.c @@ -453,6 +453,7 @@ static void handle_request(struct request_client *client, char *buffer) int request_type; int ret; int buffer_len = REQUEST_BUFFER_MAX; + char err_buf[BUFF_MAX]; request_type = split_request_type_and_args(buffer, &args); @@ -644,8 +645,10 @@ static void handle_request(struct request_client *client, char *buffer) } ADD_RESPONSE(response, buffer_len, "%d", ret); - if (send(client->socket_fd, _response, strlen(_response), 0) < 0) - _E("Failed to send respones, error: %s", strerror(errno)); + if (send(client->socket_fd, _response, strlen(_response), 0) < 0) { + strerror_r(errno, err_buf, BUFF_MAX); + _E("Failed to send respones, errno: %d, error: %s", errno, err_buf); + } } static GList *g_request_client_head; @@ -684,6 +687,7 @@ static int request_handler_func(void *data, void **result) char buffer[REQUEST_BUFFER_MAX + 1]; struct request_client *client = (struct request_client *)data; int len; + char err_buf[BUFF_MAX]; _D("Start worker thread for client-%d", client->socket_fd); @@ -695,7 +699,9 @@ static int request_handler_func(void *data, void **result) } if (len < 0) { - _E("Error occurs while receiving request: %s", strerror(errno)); + strerror_r(errno, err_buf, BUFF_MAX); + _E("Error occurs while receiving request: errno: %d, error: %s", + errno, err_buf); goto out; } -- 2.7.4 From 83fb619c9a0dd37f2def21090ff2e8fd632f67dc Mon Sep 17 00:00:00 2001 From: Chanwoo Choi Date: Mon, 21 Mar 2022 14:03:21 +0900 Subject: [PATCH 10/16] resource: process: Fix memory leak issue Change-Id: I15674f225da17e339493327b6ec870c86ad826a7 Signed-off-by: Chanwoo Choi --- src/resource/resource-process.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/resource/resource-process.c b/src/resource/resource-process.c index fbfbd6c..8baf5dc 100644 --- a/src/resource/resource-process.c +++ b/src/resource/resource-process.c @@ -378,7 +378,7 @@ static int query_taskstats(struct taskstats *stats, int cmd_type, pid_t pid) ret = nla_put_u32(msg, cmd_type, pid); if (ret < 0) - goto err_genl_close; + goto err_msg_free; ret = nl_send_auto_complete(sock, msg); nlmsg_free(msg); @@ -399,6 +399,8 @@ static int query_taskstats(struct taskstats *stats, int cmd_type, pid_t pid) return 0; +err_msg_free: + nlmsg_free(msg); err_genl_close: nl_close(sock); err_free_sock: -- 2.7.4 From 2aaf79c894a1b4d2816c5f345ea14beb07f42116 Mon Sep 17 00:00:00 2001 From: Dongwoo Lee Date: Mon, 21 Mar 2022 17:21:21 +0900 Subject: [PATCH 11/16] monitor: request-handler: Fix to delete resource properly Since resources are managed by hash table, it should be removed from hash table before removing resource. Otherwise, it can cause double-free when the client is disconnected. So, this fixes create and remove procedures to handle hash table properly. Change-Id: I466e5cc6c289c20cd827964aae0c191b85356938 Signed-off-by: Dongwoo Lee --- src/monitor/request-handler.c | 32 +++++++++----------------------- 1 file changed, 9 insertions(+), 23 deletions(-) diff --git a/src/monitor/request-handler.c b/src/monitor/request-handler.c index b70f504..cd2904f 100644 --- a/src/monitor/request-handler.c +++ b/src/monitor/request-handler.c @@ -41,13 +41,6 @@ #include #include -static void free_resource(gpointer key, gpointer value, gpointer user_data) -{ - struct resource *res = value; - - delete_resource(res); -} - static void update_resource(gpointer key, gpointer value, gpointer user_data) { struct resource *res = value; @@ -59,19 +52,16 @@ static void update_resource(gpointer key, gpointer value, gpointer user_data) res->name, res->id); } -static void finalize_request_client(struct request_client *client) +static void +register_resource_to_client(struct request_client *client, struct resource *res) { - if (!client) - return; - - if (client->resource_table) - g_hash_table_foreach(client->resource_table, (GHFunc)free_resource, NULL); + g_hash_table_insert(client->resource_table, (gpointer)&res->id, (gpointer)res); } static void -register_resource_to_client(struct request_client *client, struct resource *res) +unregister_resource_from_client(struct request_client *client, int resource_id) { - g_hash_table_insert(client->resource_table, (gpointer)&res->id, (gpointer)res); + g_hash_table_remove(client->resource_table, (gpointer)&resource_id); } static struct resource * @@ -109,7 +99,6 @@ static int handle_request_create_resource(struct request_client *client, char *a static int handle_request_delete_resource(struct request_client *client, char *args) { - struct resource *res; int resource_id; if (!client || !args) @@ -121,11 +110,7 @@ static int handle_request_delete_resource(struct request_client *client, char *a */ resource_id = atoi(args); - res = get_resource_by_id(client, resource_id); - if (!res) - return -EINVAL; - - delete_resource(res); + unregister_resource_from_client(client, resource_id); return 0; } @@ -709,7 +694,7 @@ static int request_handler_func(void *data, void **result) handle_request(client, buffer); } out: - finalize_request_client(client); + g_hash_table_destroy(client->resource_table); close(client->socket_fd); destroy_request_client(client); @@ -727,7 +712,8 @@ int create_request_client(int socket_fd) } client->socket_fd = socket_fd; - client->resource_table = g_hash_table_new(g_int_hash, g_int_equal); + client->resource_table = g_hash_table_new_full(g_int_hash, g_int_equal, + NULL, delete_resource); create_daemon_thread(&client->worker, request_handler_func, client); -- 2.7.4 From a92ec779bffa95aaa82d66b42895cad28e24abea Mon Sep 17 00:00:00 2001 From: Dongwoo Lee Date: Tue, 22 Mar 2022 10:22:46 +0900 Subject: [PATCH 12/16] resource: process: Set attributes as always supported To support skeleton process resource driver which is representing process on demand, it should be possible to set interesting attributes list before set controls. To this end, all attributes in process is now set to always supported. Change-Id: Ib595d9093b90c860d9f8fb3922d1d295a9957af8 Signed-off-by: Dongwoo Lee --- src/resource/resource-process.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/src/resource/resource-process.c b/src/resource/resource-process.c index 8baf5dc..0e050af 100644 --- a/src/resource/resource-process.c +++ b/src/resource/resource-process.c @@ -219,6 +219,7 @@ static const struct resource_attribute process_attrs[] = { .type = DATA_TYPE_DOUBLE, .ops = { .get = process_get_cpu_util, + .is_supported = resource_attr_supported_always, }, }, { .name = "PROCESS_ATTR_MEM_VIRT", @@ -226,6 +227,7 @@ static const struct resource_attribute process_attrs[] = { .type = DATA_TYPE_UINT64, .ops = { .get = process_get_mem_virt, + .is_supported = resource_attr_supported_always, }, }, { .name = "PROCESS_ATTR_MEM_RSS", @@ -233,6 +235,7 @@ static const struct resource_attribute process_attrs[] = { .type = DATA_TYPE_UINT64, .ops = { .get = process_get_mem_rss, + .is_supported = resource_attr_supported_always, }, }, { .name = "PROCESS_ATTR_MEM_RSS_PERCENT", @@ -240,6 +243,7 @@ static const struct resource_attribute process_attrs[] = { .type = DATA_TYPE_DOUBLE, .ops = { .get = process_get_mem_rss, + .is_supported = resource_attr_supported_always, }, }, { .name = "PROCESS_ATTR_DISK_READ_BPS", @@ -247,6 +251,7 @@ static const struct resource_attribute process_attrs[] = { .type = DATA_TYPE_UINT, .ops = { .get = process_get_disk_bps, + .is_supported = resource_attr_supported_always, }, }, { .name = "PROCESS_ATTR_DISK_WRITE_BPS", @@ -254,6 +259,7 @@ static const struct resource_attribute process_attrs[] = { .type = DATA_TYPE_UINT, .ops = { .get = process_get_disk_bps, + .is_supported = resource_attr_supported_always, }, }, { .name = "PROCESS_ATTR_COMM", @@ -261,6 +267,7 @@ static const struct resource_attribute process_attrs[] = { .type = DATA_TYPE_STRING, .ops = { .get = process_get_context_data, + .is_supported = resource_attr_supported_always, }, }, { .name = "PROCESS_ATTR_PGID", @@ -268,6 +275,7 @@ static const struct resource_attribute process_attrs[] = { .type = DATA_TYPE_INT, .ops = { .get = process_get_context_data, + .is_supported = resource_attr_supported_always, }, }, { .name = "PROCESS_ATTR_PPID", @@ -275,6 +283,7 @@ static const struct resource_attribute process_attrs[] = { .type = DATA_TYPE_INT, .ops = { .get = process_get_context_data, + .is_supported = resource_attr_supported_always, }, }, }; -- 2.7.4 From 84b26363de6daf6b4dae4ec836eee66b02697c72 Mon Sep 17 00:00:00 2001 From: Chanwoo Choi Date: Tue, 22 Mar 2022 14:53:22 +0900 Subject: [PATCH 13/16] lib: tmonitor: Include mandatory header file for variable types When the client refer to tmonitor.h header file, build error happen because tmonitor.h doesn't include the 'sys/type.h' header file. So that include mandatory header file for variable types such as u_int64_t. Change-Id: I3b69e5a95e644ccc160da8aa2583674c91f3725e Signed-off-by: Chanwoo Choi --- lib/tmonitor/tmonitor.h | 1 + 1 file changed, 1 insertion(+) diff --git a/lib/tmonitor/tmonitor.h b/lib/tmonitor/tmonitor.h index 5cda25d..224a186 100644 --- a/lib/tmonitor/tmonitor.h +++ b/lib/tmonitor/tmonitor.h @@ -21,6 +21,7 @@ #include #include +#include #ifdef __cplusplus extern "C" { -- 2.7.4 From 08e24596da748b009564a4541e12e158b621a69c Mon Sep 17 00:00:00 2001 From: Dongwoo Lee Date: Tue, 22 Mar 2022 14:34:27 +0900 Subject: [PATCH 14/16] monitor: request-handler: Fix build warning Change-Id: If5b45861fe807d0c703baf8ae37dcc90ee307389 Signed-off-by: Dongwoo Lee --- src/monitor/request-handler.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/monitor/request-handler.c b/src/monitor/request-handler.c index cd2904f..647a704 100644 --- a/src/monitor/request-handler.c +++ b/src/monitor/request-handler.c @@ -713,7 +713,7 @@ int create_request_client(int socket_fd) client->socket_fd = socket_fd; client->resource_table = g_hash_table_new_full(g_int_hash, g_int_equal, - NULL, delete_resource); + NULL, (GDestroyNotify)delete_resource); create_daemon_thread(&client->worker, request_handler_func, client); -- 2.7.4 From d4459b40c388a07af1a05488e2f88a3dffa907d9 Mon Sep 17 00:00:00 2001 From: Chanwoo Choi Date: Wed, 23 Mar 2022 13:54:39 +0900 Subject: [PATCH 15/16] Revert "util: kernel: Fix overflow issue when multiply operation" This reverts commit 8c98239629e4b49f934de535f881bff26cc52ae9. Change-Id: I1757a90f63ed45ed6ee1c987f9bc7eb45b4e68fb Signed-off-by: Chanwoo Choi --- src/util/kernel.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/util/kernel.c b/src/util/kernel.c index a0f267c..bd797fc 100644 --- a/src/util/kernel.c +++ b/src/util/kernel.c @@ -184,7 +184,7 @@ int kernel_get_memory_info(const char *key, u_int64_t *val) if (!strncmp(buf, key, strlen(key))) { sscanf(buf, "%*s %"PRIu64, val); if (strstr(buf, "kB")) - *val = (u_int64_t)(*val * 1024); + *val *= 1024; break; } } -- 2.7.4 From 0c5633b4fc5fd39698a9f9bea446261b513ba1be Mon Sep 17 00:00:00 2001 From: Chanwoo Choi Date: Wed, 23 Mar 2022 13:59:10 +0900 Subject: [PATCH 16/16] util: kernel: Fix overflow with bit operations Drop 10 MSB bit and 10 left shift operation without multiply operation. Change-Id: I9cc0d5a3f131686c49757edfc2565f25e6a1ecef Signed-off-by: Chanwoo Choi --- include/util/common.h | 3 +++ src/util/kernel.c | 6 ++++-- 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/include/util/common.h b/include/util/common.h index 9cb9373..48315b8 100644 --- a/include/util/common.h +++ b/include/util/common.h @@ -99,6 +99,9 @@ typedef unsigned long long uint64; #ifndef BIT32 #define BIT32(x) (1UL << x) #endif +#ifndef GENMASK64 +#define GENMASK64(h, l) (((~0ULL) << (l)) & (~0ULL >> (64 - 1 - (h)))) +#endif #ifndef container_of #define container_of(ptr, type, member) ({ \ diff --git a/src/util/kernel.c b/src/util/kernel.c index bd797fc..3a9c2d6 100644 --- a/src/util/kernel.c +++ b/src/util/kernel.c @@ -183,8 +183,10 @@ int kernel_get_memory_info(const char *key, u_int64_t *val) while (fgets(buf, BUFF_MAX, fp)) { if (!strncmp(buf, key, strlen(key))) { sscanf(buf, "%*s %"PRIu64, val); - if (strstr(buf, "kB")) - *val *= 1024; + if (strstr(buf, "kB")) { + *val &= GENMASK64(53, 0); + *val <<= 10; + } break; } } -- 2.7.4