From 513e96eb94841734274c0607aae2c9f212411eee Mon Sep 17 00:00:00 2001 From: "Dmitry V. Levin" Date: Mon, 26 Jan 2015 01:17:08 +0000 Subject: [PATCH] Rework string_quote API string_quote() has proven to be too hard to use, replace it with print_quoted_string() that does memory allocation and prints the result. * defs.h (string_quote): Remove. (QUOTE_0_TERMINATED, QUOTE_OMIT_LEADING_TRAILING_QUOTES): New macros. (print_quoted_string): New prototype. * util.c (string_quote): Make static; take "style" flags instead of "len", treat QUOTE_0_TERMINATED style flag as former (len == -1); add QUOTE_OMIT_LEADING_TRAILING_QUOTES style flag support. (ALLOCA_CUTOFF, use_alloca): New macros. (print_quoted_string): New function. (printpathn, printstr): Update to new API. * loop.c (loop_ioctl): Likewise. * mtd.c (ubi_ioctl): Likewise. * net.c (print_scm_security): Likewise. * socketutils.c (unix_parse_response): Likewise. --- defs.h | 6 ++- loop.c | 26 ++++++----- mtd.c | 25 ++++++----- net.c | 12 ++---- socketutils.c | 12 +++--- util.c | 117 ++++++++++++++++++++++++++++++++++++++------------ 6 files changed, 133 insertions(+), 65 deletions(-) diff --git a/defs.h b/defs.h index 8d654a59..97865daf 100644 --- a/defs.h +++ b/defs.h @@ -665,9 +665,13 @@ extern const char *xlookup(const struct xlat *, const unsigned int); extern const char *xlat_search(const struct xlat *, const size_t, const unsigned int); extern int string_to_uint(const char *str); -extern int string_quote(const char *, char *, long, int); extern int next_set_bit(const void *bit_array, unsigned cur_bit, unsigned size_bits); +#define QUOTE_0_TERMINATED 0x01 +#define QUOTE_OMIT_LEADING_TRAILING_QUOTES 0x02 + +extern int print_quoted_string(const char *, unsigned int, unsigned int); + /* a refers to the lower numbered u_arg, * b refers to the higher numbered u_arg */ diff --git a/loop.c b/loop.c index 6ce6545a..bb622fd9 100644 --- a/loop.c +++ b/loop.c @@ -39,7 +39,6 @@ loop_ioctl(struct tcb *tcp, const unsigned int code, long arg) { struct loop_info info; struct loop_info64 info64; - char *s = alloca((LO_NAME_SIZE + LO_KEY_SIZE) * 4); if (entering(tcp)) return 0; @@ -72,12 +71,14 @@ loop_ioctl(struct tcb *tcp, const unsigned int code, long arg) tprints(", flags="); printflags(loop_flags_options, info.lo_flags, "LO_FLAGS_???"); - string_quote(info.lo_name, s, -1, LO_NAME_SIZE); - tprintf(", name=%s", s); + tprints(", name="); + print_quoted_string(info.lo_name, LO_NAME_SIZE, + QUOTE_0_TERMINATED); if (!abbrev(tcp) || info.lo_encrypt_type != LO_CRYPT_NONE) { - string_quote((void *) info.lo_encrypt_key, s, 0, LO_KEY_SIZE); - tprintf(", encrypt_key=%s", s); + tprints(", encrypt_key="); + print_quoted_string((void *) info.lo_encrypt_key, + LO_KEY_SIZE, 0); } if (!abbrev(tcp)) @@ -125,14 +126,17 @@ loop_ioctl(struct tcb *tcp, const unsigned int code, long arg) tprints(", flags="); printflags(loop_flags_options, info64.lo_flags, "LO_FLAGS_???"); - string_quote((void *) info64.lo_file_name, s, -1, LO_NAME_SIZE); - tprintf(", file_name=%s", s); + tprints(", file_name="); + print_quoted_string((void *) info64.lo_file_name, + LO_NAME_SIZE, QUOTE_0_TERMINATED); if (!abbrev(tcp) || info64.lo_encrypt_type != LO_CRYPT_NONE) { - string_quote((void *) info64.lo_crypt_name, s, -1, LO_NAME_SIZE); - tprintf(", crypt_name=%s", s); - string_quote((void *) info64.lo_encrypt_key, s, 0, LO_KEY_SIZE); - tprintf(", encrypt_key=%s", s); + tprints(", crypt_name="); + print_quoted_string((void *) info64.lo_crypt_name, + LO_NAME_SIZE, QUOTE_0_TERMINATED); + tprints(", encrypt_key="); + print_quoted_string((void *) info64.lo_encrypt_key, + LO_KEY_SIZE, 0); } if (!abbrev(tcp)) diff --git a/mtd.c b/mtd.c index 8f05d040..87a6e5d1 100644 --- a/mtd.c +++ b/mtd.c @@ -262,9 +262,6 @@ ubi_ioctl(struct tcb *tcp, const unsigned int code, long arg) struct ubi_attach_req attach; struct ubi_map_req map; struct ubi_set_vol_prop_req prop; - /* 4*(n-1) + 3 for quotes and NUL */ - char vol_name[(UBI_MAX_VOLUME_NAME + 1) * 4]; - int ret; if (entering(tcp)) return 0; @@ -278,10 +275,12 @@ ubi_ioctl(struct tcb *tcp, const unsigned int code, long arg) ", bytes=%" PRIi64 ", vol_type=", mkvol.vol_id, mkvol.alignment, (int64_t)mkvol.bytes); printxval(ubi_volume_types, mkvol.vol_type, "UBI_???_VOLUME"); - ret = string_quote(mkvol.name, vol_name, -1, - CLAMP(mkvol.name_len, 0, UBI_MAX_VOLUME_NAME)); - tprintf(", name_len=%" PRIi16 ", name=%s%s", - mkvol.name_len, vol_name, ret ? "..." : ""); + tprintf(", name_len=%" PRIi16 ", name=", mkvol.name_len); + if (print_quoted_string(mkvol.name, + CLAMP(mkvol.name_len, 0, UBI_MAX_VOLUME_NAME), + QUOTE_0_TERMINATED) > 0) { + tprints("..."); + } tprints("}"); return 1; @@ -303,11 +302,15 @@ ubi_ioctl(struct tcb *tcp, const unsigned int code, long arg) for (c = 0; c < CLAMP(rnvol.count, 0, UBI_MAX_RNVOL); ++c) { if (c) tprints(", "); - ret = string_quote(rnvol.ents[c].name, vol_name, -1, - CLAMP(rnvol.ents[c].name_len, 0, UBI_MAX_VOLUME_NAME)); tprintf("{vol_id=%" PRIi32 ", name_len=%" PRIi16 - ", name=%s%s}", rnvol.ents[c].vol_id, - rnvol.ents[c].name_len, vol_name, ret ? "..." : ""); + ", name=", rnvol.ents[c].vol_id, + rnvol.ents[c].name_len); + if (print_quoted_string(rnvol.ents[c].name, + CLAMP(rnvol.ents[c].name_len, 0, UBI_MAX_VOLUME_NAME), + QUOTE_0_TERMINATED) > 0) { + tprints("..."); + } + tprints("}"); } tprints("]}"); return 1; diff --git a/net.c b/net.c index 829f3ad8..ef72d4fe 100644 --- a/net.c +++ b/net.c @@ -402,17 +402,11 @@ print_scm_security(struct tcb *tcp, size_t cmsg_size, char *ptr, size_t cmsg_len const char *label = (const char *) (ptr + cmsg_size); const size_t label_len = cmsg_len - cmsg_size; - char *outstr; - const size_t alloc_len = 4 * label_len + 3; - if (label_len != alloc_len / 4 || - !(outstr = malloc(alloc_len))) - return false; - - string_quote(label, outstr, 0, label_len); - tprintf(", %s}", outstr); + tprints(", "); + print_quoted_string(label, label_len, 0); + tprints("}"); - free(outstr); return true; } diff --git a/socketutils.c b/socketutils.c index 93bb0c3c..2de59cd3 100644 --- a/socketutils.c +++ b/socketutils.c @@ -252,13 +252,13 @@ unix_parse_response(const char *proto_name, const void *data, int data_len, tprintf("->%u", peer); if (path_len) { if (path[0] == '\0') { - char *outstr = alloca(4 * path_len - 1); - string_quote(path + 1, outstr, -1, path_len); - tprintf(",@%s", outstr); + tprints(",@"); + print_quoted_string(path + 1, path_len, + QUOTE_0_TERMINATED); } else { - char *outstr = alloca(4 * path_len + 3); - string_quote(path, outstr, -1, path_len + 1); - tprintf(",%s", outstr); + tprints(","); + print_quoted_string(path, path_len + 1, + QUOTE_0_TERMINATED); } } tprints("]"); diff --git a/util.c b/util.c index 3b50191d..00ee5a02 100644 --- a/util.c +++ b/util.c @@ -519,24 +519,30 @@ printfd(struct tcb *tcp, int fd) /* * Quote string `instr' of length `size' * Write up to (3 + `size' * 4) bytes to `outstr' buffer. - * If `len' is -1, treat `instr' as a NUL-terminated string - * and quote at most (`size' - 1) bytes. * - * Returns 0 if len == -1 and NUL was seen, 1 otherwise. - * Note that if len >= 0, always returns 1. + * If QUOTE_0_TERMINATED `style' flag is set, + * treat `instr' as a NUL-terminated string, + * checking up to (`size' + 1) bytes of `instr'. + * + * If QUOTE_OMIT_LEADING_TRAILING_QUOTES `style' flag is set, + * do not add leading and trailing quoting symbols. + * + * Returns 0 if QUOTE_0_TERMINATED is set and NUL was seen, 1 otherwise. + * Note that if QUOTE_0_TERMINATED is not set, always returns 1. */ -int -string_quote(const char *instr, char *outstr, long len, int size) +static int +string_quote(const char *instr, char *outstr, const unsigned int size, + const unsigned int style) { const unsigned char *ustr = (const unsigned char *) instr; char *s = outstr; - int usehex, c, i, eol; + unsigned int i; + int usehex, c, eol; - eol = 0x100; /* this can never match a char */ - if (len == -1) { - size--; + if (style & QUOTE_0_TERMINATED) eol = '\0'; - } + else + eol = 0x100; /* this can never match a char */ usehex = 0; if (xflag > 1) @@ -565,7 +571,8 @@ string_quote(const char *instr, char *outstr, long len, int size) } } - *s++ = '\"'; + if (!(style & QUOTE_OMIT_LEADING_TRAILING_QUOTES)) + *s++ = '\"'; if (usehex) { /* Hex-quote the whole string. */ @@ -638,11 +645,12 @@ string_quote(const char *instr, char *outstr, long len, int size) } } - *s++ = '\"'; + if (!(style & QUOTE_OMIT_LEADING_TRAILING_QUOTES)) + *s++ = '\"'; *s = '\0'; /* Return zero if we printed entire ASCIZ string (didn't truncate it) */ - if (len == -1 && ustr[i] == '\0') { + if (style & QUOTE_0_TERMINATED && ustr[i] == '\0') { /* We didn't see NUL yet (otherwise we'd jump to 'asciz_ended') * but next char is NUL. */ @@ -652,12 +660,70 @@ string_quote(const char *instr, char *outstr, long len, int size) return 1; asciz_ended: - *s++ = '\"'; + if (!(style & QUOTE_OMIT_LEADING_TRAILING_QUOTES)) + *s++ = '\"'; *s = '\0'; /* Return zero: we printed entire ASCIZ string (didn't truncate it) */ return 0; } +#ifndef ALLOCA_CUTOFF +# define ALLOCA_CUTOFF 4032 +#endif +#define use_alloca(n) ((n) <= ALLOCA_CUTOFF) + +/* + * Quote string `str' of length `size' and print the result. + * + * If QUOTE_0_TERMINATED `style' flag is set, + * treat `str' as a NUL-terminated string and + * quote at most (`size' - 1) bytes. + * + * If QUOTE_OMIT_LEADING_TRAILING_QUOTES `style' flag is set, + * do not add leading and trailing quoting symbols. + * + * Returns 0 if QUOTE_0_TERMINATED is set and NUL was seen, 1 otherwise. + * Note that if QUOTE_0_TERMINATED is not set, always returns 1. + */ +int +print_quoted_string(const char *str, unsigned int size, + const unsigned int style) +{ + char *buf; + char *outstr; + unsigned int alloc_size; + int rc; + + if (size && style & QUOTE_0_TERMINATED) + --size; + + alloc_size = 4 * size; + if (alloc_size / 4 != size) { + error_msg("Out of memory"); + tprints("???"); + return -1; + } + alloc_size += 1 + (style & QUOTE_OMIT_LEADING_TRAILING_QUOTES ? 0 : 2); + + if (use_alloca(alloc_size)) { + outstr = alloca(alloc_size); + buf = NULL; + } else { + outstr = buf = malloc(alloc_size); + if (!buf) { + error_msg("Out of memory"); + tprints("???"); + return -1; + } + } + + rc = string_quote(str, outstr, size, style); + tprints(outstr); + + free(buf); + return rc; +} + /* * Print path string specified by address `addr' and length `n'. * If path length exceeds `n', append `...' to the output. @@ -682,13 +748,8 @@ printpathn(struct tcb *tcp, long addr, unsigned int n) if (nul_seen < 0) tprintf("%#lx", addr); else { - char *outstr; - - path[n] = '\0'; - n++; - outstr = alloca(4 * n); /* 4*(n-1) + 3 for quotes and NUL */ - string_quote(path, outstr, -1, n); - tprints(outstr); + path[n++] = '\0'; + print_quoted_string(path, n, QUOTE_0_TERMINATED); if (!nul_seen) tprints("..."); } @@ -712,6 +773,7 @@ printstr(struct tcb *tcp, long addr, long len) static char *str = NULL; static char *outstr; unsigned int size; + unsigned int style; int ellipsis; if (!addr) { @@ -732,31 +794,32 @@ printstr(struct tcb *tcp, long addr, long len) die_out_of_memory(); } + size = max_strlen; if (len == -1) { /* * Treat as a NUL-terminated string: fetch one byte more - * because string_quote() quotes one byte less. + * because string_quote may look one byte ahead. */ - size = max_strlen + 1; - if (umovestr(tcp, addr, size, str) < 0) { + if (umovestr(tcp, addr, size + 1, str) < 0) { tprintf("%#lx", addr); return; } + style = QUOTE_0_TERMINATED; } else { - size = max_strlen; if (size > (unsigned long)len) size = (unsigned long)len; if (umoven(tcp, addr, size, str) < 0) { tprintf("%#lx", addr); return; } + style = 0; } /* If string_quote didn't see NUL and (it was supposed to be ASCIZ str * or we were requested to print more than -s NUM chars)... */ - ellipsis = (string_quote(str, outstr, len, size) && + ellipsis = (string_quote(str, outstr, size, style) && (len < 0 || (unsigned long) len > max_strlen)); tprints(outstr); -- 2.40.0