aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/block/drbd/drbd_nl.c
diff options
context:
space:
mode:
authorAndreas Gruenbacher <agruen@linbit.com>2011-06-09 11:52:12 -0400
committerPhilipp Reisner <philipp.reisner@linbit.com>2012-11-08 10:57:45 -0500
commit7c3063cc6f0e75cdf312f5f318f9a4c02e460397 (patch)
treeed54e6066aed1994577e20fc6d635d856627cbab /drivers/block/drbd/drbd_nl.c
parent789c1b626cb490acb36cf481b45040b324f60fde (diff)
drbd: Also need to check for DRBD_GENLA_F_MANDATORY flags before nla_find_nested()
This is done by introducing drbd_nla_find_nested() which handles the flag before calling nla_find_nested(). Signed-off-by: Philipp Reisner <philipp.reisner@linbit.com> Signed-off-by: Lars Ellenberg <lars.ellenberg@linbit.com>
Diffstat (limited to 'drivers/block/drbd/drbd_nl.c')
-rw-r--r--drivers/block/drbd/drbd_nl.c96
1 files changed, 76 insertions, 20 deletions
diff --git a/drivers/block/drbd/drbd_nl.c b/drivers/block/drbd/drbd_nl.c
index 5b4090f52f5a..24187f1c93d5 100644
--- a/drivers/block/drbd/drbd_nl.c
+++ b/drivers/block/drbd/drbd_nl.c
@@ -92,7 +92,7 @@ static struct drbd_config_context {
92#define VOLUME_UNSPECIFIED (-1U) 92#define VOLUME_UNSPECIFIED (-1U)
93 /* pointer into the request skb, 93 /* pointer into the request skb,
94 * limited lifetime! */ 94 * limited lifetime! */
95 char *conn_name; 95 char *resource_name;
96 96
97 /* reply buffer */ 97 /* reply buffer */
98 struct sk_buff *reply_skb; 98 struct sk_buff *reply_skb;
@@ -191,15 +191,15 @@ static int drbd_adm_prepare(struct sk_buff *skb, struct genl_info *info,
191 /* and assign stuff to the global adm_ctx */ 191 /* and assign stuff to the global adm_ctx */
192 nla = nested_attr_tb[__nla_type(T_ctx_volume)]; 192 nla = nested_attr_tb[__nla_type(T_ctx_volume)];
193 adm_ctx.volume = nla ? nla_get_u32(nla) : VOLUME_UNSPECIFIED; 193 adm_ctx.volume = nla ? nla_get_u32(nla) : VOLUME_UNSPECIFIED;
194 nla = nested_attr_tb[__nla_type(T_ctx_conn_name)]; 194 nla = nested_attr_tb[__nla_type(T_ctx_resource_name)];
195 if (nla) 195 if (nla)
196 adm_ctx.conn_name = nla_data(nla); 196 adm_ctx.resource_name = nla_data(nla);
197 } else 197 } else
198 adm_ctx.volume = VOLUME_UNSPECIFIED; 198 adm_ctx.volume = VOLUME_UNSPECIFIED;
199 199
200 adm_ctx.minor = d_in->minor; 200 adm_ctx.minor = d_in->minor;
201 adm_ctx.mdev = minor_to_mdev(d_in->minor); 201 adm_ctx.mdev = minor_to_mdev(d_in->minor);
202 adm_ctx.tconn = conn_get_by_name(adm_ctx.conn_name); 202 adm_ctx.tconn = conn_get_by_name(adm_ctx.resource_name);
203 203
204 if (!adm_ctx.mdev && (flags & DRBD_ADM_NEED_MINOR)) { 204 if (!adm_ctx.mdev && (flags & DRBD_ADM_NEED_MINOR)) {
205 drbd_msg_put_info("unknown minor"); 205 drbd_msg_put_info("unknown minor");
@@ -214,7 +214,8 @@ static int drbd_adm_prepare(struct sk_buff *skb, struct genl_info *info,
214 if (adm_ctx.mdev && adm_ctx.tconn && 214 if (adm_ctx.mdev && adm_ctx.tconn &&
215 adm_ctx.mdev->tconn != adm_ctx.tconn) { 215 adm_ctx.mdev->tconn != adm_ctx.tconn) {
216 pr_warning("request: minor=%u, conn=%s; but that minor belongs to connection %s\n", 216 pr_warning("request: minor=%u, conn=%s; but that minor belongs to connection %s\n",
217 adm_ctx.minor, adm_ctx.conn_name, adm_ctx.mdev->tconn->name); 217 adm_ctx.minor, adm_ctx.resource_name,
218 adm_ctx.mdev->tconn->name);
218 drbd_msg_put_info("minor exists in different connection"); 219 drbd_msg_put_info("minor exists in different connection");
219 return ERR_INVALID_REQUEST; 220 return ERR_INVALID_REQUEST;
220 } 221 }
@@ -239,7 +240,7 @@ fail:
239static int drbd_adm_finish(struct genl_info *info, int retcode) 240static int drbd_adm_finish(struct genl_info *info, int retcode)
240{ 241{
241 struct nlattr *nla; 242 struct nlattr *nla;
242 const char *conn_name = NULL; 243 const char *resource_name = NULL;
243 244
244 if (adm_ctx.tconn) { 245 if (adm_ctx.tconn) {
245 kref_put(&adm_ctx.tconn->kref, &conn_destroy); 246 kref_put(&adm_ctx.tconn->kref, &conn_destroy);
@@ -253,9 +254,10 @@ static int drbd_adm_finish(struct genl_info *info, int retcode)
253 254
254 nla = info->attrs[DRBD_NLA_CFG_CONTEXT]; 255 nla = info->attrs[DRBD_NLA_CFG_CONTEXT];
255 if (nla) { 256 if (nla) {
256 nla = nla_find_nested(nla, __nla_type(T_ctx_conn_name)); 257 int maxtype = ARRAY_SIZE(drbd_cfg_context_nl_policy) - 1;
257 if (nla) 258 nla = drbd_nla_find_nested(maxtype, nla, __nla_type(T_ctx_resource_name));
258 conn_name = nla_data(nla); 259 if (nla && !IS_ERR(nla))
260 resource_name = nla_data(nla);
259 } 261 }
260 262
261 drbd_adm_send_reply(adm_ctx.reply_skb, info); 263 drbd_adm_send_reply(adm_ctx.reply_skb, info);
@@ -2526,7 +2528,7 @@ int drbd_adm_outdate(struct sk_buff *skb, struct genl_info *info)
2526 return drbd_adm_simple_request_state(skb, info, NS(disk, D_OUTDATED)); 2528 return drbd_adm_simple_request_state(skb, info, NS(disk, D_OUTDATED));
2527} 2529}
2528 2530
2529int nla_put_drbd_cfg_context(struct sk_buff *skb, const char *conn_name, unsigned vnr) 2531int nla_put_drbd_cfg_context(struct sk_buff *skb, const char *resource_name, unsigned vnr)
2530{ 2532{
2531 struct nlattr *nla; 2533 struct nlattr *nla;
2532 nla = nla_nest_start(skb, DRBD_NLA_CFG_CONTEXT); 2534 nla = nla_nest_start(skb, DRBD_NLA_CFG_CONTEXT);
@@ -2534,7 +2536,7 @@ int nla_put_drbd_cfg_context(struct sk_buff *skb, const char *conn_name, unsigne
2534 goto nla_put_failure; 2536 goto nla_put_failure;
2535 if (vnr != VOLUME_UNSPECIFIED) 2537 if (vnr != VOLUME_UNSPECIFIED)
2536 NLA_PUT_U32(skb, T_ctx_volume, vnr); 2538 NLA_PUT_U32(skb, T_ctx_volume, vnr);
2537 NLA_PUT_STRING(skb, T_ctx_conn_name, conn_name); 2539 NLA_PUT_STRING(skb, T_ctx_resource_name, resource_name);
2538 nla_nest_end(skb, nla); 2540 nla_nest_end(skb, nla);
2539 return 0; 2541 return 0;
2540 2542
@@ -2778,8 +2780,9 @@ int drbd_adm_get_status_all(struct sk_buff *skb, struct netlink_callback *cb)
2778{ 2780{
2779 const unsigned hdrlen = GENL_HDRLEN + GENL_MAGIC_FAMILY_HDRSZ; 2781 const unsigned hdrlen = GENL_HDRLEN + GENL_MAGIC_FAMILY_HDRSZ;
2780 struct nlattr *nla; 2782 struct nlattr *nla;
2781 const char *conn_name; 2783 const char *resource_name;
2782 struct drbd_tconn *tconn; 2784 struct drbd_tconn *tconn;
2785 int maxtype;
2783 2786
2784 /* Is this a followup call? */ 2787 /* Is this a followup call? */
2785 if (cb->args[0]) { 2788 if (cb->args[0]) {
@@ -2799,12 +2802,15 @@ int drbd_adm_get_status_all(struct sk_buff *skb, struct netlink_callback *cb)
2799 /* No explicit context given. Dump all. */ 2802 /* No explicit context given. Dump all. */
2800 if (!nla) 2803 if (!nla)
2801 goto dump; 2804 goto dump;
2802 nla = nla_find_nested(nla, __nla_type(T_ctx_conn_name)); 2805 maxtype = ARRAY_SIZE(drbd_cfg_context_nl_policy) - 1;
2806 nla = drbd_nla_find_nested(maxtype, nla, __nla_type(T_ctx_resource_name));
2807 if (IS_ERR(nla))
2808 return PTR_ERR(nla);
2803 /* context given, but no name present? */ 2809 /* context given, but no name present? */
2804 if (!nla) 2810 if (!nla)
2805 return -EINVAL; 2811 return -EINVAL;
2806 conn_name = nla_data(nla); 2812 resource_name = nla_data(nla);
2807 tconn = conn_get_by_name(conn_name); 2813 tconn = conn_get_by_name(resource_name);
2808 2814
2809 if (!tconn) 2815 if (!tconn)
2810 return -ENODEV; 2816 return -ENODEV;
@@ -2957,16 +2963,16 @@ out_nolock:
2957} 2963}
2958 2964
2959static enum drbd_ret_code 2965static enum drbd_ret_code
2960drbd_check_conn_name(const char *name) 2966drbd_check_resource_name(const char *name)
2961{ 2967{
2962 if (!name || !name[0]) { 2968 if (!name || !name[0]) {
2963 drbd_msg_put_info("connection name missing"); 2969 drbd_msg_put_info("resource name missing");
2964 return ERR_MANDATORY_TAG; 2970 return ERR_MANDATORY_TAG;
2965 } 2971 }
2966 /* if we want to use these in sysfs/configfs/debugfs some day, 2972 /* if we want to use these in sysfs/configfs/debugfs some day,
2967 * we must not allow slashes */ 2973 * we must not allow slashes */
2968 if (strchr(name, '/')) { 2974 if (strchr(name, '/')) {
2969 drbd_msg_put_info("invalid connection name"); 2975 drbd_msg_put_info("invalid resource name");
2970 return ERR_INVALID_REQUEST; 2976 return ERR_INVALID_REQUEST;
2971 } 2977 }
2972 return NO_ERROR; 2978 return NO_ERROR;
@@ -2982,7 +2988,7 @@ int drbd_adm_new_resource(struct sk_buff *skb, struct genl_info *info)
2982 if (retcode != NO_ERROR) 2988 if (retcode != NO_ERROR)
2983 goto out; 2989 goto out;
2984 2990
2985 retcode = drbd_check_conn_name(adm_ctx.conn_name); 2991 retcode = drbd_check_resource_name(adm_ctx.resource_name);
2986 if (retcode != NO_ERROR) 2992 if (retcode != NO_ERROR)
2987 goto out; 2993 goto out;
2988 2994
@@ -2995,7 +3001,7 @@ int drbd_adm_new_resource(struct sk_buff *skb, struct genl_info *info)
2995 goto out; 3001 goto out;
2996 } 3002 }
2997 3003
2998 if (!conn_create(adm_ctx.conn_name)) 3004 if (!conn_create(adm_ctx.resource_name))
2999 retcode = ERR_NOMEM; 3005 retcode = ERR_NOMEM;
3000out: 3006out:
3001 drbd_adm_finish(info, retcode); 3007 drbd_adm_finish(info, retcode);
@@ -3213,3 +3219,53 @@ failed:
3213 "Event seq:%u sib_reason:%u\n", 3219 "Event seq:%u sib_reason:%u\n",
3214 err, seq, sib->sib_reason); 3220 err, seq, sib->sib_reason);
3215} 3221}
3222
3223int drbd_nla_check_mandatory(int maxtype, struct nlattr *nla)
3224{
3225 struct nlattr *head = nla_data(nla);
3226 int len = nla_len(nla);
3227 int rem;
3228
3229 /*
3230 * validate_nla (called from nla_parse_nested) ignores attributes
3231 * beyond maxtype, and does not understand the DRBD_GENLA_F_MANDATORY flag.
3232 * In order to have it validate attributes with the DRBD_GENLA_F_MANDATORY
3233 * flag set also, check and remove that flag before calling
3234 * nla_parse_nested.
3235 */
3236
3237 nla_for_each_attr(nla, head, len, rem) {
3238 if (nla->nla_type & DRBD_GENLA_F_MANDATORY) {
3239 nla->nla_type &= ~DRBD_GENLA_F_MANDATORY;
3240 if (nla_type(nla) > maxtype)
3241 return -EOPNOTSUPP;
3242 }
3243 }
3244 return 0;
3245}
3246
3247int drbd_nla_parse_nested(struct nlattr *tb[], int maxtype, struct nlattr *nla,
3248 const struct nla_policy *policy)
3249{
3250 int err;
3251
3252 err = drbd_nla_check_mandatory(maxtype, nla);
3253 if (!err)
3254 err = nla_parse_nested(tb, maxtype, nla, policy);
3255
3256 return err;
3257}
3258
3259struct nlattr *drbd_nla_find_nested(int maxtype, struct nlattr *nla, int attrtype)
3260{
3261 int err;
3262 /*
3263 * If any nested attribute has the DRBD_GENLA_F_MANDATORY flag set and
3264 * we don't know about that attribute, reject all the nested
3265 * attributes.
3266 */
3267 err = drbd_nla_check_mandatory(maxtype, nla);
3268 if (err)
3269 return ERR_PTR(err);
3270 return nla_find_nested(nla, attrtype);
3271}