aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/block
diff options
context:
space:
mode:
authorAlex Elder <elder@dreamhost.com>2012-02-02 09:13:30 -0500
committerAlex Elder <elder@dreamhost.com>2012-03-22 11:47:49 -0400
commite28fff268e7d40ea7a936478c97ce41b6c22815f (patch)
treebf228f2fa056b5fcbe41c06b07f960cf8a0cc757 /drivers/block
parenta725f65e52de73defb3c7033c471c48c56ca6cdd (diff)
rbd: don't use sscanf() in rbd_add_parse_args()
Make use of a few simple helper routines to parse the arguments rather than sscanf(). This will treat both missing and too-long arguments as invalid input (rather than silently truncating the input in the too-long case). In time this can also be used by rbd_add() to use the passed-in buffer in place, rather than copying its contents into new buffers. It appears to me that the sscanf() previously used would not correctly handle a supplied snapshot--the two final "%s" conversion specifications were not separated by a space, and I'm not sure how sscanf() handles that situation. It may not be well-defined. So that may be a bug this change fixes (but I didn't verify that). The sizes of the mon_addrs and options buffers are now passed to rbd_add_parse_args(), so they can be supplied to copy_token(). Signed-off-by: Alex Elder <elder@dreamhost.com>
Diffstat (limited to 'drivers/block')
-rw-r--r--drivers/block/rbd.c99
1 files changed, 85 insertions, 14 deletions
diff --git a/drivers/block/rbd.c b/drivers/block/rbd.c
index caafe1d87a4b..085df6765d21 100644
--- a/drivers/block/rbd.c
+++ b/drivers/block/rbd.c
@@ -2221,6 +2221,53 @@ static void rbd_id_put(struct rbd_device *rbd_dev)
2221} 2221}
2222 2222
2223/* 2223/*
2224 * Skips over white space at *buf, and updates *buf to point to the
2225 * first found non-space character (if any). Returns the length of
2226 * the token (string of non-white space characters) found.
2227 */
2228static inline size_t next_token(const char **buf)
2229{
2230 /*
2231 * These are the characters that produce nonzero for
2232 * isspace() in the "C" and "POSIX" locales.
2233 */
2234 const char *spaces = " \f\n\r\t\v";
2235
2236 *buf += strspn(*buf, spaces); /* Find start of token */
2237
2238 return strcspn(*buf, spaces); /* Return token length */
2239}
2240
2241/*
2242 * Finds the next token in *buf, and if the provided token buffer is
2243 * big enough, copies the found token into it. The result, if
2244 * copied, is guaranteed to be terminated with '\0'.
2245 *
2246 * Returns the length of the token found (not including the '\0').
2247 * Return value will be 0 if no token is found, and it will be >=
2248 * token_size if the token would not fit.
2249 *
2250 * The *buf pointer will be updated point beyond the end of the
2251 * found token. Note that this occurs even if the token buffer is
2252 * too small to hold it.
2253 */
2254static inline size_t copy_token(const char **buf,
2255 char *token,
2256 size_t token_size)
2257{
2258 size_t len;
2259
2260 len = next_token(buf);
2261 if (len < token_size) {
2262 memcpy(token, *buf, len);
2263 *(token + len) = '\0';
2264 }
2265 *buf += len;
2266
2267 return len;
2268}
2269
2270/*
2224 * This fills in the pool_name, obj, obj_len, snap_name, obj_len, 2271 * This fills in the pool_name, obj, obj_len, snap_name, obj_len,
2225 * rbd_dev, rbd_md_name, and name fields of the given rbd_dev, based 2272 * rbd_dev, rbd_md_name, and name fields of the given rbd_dev, based
2226 * on the list of monitor addresses and other options provided via 2273 * on the list of monitor addresses and other options provided via
@@ -2229,25 +2276,48 @@ static void rbd_id_put(struct rbd_device *rbd_dev)
2229static int rbd_add_parse_args(struct rbd_device *rbd_dev, 2276static int rbd_add_parse_args(struct rbd_device *rbd_dev,
2230 const char *buf, 2277 const char *buf,
2231 char *mon_addrs, 2278 char *mon_addrs,
2232 char *options) 2279 size_t mon_addrs_size,
2233{ 2280 char *options,
2234 if (sscanf(buf, "%" __stringify(RBD_MAX_OPT_LEN) "s " 2281 size_t options_size)
2235 "%" __stringify(RBD_MAX_OPT_LEN) "s " 2282{
2236 "%" __stringify(RBD_MAX_POOL_NAME_LEN) "s " 2283 size_t len;
2237 "%" __stringify(RBD_MAX_OBJ_NAME_LEN) "s" 2284
2238 "%" __stringify(RBD_MAX_SNAP_NAME_LEN) "s", 2285 /* The first four tokens are required */
2239 mon_addrs, options, rbd_dev->pool_name, 2286
2240 rbd_dev->obj, rbd_dev->snap_name) < 4) 2287 len = copy_token(&buf, mon_addrs, mon_addrs_size);
2288 if (!len || len >= mon_addrs_size)
2241 return -EINVAL; 2289 return -EINVAL;
2242 2290
2243 if (rbd_dev->snap_name[0] == 0) 2291 len = copy_token(&buf, options, options_size);
2244 memcpy(rbd_dev->snap_name, RBD_SNAP_HEAD_NAME, 2292 if (!len || len >= options_size)
2245 sizeof (RBD_SNAP_HEAD_NAME)); 2293 return -EINVAL;
2294
2295 len = copy_token(&buf, rbd_dev->pool_name, sizeof (rbd_dev->pool_name));
2296 if (!len || len >= sizeof (rbd_dev->pool_name))
2297 return -EINVAL;
2298
2299 len = copy_token(&buf, rbd_dev->obj, sizeof (rbd_dev->obj));
2300 if (!len || len >= sizeof (rbd_dev->obj))
2301 return -EINVAL;
2302
2303 /* We have the object length in hand, save it. */
2304
2305 rbd_dev->obj_len = len;
2246 2306
2247 rbd_dev->obj_len = strlen(rbd_dev->obj);
2248 snprintf(rbd_dev->obj_md_name, sizeof(rbd_dev->obj_md_name), "%s%s", 2307 snprintf(rbd_dev->obj_md_name, sizeof(rbd_dev->obj_md_name), "%s%s",
2249 rbd_dev->obj, RBD_SUFFIX); 2308 rbd_dev->obj, RBD_SUFFIX);
2250 2309
2310 /*
2311 * The snapshot name is optional, but it's an error if it's
2312 * too long. If no snapshot is supplied, fill in the default.
2313 */
2314 len = copy_token(&buf, rbd_dev->snap_name, sizeof (rbd_dev->snap_name));
2315 if (!len)
2316 memcpy(rbd_dev->snap_name, RBD_SNAP_HEAD_NAME,
2317 sizeof (RBD_SNAP_HEAD_NAME));
2318 else if (len >= sizeof (rbd_dev->snap_name))
2319 return -EINVAL;
2320
2251 return 0; 2321 return 0;
2252} 2322}
2253 2323
@@ -2288,7 +2358,8 @@ static ssize_t rbd_add(struct bus_type *bus,
2288 snprintf(rbd_dev->name, DEV_NAME_LEN, RBD_DRV_NAME "%d", rbd_dev->id); 2358 snprintf(rbd_dev->name, DEV_NAME_LEN, RBD_DRV_NAME "%d", rbd_dev->id);
2289 2359
2290 /* parse add command */ 2360 /* parse add command */
2291 rc = rbd_add_parse_args(rbd_dev, buf, mon_addrs, options); 2361 rc = rbd_add_parse_args(rbd_dev, buf, mon_addrs, count,
2362 options, count);
2292 if (rc) 2363 if (rc)
2293 goto err_put_id; 2364 goto err_put_id;
2294 2365