aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJohannes Berg <johannes.berg@intel.com>2013-11-19 09:19:33 -0500
committerDavid S. Miller <davem@davemloft.net>2013-11-19 16:39:05 -0500
commit2ecf7536b2787580616d23b6507005d930975ca0 (patch)
tree050b07aaf96d86a83ed42c34511a3f28e1c0d1d4
parente5dcecba015f9774a402ba559b80b16999747e3b (diff)
quota/genetlink: use proper genetlink multicast APIs
The quota code is abusing the genetlink API and is using its family ID as the multicast group ID, which is invalid and may belong to somebody else (and likely will.) Make the quota code use the correct API, but since this is already used as-is by userspace, reserve a family ID for this code and also reserve that group ID to not break userspace assumptions. Acked-by: Jan Kara <jack@suse.cz> Signed-off-by: Johannes Berg <johannes.berg@intel.com> Signed-off-by: David S. Miller <davem@davemloft.net>
-rw-r--r--fs/quota/netlink.c17
-rw-r--r--include/uapi/linux/genetlink.h1
-rw-r--r--net/netlink/genetlink.c10
3 files changed, 24 insertions, 4 deletions
diff --git a/fs/quota/netlink.c b/fs/quota/netlink.c
index 16e8abb7709b..aa22fe03b76c 100644
--- a/fs/quota/netlink.c
+++ b/fs/quota/netlink.c
@@ -11,13 +11,23 @@
11 11
12/* Netlink family structure for quota */ 12/* Netlink family structure for quota */
13static struct genl_family quota_genl_family = { 13static struct genl_family quota_genl_family = {
14 .id = GENL_ID_GENERATE, 14 /*
15 * Needed due to multicast group ID abuse - old code assumed
16 * the family ID was also a valid multicast group ID (which
17 * isn't true) and userspace might thus rely on it. Assign a
18 * static ID for this group to make dealing with that easier.
19 */
20 .id = GENL_ID_VFS_DQUOT,
15 .hdrsize = 0, 21 .hdrsize = 0,
16 .name = "VFS_DQUOT", 22 .name = "VFS_DQUOT",
17 .version = 1, 23 .version = 1,
18 .maxattr = QUOTA_NL_A_MAX, 24 .maxattr = QUOTA_NL_A_MAX,
19}; 25};
20 26
27static struct genl_multicast_group quota_mcgrp = {
28 .name = "events",
29};
30
21/** 31/**
22 * quota_send_warning - Send warning to userspace about exceeded quota 32 * quota_send_warning - Send warning to userspace about exceeded quota
23 * @type: The quota type: USRQQUOTA, GRPQUOTA,... 33 * @type: The quota type: USRQQUOTA, GRPQUOTA,...
@@ -78,7 +88,7 @@ void quota_send_warning(struct kqid qid, dev_t dev,
78 goto attr_err_out; 88 goto attr_err_out;
79 genlmsg_end(skb, msg_head); 89 genlmsg_end(skb, msg_head);
80 90
81 genlmsg_multicast(skb, 0, quota_genl_family.id, GFP_NOFS); 91 genlmsg_multicast(skb, 0, quota_mcgrp.id, GFP_NOFS);
82 return; 92 return;
83attr_err_out: 93attr_err_out:
84 printk(KERN_ERR "VFS: Not enough space to compose quota message!\n"); 94 printk(KERN_ERR "VFS: Not enough space to compose quota message!\n");
@@ -92,6 +102,9 @@ static int __init quota_init(void)
92 if (genl_register_family(&quota_genl_family) != 0) 102 if (genl_register_family(&quota_genl_family) != 0)
93 printk(KERN_ERR 103 printk(KERN_ERR
94 "VFS: Failed to create quota netlink interface.\n"); 104 "VFS: Failed to create quota netlink interface.\n");
105 if (genl_register_mc_group(&quota_genl_family, &quota_mcgrp))
106 printk(KERN_ERR
107 "VFS: Failed to register quota mcast group.\n");
95 return 0; 108 return 0;
96}; 109};
97 110
diff --git a/include/uapi/linux/genetlink.h b/include/uapi/linux/genetlink.h
index c880a417d8a9..1af72d8228e0 100644
--- a/include/uapi/linux/genetlink.h
+++ b/include/uapi/linux/genetlink.h
@@ -27,6 +27,7 @@ struct genlmsghdr {
27 */ 27 */
28#define GENL_ID_GENERATE 0 28#define GENL_ID_GENERATE 0
29#define GENL_ID_CTRL NLMSG_MIN_TYPE 29#define GENL_ID_CTRL NLMSG_MIN_TYPE
30#define GENL_ID_VFS_DQUOT (NLMSG_MIN_TYPE + 1)
30 31
31/************************************************************************** 32/**************************************************************************
32 * Controller 33 * Controller
diff --git a/net/netlink/genetlink.c b/net/netlink/genetlink.c
index 353909d46dda..bee91a7527a5 100644
--- a/net/netlink/genetlink.c
+++ b/net/netlink/genetlink.c
@@ -69,8 +69,11 @@ static struct list_head family_ht[GENL_FAM_TAB_SIZE];
69 * abuses the API and thinks it can statically use group 1. 69 * abuses the API and thinks it can statically use group 1.
70 * That group will typically conflict with other groups that 70 * That group will typically conflict with other groups that
71 * any proper users use. 71 * any proper users use.
72 * Bit 17 is marked as already used since the VFS quota code
73 * also abused this API and relied on family == group ID, we
74 * cater to that by giving it a static family and group ID.
72 */ 75 */
73static unsigned long mc_group_start = 0x3; 76static unsigned long mc_group_start = 0x3 | BIT(GENL_ID_VFS_DQUOT);
74static unsigned long *mc_groups = &mc_group_start; 77static unsigned long *mc_groups = &mc_group_start;
75static unsigned long mc_groups_longs = 1; 78static unsigned long mc_groups_longs = 1;
76 79
@@ -130,7 +133,8 @@ static u16 genl_generate_id(void)
130 int i; 133 int i;
131 134
132 for (i = 0; i <= GENL_MAX_ID - GENL_MIN_ID; i++) { 135 for (i = 0; i <= GENL_MAX_ID - GENL_MIN_ID; i++) {
133 if (!genl_family_find_byid(id_gen_idx)) 136 if (id_gen_idx != GENL_ID_VFS_DQUOT &&
137 !genl_family_find_byid(id_gen_idx))
134 return id_gen_idx; 138 return id_gen_idx;
135 if (++id_gen_idx > GENL_MAX_ID) 139 if (++id_gen_idx > GENL_MAX_ID)
136 id_gen_idx = GENL_MIN_ID; 140 id_gen_idx = GENL_MIN_ID;
@@ -169,6 +173,8 @@ int genl_register_mc_group(struct genl_family *family,
169 id = GENL_ID_CTRL; 173 id = GENL_ID_CTRL;
170 else if (strcmp(family->name, "NET_DM") == 0) 174 else if (strcmp(family->name, "NET_DM") == 0)
171 id = 1; 175 id = 1;
176 else if (strcmp(family->name, "VFS_DQUOT") == 0)
177 id = GENL_ID_VFS_DQUOT;
172 else 178 else
173 id = find_first_zero_bit(mc_groups, 179 id = find_first_zero_bit(mc_groups,
174 mc_groups_longs * BITS_PER_LONG); 180 mc_groups_longs * BITS_PER_LONG);