hc
2024-10-22 8ac6c7a54ed1b98d142dce24b11c6de6a1e239a5
kernel/net/core/scm.c
....@@ -1,12 +1,8 @@
1
+// SPDX-License-Identifier: GPL-2.0-or-later
12 /* scm.c - Socket level control messages processing.
23 *
34 * Author: Alexey Kuznetsov, <kuznet@ms2.inr.ac.ru>
45 * Alignment and value checking mods by Craig Metz
5
- *
6
- * This program is free software; you can redistribute it and/or
7
- * modify it under the terms of the GNU General Public License
8
- * as published by the Free Software Foundation; either version
9
- * 2 of the License, or (at your option) any later version.
106 */
117
128 #include <linux/module.h>
....@@ -29,6 +25,7 @@
2925 #include <linux/pid.h>
3026 #include <linux/nsproxy.h>
3127 #include <linux/slab.h>
28
+#include <linux/errqueue.h>
3229
3330 #include <linux/uaccess.h>
3431
....@@ -215,16 +212,12 @@
215212
216213 int put_cmsg(struct msghdr * msg, int level, int type, int len, void *data)
217214 {
218
- struct cmsghdr __user *cm
219
- = (__force struct cmsghdr __user *)msg->msg_control;
220
- struct cmsghdr cmhdr;
221215 int cmlen = CMSG_LEN(len);
222
- int err;
223216
224
- if (MSG_CMSG_COMPAT & msg->msg_flags)
217
+ if (msg->msg_flags & MSG_CMSG_COMPAT)
225218 return put_cmsg_compat(msg, level, type, len, data);
226219
227
- if (cm==NULL || msg->msg_controllen < sizeof(*cm)) {
220
+ if (!msg->msg_control || msg->msg_controllen < sizeof(struct cmsghdr)) {
228221 msg->msg_flags |= MSG_CTRUNC;
229222 return 0; /* XXX: return error? check spec. */
230223 }
....@@ -232,98 +225,115 @@
232225 msg->msg_flags |= MSG_CTRUNC;
233226 cmlen = msg->msg_controllen;
234227 }
235
- cmhdr.cmsg_level = level;
236
- cmhdr.cmsg_type = type;
237
- cmhdr.cmsg_len = cmlen;
238228
239
- err = -EFAULT;
240
- if (copy_to_user(cm, &cmhdr, sizeof cmhdr))
241
- goto out;
242
- if (copy_to_user(CMSG_DATA(cm), data, cmlen - sizeof(struct cmsghdr)))
243
- goto out;
244
- cmlen = CMSG_SPACE(len);
245
- if (msg->msg_controllen < cmlen)
246
- cmlen = msg->msg_controllen;
229
+ if (msg->msg_control_is_user) {
230
+ struct cmsghdr __user *cm = msg->msg_control_user;
231
+ struct cmsghdr cmhdr;
232
+
233
+ cmhdr.cmsg_level = level;
234
+ cmhdr.cmsg_type = type;
235
+ cmhdr.cmsg_len = cmlen;
236
+ if (copy_to_user(cm, &cmhdr, sizeof cmhdr) ||
237
+ copy_to_user(CMSG_USER_DATA(cm), data, cmlen - sizeof(*cm)))
238
+ return -EFAULT;
239
+ } else {
240
+ struct cmsghdr *cm = msg->msg_control;
241
+
242
+ cm->cmsg_level = level;
243
+ cm->cmsg_type = type;
244
+ cm->cmsg_len = cmlen;
245
+ memcpy(CMSG_DATA(cm), data, cmlen - sizeof(*cm));
246
+ }
247
+
248
+ cmlen = min(CMSG_SPACE(len), msg->msg_controllen);
247249 msg->msg_control += cmlen;
248250 msg->msg_controllen -= cmlen;
249
- err = 0;
250
-out:
251
- return err;
251
+ return 0;
252252 }
253253 EXPORT_SYMBOL(put_cmsg);
254254
255
+void put_cmsg_scm_timestamping64(struct msghdr *msg, struct scm_timestamping_internal *tss_internal)
256
+{
257
+ struct scm_timestamping64 tss;
258
+ int i;
259
+
260
+ for (i = 0; i < ARRAY_SIZE(tss.ts); i++) {
261
+ tss.ts[i].tv_sec = tss_internal->ts[i].tv_sec;
262
+ tss.ts[i].tv_nsec = tss_internal->ts[i].tv_nsec;
263
+ }
264
+
265
+ put_cmsg(msg, SOL_SOCKET, SO_TIMESTAMPING_NEW, sizeof(tss), &tss);
266
+}
267
+EXPORT_SYMBOL(put_cmsg_scm_timestamping64);
268
+
269
+void put_cmsg_scm_timestamping(struct msghdr *msg, struct scm_timestamping_internal *tss_internal)
270
+{
271
+ struct scm_timestamping tss;
272
+ int i;
273
+
274
+ for (i = 0; i < ARRAY_SIZE(tss.ts); i++) {
275
+ tss.ts[i].tv_sec = tss_internal->ts[i].tv_sec;
276
+ tss.ts[i].tv_nsec = tss_internal->ts[i].tv_nsec;
277
+ }
278
+
279
+ put_cmsg(msg, SOL_SOCKET, SO_TIMESTAMPING_OLD, sizeof(tss), &tss);
280
+}
281
+EXPORT_SYMBOL(put_cmsg_scm_timestamping);
282
+
283
+static int scm_max_fds(struct msghdr *msg)
284
+{
285
+ if (msg->msg_controllen <= sizeof(struct cmsghdr))
286
+ return 0;
287
+ return (msg->msg_controllen - sizeof(struct cmsghdr)) / sizeof(int);
288
+}
289
+
255290 void scm_detach_fds(struct msghdr *msg, struct scm_cookie *scm)
256291 {
257
- struct cmsghdr __user *cm
258
- = (__force struct cmsghdr __user*)msg->msg_control;
259
-
260
- int fdmax = 0;
261
- int fdnum = scm->fp->count;
262
- struct file **fp = scm->fp->fp;
263
- int __user *cmfptr;
292
+ struct cmsghdr __user *cm =
293
+ (__force struct cmsghdr __user *)msg->msg_control;
294
+ unsigned int o_flags = (msg->msg_flags & MSG_CMSG_CLOEXEC) ? O_CLOEXEC : 0;
295
+ int fdmax = min_t(int, scm_max_fds(msg), scm->fp->count);
296
+ int __user *cmsg_data = CMSG_USER_DATA(cm);
264297 int err = 0, i;
265298
266
- if (MSG_CMSG_COMPAT & msg->msg_flags) {
299
+ /* no use for FD passing from kernel space callers */
300
+ if (WARN_ON_ONCE(!msg->msg_control_is_user))
301
+ return;
302
+
303
+ if (msg->msg_flags & MSG_CMSG_COMPAT) {
267304 scm_detach_fds_compat(msg, scm);
268305 return;
269306 }
270307
271
- if (msg->msg_controllen > sizeof(struct cmsghdr))
272
- fdmax = ((msg->msg_controllen - sizeof(struct cmsghdr))
273
- / sizeof(int));
274
-
275
- if (fdnum < fdmax)
276
- fdmax = fdnum;
277
-
278
- for (i=0, cmfptr=(__force int __user *)CMSG_DATA(cm); i<fdmax;
279
- i++, cmfptr++)
280
- {
281
- struct socket *sock;
282
- int new_fd;
283
- err = security_file_receive(fp[i]);
284
- if (err)
285
- break;
286
- err = get_unused_fd_flags(MSG_CMSG_CLOEXEC & msg->msg_flags
287
- ? O_CLOEXEC : 0);
308
+ for (i = 0; i < fdmax; i++) {
309
+ err = receive_fd_user(scm->fp->fp[i], cmsg_data + i, o_flags);
288310 if (err < 0)
289311 break;
290
- new_fd = err;
291
- err = put_user(new_fd, cmfptr);
292
- if (err) {
293
- put_unused_fd(new_fd);
294
- break;
295
- }
296
- /* Bump the usage count and install the file. */
297
- sock = sock_from_file(fp[i], &err);
298
- if (sock) {
299
- sock_update_netprioidx(&sock->sk->sk_cgrp_data);
300
- sock_update_classid(&sock->sk->sk_cgrp_data);
301
- }
302
- fd_install(new_fd, get_file(fp[i]));
303312 }
304313
305
- if (i > 0)
306
- {
307
- int cmlen = CMSG_LEN(i*sizeof(int));
314
+ if (i > 0) {
315
+ int cmlen = CMSG_LEN(i * sizeof(int));
316
+
308317 err = put_user(SOL_SOCKET, &cm->cmsg_level);
309318 if (!err)
310319 err = put_user(SCM_RIGHTS, &cm->cmsg_type);
311320 if (!err)
312321 err = put_user(cmlen, &cm->cmsg_len);
313322 if (!err) {
314
- cmlen = CMSG_SPACE(i*sizeof(int));
323
+ cmlen = CMSG_SPACE(i * sizeof(int));
315324 if (msg->msg_controllen < cmlen)
316325 cmlen = msg->msg_controllen;
317326 msg->msg_control += cmlen;
318327 msg->msg_controllen -= cmlen;
319328 }
320329 }
321
- if (i < fdnum || (fdnum && fdmax <= 0))
330
+
331
+ if (i < scm->fp->count || (scm->fp->count && fdmax <= 0))
322332 msg->msg_flags |= MSG_CTRUNC;
323333
324334 /*
325
- * All of the files that fit in the message have had their
326
- * usage counts incremented, so we just free the list.
335
+ * All of the files that fit in the message have had their usage counts
336
+ * incremented, so we just free the list.
327337 */
328338 __scm_destroy(scm);
329339 }