CVSROOT: /cvs/cluster
Module name: cluster
Changes by: [EMAIL PROTECTED] 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;
}