aboutsummaryrefslogtreecommitdiffstats
path: root/net/netlink
diff options
context:
space:
mode:
authorChristophe Ricard <christophe.ricard@gmail.com>2015-08-28 01:07:48 -0400
committerDavid S. Miller <davem@davemloft.net>2015-08-29 01:25:42 -0400
commit0a6a3a23ea6efde079a5b77688541a98bf202721 (patch)
treeec9cd4b088e93a12c26ebf9fcb8b7bf5abe2510d /net/netlink
parent4941b8f0c2b9d88e8a6dacebf8b7faf603b98368 (diff)
netlink: add NETLINK_CAP_ACK socket option
Since commit c05cdb1b864f ("netlink: allow large data transfers from user-space"), the kernel may fail to allocate the necessary room for the acknowledgment message back to userspace. This patch introduces a new socket option that trims off the payload of the original netlink message. The netlink message header is still included, so the user can guess from the sequence number what is the message that has triggered the acknowledgment. Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org> Signed-off-by: Christophe Ricard <christophe-h.ricard@st.com> Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net/netlink')
-rw-r--r--net/netlink/af_netlink.c27
1 files changed, 24 insertions, 3 deletions
diff --git a/net/netlink/af_netlink.c b/net/netlink/af_netlink.c
index a774985489e2..3eea0b2a3239 100644
--- a/net/netlink/af_netlink.c
+++ b/net/netlink/af_netlink.c
@@ -84,6 +84,7 @@ struct listeners {
84#define NETLINK_F_BROADCAST_SEND_ERROR 0x4 84#define NETLINK_F_BROADCAST_SEND_ERROR 0x4
85#define NETLINK_F_RECV_NO_ENOBUFS 0x8 85#define NETLINK_F_RECV_NO_ENOBUFS 0x8
86#define NETLINK_F_LISTEN_ALL_NSID 0x10 86#define NETLINK_F_LISTEN_ALL_NSID 0x10
87#define NETLINK_F_CAP_ACK 0x20
87 88
88static inline int netlink_is_kernel(struct sock *sk) 89static inline int netlink_is_kernel(struct sock *sk)
89{ 90{
@@ -2258,6 +2259,13 @@ static int netlink_setsockopt(struct socket *sock, int level, int optname,
2258 nlk->flags &= ~NETLINK_F_LISTEN_ALL_NSID; 2259 nlk->flags &= ~NETLINK_F_LISTEN_ALL_NSID;
2259 err = 0; 2260 err = 0;
2260 break; 2261 break;
2262 case NETLINK_CAP_ACK:
2263 if (val)
2264 nlk->flags |= NETLINK_F_CAP_ACK;
2265 else
2266 nlk->flags &= ~NETLINK_F_CAP_ACK;
2267 err = 0;
2268 break;
2261 default: 2269 default:
2262 err = -ENOPROTOOPT; 2270 err = -ENOPROTOOPT;
2263 } 2271 }
@@ -2332,6 +2340,16 @@ static int netlink_getsockopt(struct socket *sock, int level, int optname,
2332 netlink_table_ungrab(); 2340 netlink_table_ungrab();
2333 break; 2341 break;
2334 } 2342 }
2343 case NETLINK_CAP_ACK:
2344 if (len < sizeof(int))
2345 return -EINVAL;
2346 len = sizeof(int);
2347 val = nlk->flags & NETLINK_F_CAP_ACK ? 1 : 0;
2348 if (put_user(len, optlen) ||
2349 put_user(val, optval))
2350 return -EFAULT;
2351 err = 0;
2352 break;
2335 default: 2353 default:
2336 err = -ENOPROTOOPT; 2354 err = -ENOPROTOOPT;
2337 } 2355 }
@@ -2873,9 +2891,12 @@ void netlink_ack(struct sk_buff *in_skb, struct nlmsghdr *nlh, int err)
2873 struct nlmsghdr *rep; 2891 struct nlmsghdr *rep;
2874 struct nlmsgerr *errmsg; 2892 struct nlmsgerr *errmsg;
2875 size_t payload = sizeof(*errmsg); 2893 size_t payload = sizeof(*errmsg);
2894 struct netlink_sock *nlk = nlk_sk(NETLINK_CB(in_skb).sk);
2876 2895
2877 /* error messages get the original request appened */ 2896 /* Error messages get the original request appened, unless the user
2878 if (err) 2897 * requests to cap the error message.
2898 */
2899 if (!(nlk->flags & NETLINK_F_CAP_ACK) && err)
2879 payload += nlmsg_len(nlh); 2900 payload += nlmsg_len(nlh);
2880 2901
2881 skb = netlink_alloc_skb(in_skb->sk, nlmsg_total_size(payload), 2902 skb = netlink_alloc_skb(in_skb->sk, nlmsg_total_size(payload),
@@ -2898,7 +2919,7 @@ void netlink_ack(struct sk_buff *in_skb, struct nlmsghdr *nlh, int err)
2898 NLMSG_ERROR, payload, 0); 2919 NLMSG_ERROR, payload, 0);
2899 errmsg = nlmsg_data(rep); 2920 errmsg = nlmsg_data(rep);
2900 errmsg->error = err; 2921 errmsg->error = err;
2901 memcpy(&errmsg->msg, nlh, err ? nlh->nlmsg_len : sizeof(*nlh)); 2922 memcpy(&errmsg->msg, nlh, payload > sizeof(*errmsg) ? nlh->nlmsg_len : sizeof(*nlh));
2902 netlink_unicast(in_skb->sk, skb, NETLINK_CB(in_skb).portid, MSG_DONTWAIT); 2923 netlink_unicast(in_skb->sk, skb, NETLINK_CB(in_skb).portid, MSG_DONTWAIT);
2903} 2924}
2904EXPORT_SYMBOL(netlink_ack); 2925EXPORT_SYMBOL(netlink_ack);