为什么我在netlink_setsockopt中无法调用wake_up_interruptible() 函数
我正在尝试在Linux内核3.16中访问在 netlink_setsockopt() 内的 wake_up_interruptible() 调用。不过我注意到,只有在我提供的 optlen 的情况下,代码路径才会到达。
当我对 setsockopt 进行调用,长度为 1 时,无法到达目标代码:
char *val = "A";
setsockopt(dangling_fd, SOL_NETLINK, NETLINK_NO_ENOBUFS, &val, 1);
然而,如果我使用 sizeof(val),则按预期工作:
char *val = "A";
setsockopt(dangling_fd, SOL_NETLINK, NETLINK_NO_ENOBUFS, &val, sizeof(val));
查看内核源码,我看到这是这样的检查:
static int netlink_setsockopt(struct socket *sock, int level, int optname,
char __user *optval, unsigned int optlen)
{
struct sock *sk = sock->sk;
struct netlink_sock *nlk = nlk_sk(sk);
unsigned int val = 0;
int err;
if (level != SOL_NETLINK)
return -ENOPROTOOPT;
if (optname != NETLINK_RX_RING && optname != NETLINK_TX_RING &&
optlen >= sizeof(int) &&
get_user(val, (unsigned int __user *)optval))
return -EFAULT;
switch (optname) {
...
case NETLINK_NO_ENOBUFS:
if (val) {
nlk->flags |= NETLINK_RECV_NO_ENOBUFS;
clear_bit(NETLINK_CONGESTED, &nlk->state);
wake_up_interruptible(&nlk->wait);
} else {
nlk->flags &= ~NETLINK_RECV_NO_ENOBUFS;
}
err = 0;
break;
...
#endif /* CONFIG_NETLINK_MMAP */
default:
err = -ENOPROTOOPT;
}
return err;
}
为什么第一种方法无法进入 NETLINK_NO_ENOBUFS 的逻辑?
解决方案
经过一番研究和试错,我发现把 optlen 设为1,意味着它小于 sizeof(int),后者的值是4。
这意味着。
if (optname != NETLINK_RX_RING && optname != NETLINK_TX_RING &&
optlen >= sizeof(int) &&
get_user(val, (unsigned int __user *)optval))
return -EFAULT;
...
optlen >= sizeof(int) // 1 is not greater than 4
因为,在该if语句中,我们的第三个条件返回了false。我们的 get_user(val, (unsigned int __user *)optval) 被跳过,所以val仍然是0。后面的if语句返回了false,这就是为什么 wake_up_interruptible() 无法被调用的原因。
case NETLINK_NO_ENOBUFS:
if (val) { // This will be false because our val is still 0.
nlk->flags |= NETLINK_RECV_NO_ENOBUFS;
clear_bit(NETLINK_CONGESTED, &nlk->state);
wake_up_interruptible(&nlk->wait);
} else {
nlk->flags &= ~NETLINK_RECV_NO_ENOBUFS;
}
站内所有文章版权归属LeftHeroAI导航站,无授权禁止任何主体转载、抄袭、复制内容,亦不得私自架设镜像站点。一经侵权,本站将通过法律途径追责。