Bug#448139: cfagent crashes with a segmentation fault when 31+ arguments are supplied
Patch applied to correct the problem as reported. Iain Patterson wrote: Quoth Mark Burgess, This is probably true, but the case cited in the mail is not a limitation of cfengine but the argument getopt code in the operating system concerned. It is normal that Unix limits to 31 args, and internally cfengine does the same for consistency. I tried compiling the getopt example code at http://www.gnu.org/software/libc/manual/html_node/Getopt.html and didn't get a segfault with 31 arguments on Linux x86_64. cfagent 2.2.1 on the same OS did indeed segfault with 31 arguments. The conclusion is that, while I agree there should be no segfault, I am not sure what I can do about it, since there is no code in cfengine that lead to this fault. It seems the bug is in the code which preparses arguments. Line 253 of cfagent.c (at least in version 2.2.1) describes the case where a script is called with the shell magic #!/bla/cfengine -v -f and this ends up being passed in argv[1] as a single string. cfagent then parses this into an array of size CF_MAXARGS, which is 31 as you state. The attached quick and very dirty patch does the preparse in two stages, first allocating a dynamic buffer big enough for the arguments and then filling it in as before. An alternative option (if you excuse the pun) would be to use popt, which has the function poptParseArgvString(). The downside is that this is an added dependency. --- cfengine-2.2.1/src/cf.defs.h.orig 2007-11-30 08:24:22.122979592 + +++ cfengine-2.2.1/src/cf.defs.h 2007-11-30 08:24:26.734643977 + @@ -287,7 +287,6 @@ #define CF_NONCELEN (CF_BUFSIZE/16) #define CF_MAXLINKSIZE 256 #define CF_MAXLINKLEVEL 4 -#define CF_MAXARGS 31 #define CF_MAXFARGS 8 #define CF_MAX_IP_LEN 64 /* numerical ip length */ #define CF_PROCCOLS 16 --- cfengine-2.2.1/src/cfagent.c.orig 2007-11-30 08:24:04.652251054 + +++ cfengine-2.2.1/src/cfagent.c 2007-11-30 08:47:17.382186413 + @@ -198,8 +198,8 @@ void Initialize(int argc,char *argv[]) -{ char *sp, *cfargv[CF_MAXARGS]; - int i, cfargc, seed; +{ char *sp, **cfargv; + int i, j, cfargc, seed; struct stat statbuf; unsigned char s[16]; char ebuff[CF_EXPANDSIZE]; @@ -235,9 +235,40 @@ /* Everything ends up inside a single argument! Here's the fix */ cfargc = 1; -cfargv[0]=cfagent; -for (i = 1; i argc; i++) +/* Pass 1: Find how many arguments there are. */ +for (i = 1, j = 1; i argc; i++) + { + sp = argv[i]; + + while (*sp != '\0') + { + while (*sp == ' ' *sp != '\0') /* Skip to arg */ + { + sp++; + } + + cfargc++; + + while (*sp != ' ' *sp != '\0') /* Skip to white space */ + { + sp++; + } + } + } + +/* Allocate memory for cfargv. */ +cfargv = (char **) malloc(sizeof(char *) * cfargc + 1); +if (! cfargv) + { + /* I guess CfLog(cferror, ...) isn't available yet. */ + fprintf(stderr,cfagent: Out of memory parsing arguments\n); + exit(111); + } + +/* Pass 2: Parse the arguments. */ +cfargv[0] = cfagent; +for (i = 1, j = 1; i argc; i++) { sp = argv[i]; @@ -252,7 +283,7 @@ sp++; } - cfargv[cfargc++] = sp; + cfargv[j++] = sp; while (*sp != ' ' *sp != '\0') /* Skip to white space */ { @@ -260,6 +291,7 @@ } } } +cfargv[j] = 0; VDEFAULTBINSERVER.name = ; @@ -315,6 +347,7 @@ seed = ElfHash(s); srand48((long)seed); CheckOpts(cfargc,cfargv); + free(cfargv); AddInstallable(no_default_route); CfenginePort(); ___ Bug-cfengine mailing list [EMAIL PROTECTED] https://cfengine.org/mailman/listinfo/bug-cfengine -- Mark Burgess Professor of Network and System Administration Oslo University College ~~ Work: +47 22453272Email: [EMAIL PROTECTED] Fax : +47 22453205WWW : http://www.iu.hio.no/~mark ~~ -- To UNSUBSCRIBE, email to [EMAIL PROTECTED] with a subject of unsubscribe. Trouble? Contact [EMAIL PROTECTED]
Bug#448139: cfagent crashes with a segmentation fault when 31+ arguments are supplied
THank you for this analysis. The original bug message did not contain enough context to see this interaction. M Iain Patterson wrote: Quoth Mark Burgess, This is probably true, but the case cited in the mail is not a limitation of cfengine but the argument getopt code in the operating system concerned. It is normal that Unix limits to 31 args, and internally cfengine does the same for consistency. I tried compiling the getopt example code at http://www.gnu.org/software/libc/manual/html_node/Getopt.html and didn't get a segfault with 31 arguments on Linux x86_64. cfagent 2.2.1 on the same OS did indeed segfault with 31 arguments. The conclusion is that, while I agree there should be no segfault, I am not sure what I can do about it, since there is no code in cfengine that lead to this fault. It seems the bug is in the code which preparses arguments. Line 253 of cfagent.c (at least in version 2.2.1) describes the case where a script is called with the shell magic #!/bla/cfengine -v -f and this ends up being passed in argv[1] as a single string. cfagent then parses this into an array of size CF_MAXARGS, which is 31 as you state. The attached quick and very dirty patch does the preparse in two stages, first allocating a dynamic buffer big enough for the arguments and then filling it in as before. An alternative option (if you excuse the pun) would be to use popt, which has the function poptParseArgvString(). The downside is that this is an added dependency. --- cfengine-2.2.1/src/cf.defs.h.orig 2007-11-30 08:24:22.122979592 + +++ cfengine-2.2.1/src/cf.defs.h 2007-11-30 08:24:26.734643977 + @@ -287,7 +287,6 @@ #define CF_NONCELEN (CF_BUFSIZE/16) #define CF_MAXLINKSIZE 256 #define CF_MAXLINKLEVEL 4 -#define CF_MAXARGS 31 #define CF_MAXFARGS 8 #define CF_MAX_IP_LEN 64 /* numerical ip length */ #define CF_PROCCOLS 16 --- cfengine-2.2.1/src/cfagent.c.orig 2007-11-30 08:24:04.652251054 + +++ cfengine-2.2.1/src/cfagent.c 2007-11-30 08:47:17.382186413 + @@ -198,8 +198,8 @@ void Initialize(int argc,char *argv[]) -{ char *sp, *cfargv[CF_MAXARGS]; - int i, cfargc, seed; +{ char *sp, **cfargv; + int i, j, cfargc, seed; struct stat statbuf; unsigned char s[16]; char ebuff[CF_EXPANDSIZE]; @@ -235,9 +235,40 @@ /* Everything ends up inside a single argument! Here's the fix */ cfargc = 1; -cfargv[0]=cfagent; -for (i = 1; i argc; i++) +/* Pass 1: Find how many arguments there are. */ +for (i = 1, j = 1; i argc; i++) + { + sp = argv[i]; + + while (*sp != '\0') + { + while (*sp == ' ' *sp != '\0') /* Skip to arg */ + { + sp++; + } + + cfargc++; + + while (*sp != ' ' *sp != '\0') /* Skip to white space */ + { + sp++; + } + } + } + +/* Allocate memory for cfargv. */ +cfargv = (char **) malloc(sizeof(char *) * cfargc + 1); +if (! cfargv) + { + /* I guess CfLog(cferror, ...) isn't available yet. */ + fprintf(stderr,cfagent: Out of memory parsing arguments\n); + exit(111); + } + +/* Pass 2: Parse the arguments. */ +cfargv[0] = cfagent; +for (i = 1, j = 1; i argc; i++) { sp = argv[i]; @@ -252,7 +283,7 @@ sp++; } - cfargv[cfargc++] = sp; + cfargv[j++] = sp; while (*sp != ' ' *sp != '\0') /* Skip to white space */ { @@ -260,6 +291,7 @@ } } } +cfargv[j] = 0; VDEFAULTBINSERVER.name = ; @@ -315,6 +347,7 @@ seed = ElfHash(s); srand48((long)seed); CheckOpts(cfargc,cfargv); + free(cfargv); AddInstallable(no_default_route); CfenginePort(); ___ Bug-cfengine mailing list [EMAIL PROTECTED] https://cfengine.org/mailman/listinfo/bug-cfengine -- Mark Burgess Professor of Network and System Administration Oslo University College ~~ Work: +47 22453272Email: [EMAIL PROTECTED] Fax : +47 22453205WWW : http://www.iu.hio.no/~mark ~~ -- To UNSUBSCRIBE, email to [EMAIL PROTECTED] with a subject of unsubscribe. Trouble? Contact [EMAIL PROTECTED]
Bug#448139: cfagent crashes with a segmentation fault when 31+ arguments are supplied
Quoth Mark Burgess, This is probably true, but the case cited in the mail is not a limitation of cfengine but the argument getopt code in the operating system concerned. It is normal that Unix limits to 31 args, and internally cfengine does the same for consistency. I tried compiling the getopt example code at http://www.gnu.org/software/libc/manual/html_node/Getopt.html and didn't get a segfault with 31 arguments on Linux x86_64. cfagent 2.2.1 on the same OS did indeed segfault with 31 arguments. The conclusion is that, while I agree there should be no segfault, I am not sure what I can do about it, since there is no code in cfengine that lead to this fault. It seems the bug is in the code which preparses arguments. Line 253 of cfagent.c (at least in version 2.2.1) describes the case where a script is called with the shell magic #!/bla/cfengine -v -f and this ends up being passed in argv[1] as a single string. cfagent then parses this into an array of size CF_MAXARGS, which is 31 as you state. The attached quick and very dirty patch does the preparse in two stages, first allocating a dynamic buffer big enough for the arguments and then filling it in as before. An alternative option (if you excuse the pun) would be to use popt, which has the function poptParseArgvString(). The downside is that this is an added dependency. --- cfengine-2.2.1/src/cf.defs.h.orig 2007-11-30 08:24:22.122979592 + +++ cfengine-2.2.1/src/cf.defs.h 2007-11-30 08:24:26.734643977 + @@ -287,7 +287,6 @@ #define CF_NONCELEN (CF_BUFSIZE/16) #define CF_MAXLINKSIZE 256 #define CF_MAXLINKLEVEL 4 -#define CF_MAXARGS 31 #define CF_MAXFARGS 8 #define CF_MAX_IP_LEN 64 /* numerical ip length */ #define CF_PROCCOLS 16 --- cfengine-2.2.1/src/cfagent.c.orig 2007-11-30 08:24:04.652251054 + +++ cfengine-2.2.1/src/cfagent.c 2007-11-30 08:47:17.382186413 + @@ -198,8 +198,8 @@ void Initialize(int argc,char *argv[]) -{ char *sp, *cfargv[CF_MAXARGS]; - int i, cfargc, seed; +{ char *sp, **cfargv; + int i, j, cfargc, seed; struct stat statbuf; unsigned char s[16]; char ebuff[CF_EXPANDSIZE]; @@ -235,9 +235,40 @@ /* Everything ends up inside a single argument! Here's the fix */ cfargc = 1; -cfargv[0]=cfagent; -for (i = 1; i argc; i++) +/* Pass 1: Find how many arguments there are. */ +for (i = 1, j = 1; i argc; i++) + { + sp = argv[i]; + + while (*sp != '\0') + { + while (*sp == ' ' *sp != '\0') /* Skip to arg */ + { + sp++; + } + + cfargc++; + + while (*sp != ' ' *sp != '\0') /* Skip to white space */ + { + sp++; + } + } + } + +/* Allocate memory for cfargv. */ +cfargv = (char **) malloc(sizeof(char *) * cfargc + 1); +if (! cfargv) + { + /* I guess CfLog(cferror, ...) isn't available yet. */ + fprintf(stderr,cfagent: Out of memory parsing arguments\n); + exit(111); + } + +/* Pass 2: Parse the arguments. */ +cfargv[0] = cfagent; +for (i = 1, j = 1; i argc; i++) { sp = argv[i]; @@ -252,7 +283,7 @@ sp++; } - cfargv[cfargc++] = sp; + cfargv[j++] = sp; while (*sp != ' ' *sp != '\0') /* Skip to white space */ { @@ -260,6 +291,7 @@ } } } +cfargv[j] = 0; VDEFAULTBINSERVER.name = ; @@ -315,6 +347,7 @@ seed = ElfHash(s); srand48((long)seed); CheckOpts(cfargc,cfargv); + free(cfargv); AddInstallable(no_default_route); CfenginePort();
Bug#448139: cfagent crashes with a segmentation fault when 31+ arguments are supplied
Pardon me for saying so, but one recalls the story of the patient visiting the doctor: Doctor, doctor, it hurts when I do this. To which the answer is Then don't do that! Can anyone provide an example of a case in which one need to approach this number of arguments? M Morten Werner Forsbring wrote: tags 448139 upstream thanks Hi, here is a bugreport from one of our Debian users. I've confirmed this bug on cfengine version 2.2.2. - Werner Cyril Bouthors [EMAIL PROTECTED] writes: Package: cfengine2 Version: 2.1.22-2 Severity: critical cfagent crashes with a segmentation fault when 31+ arguments are supplied It can easily be reproduced with: $ cfagent -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a Segmentation fault $ The typical use case of 31+ arguments is with multiple -Dfoo arguments, like: $ cfagent --no-lock -x -H -Dmyfai_munin_node -Dmyfai_eth0 -Dmyfai_libnssdb_passwd -Dmyfai_libnssdb_shadow -Dmyfai_resolv_conf -Dmyfai_etc_hosts -Dmyfai_lilo -Dmyfai_firewall_web -Dmyfai_apt_preferences -Dmyfai_apt_list_changes -Dmyfai_apt_sources_list -Dmyfai_forward_root_emails -Dmyfai_exim_smarthost -Dmyfai_cyb_dotfiles -Dmyfai_ssh_key_root -Dmyfai_apt_cache_limit -Dmyfai_init_d_oshosting_nfs_mounts -Dmyfai_init_d_oshosting_links -Dmyfai_init_d_oshosting_update_config_web -Dmyfai_init_d_oshosting_update_nssdb_passwd -Dmyfai_init_d_oshosting_update_nssdb_shadow -Dmyfai_nfsmount_sessions -Dmyfai_nfsmount_myfai -Dmyfai_enable_rsyncd -Dmyfai_oshosting_nfs_mounts -Dmyfai_web_suexec_romain -Dmyfai_web_oshosting_phpkill -Dmyfai_bind9_forwarders -Dmyfai_static_route_to_mail_by_lbgw -Dmyfai_static_route_to_ns_by_lbgw -Dmyfai_enable_spamd -Dmyfai_spamd_flock -Dmyfai_spamd_disable_bayes -Dmyfai_spamd_enable_network -Dmyfai_cron_d_myfai_ntp -f /usr/local/myfai/etc/cfengine/generic.c ! onf Segmentation fault $ I'm almost sure that this command used to be working on previous versions of cfengine. ___ Bug-cfengine mailing list [EMAIL PROTECTED] https://cfengine.org/mailman/listinfo/bug-cfengine -- Mark Burgess Professor of Network and System Administration Oslo University College ~~ Work: +47 22453272Email: [EMAIL PROTECTED] Fax : +47 22453205WWW : http://www.iu.hio.no/~mark ~~ -- To UNSUBSCRIBE, email to [EMAIL PROTECTED] with a subject of unsubscribe. Trouble? Contact [EMAIL PROTECTED]
Bug#448139: cfagent crashes with a segmentation fault when 31+ arguments are supplied
Mark Burgess [EMAIL PROTECTED] writes: Pardon me for saying so, but one recalls the story of the patient visiting the doctor: Doctor, doctor, it hurts when I do this. To which the answer is Then don't do that! I don't agree with your comparison here, but ok. In my opinion a program shouldn't _segfault_ just if it's called with more than 31 arguments. Can anyone provide an example of a case in which one need to approach this number of arguments? As written in the bugreport: The typical use case of 31+ arguments is with multiple -Dfoo arguments, like: $ cfagent --no-lock -x -H -Dmyfai_munin_node -Dmyfai_eth0 -Dmyfai_libnssdb_passwd -Dmyfai_libnssdb_shadow -Dmyfai_resolv_conf -Dmyfai_etc_hosts -Dmyfai_lilo -Dmyfai_firewall_web -Dmyfai_apt_preferences -Dmyfai_apt_list_changes -Dmyfai_apt_sources_list -Dmyfai_forward_root_emails -Dmyfai_exim_smarthost -Dmyfai_cyb_dotfiles -Dmyfai_ssh_key_root -Dmyfai_apt_cache_limit -Dmyfai_init_d_oshosting_nfs_mounts -Dmyfai_init_d_oshosting_links -Dmyfai_init_d_oshosting_update_config_web -Dmyfai_init_d_oshosting_update_nssdb_passwd -Dmyfai_init_d_oshosting_update_nssdb_shadow -Dmyfai_nfsmount_sessions -Dmyfai_nfsmount_myfai -Dmyfai_enable_rsyncd -Dmyfai_oshosting_nfs_mounts -Dmyfai_web_suexec_romain -Dmyfai_web_oshosting_phpkill -Dmyfai_bind9_forwarders -Dmyfai_static_route_to_mail_by_lbgw -Dmyfai_static_route_to_ns_by_lbgw -Dmyfai_enable_spamd -Dmyfai_spamd_flock -Dmyfai_spamd_disable_bayes -Dmyfai_spamd_enable_network -Dmyfai_cron_d_myfai_ntp -f /usr/local/myfai/etc/cfengine/generic.c ! onf Segmentation fault This seems like something typically done when kickstarting a new system using e.g. fai [1]. - Werner [1] http://www.informatik.uni-koeln.de/fai/ -- To UNSUBSCRIBE, email to [EMAIL PROTECTED] with a subject of unsubscribe. Trouble? Contact [EMAIL PROTECTED]
Bug#448139: cfagent crashes with a segmentation fault when 31+ arguments are supplied
Morten Werner Forsbring wrote: Mark Burgess [EMAIL PROTECTED] writes: Pardon me for saying so, but one recalls the story of the patient visiting the doctor: Doctor, doctor, it hurts when I do this. To which the answer is Then don't do that! I don't agree with your comparison here, but ok. In my opinion a program shouldn't _segfault_ just if it's called with more than 31 arguments. This is probably true, but the case cited in the mail is not a limitation of cfengine but the argument getopt code in the operating system concerned. It is normal that Unix limits to 31 args, and internally cfengine does the same for consistency. The conclusion is that, while I agree there should be no segfault, I am not sure what I can do about it, since there is no code in cfengine that lead to this fault. As you see: (gdb) run -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a Starting program: /home/mark/LapTop/GNU-cfengine/trunk/src/cfagent -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a Failed to read a valid object file image from memory. [Thread debugging using libthread_db enabled] [New Thread -1212573488 (LWP 12444)] Program received signal SIGSEGV, Segmentation fault. [Switching to Thread -1212573488 (LWP 12444)] 0xb7c77b34 in _getopt_internal_r () from /lib/libc.so.6 (gdb) back #0 0xb7c77b34 in _getopt_internal_r () from /lib/libc.so.6 #1 0xb7c78721 in _getopt_internal () from /lib/libc.so.6 #2 0xb7c788d1 in getopt_long () from /lib/libc.so.6 #3 0x0804b4cf in CheckOpts (argc=32, argv=0xbf9926f0) at cfagent.c:1693 #4 0x0804ec3b in Initialize (argc=32, argv=0xbf9928a4) at cfagent.c:379 #5 0x0804edad in main (argc=Cannot access memory at address 0x1f -- To UNSUBSCRIBE, email to [EMAIL PROTECTED] with a subject of unsubscribe. Trouble? Contact [EMAIL PROTECTED]
Bug#448139: cfagent crashes with a segmentation fault when 31+ arguments are supplied
tags 448139 upstream thanks Hi, here is a bugreport from one of our Debian users. I've confirmed this bug on cfengine version 2.2.2. - Werner Cyril Bouthors [EMAIL PROTECTED] writes: Package: cfengine2 Version: 2.1.22-2 Severity: critical cfagent crashes with a segmentation fault when 31+ arguments are supplied It can easily be reproduced with: $ cfagent -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a Segmentation fault $ The typical use case of 31+ arguments is with multiple -Dfoo arguments, like: $ cfagent --no-lock -x -H -Dmyfai_munin_node -Dmyfai_eth0 -Dmyfai_libnssdb_passwd -Dmyfai_libnssdb_shadow -Dmyfai_resolv_conf -Dmyfai_etc_hosts -Dmyfai_lilo -Dmyfai_firewall_web -Dmyfai_apt_preferences -Dmyfai_apt_list_changes -Dmyfai_apt_sources_list -Dmyfai_forward_root_emails -Dmyfai_exim_smarthost -Dmyfai_cyb_dotfiles -Dmyfai_ssh_key_root -Dmyfai_apt_cache_limit -Dmyfai_init_d_oshosting_nfs_mounts -Dmyfai_init_d_oshosting_links -Dmyfai_init_d_oshosting_update_config_web -Dmyfai_init_d_oshosting_update_nssdb_passwd -Dmyfai_init_d_oshosting_update_nssdb_shadow -Dmyfai_nfsmount_sessions -Dmyfai_nfsmount_myfai -Dmyfai_enable_rsyncd -Dmyfai_oshosting_nfs_mounts -Dmyfai_web_suexec_romain -Dmyfai_web_oshosting_phpkill -Dmyfai_bind9_forwarders -Dmyfai_static_route_to_mail_by_lbgw -Dmyfai_static_route_to_ns_by_lbgw -Dmyfai_enable_spamd -Dmyfai_spamd_flock -Dmyfai_spamd_disable_bayes -Dmyfai_spamd_enable_network -Dmyfai_cron_d_myfai_ntp -f /usr/local/myfai/etc/cfengine/generic.conf Segmentation fault $ I'm almost sure that this command used to be working on previous versions of cfengine. -- To UNSUBSCRIBE, email to [EMAIL PROTECTED] with a subject of unsubscribe. Trouble? Contact [EMAIL PROTECTED]