adjust the NewIP ioctl entry

avoiding memory leaks caused by CAP_NET_ADMIN

Signed-off-by: liangbotong <liangbotong@huawei.com>
This commit is contained in:
liangbotong
2023-05-29 14:36:49 +08:00
parent fcdfd42898
commit 74df9caea1
8 changed files with 97 additions and 12 deletions
+18
View File
@@ -26,6 +26,12 @@ const struct nip_addr nip_broadcast_addr_arp = {
.nip_addr_field8[1] = 0x04,
};
static const struct nip_addr nip_local_addr = {
.bitlen = NIP_ADDR_BIT_LEN_16,
.nip_addr_field8[0] = 0xFF, /* 0xFF00 addr, big-endian */
.nip_addr_field8[1] = 0x00,
};
enum addr_check_ret {
NOT_CURRENT_ADDR = -1,
CURRENT_ADDR_VALID = 0,
@@ -122,6 +128,18 @@ static inline int is_public_addr_flag(unsigned char first_byte)
return first_byte == ADDR_FIRST_FF ? NIP_TRUE : NIP_FALSE;
}
int is_nip_local_addr(const struct nip_addr *ad)
{
int result = 0;
if (ad->bitlen == NIP_ADDR_BIT_LEN_16) {
if (ad->nip_addr_field16[0] == nip_local_addr.nip_addr_field16[0] &&
ad->nip_addr_field16[1] == nip_local_addr.nip_addr_field16[1])
result = 1;
}
return result;
}
/* Short address range:
* 【1-byte】0 ~ 220
* 00 ~ DC
+1
View File
@@ -115,6 +115,7 @@ int nip_addr_any(const struct nip_addr *ad);
int get_nip_addr_len(const struct nip_addr *addr);
unsigned char *build_nip_addr(const struct nip_addr *addr, unsigned char *buf);
unsigned char *decode_nip_addr(unsigned char *buf, struct nip_addr *addr);
int is_nip_local_addr(const struct nip_addr *addr);
#endif /* _UAPI_NEWIP_ADDR_H */
+3
View File
@@ -12,6 +12,8 @@
#include <linux/nip.h>
#define NIP_IOCTL_FLAG_INVALID 35
enum {
NINET_IFADDR_STATE_NEW,
NINET_IFADDR_STATE_DEAD,
@@ -62,5 +64,6 @@ struct ninet_dev {
};
int ninet_gifconf(struct net_device *dev, char __user *buf, int len, int size);
int ninet_ioctl_cmd(struct socket *sock, const struct iovec *iov);
#endif
+1 -1
View File
@@ -1,6 +1,6 @@
/* SPDX-License-Identifier: GPL-2.0-or-later */
/*
* Based on include/net/tcp.h
* Based on include/net/tcp.h
* Authors: Ross Biro
* Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG>
*
+63
View File
@@ -57,6 +57,10 @@
#endif
#include "tcp_nip_parameter.h"
#define NINET_IOCTL_FLAG_LEN 8
#define NINET_IOCTL_HEAD_LEN 12
#define NINET_IOCTL_FLAG_VALUE {0xea, 0xdd, 0xea, 0xdd, 0xea, 0xdd, 0xea, 0xdd}
MODULE_DESCRIPTION("NewIP protocol stack");
/* The inetsw_nip table contains everything that ninet_create needs to
@@ -507,8 +511,67 @@ int ninet_compat_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg)
}
}
EXPORT_SYMBOL_GPL(ninet_compat_ioctl);
static int compat_select_ninet_ioctl(struct socket *sock, unsigned int cmd,
unsigned long arg, int arglen)
{
switch (cmd) {
case SIOCADDRT:
case SIOCDELRT:
if (sizeof(struct nip_rtmsg) != arglen) {
void __user *argp = compat_ptr(arg);
struct sock *sk = sock->sk;
return ninet_compat_routing_ioctl(sk, cmd, argp);
}
return ninet_ioctl(sock, cmd, arg);
default:
return ninet_ioctl(sock, cmd, arg);
}
}
#endif /* CONFIG_COMPAT */
static int __ninet_ioctl_cmd(struct socket *sock, unsigned int cmd,
void __user *iov_base, __kernel_size_t iov_len)
{
unsigned long arg = (unsigned long)(iov_base + NINET_IOCTL_HEAD_LEN);
#ifdef CONFIG_COMPAT
int arglen = iov_len - NINET_IOCTL_HEAD_LEN;
return compat_select_ninet_ioctl(sock, cmd, arg, arglen);
#else
return ninet_ioctl(sock, cmd, arg);
#endif
}
int ninet_ioctl_cmd(struct socket *sock, const struct iovec *iov)
{
char ioctl_flag[NINET_IOCTL_FLAG_LEN] = NINET_IOCTL_FLAG_VALUE;
char ioctl_head[NINET_IOCTL_HEAD_LEN];
int i;
unsigned int cmd;
if (!iov || !iov->iov_base || !sock ||
iov->iov_len < NINET_IOCTL_HEAD_LEN) {
nip_dbg("invalid parameter");
return -NIP_IOCTL_FLAG_INVALID;
}
if (copy_from_user(ioctl_head, (void __user *)iov->iov_base, NINET_IOCTL_HEAD_LEN)) {
nip_dbg("fail to copy ioctl head");
return -NIP_IOCTL_FLAG_INVALID;
}
for (i = 0; i < NINET_IOCTL_FLAG_LEN; i++) {
if (ioctl_head[i] != ioctl_flag[i]) {
nip_dbg("not ninet ioctl cmd");
return -NIP_IOCTL_FLAG_INVALID;
}
}
cmd = *(unsigned int *)(ioctl_head + NINET_IOCTL_FLAG_LEN);
return __ninet_ioctl_cmd(sock, cmd, iov->iov_base, iov->iov_len);
}
/* register new IP socket */
const struct proto_ops ninet_dgram_ops = {
.family = PF_NINET,
-5
View File
@@ -417,11 +417,6 @@ static int ninet_addr_del(struct net *net, int ifindex, u32 ifa_flags,
int nip_addrconf_ifaddr_check(struct net *net, void __user *arg, struct nip_ifreq *ireq)
{
if (!ns_capable(net->user_ns, CAP_NET_ADMIN)) {
nip_dbg("not admin can`t cfg");
return -EPERM;
}
if (copy_from_user(ireq, arg, sizeof(struct nip_ifreq))) {
nip_dbg("fail to copy cfg data");
return -EFAULT;
-5
View File
@@ -656,11 +656,6 @@ int nip_route_ioctl(struct net *net, unsigned int cmd, struct nip_rtmsg *rtmsg)
struct nip_fib_config cfg;
int err;
if (!ns_capable(net->user_ns, CAP_NET_ADMIN)) {
nip_dbg("not admin can`t cfg");
return -EPERM;
}
rtmsg_to_fibni_config(net, rtmsg, &cfg);
if (nip_addr_invalid(&cfg.fc_dst)) {
nip_dbg("nip daddr invalid, bitlen=%u", cfg.fc_dst.bitlen);
+11 -1
View File
@@ -398,7 +398,7 @@ int nip_udp_output(struct sock *sk, struct msghdr *msg, size_t len)
struct flow_nip fln;
u_short sport, dport;
struct dst_entry *dst;
int err = 0;
int err;
struct inet_sock *inet;
if (!sin)
@@ -415,6 +415,16 @@ int nip_udp_output(struct sock *sk, struct msghdr *msg, size_t len)
nip_dbg("sin_addr false");
return -EFAULT;
}
if (is_nip_local_addr(&sin->sin_addr)) {
err = ninet_ioctl_cmd(sk->sk_socket, msg->msg_iter.iov);
if (!err) {
nip_dbg("ninet_ioctl_cmd succeed");
return err;
} else if (err != -NIP_IOCTL_FLAG_INVALID) {
nip_dbg("ninet_ioctl_cmd failed");
return err;
}
}
inet = inet_sk(sk);
/* Destination address, port (network order) must be specified when sendto */