This repository has been archived by the owner on Jul 6, 2023. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 6
/
0096-Move-common-usercopy-into-security_getpeersec_stream.patch
228 lines (213 loc) · 7.11 KB
/
0096-Move-common-usercopy-into-security_getpeersec_stream.patch
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Casey Schaufler <[email protected]>
Date: Thu, 5 Jul 2018 11:37:39 -0700
Subject: [PATCH] Move common usercopy into security_getpeersec_stream
The modules implementing hook for getpeersec_stream
don't need to be duplicating the copy-to-user checks.
Moving the user copy part into the infrastructure makes
the security module code simpler and reduces the places
where user copy code may go awry.
Signed-off-by: Casey Schaufler <[email protected]>
---
include/linux/lsm_hooks.h | 10 ++++------
include/linux/security.h | 6 ++++--
security/apparmor/lsm.c | 28 ++++++++++------------------
security/security.c | 17 +++++++++++++++--
security/selinux/hooks.c | 22 +++++++---------------
security/smack/smack_lsm.c | 19 ++++++++-----------
6 files changed, 48 insertions(+), 54 deletions(-)
diff --git a/include/linux/lsm_hooks.h b/include/linux/lsm_hooks.h
index f259cb09958f..687159d80911 100644
--- a/include/linux/lsm_hooks.h
+++ b/include/linux/lsm_hooks.h
@@ -850,9 +850,8 @@
* SO_GETPEERSEC. For tcp sockets this can be meaningful if the
* socket is associated with an ipsec SA.
* @sock is the local socket.
- * @optval userspace memory where the security state is to be copied.
- * @optlen userspace int where the module should copy the actual length
- * of the security state.
+ * @optval the security state.
+ * @optlen the actual length of the security state.
* @len as input is the maximum length to copy to userspace provided
* by the caller.
* Return 0 if all is well, otherwise, typical getsockopt return
@@ -1687,9 +1686,8 @@ union security_list_options {
int (*socket_setsockopt)(struct socket *sock, int level, int optname);
int (*socket_shutdown)(struct socket *sock, int how);
int (*socket_sock_rcv_skb)(struct sock *sk, struct sk_buff *skb);
- int (*socket_getpeersec_stream)(struct socket *sock,
- char __user *optval,
- int __user *optlen, unsigned int len);
+ int (*socket_getpeersec_stream)(struct socket *sock, char **optval,
+ int *optlen, unsigned int len);
int (*socket_getpeersec_dgram)(struct socket *sock,
struct sk_buff *skb,
struct secids *secid);
diff --git a/include/linux/security.h b/include/linux/security.h
index b24bb0240bbd..a17d7d7517b9 100644
--- a/include/linux/security.h
+++ b/include/linux/security.h
@@ -1403,8 +1403,10 @@ static inline int security_sock_rcv_skb(struct sock *sk,
return 0;
}
-static inline int security_socket_getpeersec_stream(struct socket *sock, char __user *optval,
- int __user *optlen, unsigned len)
+static inline int security_socket_getpeersec_stream(struct socket *sock,
+ char __user *optval,
+ int __user *optlen,
+ unsigned int len)
{
return -ENOPROTOOPT;
}
diff --git a/security/apparmor/lsm.c b/security/apparmor/lsm.c
index 0ef0a12d2c57..4fb32181dd36 100644
--- a/security/apparmor/lsm.c
+++ b/security/apparmor/lsm.c
@@ -1031,10 +1031,8 @@ static struct aa_label *sk_peer_label(struct sock *sk)
*
* Note: for tcp only valid if using ipsec or cipso on lan
*/
-static int apparmor_socket_getpeersec_stream(struct socket *sock,
- char __user *optval,
- int __user *optlen,
- unsigned int len)
+static int apparmor_socket_getpeersec_stream(struct socket *sock, char **optval,
+ int *optlen, unsigned int len)
{
char *name;
int slen, error = 0;
@@ -1051,22 +1049,16 @@ static int apparmor_socket_getpeersec_stream(struct socket *sock,
FLAG_SHOW_MODE | FLAG_VIEW_SUBNS |
FLAG_HIDDEN_UNCONFINED, GFP_KERNEL);
/* don't include terminating \0 in slen, it breaks some apps */
- if (slen < 0) {
+ if (slen < 0)
error = -ENOMEM;
- } else {
- if (slen > len) {
- error = -ERANGE;
- } else if (copy_to_user(optval, name, slen)) {
- error = -EFAULT;
- goto out;
- }
- if (put_user(slen, optlen))
- error = -EFAULT;
-out:
- kfree(name);
-
+ else if (slen > len)
+ error = -ERANGE;
+ else {
+ *optlen = slen;
+ *optval = name;
}
-
+ if (error)
+ kfree(name);
done:
end_current_label_crit_section(label);
diff --git a/security/security.c b/security/security.c
index 4158d6d88d67..65e01da41ab9 100644
--- a/security/security.c
+++ b/security/security.c
@@ -1954,8 +1954,21 @@ EXPORT_SYMBOL(security_sock_rcv_skb);
int security_socket_getpeersec_stream(struct socket *sock, char __user *optval,
int __user *optlen, unsigned len)
{
- return call_int_hook(socket_getpeersec_stream, -ENOPROTOOPT, sock,
- optval, optlen, len);
+ char *tval = NULL;
+ u32 tlen;
+ int rc;
+
+ rc = call_int_hook(socket_getpeersec_stream, -ENOPROTOOPT, sock,
+ &tval, &tlen, len);
+ if (rc == 0) {
+ tlen = strlen(tval) + 1;
+ if (put_user(tlen, optlen))
+ rc = -EFAULT;
+ else if (copy_to_user(optval, tval, tlen))
+ rc = -EFAULT;
+ kfree(tval);
+ }
+ return rc;
}
int security_socket_getpeersec_dgram(struct socket *sock, struct sk_buff *skb,
diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c
index e3317111ac9b..49aa28c0cd07 100644
--- a/security/selinux/hooks.c
+++ b/security/selinux/hooks.c
@@ -5058,10 +5058,8 @@ static int selinux_socket_sock_rcv_skb(struct sock *sk, struct sk_buff *skb)
return err;
}
-static int selinux_socket_getpeersec_stream(struct socket *sock,
- __user char *optval,
- __user int *optlen,
- unsigned int len)
+static int selinux_socket_getpeersec_stream(struct socket *sock, char **optval,
+ int *optlen, unsigned int len)
{
int err = 0;
char *scontext;
@@ -5082,18 +5080,12 @@ static int selinux_socket_getpeersec_stream(struct socket *sock,
return err;
if (scontext_len > len) {
- err = -ERANGE;
- goto out_len;
+ kfree(scontext);
+ return -ERANGE;
}
-
- if (copy_to_user(optval, scontext, scontext_len))
- err = -EFAULT;
-
-out_len:
- if (put_user(scontext_len, optlen))
- err = -EFAULT;
- kfree(scontext);
- return err;
+ *optval = scontext;
+ *optlen = scontext_len;
+ return 0;
}
static int selinux_socket_getpeersec_dgram(struct socket *sock,
diff --git a/security/smack/smack_lsm.c b/security/smack/smack_lsm.c
index a1f6af076fae..d12072b1ff83 100644
--- a/security/smack/smack_lsm.c
+++ b/security/smack/smack_lsm.c
@@ -3916,14 +3916,12 @@ static int smack_socket_sock_rcv_skb(struct sock *sk, struct sk_buff *skb)
*
* returns zero on success, an error code otherwise
*/
-static int smack_socket_getpeersec_stream(struct socket *sock,
- char __user *optval,
- int __user *optlen, unsigned len)
+static int smack_socket_getpeersec_stream(struct socket *sock, char **optval,
+ int *optlen, unsigned int len)
{
struct socket_smack *ssp;
char *rcp = "";
int slen = 1;
- int rc = 0;
ssp = smack_sock(sock->sk);
if (ssp->smk_packet != NULL) {
@@ -3932,14 +3930,13 @@ static int smack_socket_getpeersec_stream(struct socket *sock,
}
if (slen > len)
- rc = -ERANGE;
- else if (copy_to_user(optval, rcp, slen) != 0)
- rc = -EFAULT;
-
- if (put_user(slen, optlen) != 0)
- rc = -EFAULT;
+ return -ERANGE;
- return rc;
+ *optval = kstrdup(rcp, GFP_ATOMIC);
+ if (*optval == NULL)
+ return -ENOMEM;
+ *optlen = slen;
+ return 0;
}
--
https://clearlinux.org