In this patch I am extending the rule instantiator to create the comment node where supported, which is the case for iptables and ip6tables. Since commands are written in the format cmd="iptables ...-m comment --comment \"\" " certain characters ("$`\) in the comment need to be escaped (twice) to prevent comments from becoming commands themselves or cause other forms of (bash) substitutions. I have tested this with various input and in my tests the input made it straight into the comment. A test case for TCK will be provided separately that tests this. To prevent consecutive spaces in comments from becoming a single space (by bash), the IFS variable is now set to an empty string. Also, commands are now executed using bash's 'eval' command. Since the regular strchr() function causes a compiler warning when neither one of the parameters is a constant, I reimplemented this function and called it _strchr(). Here is the reference to this bug http://gcc.gnu.org/bugzilla/show_bug.cgi?id=36513 Signed-off-by: Stefan Berger --- src/nwfilter/nwfilter_ebiptables_driver.c | 68 +++++++++++++++++++++++++++++- src/nwfilter/nwfilter_ebiptables_driver.h | 3 + 2 files changed, 69 insertions(+), 2 deletions(-) Index: libvirt-acl/src/nwfilter/nwfilter_ebiptables_driver.c =================================================================== --- libvirt-acl.orig/src/nwfilter/nwfilter_ebiptables_driver.c +++ libvirt-acl/src/nwfilter/nwfilter_ebiptables_driver.c @@ -55,7 +55,7 @@ #define CMD_DEF_PRE "cmd=\"" #define CMD_DEF_POST "\"" #define CMD_DEF(X) CMD_DEF_PRE X CMD_DEF_POST -#define CMD_EXEC "res=`${cmd}`" CMD_SEPARATOR +#define CMD_EXEC "res=`eval ${cmd}`" CMD_SEPARATOR #define CMD_STOPONERR(X) \ X ? "if [ $? -ne 0 ]; then" \ " echo \"Failure to execute command '${cmd}'.\";" \ @@ -291,6 +291,58 @@ printDataTypeAsHex(virNWFilterHashTableP } +/* avoiding a compiler warning trough own implementation */ +static const char * +_strchr(const char *s, int c) +{ + while (*s && *s != (char)c) + s++; + if (*s) + return s; + return NULL; +} + + +static char * +shellEscapeString(const char *data, size_t maxlen, + const char *s, bool doubleEscape) +{ + char *res; + size_t i, j, add = 0, len = strlen(data); + + if (len > maxlen) + len = maxlen; + + for (i = 0; i < len; i++) { + if (_strchr(s, data[i])) { + add += 1; + if (doubleEscape) + add += 2; + } + } + + if (VIR_ALLOC_VAR(res, char, len+add+1) < 0) { + virReportOOMError(); + return NULL; + } + + j = 0; + for (i = 0; i < len; i++) { + if (_strchr(s, data[i])) { + res[j++] = '\\'; + if (doubleEscape) { + res[j++] = '\\'; + res[j++] = '\\'; + } + } + res[j++] = data[i]; + } + res[j] = 0; + + return res; +} + + static void ebiptablesRuleInstFree(ebiptablesRuleInstPtr inst) { @@ -993,6 +1045,18 @@ iptablesHandleIpHdr(virBufferPtr buf, } } + if (HAS_ENTRY_ITEM(&ipHdr->dataComment)) { + char *cmt = shellEscapeString(ipHdr->dataComment.u.string, + IPTABLES_MAX_COMMENT_SIZE, + "\"`\\$", true); + if (!cmt) + goto err_exit; + virBufferVSprintf(buf, + " -m comment --comment \\\"%s\\\"", + cmt); + VIR_FREE(cmt); + } + return 0; err_exit: @@ -2211,7 +2275,7 @@ ebiptablesWriteToTempFile(const char *st char *header; size_t written; - virBufferVSprintf(&buf, "#!%s\n", bash_cmd_path); + virBufferVSprintf(&buf, "#!%s\nIFS=""\n", bash_cmd_path); if (virBufferError(&buf)) { virBufferFreeAndReset(&buf); Index: libvirt-acl/src/nwfilter/nwfilter_ebiptables_driver.h =================================================================== --- libvirt-acl.orig/src/nwfilter/nwfilter_ebiptables_driver.h +++ libvirt-acl/src/nwfilter/nwfilter_ebiptables_driver.h @@ -45,4 +45,7 @@ extern virNWFilterTechDriver ebiptables_ # define EBIPTABLES_DRIVER_ID "ebiptables" + +# define IPTABLES_MAX_COMMENT_SIZE 256 + #endif