~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~ [ freetext search ] ~ [ file search ] ~

Linux Cross Reference
Linux/net/core/scm.c

Version: ~ [ 2.4.0 ] ~
Architecture: ~ [ i386 ] ~ [ alpha ] ~ [ m68k ] ~ [ mips ] ~ [ ppc ] ~ [ sparc ] ~ [ sparc64 ] ~

  1 /* scm.c - Socket level control messages processing.
  2  *
  3  * Author:      Alexey Kuznetsov, <kuznet@ms2.inr.ac.ru>
  4  *              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.
 10  */
 11 
 12 #include <linux/signal.h>
 13 #include <linux/errno.h>
 14 #include <linux/sched.h>
 15 #include <linux/mm.h>
 16 #include <linux/kernel.h>
 17 #include <linux/major.h>
 18 #include <linux/stat.h>
 19 #include <linux/socket.h>
 20 #include <linux/file.h>
 21 #include <linux/fcntl.h>
 22 #include <linux/net.h>
 23 #include <linux/interrupt.h>
 24 #include <linux/netdevice.h>
 25 
 26 #include <asm/system.h>
 27 #include <asm/uaccess.h>
 28 
 29 #include <linux/inet.h>
 30 #include <net/ip.h>
 31 #include <net/protocol.h>
 32 #include <net/tcp.h>
 33 #include <net/udp.h>
 34 #include <linux/skbuff.h>
 35 #include <net/sock.h>
 36 #include <net/scm.h>
 37 
 38 
 39 /*
 40  *      Only allow a user to send credentials, that they could set with 
 41  *      setu(g)id.
 42  */
 43 
 44 static __inline__ int scm_check_creds(struct ucred *creds)
 45 {
 46         if ((creds->pid == current->pid || capable(CAP_SYS_ADMIN)) &&
 47             ((creds->uid == current->uid || creds->uid == current->euid ||
 48               creds->uid == current->suid) || capable(CAP_SETUID)) &&
 49             ((creds->gid == current->gid || creds->gid == current->egid ||
 50               creds->gid == current->sgid) || capable(CAP_SETGID))) {
 51                return 0;
 52         }
 53         return -EPERM;
 54 }
 55 
 56 static int scm_fp_copy(struct cmsghdr *cmsg, struct scm_fp_list **fplp)
 57 {
 58         int *fdp = (int*)CMSG_DATA(cmsg);
 59         struct scm_fp_list *fpl = *fplp;
 60         struct file **fpp;
 61         int i, num;
 62 
 63         num = (cmsg->cmsg_len - CMSG_ALIGN(sizeof(struct cmsghdr)))/sizeof(int);
 64 
 65         if (num <= 0)
 66                 return 0;
 67 
 68         if (num > SCM_MAX_FD)
 69                 return -EINVAL;
 70 
 71         if (!fpl)
 72         {
 73                 fpl = kmalloc(sizeof(struct scm_fp_list), GFP_KERNEL);
 74                 if (!fpl)
 75                         return -ENOMEM;
 76                 *fplp = fpl;
 77                 fpl->count = 0;
 78         }
 79         fpp = &fpl->fp[fpl->count];
 80 
 81         if (fpl->count + num > SCM_MAX_FD)
 82                 return -EINVAL;
 83         
 84         /*
 85          *      Verify the descriptors and increment the usage count.
 86          */
 87          
 88         for (i=0; i< num; i++)
 89         {
 90                 int fd = fdp[i];
 91                 struct file *file;
 92 
 93                 if (fd < 0 || !(file = fget(fd)))
 94                         return -EBADF;
 95                 *fpp++ = file;
 96                 fpl->count++;
 97         }
 98         return num;
 99 }
100 
101 void __scm_destroy(struct scm_cookie *scm)
102 {
103         struct scm_fp_list *fpl = scm->fp;
104         int i;
105 
106         if (fpl) {
107                 scm->fp = NULL;
108                 for (i=fpl->count-1; i>=0; i--)
109                         fput(fpl->fp[i]);
110                 kfree(fpl);
111         }
112 }
113 
114 int __scm_send(struct socket *sock, struct msghdr *msg, struct scm_cookie *p)
115 {
116         struct cmsghdr *cmsg;
117         int err;
118 
119         for (cmsg = CMSG_FIRSTHDR(msg); cmsg; cmsg = CMSG_NXTHDR(msg, cmsg))
120         {
121                 err = -EINVAL;
122 
123                 /* Verify that cmsg_len is at least sizeof(struct cmsghdr) */
124                 /* The first check was omitted in <= 2.2.5. The reasoning was
125                    that parser checks cmsg_len in any case, so that
126                    additional check would be work duplication.
127                    But if cmsg_level is not SOL_SOCKET, we do not check 
128                    for too short ancillary data object at all! Oops.
129                    OK, let's add it...
130                  */
131                 if (cmsg->cmsg_len < sizeof(struct cmsghdr) ||
132                     (unsigned long)(((char*)cmsg - (char*)msg->msg_control)
133                                     + cmsg->cmsg_len) > msg->msg_controllen)
134                         goto error;
135 
136                 if (cmsg->cmsg_level != SOL_SOCKET)
137                         continue;
138 
139                 switch (cmsg->cmsg_type)
140                 {
141                 case SCM_RIGHTS:
142                         err=scm_fp_copy(cmsg, &p->fp);
143                         if (err<0)
144                                 goto error;
145                         break;
146                 case SCM_CREDENTIALS:
147                         if (cmsg->cmsg_len != CMSG_LEN(sizeof(struct ucred)))
148                                 goto error;
149                         memcpy(&p->creds, CMSG_DATA(cmsg), sizeof(struct ucred));
150                         err = scm_check_creds(&p->creds);
151                         if (err)
152                                 goto error;
153                         break;
154                 default:
155                         goto error;
156                 }
157         }
158 
159         if (p->fp && !p->fp->count)
160         {
161                 kfree(p->fp);
162                 p->fp = NULL;
163         }
164         return 0;
165         
166 error:
167         scm_destroy(p);
168         return err;
169 }
170 
171 int put_cmsg(struct msghdr * msg, int level, int type, int len, void *data)
172 {
173         struct cmsghdr *cm = (struct cmsghdr*)msg->msg_control;
174         struct cmsghdr cmhdr;
175         int cmlen = CMSG_LEN(len);
176         int err;
177 
178         if (cm==NULL || msg->msg_controllen < sizeof(*cm)) {
179                 msg->msg_flags |= MSG_CTRUNC;
180                 return 0; /* XXX: return error? check spec. */
181         }
182         if (msg->msg_controllen < cmlen) {
183                 msg->msg_flags |= MSG_CTRUNC;
184                 cmlen = msg->msg_controllen;
185         }
186         cmhdr.cmsg_level = level;
187         cmhdr.cmsg_type = type;
188         cmhdr.cmsg_len = cmlen;
189 
190         err = -EFAULT;
191         if (copy_to_user(cm, &cmhdr, sizeof cmhdr))
192                 goto out; 
193         if (copy_to_user(CMSG_DATA(cm), data, cmlen - sizeof(struct cmsghdr)))
194                 goto out;
195         cmlen = CMSG_SPACE(len);
196         msg->msg_control += cmlen;
197         msg->msg_controllen -= cmlen;
198         err = 0;
199 out:
200         return err;
201 }
202 
203 void scm_detach_fds(struct msghdr *msg, struct scm_cookie *scm)
204 {
205         struct cmsghdr *cm = (struct cmsghdr*)msg->msg_control;
206 
207         int fdmax = 0;
208         int fdnum = scm->fp->count;
209         struct file **fp = scm->fp->fp;
210         int *cmfptr;
211         int err = 0, i;
212 
213         if (msg->msg_controllen > sizeof(struct cmsghdr))
214                 fdmax = ((msg->msg_controllen - sizeof(struct cmsghdr))
215                          / sizeof(int));
216 
217         if (fdnum < fdmax)
218                 fdmax = fdnum;
219 
220         for (i=0, cmfptr=(int*)CMSG_DATA(cm); i<fdmax; i++, cmfptr++)
221         {
222                 int new_fd;
223                 err = get_unused_fd();
224                 if (err < 0)
225                         break;
226                 new_fd = err;
227                 err = put_user(new_fd, cmfptr);
228                 if (err) {
229                         put_unused_fd(new_fd);
230                         break;
231                 }
232                 /* Bump the usage count and install the file. */
233                 get_file(fp[i]);
234                 fd_install(new_fd, fp[i]);
235         }
236 
237         if (i > 0)
238         {
239                 int cmlen = CMSG_LEN(i*sizeof(int));
240                 if (!err)
241                         err = put_user(SOL_SOCKET, &cm->cmsg_level);
242                 if (!err)
243                         err = put_user(SCM_RIGHTS, &cm->cmsg_type);
244                 if (!err)
245                         err = put_user(cmlen, &cm->cmsg_len);
246                 if (!err) {
247                         cmlen = CMSG_SPACE(i*sizeof(int));
248                         msg->msg_control += cmlen;
249                         msg->msg_controllen -= cmlen;
250                 }
251         }
252         if (i < fdnum || (fdnum && fdmax <= 0))
253                 msg->msg_flags |= MSG_CTRUNC;
254 
255         /*
256          * All of the files that fit in the message have had their
257          * usage counts incremented, so we just free the list.
258          */
259         __scm_destroy(scm);
260 }
261 
262 struct scm_fp_list *scm_fp_dup(struct scm_fp_list *fpl)
263 {
264         struct scm_fp_list *new_fpl;
265         int i;
266 
267         if (!fpl)
268                 return NULL;
269 
270         new_fpl = kmalloc(sizeof(*fpl), GFP_KERNEL);
271         if (new_fpl) {
272                 for (i=fpl->count-1; i>=0; i--)
273                         get_file(fpl->fp[i]);
274                 memcpy(new_fpl, fpl, sizeof(*fpl));
275         }
276         return new_fpl;
277 }
278 

~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~ [ freetext search ] ~ [ file search ] ~

This page was automatically generated by the LXR engine.
Visit the LXR main site for more information.