Skip to content

Commit 0003041

Browse files
committed
Merge branch 'sockptr_t-fixes-v2'
Christoph Hellwig says: ==================== sockptr_t fixes v2 a bunch of fixes for the sockptr_t conversion Changes since v1: - fix a user pointer dereference braino in bpfilter ==================== Signed-off-by: David S. Miller <[email protected]>
2 parents 21db923 + a31edb2 commit 0003041

File tree

12 files changed

+61
-64
lines changed

12 files changed

+61
-64
lines changed

drivers/crypto/chelsio/chtls/chtls_main.c

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -525,9 +525,9 @@ static int do_chtls_setsockopt(struct sock *sk, int optname,
525525
/* Obtain version and type from previous copy */
526526
crypto_info[0] = tmp_crypto_info;
527527
/* Now copy the following data */
528-
sockptr_advance(optval, sizeof(*crypto_info));
529-
rc = copy_from_sockptr((char *)crypto_info + sizeof(*crypto_info),
530-
optval,
528+
rc = copy_from_sockptr_offset((char *)crypto_info +
529+
sizeof(*crypto_info),
530+
optval, sizeof(*crypto_info),
531531
sizeof(struct tls12_crypto_info_aes_gcm_128)
532532
- sizeof(*crypto_info));
533533

@@ -542,9 +542,9 @@ static int do_chtls_setsockopt(struct sock *sk, int optname,
542542
}
543543
case TLS_CIPHER_AES_GCM_256: {
544544
crypto_info[0] = tmp_crypto_info;
545-
sockptr_advance(optval, sizeof(*crypto_info));
546-
rc = copy_from_sockptr((char *)crypto_info + sizeof(*crypto_info),
547-
optval,
545+
rc = copy_from_sockptr_offset((char *)crypto_info +
546+
sizeof(*crypto_info),
547+
optval, sizeof(*crypto_info),
548548
sizeof(struct tls12_crypto_info_aes_gcm_256)
549549
- sizeof(*crypto_info));
550550

include/linux/sockptr.h

Lines changed: 22 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -27,14 +27,6 @@ static inline sockptr_t KERNEL_SOCKPTR(void *p)
2727
{
2828
return (sockptr_t) { .kernel = p };
2929
}
30-
31-
static inline int __must_check init_user_sockptr(sockptr_t *sp, void __user *p)
32-
{
33-
if ((unsigned long)p >= TASK_SIZE)
34-
return -EFAULT;
35-
sp->user = p;
36-
return 0;
37-
}
3830
#else /* CONFIG_ARCH_HAS_NON_OVERLAPPING_ADDRESS_SPACE */
3931
typedef struct {
4032
union {
@@ -53,33 +45,44 @@ static inline sockptr_t KERNEL_SOCKPTR(void *p)
5345
{
5446
return (sockptr_t) { .kernel = p, .is_kernel = true };
5547
}
48+
#endif /* CONFIG_ARCH_HAS_NON_OVERLAPPING_ADDRESS_SPACE */
5649

57-
static inline int __must_check init_user_sockptr(sockptr_t *sp, void __user *p)
50+
static inline int __must_check init_user_sockptr(sockptr_t *sp, void __user *p,
51+
size_t size)
5852
{
59-
sp->user = p;
60-
sp->is_kernel = false;
53+
if (!access_ok(p, size))
54+
return -EFAULT;
55+
*sp = (sockptr_t) { .user = p };
6156
return 0;
6257
}
63-
#endif /* CONFIG_ARCH_HAS_NON_OVERLAPPING_ADDRESS_SPACE */
6458

6559
static inline bool sockptr_is_null(sockptr_t sockptr)
6660
{
67-
return !sockptr.user && !sockptr.kernel;
61+
if (sockptr_is_kernel(sockptr))
62+
return !sockptr.kernel;
63+
return !sockptr.user;
6864
}
6965

70-
static inline int copy_from_sockptr(void *dst, sockptr_t src, size_t size)
66+
static inline int copy_from_sockptr_offset(void *dst, sockptr_t src,
67+
size_t offset, size_t size)
7168
{
7269
if (!sockptr_is_kernel(src))
73-
return copy_from_user(dst, src.user, size);
74-
memcpy(dst, src.kernel, size);
70+
return copy_from_user(dst, src.user + offset, size);
71+
memcpy(dst, src.kernel + offset, size);
7572
return 0;
7673
}
7774

78-
static inline int copy_to_sockptr(sockptr_t dst, const void *src, size_t size)
75+
static inline int copy_from_sockptr(void *dst, sockptr_t src, size_t size)
76+
{
77+
return copy_from_sockptr_offset(dst, src, 0, size);
78+
}
79+
80+
static inline int copy_to_sockptr_offset(sockptr_t dst, size_t offset,
81+
const void *src, size_t size)
7982
{
8083
if (!sockptr_is_kernel(dst))
81-
return copy_to_user(dst.user, src, size);
82-
memcpy(dst.kernel, src, size);
84+
return copy_to_user(dst.user + offset, src, size);
85+
memcpy(dst.kernel + offset, src, size);
8386
return 0;
8487
}
8588

@@ -110,14 +113,6 @@ static inline void *memdup_sockptr_nul(sockptr_t src, size_t len)
110113
return p;
111114
}
112115

113-
static inline void sockptr_advance(sockptr_t sockptr, size_t len)
114-
{
115-
if (sockptr_is_kernel(sockptr))
116-
sockptr.kernel += len;
117-
else
118-
sockptr.user += len;
119-
}
120-
121116
static inline long strncpy_from_sockptr(char *dst, sockptr_t src, size_t count)
122117
{
123118
if (sockptr_is_kernel(src)) {

net/dccp/proto.c

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -426,9 +426,8 @@ static int dccp_setsockopt_service(struct sock *sk, const __be32 service,
426426
return -ENOMEM;
427427

428428
sl->dccpsl_nr = optlen / sizeof(u32) - 1;
429-
sockptr_advance(optval, sizeof(service));
430-
if (copy_from_sockptr(sl->dccpsl_list, optval,
431-
optlen - sizeof(service)) ||
429+
if (copy_from_sockptr_offset(sl->dccpsl_list, optval,
430+
sizeof(service), optlen - sizeof(service)) ||
432431
dccp_list_has_service(sl, DCCP_SERVICE_INVALID_VALUE)) {
433432
kfree(sl);
434433
return -EFAULT;

net/ipv4/bpfilter/sockopt.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -65,7 +65,7 @@ int bpfilter_ip_get_sockopt(struct sock *sk, int optname,
6565

6666
if (get_user(len, optlen))
6767
return -EFAULT;
68-
err = init_user_sockptr(&optval, user_optval);
68+
err = init_user_sockptr(&optval, user_optval, len);
6969
if (err)
7070
return err;
7171
return bpfilter_mbox_request(sk, optname, optval, len, false);

net/ipv4/netfilter/arp_tables.c

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
1+
// SPDX-License-Identifier: GPL-2.0-only
22
/*
33
* Packet matching code for ARP packets.
44
*
@@ -971,8 +971,8 @@ static int do_replace(struct net *net, sockptr_t arg, unsigned int len)
971971
return -ENOMEM;
972972

973973
loc_cpu_entry = newinfo->entries;
974-
sockptr_advance(arg, sizeof(tmp));
975-
if (copy_from_sockptr(loc_cpu_entry, arg, tmp.size) != 0) {
974+
if (copy_from_sockptr_offset(loc_cpu_entry, arg, sizeof(tmp),
975+
tmp.size) != 0) {
976976
ret = -EFAULT;
977977
goto free_newinfo;
978978
}
@@ -1267,8 +1267,8 @@ static int compat_do_replace(struct net *net, sockptr_t arg, unsigned int len)
12671267
return -ENOMEM;
12681268

12691269
loc_cpu_entry = newinfo->entries;
1270-
sockptr_advance(arg, sizeof(tmp));
1271-
if (copy_from_sockptr(loc_cpu_entry, arg, tmp.size) != 0) {
1270+
if (copy_from_sockptr_offset(loc_cpu_entry, arg, sizeof(tmp),
1271+
tmp.size) != 0) {
12721272
ret = -EFAULT;
12731273
goto free_newinfo;
12741274
}

net/ipv4/netfilter/ip_tables.c

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1126,8 +1126,8 @@ do_replace(struct net *net, sockptr_t arg, unsigned int len)
11261126
return -ENOMEM;
11271127

11281128
loc_cpu_entry = newinfo->entries;
1129-
sockptr_advance(arg, sizeof(tmp));
1130-
if (copy_from_sockptr(loc_cpu_entry, arg, tmp.size) != 0) {
1129+
if (copy_from_sockptr_offset(loc_cpu_entry, arg, sizeof(tmp),
1130+
tmp.size) != 0) {
11311131
ret = -EFAULT;
11321132
goto free_newinfo;
11331133
}
@@ -1508,8 +1508,8 @@ compat_do_replace(struct net *net, sockptr_t arg, unsigned int len)
15081508
return -ENOMEM;
15091509

15101510
loc_cpu_entry = newinfo->entries;
1511-
sockptr_advance(arg, sizeof(tmp));
1512-
if (copy_from_sockptr(loc_cpu_entry, arg, tmp.size) != 0) {
1511+
if (copy_from_sockptr_offset(loc_cpu_entry, arg, sizeof(tmp),
1512+
tmp.size) != 0) {
15131513
ret = -EFAULT;
15141514
goto free_newinfo;
15151515
}

net/ipv4/tcp.c

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2801,12 +2801,13 @@ static int tcp_repair_options_est(struct sock *sk, sockptr_t optbuf,
28012801
{
28022802
struct tcp_sock *tp = tcp_sk(sk);
28032803
struct tcp_repair_opt opt;
2804+
size_t offset = 0;
28042805

28052806
while (len >= sizeof(opt)) {
2806-
if (copy_from_sockptr(&opt, optbuf, sizeof(opt)))
2807+
if (copy_from_sockptr_offset(&opt, optbuf, offset, sizeof(opt)))
28072808
return -EFAULT;
28082809

2809-
sockptr_advance(optbuf, sizeof(opt));
2810+
offset += sizeof(opt);
28102811
len -= sizeof(opt);
28112812

28122813
switch (opt.opt_code) {

net/ipv6/ip6_flowlabel.c

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -401,8 +401,8 @@ fl_create(struct net *net, struct sock *sk, struct in6_flowlabel_req *freq,
401401
memset(fl->opt, 0, sizeof(*fl->opt));
402402
fl->opt->tot_len = sizeof(*fl->opt) + olen;
403403
err = -EFAULT;
404-
sockptr_advance(optval, CMSG_ALIGN(sizeof(*freq)));
405-
if (copy_from_sockptr(fl->opt + 1, optval, olen))
404+
if (copy_from_sockptr_offset(fl->opt + 1, optval,
405+
CMSG_ALIGN(sizeof(*freq)), olen))
406406
goto done;
407407

408408
msg.msg_controllen = olen;
@@ -703,9 +703,10 @@ static int ipv6_flowlabel_get(struct sock *sk, struct in6_flowlabel_req *freq,
703703
goto recheck;
704704

705705
if (!freq->flr_label) {
706-
sockptr_advance(optval,
707-
offsetof(struct in6_flowlabel_req, flr_label));
708-
if (copy_to_sockptr(optval, &fl->label, sizeof(fl->label))) {
706+
size_t offset = offsetof(struct in6_flowlabel_req, flr_label);
707+
708+
if (copy_to_sockptr_offset(optval, offset, &fl->label,
709+
sizeof(fl->label))) {
709710
/* Intentionally ignore fault. */
710711
}
711712
}

net/ipv6/netfilter/ip6_tables.c

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1143,8 +1143,8 @@ do_replace(struct net *net, sockptr_t arg, unsigned int len)
11431143
return -ENOMEM;
11441144

11451145
loc_cpu_entry = newinfo->entries;
1146-
sockptr_advance(arg, sizeof(tmp));
1147-
if (copy_from_sockptr(loc_cpu_entry, arg, tmp.size) != 0) {
1146+
if (copy_from_sockptr_offset(loc_cpu_entry, arg, sizeof(tmp),
1147+
tmp.size) != 0) {
11481148
ret = -EFAULT;
11491149
goto free_newinfo;
11501150
}
@@ -1517,8 +1517,8 @@ compat_do_replace(struct net *net, sockptr_t arg, unsigned int len)
15171517
return -ENOMEM;
15181518

15191519
loc_cpu_entry = newinfo->entries;
1520-
sockptr_advance(arg, sizeof(tmp));
1521-
if (copy_from_sockptr(loc_cpu_entry, arg, tmp.size) != 0) {
1520+
if (copy_from_sockptr_offset(loc_cpu_entry, arg, sizeof(tmp),
1521+
tmp.size) != 0) {
15221522
ret = -EFAULT;
15231523
goto free_newinfo;
15241524
}

net/netfilter/x_tables.c

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1050,6 +1050,7 @@ EXPORT_SYMBOL_GPL(xt_check_target);
10501050
void *xt_copy_counters(sockptr_t arg, unsigned int len,
10511051
struct xt_counters_info *info)
10521052
{
1053+
size_t offset;
10531054
void *mem;
10541055
u64 size;
10551056

@@ -1067,7 +1068,7 @@ void *xt_copy_counters(sockptr_t arg, unsigned int len,
10671068

10681069
memcpy(info->name, compat_tmp.name, sizeof(info->name) - 1);
10691070
info->num_counters = compat_tmp.num_counters;
1070-
sockptr_advance(arg, sizeof(compat_tmp));
1071+
offset = sizeof(compat_tmp);
10711072
} else
10721073
#endif
10731074
{
@@ -1078,7 +1079,7 @@ void *xt_copy_counters(sockptr_t arg, unsigned int len,
10781079
if (copy_from_sockptr(info, arg, sizeof(*info)) != 0)
10791080
return ERR_PTR(-EFAULT);
10801081

1081-
sockptr_advance(arg, sizeof(*info));
1082+
offset = sizeof(*info);
10821083
}
10831084
info->name[sizeof(info->name) - 1] = '\0';
10841085

@@ -1092,7 +1093,7 @@ void *xt_copy_counters(sockptr_t arg, unsigned int len,
10921093
if (!mem)
10931094
return ERR_PTR(-ENOMEM);
10941095

1095-
if (copy_from_sockptr(mem, arg, len) == 0)
1096+
if (copy_from_sockptr_offset(mem, arg, offset, len) == 0)
10961097
return mem;
10971098

10981099
vfree(mem);

net/socket.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2105,7 +2105,7 @@ int __sys_setsockopt(int fd, int level, int optname, char __user *user_optval,
21052105
if (optlen < 0)
21062106
return -EINVAL;
21072107

2108-
err = init_user_sockptr(&optval, user_optval);
2108+
err = init_user_sockptr(&optval, user_optval, optlen);
21092109
if (err)
21102110
return err;
21112111

net/tls/tls_main.c

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -522,9 +522,9 @@ static int do_tls_setsockopt_conf(struct sock *sk, sockptr_t optval,
522522
goto err_crypto_info;
523523
}
524524

525-
sockptr_advance(optval, sizeof(*crypto_info));
526-
rc = copy_from_sockptr(crypto_info + 1, optval,
527-
optlen - sizeof(*crypto_info));
525+
rc = copy_from_sockptr_offset(crypto_info + 1, optval,
526+
sizeof(*crypto_info),
527+
optlen - sizeof(*crypto_info));
528528
if (rc) {
529529
rc = -EFAULT;
530530
goto err_crypto_info;

0 commit comments

Comments
 (0)