Skip to content

Commit 0a6a3a2

Browse files
cricard13davem330
authored andcommitted
netlink: add NETLINK_CAP_ACK socket option
Since commit c05cdb1 ("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 <[email protected]> Signed-off-by: Christophe Ricard <[email protected]> Signed-off-by: David S. Miller <[email protected]>
1 parent 4941b8f commit 0a6a3a2

File tree

2 files changed

+25
-3
lines changed

2 files changed

+25
-3
lines changed

include/uapi/linux/netlink.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -110,6 +110,7 @@ struct nlmsgerr {
110110
#define NETLINK_TX_RING 7
111111
#define NETLINK_LISTEN_ALL_NSID 8
112112
#define NETLINK_LIST_MEMBERSHIPS 9
113+
#define NETLINK_CAP_ACK 10
113114

114115
struct nl_pktinfo {
115116
__u32 group;

net/netlink/af_netlink.c

Lines changed: 24 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -84,6 +84,7 @@ struct listeners {
8484
#define NETLINK_F_BROADCAST_SEND_ERROR 0x4
8585
#define NETLINK_F_RECV_NO_ENOBUFS 0x8
8686
#define NETLINK_F_LISTEN_ALL_NSID 0x10
87+
#define NETLINK_F_CAP_ACK 0x20
8788

8889
static inline int netlink_is_kernel(struct sock *sk)
8990
{
@@ -2258,6 +2259,13 @@ static int netlink_setsockopt(struct socket *sock, int level, int optname,
22582259
nlk->flags &= ~NETLINK_F_LISTEN_ALL_NSID;
22592260
err = 0;
22602261
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;
22612269
default:
22622270
err = -ENOPROTOOPT;
22632271
}
@@ -2332,6 +2340,16 @@ static int netlink_getsockopt(struct socket *sock, int level, int optname,
23322340
netlink_table_ungrab();
23332341
break;
23342342
}
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;
23352353
default:
23362354
err = -ENOPROTOOPT;
23372355
}
@@ -2873,9 +2891,12 @@ void netlink_ack(struct sk_buff *in_skb, struct nlmsghdr *nlh, int err)
28732891
struct nlmsghdr *rep;
28742892
struct nlmsgerr *errmsg;
28752893
size_t payload = sizeof(*errmsg);
2894+
struct netlink_sock *nlk = nlk_sk(NETLINK_CB(in_skb).sk);
28762895

2877-
/* error messages get the original request appened */
2878-
if (err)
2896+
/* Error messages get the original request appened, unless the user
2897+
* requests to cap the error message.
2898+
*/
2899+
if (!(nlk->flags & NETLINK_F_CAP_ACK) && err)
28792900
payload += nlmsg_len(nlh);
28802901

28812902
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)
28982919
NLMSG_ERROR, payload, 0);
28992920
errmsg = nlmsg_data(rep);
29002921
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));
29022923
netlink_unicast(in_skb->sk, skb, NETLINK_CB(in_skb).portid, MSG_DONTWAIT);
29032924
}
29042925
EXPORT_SYMBOL(netlink_ack);

0 commit comments

Comments
 (0)