From mboxrd@z Thu Jan 1 00:00:00 1970 From: rmccabe@sourceware.org Date: 24 Oct 2007 05:55:07 -0000 Subject: [Cluster-devel] cluster/cman/daemon cmanccs.c Message-ID: <20071024055507.413.qmail@sourceware.org> List-Id: To: cluster-devel.redhat.com MIME-Version: 1.0 Content-Type: text/plain; charset="us-ascii" Content-Transfer-Encoding: 7bit CVSROOT: /cvs/cluster Module name: cluster Changes by: rmccabe at sourceware.org 2007-10-24 05:55:07 Modified files: cman/daemon : cmanccs.c Log message: - Fix unsafe string handling: - replace memset(s,c,n);sprintf(s,...); with snprintf with proper error checking - don't overflow the stack if the cluster name specified in the env var is too long - don't overflow the stack if the local nodename from uname(2) is too long - don't overflow the stack if the local nodename specified in the env var is too long - Don't leak the ccs descriptor in get_ccs_join_info() on errors Patches: http://sourceware.org/cgi-bin/cvsweb.cgi/cluster/cman/daemon/cmanccs.c.diff?cvsroot=cluster&r1=1.34&r2=1.35 --- cluster/cman/daemon/cmanccs.c 2007/10/24 03:21:45 1.34 +++ cluster/cman/daemon/cmanccs.c 2007/10/24 05:55:07 1.35 @@ -1,7 +1,7 @@ /****************************************************************************** ******************************************************************************* ** -** Copyright (C) 2005-2006 Red Hat, Inc. All rights reserved. +** Copyright (C) 2005-2007 Red Hat, Inc. All rights reserved. ** ** This copyrighted material is made available to anyone wishing to use, ** modify, copy, or redistribute it subject to the terms and conditions @@ -125,49 +125,60 @@ if (!ccs_get(ctree, TWO_NODE_PATH, &str)) { two_node = atoi(str); free(str); - } - else - two_node = 0; + } else + two_node = 0; for (i=1;;i++) { - char path[MAX_PATH_LEN]; - int votes=0, nodeid=0; + char path[MAX_PATH_LEN]; + int votes=0, nodeid=0; + int ret; + + ret = snprintf(path, sizeof(path), NODE_NAME_PATH_BYNUM, i); + if (ret < 0 || (size_t) ret >= sizeof(path)) + return -E2BIG; - memset(path, 0, MAX_PATH_LEN); - sprintf(path, NODE_NAME_PATH_BYNUM, i); - error = ccs_get(ctree, path, &nodename); - if (error) - break; + error = ccs_get(ctree, path, &nodename); + if (error) + break; - memset(path, 0, MAX_PATH_LEN); - sprintf(path, NODE_VOTES_PATH, nodename); - if (!ccs_get(ctree, path, &str)) { - votes = atoi(str); - free(str); - } else - votes = 1; + ret = snprintf(path, sizeof(path), NODE_VOTES_PATH, nodename); + if (ret < 0 || ret >= sizeof(path)) { + error = -E2BIG; + goto out_err; + } - memset(path, 0, MAX_PATH_LEN); - sprintf(path, NODE_NODEID_PATH, nodename); - if (!ccs_get(ctree, path, &str)) { - nodeid = atoi(str); - free(str); + if (!ccs_get(ctree, path, &str)) { + votes = atoi(str); + free(str); + } else + votes = 1; - } + ret = snprintf(path, sizeof(path), NODE_NODEID_PATH, nodename); + if (ret < 0 || (size_t) ret >= sizeof(path)) { + error = -E2BIG; + goto out_err; + } - if (check_nodeids && nodeid == 0) { - char message[132]; + if (!ccs_get(ctree, path, &str)) { + nodeid = atoi(str); + free(str); + } - sprintf(message, "No node ID for %s, run 'ccs_tool addnodeids' to fix", nodename); - log_printf(LOG_ERR, message); - write_cman_pipe(message); - return -1; - } + if (check_nodeids && nodeid == 0) { + char message[132]; - P_MEMB("Got node %s from ccs (id=%d, votes=%d)\n", nodename, nodeid, votes); - add_ccs_node(nodename, nodeid, votes, expected); + snprintf(message, sizeof(message), + "No node ID for %s, run 'ccs_tool addnodeids' to fix", + nodename); + log_printf(LOG_ERR, message); + write_cman_pipe(message); + error = -EINVAL; + goto out_err; + } - free(nodename); + P_MEMB("Got node %s from ccs (id=%d, votes=%d)\n", nodename, nodeid, votes); + add_ccs_node(nodename, nodeid, votes, expected); + free(nodename); } if (expected) @@ -177,6 +188,11 @@ ccs_disconnect(ctree); return 0; + +out_err: + free(nodename); + ccs_disconnect(ctree); + return error; } static char *default_mcast(uint16_t cluster_id) @@ -260,11 +276,14 @@ struct ifaddrs *ifa, *ifa_list; struct sockaddr *sa; int error, i; + int ret; /* nodename is either from commandline or from uname */ str = NULL; - memset(path, 0, MAX_PATH_LEN); - sprintf(path, NODE_NAME_PATH_BYNAME, nodename); + + ret = snprintf(path, sizeof(path), NODE_NAME_PATH_BYNAME, nodename); + if (ret < 0 || (size_t) ret >= sizeof(path)) + return -E2BIG; error = ccs_get(cd, path, &str); if (!error) { @@ -274,13 +293,14 @@ /* If nodename was from uname, try a domain-less version of it */ strcpy(nodename2, nodename); - dot = strstr(nodename2, "."); + dot = strchr(nodename2, '.'); if (dot) { *dot = '\0'; str = NULL; - memset(path, 0, MAX_PATH_LEN); - sprintf(path, NODE_NAME_PATH_BYNAME, nodename2); + ret = snprintf(path, sizeof(path), NODE_NAME_PATH_BYNAME, nodename2); + if (ret < 0 || (size_t) ret >= sizeof(path)) + return -E2BIG; error = ccs_get(cd, path, &str); if (!error) { @@ -290,21 +310,25 @@ } } - /* If nodename (from uname) is domain-less, try to match against cluster.conf names which may have domainname specified */ for (i = 1; ; i++) { int len; + str = NULL; - memset(path, 0, 256); - sprintf(path, "/cluster/clusternodes/clusternode[%d]/@name", i); + ret = snprintf(path, sizeof(path), + "/cluster/clusternodes/clusternode[%d]/@name", i); + if (ret < 0 || (size_t) ret >= sizeof(path)) { + error = -E2BIG; + break; + } error = ccs_get(cd, path, &str); if (error || !str) break; strcpy(nodename3, str); - dot = strstr(nodename3, "."); + dot = strchr(nodename3, '.'); if (dot) len = dot-nodename3; else @@ -328,7 +352,6 @@ return -1; for (ifa = ifa_list; ifa; ifa = ifa->ifa_next) { - /* Restore this */ strcpy(nodename2, nodename); sa = ifa->ifa_addr; @@ -341,8 +364,11 @@ goto out; str = NULL; - memset(path, 0, 256); - sprintf(path, NODE_NAME_PATH_BYNAME, nodename2); + ret = snprintf(path, sizeof(path), NODE_NAME_PATH_BYNAME, nodename2); + if (ret < 0 || (size_t) ret >= sizeof(path)) { + error = -E2BIG; + goto out; + } error = ccs_get(cd, path, &str); if (!error) { @@ -353,14 +379,17 @@ /* truncate this name and try again */ - dot = strstr(nodename2, "."); + dot = strchr(nodename2, '.'); if (!dot) continue; *dot = '\0'; str = NULL; - memset(path, 0, 256); - sprintf(path, NODE_NAME_PATH_BYNAME, nodename2); + ret = snprintf(path, sizeof(path), NODE_NAME_PATH_BYNAME, nodename2); + if (ret < 0 || (size_t) ret >= sizeof(path)) { + error = -E2BIG; + goto out; + } error = ccs_get(cd, path, &str); if (!error) { @@ -376,8 +405,11 @@ goto out; str = NULL; - memset(path, 0, 256); - sprintf(path, NODE_NAME_PATH_BYNAME, nodename2); + ret = snprintf(path, sizeof(path), NODE_NAME_PATH_BYNAME, nodename2); + if (ret < 0 || (size_t) ret >= sizeof(path)) { + error = -E2BIG; + goto out; + } error = ccs_get(cd, path, &str); if (!error) { @@ -398,7 +430,7 @@ { char path[MAX_PATH_LEN]; char nodename[MAX_CLUSTER_MEMBER_NAME_LEN+1]; - char *str, *name, *cname = NULL; + char *str, *name, *cname = NULL, *nodename_env; int cd, error, i, vote_sum = 0, node_count = 0; unsigned short port = 0; @@ -420,17 +452,26 @@ if (error) { log_printf(LOG_ERR, "cannot find cluster name in config file"); write_cman_pipe("Can't find cluster name in CCS"); - return -ENOENT; + error = -ENOENT; + goto out; } if (cname) { if (strcmp(cname, str)) { log_printf(LOG_ERR, "cluster names not equal %s %s", cname, str); write_cman_pipe("Cluster name in CCS does not match that passed to cman_tool"); - return -ENOENT; + error = -ENOENT; + goto out; } } + if (strlen(str) >= sizeof(cluster_name)) { + free(str); + write_cman_pipe("Cluster name in CCS is too long"); + error = -E2BIG; + goto out; + } + strcpy(cluster_name, str); free(str); @@ -444,32 +485,55 @@ } /* our nodename */ - memset(nodename, 0, sizeof(nodename)); + nodename_env = getenv("CMAN_NODENAME"); + if (nodename_env != NULL) { + int ret; + + if (strlen(nodename_env) >= sizeof(nodename)) { + log_printf(LOG_ERR, "Overridden node name %s is too long", nodename); + write_cman_pipe("Overridden node name is too long"); + error = -E2BIG; + goto out; + } - if (getenv("CMAN_NODENAME")) { - strcpy(nodename, getenv("CMAN_NODENAME")); + strcpy(nodename, nodename_env); log_printf(LOG_INFO, "Using override node name %s\n", nodename); - sprintf(path, NODE_NAME_PATH_BYNAME, nodename); + ret = snprintf(path, sizeof(path), NODE_NAME_PATH_BYNAME, nodename); + if (ret < 0 || (size_t) ret >= sizeof(path)) { + log_printf(LOG_ERR, "Overridden node name %s is too long", nodename); + write_cman_pipe("Overridden node name is too long"); + error = -E2BIG; + goto out; + } error = ccs_get(cd, path, &str); if (!error) { free(str); - } - else { + } else { log_printf(LOG_ERR, "Overridden node name %s is not in CCS", nodename); write_cman_pipe("Overridden node name is not in CCS"); - return -ENOENT; + error = -ENOENT; + goto out; } - } - else { + } else { struct utsname utsname; + error = uname(&utsname); if (error) { log_printf(LOG_ERR, "cannot get node name, uname failed"); write_cman_pipe("Can't determine local node name"); - return -ENOENT; + error = -ENOENT; + goto out; + } + + if (strlen(utsname.nodename) >= sizeof(nodename)) { + log_printf(LOG_ERR, "node name from uname is too long"); + write_cman_pipe("Can't determine local node name"); + error = -E2BIG; + goto out; } + strcpy(nodename, utsname.nodename); } @@ -480,9 +544,15 @@ log_printf(LOG_ERR, "local node name \"%s\" not found in cluster.conf", nodename); write_cman_pipe("Can't find local node name in cluster.conf"); - return -ENOENT; + error = -ENOENT; + goto out; } + nodenames[0] = strdup(nodename); + if (nodenames[0] == NULL) { + error = -ENOMEM; + goto out; + } expected_votes = 0; if (getenv("CMAN_EXPECTEDVOTES")) { @@ -499,9 +569,14 @@ /* Sum node votes for expected */ if (expected_votes == 0) { for (i = 1; ; i++) { + int ret; + name = NULL; - memset(path, 0, MAX_PATH_LEN); - sprintf(path, NODE_NAME_PATH_BYNUM, i); + ret = snprintf(path, sizeof(path), NODE_NAME_PATH_BYNUM, i); + if (ret < 0 || (size_t) ret >= sizeof(path)) { + error = -E2BIG; + break; + } error = ccs_get(cd, path, &name); if (error || !name) @@ -509,10 +584,14 @@ node_count++; - memset(path, 0, MAX_PATH_LEN); - sprintf(path, NODE_VOTES_PATH, name); + ret = snprintf(path, sizeof(path), NODE_VOTES_PATH, name); free(name); + if (ret < 0 || (size_t) ret >= sizeof(path)) { + error = -E2BIG; + break; + } + error = ccs_get(cd, path, &str); if (error) vote_sum++; @@ -520,7 +599,8 @@ if (atoi(str) < 0) { log_printf(LOG_ERR, "negative votes not allowed"); write_cman_pipe("Found negative votes for this node in CCS"); - return -EINVAL; + error = -EINVAL; + goto out; } vote_sum += atoi(str); free(str); @@ -572,8 +652,12 @@ } if (!votes) { - memset(path, 0, MAX_PATH_LEN); - sprintf(path, NODE_VOTES_PATH, nodename); + int ret = snprintf(path, sizeof(path), NODE_VOTES_PATH, nodename); + if (ret < 0 || (size_t) ret >= sizeof(path)) { + log_printf(LOG_ERR, "unable to find votes for %s", nodename); + write_cman_pipe("Unable to find votes for node in CCS"); + return -E2BIG; + } error = ccs_get(cd, path, &str); if (!error) { @@ -599,13 +683,14 @@ } if (!nodeid) { - memset(path, 0, MAX_PATH_LEN); - sprintf(path, NODE_NODEID_PATH, nodename); + int ret = snprintf(path, sizeof(path), NODE_NODEID_PATH, nodename); - error = ccs_get(cd, path, &str); - if (!error) { - nodeid = atoi(str); - free(str); + if (ret >= 0 && (size_t) ret < sizeof(path)) { + error = ccs_get(cd, path, &str); + if (!error) { + nodeid = atoi(str); + free(str); + } } } @@ -638,35 +723,44 @@ /* Get all alternative node names */ num_nodenames = 1; - memset(path, 0, MAX_PATH_LEN); - - for (i = 1; ; i++) { - str = NULL; - sprintf(path, NODE_ALTNAMES_PATH, nodename, i); + int ret = snprintf(path, sizeof(path), NODE_ALTNAMES_PATH, nodename, i); + if (ret < 0 || (size_t) ret >= sizeof(path)) { + error = -E2BIG; + break; + } + str = NULL; error = ccs_get(cd, path, &str); if (error || !str) break; nodenames[i] = str; - sprintf(path, NODE_ALTNAMES_PORT, nodename, i); + ret = snprintf(path, sizeof(path), NODE_ALTNAMES_PORT, nodename, i); + if (ret < 0 || (size_t) ret >= sizeof(path)) { + error = -E2BIG; + break; + } + error = ccs_get(cd, path, &str); if (error || !str) { portnums[i] = portnums[0]; - } - else { + } else { portnums[i] = atoi(str); free(str); } - sprintf(path, NODE_ALTNAMES_MCAST, nodename, i); + ret = snprintf(path, sizeof(path), NODE_ALTNAMES_MCAST, nodename, i); + if (ret < 0 || (size_t) ret >= sizeof(path)) { + error = -E2BIG; + break; + } + error = ccs_get(cd, path, &str); if (error || !str) { mcast[i] = mcast_name; - } - else { + } else { mcast[i] = str; } @@ -686,7 +780,8 @@ "votes of 1 (node_count=%d vote_sum=%d)", node_count, vote_sum); write_cman_pipe("two_node set but there are more than 2 nodes"); - return -EINVAL; + error = -EINVAL; + goto out; } if (votes != 1) { @@ -694,13 +789,17 @@ "nodes with one vote each and expected " "votes of 1 (votes=%d)", votes); write_cman_pipe("two_node set but votes not set to 1"); - return -EINVAL; + error = -EINVAL; + goto out; } } } + error = 0; + +out: ccs_disconnect(cd); - return 0; + return error; }