12874c5fdSThomas Gleixner // SPDX-License-Identifier: GPL-2.0-or-later 21da177e4SLinus Torvalds /* scm.c - Socket level control messages processing. 31da177e4SLinus Torvalds * 41da177e4SLinus Torvalds * Author: Alexey Kuznetsov, <kuznet@ms2.inr.ac.ru> 51da177e4SLinus Torvalds * Alignment and value checking mods by Craig Metz 61da177e4SLinus Torvalds */ 71da177e4SLinus Torvalds 81da177e4SLinus Torvalds #include <linux/module.h> 91da177e4SLinus Torvalds #include <linux/signal.h> 104fc268d2SRandy Dunlap #include <linux/capability.h> 111da177e4SLinus Torvalds #include <linux/errno.h> 121da177e4SLinus Torvalds #include <linux/sched.h> 138703e8a4SIngo Molnar #include <linux/sched/user.h> 141da177e4SLinus Torvalds #include <linux/mm.h> 151da177e4SLinus Torvalds #include <linux/kernel.h> 161da177e4SLinus Torvalds #include <linux/stat.h> 171da177e4SLinus Torvalds #include <linux/socket.h> 181da177e4SLinus Torvalds #include <linux/file.h> 191da177e4SLinus Torvalds #include <linux/fcntl.h> 201da177e4SLinus Torvalds #include <linux/net.h> 211da177e4SLinus Torvalds #include <linux/interrupt.h> 221da177e4SLinus Torvalds #include <linux/netdevice.h> 231da177e4SLinus Torvalds #include <linux/security.h> 2492f28d97SEric W. Biederman #include <linux/pid_namespace.h> 25b488893aSPavel Emelyanov #include <linux/pid.h> 26b488893aSPavel Emelyanov #include <linux/nsproxy.h> 275a0e3ad6STejun Heo #include <linux/slab.h> 289718475eSDeepa Dinamani #include <linux/errqueue.h> 295a33d385SPavel Begunkov #include <linux/io_uring.h> 301da177e4SLinus Torvalds 317c0f6ba6SLinus Torvalds #include <linux/uaccess.h> 321da177e4SLinus Torvalds 331da177e4SLinus Torvalds #include <net/protocol.h> 341da177e4SLinus Torvalds #include <linux/skbuff.h> 351da177e4SLinus Torvalds #include <net/sock.h> 361da177e4SLinus Torvalds #include <net/compat.h> 371da177e4SLinus Torvalds #include <net/scm.h> 38d8429506SDaniel Wagner #include <net/cls_cgroup.h> 391da177e4SLinus Torvalds 401da177e4SLinus Torvalds 411da177e4SLinus Torvalds /* 421da177e4SLinus Torvalds * Only allow a user to send credentials, that they could set with 431da177e4SLinus Torvalds * setu(g)id. 441da177e4SLinus Torvalds */ 451da177e4SLinus Torvalds 461da177e4SLinus Torvalds static __inline__ int scm_check_creds(struct ucred *creds) 471da177e4SLinus Torvalds { 4886a264abSDavid Howells const struct cred *cred = current_cred(); 49b2e4f544SEric W. Biederman kuid_t uid = make_kuid(cred->user_ns, creds->uid); 50b2e4f544SEric W. Biederman kgid_t gid = make_kgid(cred->user_ns, creds->gid); 51b2e4f544SEric W. Biederman 52b2e4f544SEric W. Biederman if (!uid_valid(uid) || !gid_valid(gid)) 53b2e4f544SEric W. Biederman return -EINVAL; 54b6dff3ecSDavid Howells 5592f28d97SEric W. Biederman if ((creds->pid == task_tgid_vnr(current) || 56d661684cSAndy Lutomirski ns_capable(task_active_pid_ns(current)->user_ns, CAP_SYS_ADMIN)) && 57b2e4f544SEric W. Biederman ((uid_eq(uid, cred->uid) || uid_eq(uid, cred->euid) || 58c7b96acfSEric W. Biederman uid_eq(uid, cred->suid)) || ns_capable(cred->user_ns, CAP_SETUID)) && 59b2e4f544SEric W. Biederman ((gid_eq(gid, cred->gid) || gid_eq(gid, cred->egid) || 60c7b96acfSEric W. Biederman gid_eq(gid, cred->sgid)) || ns_capable(cred->user_ns, CAP_SETGID))) { 611da177e4SLinus Torvalds return 0; 621da177e4SLinus Torvalds } 631da177e4SLinus Torvalds return -EPERM; 641da177e4SLinus Torvalds } 651da177e4SLinus Torvalds 661da177e4SLinus Torvalds static int scm_fp_copy(struct cmsghdr *cmsg, struct scm_fp_list **fplp) 671da177e4SLinus Torvalds { 681da177e4SLinus Torvalds int *fdp = (int*)CMSG_DATA(cmsg); 691da177e4SLinus Torvalds struct scm_fp_list *fpl = *fplp; 701da177e4SLinus Torvalds struct file **fpp; 711da177e4SLinus Torvalds int i, num; 721da177e4SLinus Torvalds 731ff8cebfSyuan linyu num = (cmsg->cmsg_len - sizeof(struct cmsghdr))/sizeof(int); 741da177e4SLinus Torvalds 751da177e4SLinus Torvalds if (num <= 0) 761da177e4SLinus Torvalds return 0; 771da177e4SLinus Torvalds 781da177e4SLinus Torvalds if (num > SCM_MAX_FD) 791da177e4SLinus Torvalds return -EINVAL; 801da177e4SLinus Torvalds 811da177e4SLinus Torvalds if (!fpl) 821da177e4SLinus Torvalds { 832c6ad20bSVasily Averin fpl = kmalloc(sizeof(struct scm_fp_list), GFP_KERNEL_ACCOUNT); 841da177e4SLinus Torvalds if (!fpl) 851da177e4SLinus Torvalds return -ENOMEM; 861da177e4SLinus Torvalds *fplp = fpl; 871da177e4SLinus Torvalds fpl->count = 0; 88bba14de9SEric Dumazet fpl->max = SCM_MAX_FD; 89415e3d3eSHannes Frederic Sowa fpl->user = NULL; 901da177e4SLinus Torvalds } 911da177e4SLinus Torvalds fpp = &fpl->fp[fpl->count]; 921da177e4SLinus Torvalds 93bba14de9SEric Dumazet if (fpl->count + num > fpl->max) 941da177e4SLinus Torvalds return -EINVAL; 951da177e4SLinus Torvalds 961da177e4SLinus Torvalds /* 971da177e4SLinus Torvalds * Verify the descriptors and increment the usage count. 981da177e4SLinus Torvalds */ 991da177e4SLinus Torvalds 1001da177e4SLinus Torvalds for (i=0; i< num; i++) 1011da177e4SLinus Torvalds { 1021da177e4SLinus Torvalds int fd = fdp[i]; 1031da177e4SLinus Torvalds struct file *file; 1041da177e4SLinus Torvalds 105326be7b4SAl Viro if (fd < 0 || !(file = fget_raw(fd))) 1061da177e4SLinus Torvalds return -EBADF; 1075a33d385SPavel Begunkov /* don't allow io_uring files */ 108*303c0a13SJens Axboe if (io_is_uring_fops(file)) { 1095a33d385SPavel Begunkov fput(file); 1105a33d385SPavel Begunkov return -EINVAL; 1115a33d385SPavel Begunkov } 1121da177e4SLinus Torvalds *fpp++ = file; 1131da177e4SLinus Torvalds fpl->count++; 1141da177e4SLinus Torvalds } 115415e3d3eSHannes Frederic Sowa 116415e3d3eSHannes Frederic Sowa if (!fpl->user) 117415e3d3eSHannes Frederic Sowa fpl->user = get_uid(current_user()); 118415e3d3eSHannes Frederic Sowa 1191da177e4SLinus Torvalds return num; 1201da177e4SLinus Torvalds } 1211da177e4SLinus Torvalds 1221da177e4SLinus Torvalds void __scm_destroy(struct scm_cookie *scm) 1231da177e4SLinus Torvalds { 1241da177e4SLinus Torvalds struct scm_fp_list *fpl = scm->fp; 1251da177e4SLinus Torvalds int i; 1261da177e4SLinus Torvalds 1271da177e4SLinus Torvalds if (fpl) { 1281da177e4SLinus Torvalds scm->fp = NULL; 1291da177e4SLinus Torvalds for (i=fpl->count-1; i>=0; i--) 1301da177e4SLinus Torvalds fput(fpl->fp[i]); 131415e3d3eSHannes Frederic Sowa free_uid(fpl->user); 1321da177e4SLinus Torvalds kfree(fpl); 1331da177e4SLinus Torvalds } 1341da177e4SLinus Torvalds } 1359e34a5b5SEric Dumazet EXPORT_SYMBOL(__scm_destroy); 1361da177e4SLinus Torvalds 1371da177e4SLinus Torvalds int __scm_send(struct socket *sock, struct msghdr *msg, struct scm_cookie *p) 1381da177e4SLinus Torvalds { 1391ded5e5aSEric Dumazet const struct proto_ops *ops = READ_ONCE(sock->ops); 1401da177e4SLinus Torvalds struct cmsghdr *cmsg; 1411da177e4SLinus Torvalds int err; 1421da177e4SLinus Torvalds 143f95b414eSGu Zheng for_each_cmsghdr(cmsg, msg) { 1441da177e4SLinus Torvalds err = -EINVAL; 1451da177e4SLinus Torvalds 1461da177e4SLinus Torvalds /* Verify that cmsg_len is at least sizeof(struct cmsghdr) */ 1471da177e4SLinus Torvalds /* The first check was omitted in <= 2.2.5. The reasoning was 1481da177e4SLinus Torvalds that parser checks cmsg_len in any case, so that 1491da177e4SLinus Torvalds additional check would be work duplication. 1501da177e4SLinus Torvalds But if cmsg_level is not SOL_SOCKET, we do not check 1511da177e4SLinus Torvalds for too short ancillary data object at all! Oops. 1521da177e4SLinus Torvalds OK, let's add it... 1531da177e4SLinus Torvalds */ 1541da177e4SLinus Torvalds if (!CMSG_OK(msg, cmsg)) 1551da177e4SLinus Torvalds goto error; 1561da177e4SLinus Torvalds 1571da177e4SLinus Torvalds if (cmsg->cmsg_level != SOL_SOCKET) 1581da177e4SLinus Torvalds continue; 1591da177e4SLinus Torvalds 1601da177e4SLinus Torvalds switch (cmsg->cmsg_type) 1611da177e4SLinus Torvalds { 1621da177e4SLinus Torvalds case SCM_RIGHTS: 1631ded5e5aSEric Dumazet if (!ops || ops->family != PF_UNIX) 16476dadd76SEric W. Biederman goto error; 1651da177e4SLinus Torvalds err=scm_fp_copy(cmsg, &p->fp); 1661da177e4SLinus Torvalds if (err<0) 1671da177e4SLinus Torvalds goto error; 1681da177e4SLinus Torvalds break; 1691da177e4SLinus Torvalds case SCM_CREDENTIALS: 170b2e4f544SEric W. Biederman { 171dbe9a417SEric W. Biederman struct ucred creds; 172b2e4f544SEric W. Biederman kuid_t uid; 173b2e4f544SEric W. Biederman kgid_t gid; 1741da177e4SLinus Torvalds if (cmsg->cmsg_len != CMSG_LEN(sizeof(struct ucred))) 1751da177e4SLinus Torvalds goto error; 176dbe9a417SEric W. Biederman memcpy(&creds, CMSG_DATA(cmsg), sizeof(struct ucred)); 177dbe9a417SEric W. Biederman err = scm_check_creds(&creds); 1781da177e4SLinus Torvalds if (err) 1791da177e4SLinus Torvalds goto error; 180257b5358SEric W. Biederman 181dbe9a417SEric W. Biederman p->creds.pid = creds.pid; 182dbe9a417SEric W. Biederman if (!p->pid || pid_vnr(p->pid) != creds.pid) { 183257b5358SEric W. Biederman struct pid *pid; 184257b5358SEric W. Biederman err = -ESRCH; 185dbe9a417SEric W. Biederman pid = find_get_pid(creds.pid); 186257b5358SEric W. Biederman if (!pid) 187257b5358SEric W. Biederman goto error; 188257b5358SEric W. Biederman put_pid(p->pid); 189257b5358SEric W. Biederman p->pid = pid; 190257b5358SEric W. Biederman } 191257b5358SEric W. Biederman 192b2e4f544SEric W. Biederman err = -EINVAL; 193dbe9a417SEric W. Biederman uid = make_kuid(current_user_ns(), creds.uid); 194dbe9a417SEric W. Biederman gid = make_kgid(current_user_ns(), creds.gid); 195b2e4f544SEric W. Biederman if (!uid_valid(uid) || !gid_valid(gid)) 196b2e4f544SEric W. Biederman goto error; 197b2e4f544SEric W. Biederman 198dbe9a417SEric W. Biederman p->creds.uid = uid; 199dbe9a417SEric W. Biederman p->creds.gid = gid; 2001da177e4SLinus Torvalds break; 201b2e4f544SEric W. Biederman } 2021da177e4SLinus Torvalds default: 2031da177e4SLinus Torvalds goto error; 2041da177e4SLinus Torvalds } 2051da177e4SLinus Torvalds } 2061da177e4SLinus Torvalds 2071da177e4SLinus Torvalds if (p->fp && !p->fp->count) 2081da177e4SLinus Torvalds { 2091da177e4SLinus Torvalds kfree(p->fp); 2101da177e4SLinus Torvalds p->fp = NULL; 2111da177e4SLinus Torvalds } 2121da177e4SLinus Torvalds return 0; 2131da177e4SLinus Torvalds 2141da177e4SLinus Torvalds error: 2151da177e4SLinus Torvalds scm_destroy(p); 2161da177e4SLinus Torvalds return err; 2171da177e4SLinus Torvalds } 2189e34a5b5SEric Dumazet EXPORT_SYMBOL(__scm_send); 2191da177e4SLinus Torvalds 2201da177e4SLinus Torvalds int put_cmsg(struct msghdr * msg, int level, int type, int len, void *data) 2211da177e4SLinus Torvalds { 2221da177e4SLinus Torvalds int cmlen = CMSG_LEN(len); 2231da177e4SLinus Torvalds 2241f466e1fSChristoph Hellwig if (msg->msg_flags & MSG_CMSG_COMPAT) 2251da177e4SLinus Torvalds return put_cmsg_compat(msg, level, type, len, data); 2261da177e4SLinus Torvalds 2271f466e1fSChristoph Hellwig if (!msg->msg_control || msg->msg_controllen < sizeof(struct cmsghdr)) { 2281da177e4SLinus Torvalds msg->msg_flags |= MSG_CTRUNC; 2291da177e4SLinus Torvalds return 0; /* XXX: return error? check spec. */ 2301da177e4SLinus Torvalds } 2311da177e4SLinus Torvalds if (msg->msg_controllen < cmlen) { 2321da177e4SLinus Torvalds msg->msg_flags |= MSG_CTRUNC; 2331da177e4SLinus Torvalds cmlen = msg->msg_controllen; 2341da177e4SLinus Torvalds } 2351f466e1fSChristoph Hellwig 2361f466e1fSChristoph Hellwig if (msg->msg_control_is_user) { 2371f466e1fSChristoph Hellwig struct cmsghdr __user *cm = msg->msg_control_user; 2381f466e1fSChristoph Hellwig 2395f1eb1ffSEric Dumazet check_object_size(data, cmlen - sizeof(*cm), true); 2405f1eb1ffSEric Dumazet 24138ebcf50SEric Dumazet if (!user_write_access_begin(cm, cmlen)) 24238ebcf50SEric Dumazet goto efault; 24338ebcf50SEric Dumazet 244e7ad33faSEric Dumazet unsafe_put_user(cmlen, &cm->cmsg_len, efault_end); 24538ebcf50SEric Dumazet unsafe_put_user(level, &cm->cmsg_level, efault_end); 24638ebcf50SEric Dumazet unsafe_put_user(type, &cm->cmsg_type, efault_end); 24738ebcf50SEric Dumazet unsafe_copy_to_user(CMSG_USER_DATA(cm), data, 24838ebcf50SEric Dumazet cmlen - sizeof(*cm), efault_end); 24938ebcf50SEric Dumazet user_write_access_end(); 2501f466e1fSChristoph Hellwig } else { 2511f466e1fSChristoph Hellwig struct cmsghdr *cm = msg->msg_control; 2521da177e4SLinus Torvalds 2531f466e1fSChristoph Hellwig cm->cmsg_level = level; 2541f466e1fSChristoph Hellwig cm->cmsg_type = type; 2551f466e1fSChristoph Hellwig cm->cmsg_len = cmlen; 2561f466e1fSChristoph Hellwig memcpy(CMSG_DATA(cm), data, cmlen - sizeof(*cm)); 2571f466e1fSChristoph Hellwig } 2581f466e1fSChristoph Hellwig 2591f466e1fSChristoph Hellwig cmlen = min(CMSG_SPACE(len), msg->msg_controllen); 260c39ef213SKevin Brodsky if (msg->msg_control_is_user) 261c39ef213SKevin Brodsky msg->msg_control_user += cmlen; 262c39ef213SKevin Brodsky else 2631da177e4SLinus Torvalds msg->msg_control += cmlen; 2641da177e4SLinus Torvalds msg->msg_controllen -= cmlen; 2651f466e1fSChristoph Hellwig return 0; 26638ebcf50SEric Dumazet 26738ebcf50SEric Dumazet efault_end: 26838ebcf50SEric Dumazet user_write_access_end(); 26938ebcf50SEric Dumazet efault: 27038ebcf50SEric Dumazet return -EFAULT; 2711da177e4SLinus Torvalds } 2729e34a5b5SEric Dumazet EXPORT_SYMBOL(put_cmsg); 2731da177e4SLinus Torvalds 2749718475eSDeepa Dinamani void put_cmsg_scm_timestamping64(struct msghdr *msg, struct scm_timestamping_internal *tss_internal) 2759718475eSDeepa Dinamani { 2769718475eSDeepa Dinamani struct scm_timestamping64 tss; 2779718475eSDeepa Dinamani int i; 2789718475eSDeepa Dinamani 2799718475eSDeepa Dinamani for (i = 0; i < ARRAY_SIZE(tss.ts); i++) { 2809718475eSDeepa Dinamani tss.ts[i].tv_sec = tss_internal->ts[i].tv_sec; 2819718475eSDeepa Dinamani tss.ts[i].tv_nsec = tss_internal->ts[i].tv_nsec; 2829718475eSDeepa Dinamani } 2839718475eSDeepa Dinamani 2849718475eSDeepa Dinamani put_cmsg(msg, SOL_SOCKET, SO_TIMESTAMPING_NEW, sizeof(tss), &tss); 2859718475eSDeepa Dinamani } 2869718475eSDeepa Dinamani EXPORT_SYMBOL(put_cmsg_scm_timestamping64); 2879718475eSDeepa Dinamani 2889718475eSDeepa Dinamani void put_cmsg_scm_timestamping(struct msghdr *msg, struct scm_timestamping_internal *tss_internal) 2899718475eSDeepa Dinamani { 2909718475eSDeepa Dinamani struct scm_timestamping tss; 2919718475eSDeepa Dinamani int i; 2929718475eSDeepa Dinamani 2930309f98fSArnd Bergmann for (i = 0; i < ARRAY_SIZE(tss.ts); i++) { 2940309f98fSArnd Bergmann tss.ts[i].tv_sec = tss_internal->ts[i].tv_sec; 2950309f98fSArnd Bergmann tss.ts[i].tv_nsec = tss_internal->ts[i].tv_nsec; 2960309f98fSArnd Bergmann } 2979718475eSDeepa Dinamani 2989718475eSDeepa Dinamani put_cmsg(msg, SOL_SOCKET, SO_TIMESTAMPING_OLD, sizeof(tss), &tss); 2999718475eSDeepa Dinamani } 3009718475eSDeepa Dinamani EXPORT_SYMBOL(put_cmsg_scm_timestamping); 3019718475eSDeepa Dinamani 3022618d530SChristoph Hellwig static int scm_max_fds(struct msghdr *msg) 3031da177e4SLinus Torvalds { 3042618d530SChristoph Hellwig if (msg->msg_controllen <= sizeof(struct cmsghdr)) 3052618d530SChristoph Hellwig return 0; 3062618d530SChristoph Hellwig return (msg->msg_controllen - sizeof(struct cmsghdr)) / sizeof(int); 3072618d530SChristoph Hellwig } 3082618d530SChristoph Hellwig 3092618d530SChristoph Hellwig void scm_detach_fds(struct msghdr *msg, struct scm_cookie *scm) 3102618d530SChristoph Hellwig { 311c0029de5SKees Cook struct cmsghdr __user *cm = 312c39ef213SKevin Brodsky (__force struct cmsghdr __user *)msg->msg_control_user; 313c0029de5SKees Cook unsigned int o_flags = (msg->msg_flags & MSG_CMSG_CLOEXEC) ? O_CLOEXEC : 0; 3142618d530SChristoph Hellwig int fdmax = min_t(int, scm_max_fds(msg), scm->fp->count); 3152618d530SChristoph Hellwig int __user *cmsg_data = CMSG_USER_DATA(cm); 3162618d530SChristoph Hellwig int err = 0, i; 3172618d530SChristoph Hellwig 318c0029de5SKees Cook /* no use for FD passing from kernel space callers */ 319c0029de5SKees Cook if (WARN_ON_ONCE(!msg->msg_control_is_user)) 320c0029de5SKees Cook return; 321c0029de5SKees Cook 3222618d530SChristoph Hellwig if (msg->msg_flags & MSG_CMSG_COMPAT) { 3232618d530SChristoph Hellwig scm_detach_fds_compat(msg, scm); 3242618d530SChristoph Hellwig return; 3252618d530SChristoph Hellwig } 3262618d530SChristoph Hellwig 3272618d530SChristoph Hellwig for (i = 0; i < fdmax; i++) { 32866590610SKees Cook err = receive_fd_user(scm->fp->fp[i], cmsg_data + i, o_flags); 329deefa7f3SKees Cook if (err < 0) 3302618d530SChristoph Hellwig break; 3312618d530SChristoph Hellwig } 3322618d530SChristoph Hellwig 3332618d530SChristoph Hellwig if (i > 0) { 3341da177e4SLinus Torvalds int cmlen = CMSG_LEN(i * sizeof(int)); 3352618d530SChristoph Hellwig 3361da177e4SLinus Torvalds err = put_user(SOL_SOCKET, &cm->cmsg_level); 3371da177e4SLinus Torvalds if (!err) 3381da177e4SLinus Torvalds err = put_user(SCM_RIGHTS, &cm->cmsg_type); 3391da177e4SLinus Torvalds if (!err) 3401da177e4SLinus Torvalds err = put_user(cmlen, &cm->cmsg_len); 3411da177e4SLinus Torvalds if (!err) { 3421da177e4SLinus Torvalds cmlen = CMSG_SPACE(i * sizeof(int)); 3436900317fSDaniel Borkmann if (msg->msg_controllen < cmlen) 3446900317fSDaniel Borkmann cmlen = msg->msg_controllen; 345c39ef213SKevin Brodsky msg->msg_control_user += cmlen; 3461da177e4SLinus Torvalds msg->msg_controllen -= cmlen; 3471da177e4SLinus Torvalds } 3481da177e4SLinus Torvalds } 3492618d530SChristoph Hellwig 3502618d530SChristoph Hellwig if (i < scm->fp->count || (scm->fp->count && fdmax <= 0)) 3511da177e4SLinus Torvalds msg->msg_flags |= MSG_CTRUNC; 3521da177e4SLinus Torvalds 3531da177e4SLinus Torvalds /* 3542618d530SChristoph Hellwig * All of the files that fit in the message have had their usage counts 3552618d530SChristoph Hellwig * incremented, so we just free the list. 3561da177e4SLinus Torvalds */ 3571da177e4SLinus Torvalds __scm_destroy(scm); 3581da177e4SLinus Torvalds } 3599e34a5b5SEric Dumazet EXPORT_SYMBOL(scm_detach_fds); 3601da177e4SLinus Torvalds 3611da177e4SLinus Torvalds struct scm_fp_list *scm_fp_dup(struct scm_fp_list *fpl) 3621da177e4SLinus Torvalds { 3631da177e4SLinus Torvalds struct scm_fp_list *new_fpl; 3641da177e4SLinus Torvalds int i; 3651da177e4SLinus Torvalds 3661da177e4SLinus Torvalds if (!fpl) 3671da177e4SLinus Torvalds return NULL; 3681da177e4SLinus Torvalds 369bba14de9SEric Dumazet new_fpl = kmemdup(fpl, offsetof(struct scm_fp_list, fp[fpl->count]), 3702c6ad20bSVasily Averin GFP_KERNEL_ACCOUNT); 3711da177e4SLinus Torvalds if (new_fpl) { 372bba14de9SEric Dumazet for (i = 0; i < fpl->count; i++) 3731da177e4SLinus Torvalds get_file(fpl->fp[i]); 374bba14de9SEric Dumazet new_fpl->max = new_fpl->count; 375415e3d3eSHannes Frederic Sowa new_fpl->user = get_uid(fpl->user); 3761da177e4SLinus Torvalds } 3771da177e4SLinus Torvalds return new_fpl; 3781da177e4SLinus Torvalds } 3791da177e4SLinus Torvalds EXPORT_SYMBOL(scm_fp_dup); 380