jail-fixaddr.diff

corecode, 01/17/2007 03:43 PM

Download (11.7 KB)

View differences:

sys/jail.h 17 Jan 2007 12:45:47 -0000
68 68
/* Used to store the IPs of the jail */
69 69

  
70 70
struct jail_ip_storage {
71
	SLIST_ENTRY(jail_ip_storage) entries;
72 71
	struct sockaddr_storage ip;
72
	SLIST_ENTRY(jail_ip_storage) entries;
73 73
};
74 74

  
75 75
/*
......
85 85
	struct nchandle pr_root;			/* namecache entry of root */
86 86
	char 		pr_host[MAXHOSTNAMELEN];	/* host name */
87 87
	SLIST_HEAD(iplist, jail_ip_storage) pr_ips;	/* list of IP addresses */
88
	struct sockaddr_storage	*local_ip4;		/* cache for a loopback ipv4 address */
89
	struct sockaddr_storage	*nonlocal_ip4;		/* cache for a non loopback ipv4 address */
90
	struct sockaddr_storage	*local_ip6;		/* cache for a loopback ipv6 address */
91
	struct sockaddr_storage	*nonlocal_ip6;		/* cache for a non loopback ipv6 address */
88
	struct sockaddr_in	*local_ip4;		/* cache for a loopback ipv4 address */
89
	struct sockaddr_in	*nonlocal_ip4;		/* cache for a non loopback ipv4 address */
90
	struct sockaddr_in6	*local_ip6;		/* cache for a loopback ipv6 address */
91
	struct sockaddr_in6	*nonlocal_ip6;		/* cache for a non loopback ipv6 address */
92 92
	void		*pr_linux;			/* Linux ABI emulation */
93 93
	int		 pr_securelevel;		/* jail securelevel */
94 94
	struct varsymset pr_varsymset;			/* jail varsyms */
......
105 105
void	prison_hold(struct prison *);
106 106
void	prison_free(struct prison *);
107 107
int	jailed_ip(struct prison *, struct sockaddr *);
108
int	prison_get_local(struct prison *pr, struct sockaddr *);
109
int	prison_get_nonlocal(struct prison *pr, struct sockaddr *);
108
struct sockaddr *
109
	prison_get_local(struct prison *pr, sa_family_t, struct sockaddr *);
110
struct sockaddr *
111
	prison_get_nonlocal(struct prison *pr, sa_family_t, struct sockaddr *);
110 112

  
111 113
/*
112 114
 * Return 1 if the passed credential is in a jail, otherwise 0.
kern/kern_jail.c 17 Jan 2007 12:53:16 -0000
59 59
#include <netinet6/in6_var.h>
60 60

  
61 61
static struct prison	*prison_find(int);
62
static void		prison_ipcache_init(struct prison *);
62 63

  
63 64
MALLOC_DEFINE(M_PRISON, "prison", "Prison structures");
64 65

  
......
195 196
	cache_copy(&nd.nl_nch, &pr->pr_root);
196 197

  
197 198
	varsymset_init(&pr->pr_varsymset, NULL);
199
	prison_ipcache_init(pr);
198 200

  
199 201
	tryprid = lastprid + 1;
200 202
	if (tryprid == JAIL_MAX)
......
255 257
	return(kern_jail_attach(uap->jid));
256 258
}
257 259

  
260
static void
261
prison_ipcache_init(struct prison *pr)
262
{
263
	struct jail_ip_storage *jis;
264
	struct sockaddr_in *ip4;
265
	struct sockaddr_in6 *ip6;
266

  
267
	SLIST_FOREACH(jis, &pr->pr_ips, entries) {
268
		switch (jis->ip.ss_family) {
269
		case AF_INET:
270
			ip4 = (struct sockaddr_in *)&jis->ip;
271
			if ((ntohl(ip4->sin_addr.s_addr) >> IN_CLASSA_NSHIFT) ==
272
			    IN_LOOPBACKNET) {
273
				/* loopback address */
274
				if (pr->local_ip4 == NULL)
275
					pr->local_ip4 = ip4;
276
			} else {
277
				/* public address */
278
				if (pr->nonlocal_ip4 == NULL)
279
					pr->nonlocal_ip4 = ip4;
280
			}
281
			break;
282

  
283
		case AF_INET6:
284
			ip6 = (struct sockaddr_in6 *)&jis->ip;
285
			if (IN6_IS_ADDR_LOOPBACK(&ip6->sin6_addr)) {
286
				/* loopback address */
287
				if (pr->local_ip6 == NULL)
288
					pr->local_ip6 = ip6;
289
			} else {
290
				/* public address */
291
				if (pr->nonlocal_ip6 == NULL)
292
					pr->nonlocal_ip6 = ip6;
293
			}
294
			break;
295
		}
296
	}
297
}
298

  
258 299
/* 
259 300
 * Changes INADDR_LOOPBACK for a valid jail address.
260 301
 * ip is in network byte order.
......
284 325
	    ip4->sin_addr.s_addr == htonl(INADDR_LOOPBACK)) ||
285 326
	    (ip->sa_family == AF_INET6 &&
286 327
	    IN6_IS_ADDR_LOOPBACK(&ip6->sin6_addr))) {
287
		if (!prison_get_local(pr, ip) && !prison_get_nonlocal(pr, ip))
328
		if (!prison_get_local(pr, ip->sa_family, ip) &&
329
		    !prison_get_nonlocal(pr, ip->sa_family, ip))
288 330
			return(0);
289 331
		else
290 332
			return(1);
......
309 351
	    ip4->sin_addr.s_addr == htonl(INADDR_LOOPBACK)) ||
310 352
	    (ip->sa_family == AF_INET6 &&
311 353
	    IN6_IS_ADDR_LOOPBACK(&ip6->sin6_addr))) {
312
		if (!prison_get_local(pr, ip) && !prison_get_nonlocal(pr, ip))
354
		if (!prison_get_local(pr, ip->sa_family, ip) &&
355
		    !prison_get_nonlocal(pr, ip->sa_family, ip))
313 356
			return(0);
314 357
		else
315 358
			return(1);
......
319 362

  
320 363
/*
321 364
 * Prison get non loopback ip:
322
 * Put on *ip the first IP address that is not a loopback address.
323
 * af is the address family of the ip we want (AF_INET|AF_INET6).
365
 * - af is the address family of the ip we want (AF_INET|AF_INET6).
366
 * - If ip != NULL, put the first IP address that is not a loopback address
367
 *   into *ip.
368
 *
324 369
 * ip is in network by order and we don't touch it unless we find a valid ip.
325
 * Return 1 if we've found a non loopback ip, else return 0.
370
 * No matter if ip == NULL or not, we return either a valid struct sockaddr *,
371
 * or NULL.  This struct may not be modified.
326 372
 */
327
int
328
prison_get_nonlocal(struct prison *pr, struct sockaddr *ip)
373
struct sockaddr *
374
prison_get_nonlocal(struct prison *pr, sa_family_t af, struct sockaddr *ip)
329 375
{
330
	struct jail_ip_storage *jis;
331
	struct sockaddr_in *jip4, *ip4;
332
	struct sockaddr_in6 *jip6, *ip6;
376
	struct sockaddr_in *ip4 = (struct sockaddr_in *)ip;
377
	struct sockaddr_in6 *ip6 = (struct sockaddr_in6 *)ip;
333 378

  
334
	ip4 = (struct sockaddr_in *)ip;
335
	ip6 = (struct sockaddr_in6 *)ip;
336 379
	/* Check if it is cached */
337
	switch(ip->sa_family) {
338
		case AF_INET:
339
			/* -1 Means that we don't have any address */
340
			if (pr->nonlocal_ip4 == (struct sockaddr_storage *)-1)
341
				return(0);
342
			if (pr->nonlocal_ip4 != NULL) {
343
				jip4 = (struct sockaddr_in *) pr->nonlocal_ip4;
344
				ip4->sin_addr.s_addr = jip4->sin_addr.s_addr;
345
			}
346
		break;
347
		case AF_INET6:
348
			/* -1 Means that we don't have any address */
349
			if (pr->nonlocal_ip6 == (struct sockaddr_storage *)-1)
350
				return(0);
351
			if (pr->nonlocal_ip6 != NULL) {
352
				jip6 = (struct sockaddr_in6 *) pr->nonlocal_ip6;
353
				ip6->sin6_addr = jip6->sin6_addr;
354
			}
355
		break;
356
	};
357
	SLIST_FOREACH(jis, &pr->pr_ips, entries) {
358
		switch (ip->sa_family) {
359
		case AF_INET:
360
			jip4 = (struct sockaddr_in *) &jis->ip;
361
			if (jip4->sin_family == AF_INET &&
362
    ((ntohl(jip4->sin_addr.s_addr) >> IN_CLASSA_NSHIFT) != IN_LOOPBACKNET)) {
363
				pr->nonlocal_ip4 = &jis->ip;
364
				ip4->sin_addr.s_addr = jip4->sin_addr.s_addr;
365
				return(1);
366
			}
367
			break;
368
		case AF_INET6:
369
			jip6 = (struct sockaddr_in6 *) &jis->ip;
370
			if ( jip6->sin6_family == AF_INET6 &&
371
			     !IN6_IS_ADDR_LOOPBACK(&jip6->sin6_addr)) {
372
				pr->nonlocal_ip6 = &jis->ip;
373
				ip6->sin6_addr = jip6->sin6_addr;
374
				return(1);
375
			}
376
			break;
377
		}
380
	switch(af) {
381
	case AF_INET:
382
		if (ip4 != NULL && pr->nonlocal_ip4 != NULL)
383
			ip4->sin_addr.s_addr = pr->nonlocal_ip4->sin_addr.s_addr;
384
		return (struct sockaddr *)pr->nonlocal_ip4;
385

  
386
	case AF_INET6:
387
		if (ip6 != NULL && pr->nonlocal_ip6 != NULL)
388
			ip6->sin6_addr = pr->nonlocal_ip6->sin6_addr;
389
		return (struct sockaddr *)pr->nonlocal_ip6;
378 390
	}
379
	if (ip->sa_family == AF_INET)
380
		pr->nonlocal_ip4 = (struct sockaddr_storage *)-1;
381
	else
382
		pr->nonlocal_ip6 = (struct sockaddr_storage *)-1;
383
	return(0);
391

  
392
	/* NOTREACHED */
393
	return NULL;
384 394
}
385 395

  
386 396
/*
387 397
 * Prison get loopback ip.
388
 * Put on *ip the first loopback IP address.
389
 * af is the address family of the ip we want (AF_INET|PF_INET).
390
 * *ip is in network by order and we don't touch it unless we find a valid ip.
391
 * return 1 if we've found a loopback ip, else return 0.
398
 * - af is the address family of the ip we want (AF_INET|AF_INET6).
399
 * - If ip != NULL, put the first IP address that is not a loopback address
400
 *   into *ip.
401
 *
402
 * ip is in network by order and we don't touch it unless we find a valid ip.
403
 * No matter if ip == NULL or not, we return either a valid struct sockaddr *,
404
 * or NULL.  This struct may not be modified.
392 405
 */
393
int
394
prison_get_local(struct prison *pr, struct sockaddr *ip)
406
struct sockaddr *
407
prison_get_local(struct prison *pr, sa_family_t af, struct sockaddr *ip)
395 408
{
396
	struct jail_ip_storage *jis;
397
	struct sockaddr_in *jip4, *ip4;
398
	struct sockaddr_in6 *jip6, *ip6;
409
	struct sockaddr_in *ip4 = (struct sockaddr_in *)ip;
410
	struct sockaddr_in6 *ip6 = (struct sockaddr_in6 *)ip;
399 411

  
400
	ip4 = (struct sockaddr_in *)ip;
401
	ip6 = (struct sockaddr_in6 *)ip;
402 412
	/* Check if it is cached */
403
	switch(ip->sa_family) {
404
		case AF_INET:
405
			/* -1 Means that we don't have any address */
406
			if (pr->local_ip4 == (struct sockaddr_storage *)-1)
407
				return(0);
408
			if (pr->local_ip4 != NULL) {
409
				jip4 = (struct sockaddr_in *) pr->local_ip4;
410
				ip4->sin_addr.s_addr = jip4->sin_addr.s_addr;
411
			}
412
		break;
413
		case AF_INET6:
414
			/* -1 Means that we don't have any address */
415
			if (pr->local_ip6 == (struct sockaddr_storage *)-1)
416
				return(0);
417
			if (pr->local_ip6 != NULL) {
418
				jip6 = (struct sockaddr_in6 *) pr->local_ip6;
419
				ip6->sin6_addr = jip6->sin6_addr;
420
			}
421
		break;
422
	};
423
	SLIST_FOREACH(jis, &pr->pr_ips, entries) {
424
		switch(ip->sa_family) {
425
		case AF_INET:
426
			jip4 = (struct sockaddr_in *) &jis->ip;
427
			if (jip4->sin_family == AF_INET &&
428
			    ((ntohl(jip4->sin_addr.s_addr) >> IN_CLASSA_NSHIFT)
429
			    == IN_LOOPBACKNET)) {
430
				pr->local_ip4 = &jis->ip;
431
				ip4->sin_addr.s_addr = jip4->sin_addr.s_addr;
432
				return(1);
433
			}
434
			break;
435
		case AF_INET6:
436
			jip6 = (struct sockaddr_in6 *) &jis->ip;
437
			if (jip6->sin6_family == AF_INET6 &&
438
			     IN6_IS_ADDR_LOOPBACK(&jip6->sin6_addr)) {
439
				pr->local_ip6 = &jis->ip;
440
				ip6->sin6_addr = jip6->sin6_addr;
441
				return(1);
442
			}
443
			break;
444
		}
413
	switch(af) {
414
	case AF_INET:
415
		if (ip4 != NULL && pr->local_ip4 != NULL)
416
			ip4->sin_addr.s_addr = pr->local_ip4->sin_addr.s_addr;
417
		return (struct sockaddr *)pr->local_ip4;
418

  
419
	case AF_INET6:
420
		if (ip6 != NULL && pr->local_ip6 != NULL)
421
			ip6->sin6_addr = pr->local_ip6->sin6_addr;
422
		return (struct sockaddr *)pr->local_ip6;
445 423
	}
446
	if (ip->sa_family == AF_INET)
447
		pr->local_ip4 = (struct sockaddr_storage *)-1;
448
	else
449
		pr->local_ip6 = (struct sockaddr_storage *)-1;
450
	return(0);
424

  
425
	/* NOTREACHED */
426
	return NULL;
451 427
}
452 428

  
453 429
/* Check if the IP is among ours, if it is return 1, else 0 */
netinet/in_pcb.c 17 Jan 2007 12:58:07 -0000
457 457
	struct in_ifaddr *ia;
458 458
	struct ucred *cred = NULL;
459 459
	struct sockaddr_in *sin = (struct sockaddr_in *)nam;
460
	struct sockaddr_in jsin;
460
	struct sockaddr *jsin;
461 461
	int jailed = 0;
462 462

  
463 463
	if (nam->sa_len != sizeof *sin)
......
579 579
		 * Don't do pcblookup call here; return interface in plocal_sin
580 580
		 * and exit to caller, that will do the lookup.
581 581
		 */
582
		if (jailed) {
583
			jsin.sin_family = AF_INET;
584
			if (!prison_get_nonlocal(cred->cr_prison,
585
			    sintosa(&jsin)) &&
586
			    !prison_get_local(cred->cr_prison, sintosa(&jsin)))
587
					/* IPv6 only Jail */
588
					return (EADDRNOTAVAIL);
589
			*plocal_sin = &jsin;
582
		if (ia == NULL && jailed) {
583
			if ((jsin = prison_get_nonlocal(cred->cr_prison, AF_INET, NULL)) != NULL ||
584
			    (jsin = prison_get_local(cred->cr_prison, AF_INET, NULL)) != NULL)
585
				*plocal_sin = satosin(jsin);
586
			else
587
				/* IPv6 only Jail */
588
				return (EADDRNOTAVAIL);
590 589
		} else {
591 590
			*plocal_sin = &ia->ia_addr;
592 591
		}